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.

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