docs: def join_(self, channel, key=None, process_only=False):
          """
          Joins a channel.
          Returns a tuple of information regarding the channel.
          Channel Information:
          * [0] - A tuple containing /NAMES.
          * [1] - Channel topic.
          * [2] - Tuple containing information regarding of whom set the topic.
          * [3] - Time object about when the topic was set.
          Required arguments:
          * channel - The channel to join.
          Optional arguments:
          * key=None - Channel key.
          * process_only=False - Only process a join, don't request one.
          """
  
          with self.lock:
              topic = ''
              users = []
              set_by = ''
              time_set = ''
              self.is_in_channel(channel, False)
              if not process_only:
                  if key:
                      self.send('JOIN %s %s' % (channel, key))
                  else:
                      self.send('JOIN %s' % channel)
  
              while self.readable(4):
                  msg = self._recv(rm_colon=True, \
                                   expected_replies=('332', '333', \
                                                     '353', 'JOIN', '366'))
  
                  if msg[0] == '332':
                      topic = msg[2].split(':', 1)[1]
                  elif msg[0] == '333':
                      set_by, time_set = msg[2].split(' ', 3)[1:]
                      if not self.UTC:
                          time_set = self._m_time.localtime(int(time_set))
                      else:
                          time_set = self._m_time.gmtime(int(time_set))
                      set_by = self._from_(set_by)
  
                  elif msg[0] == '353':
                      users.extend(msg[2].split(':', 1)[1].split())
                  elif msg[0] == 'JOIN':
                      channel = msg[1]
                      self.channels[channel] = {}
                      if not self.hide_called_events:
                          self.stepback(append=True)
                  elif msg[0] == '366':
                      break
              self.channels[channel] = {}
              self.channels[channel]['USERS'] = {}
              for user in users:
                  prefix = ''
                  if user[0] in self.priv_types:
                      prefix = user[0]
                      user = user[1:]
                  if prefix == '~':
                      self.channels[channel]['USERS'][user] = \
                      ['~', '', '', '', '']
                  elif prefix == '&':
                      self.channels[channel]['USERS'][user] = \
                      ['', '&', '', '', '']
                  elif prefix == '@':
                      self.channels[channel]['USERS'][user] = \
                      ['', '', '@', '', '']
                  elif prefix == '%':
                      self.channels[channel]['USERS'][user] = \
                      ['', '', '', '%', '']
                  elif prefix == '+':
                      self.channels[channel]['USERS'][user] = \
                      ['', '', '', '', '+']
                  else:
                      self.channels[channel]['USERS'][user] = \
                      ['', '', '', '', '']
          return users, topic, set_by, time_set