+ chan = Channel_Search(channame);
+ if (!chan && Conf_PredefChannelsOnly) {
+ /* channel must be created, but forbidden by config */
+ IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG,
+ Client_ID(Client), channame);
+ goto join_next;
+ }
+
+ /* Local client? */
+ if (Client_Type(Client) == CLIENT_USER) {
+ if (chan) {
+ /* Already existing channel: already member? */
+ if (Channel_IsMemberOf(chan, Client))
+ goto join_next;
+ }
+
+ /* Test if the user has reached the channel limit */
+ if ((Conf_MaxJoins > 0) &&
+ (Channel_CountForUser(Client) >= Conf_MaxJoins)) {
+ if (!IRC_WriteStrClient(Client,
+ ERR_TOOMANYCHANNELS_MSG,
+ Client_ID(Client), channame))
+ return DISCONNECTED;
+ goto join_next;
+ }
+
+ if (chan) {
+ /* Already existing channel: check if the
+ * client is allowed to join */
+ if (!join_allowed(Client, chan, channame, key))
+ goto join_next;
+ } else {
+ /* New channel: first user will become channel
+ * operator unless this is a modeless channel */
+ if (*channame != '+')
+ flags = "o";
+ }
+
+ /* Local client: update idle time */
+ Conn_UpdateIdle(Client_Conn(Client));
+ } else {
+ /* Remote server: we don't need to know whether the
+ * client is invited or not, but we have to make sure
+ * that the "one shot" entries (generated by INVITE
+ * commands) in this list become deleted when a user
+ * joins a channel this way. */
+ if (chan)
+ (void)Lists_Check(Channel_GetListInvites(chan),
+ target);
+ }
+
+ /* Join channel (and create channel if it doesn't exist) */
+ if (!Channel_Join(target, channame))
+ goto join_next;
+
+ if (!chan) { /* channel is new; it has been created above */
+ chan = Channel_Search(channame);
+ assert(chan != NULL);
+ if (Channel_IsModeless(chan)) {
+ Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */
+ Channel_ModeAdd(chan, 'n'); /* no external msgs */
+ }
+ }
+ assert(chan != NULL);
+
+ join_set_channelmodes(chan, target, flags);
+
+ join_forward(Client, target, chan, channame);
+
+ if (!join_send_topic(Client, target, chan, channame))
+ break; /* write error */
+
+ join_next:
+ /* next channel? */
+ channame = strtok_r(NULL, ",", &lastchan);
+ if (channame && key)
+ key = strtok_r(NULL, ",", &lastkey);