static void ms_join(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *name; int new_ts; if (!(source_p->user)) return; name = parv[1]; if ((name[0] == '0') && (name[1] == '\0')) { do_join_0(client_p, source_p); } else { if(parc > 2) { new_ts = atoi(parv[2]); } else { ts_warn("User on %s remotely JOINing new channel with no TS", source_p->user->server); } } }
/* Join a channel, ignoring forwards, +ib, etc. It notifes source_p of any errors joining * NB: this assumes a local user. */ void user_join_override(struct Client * client_p, struct Client * source_p, struct Client * target_p, const char * channels) { static char jbuf[BUFSIZE]; struct ConfItem *aconf; struct Channel *chptr = NULL; char *name; const char *modes; char *p = NULL; int flags; char *chanlist; jbuf[0] = '\0'; if(channels == NULL) return; /* rebuild the list of channels theyre supposed to be joining. */ chanlist = LOCAL_COPY(channels); for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { /* check the length and name of channel is ok */ if(!check_channel_name_loc(target_p, name) || (strlen(name) > LOC_CHANNELLEN)) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), (unsigned char *) name); continue; } /* join 0 parts all channels */ if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist) { (void) strcpy(jbuf, "0"); continue; } /* check it begins with # or & */ else if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); continue; } /* see if its resv'd */ if(!IsExemptResv(target_p) && (aconf = hash_find_resv(name))) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), name); /* dont update tracking for jupe exempt users, these * are likely to be spamtrap leaves */ if(IsExemptJupe(source_p)) aconf->port--; continue; } if(splitmode && !IsOper(target_p) && (*name != '&') && ConfigChannel.no_join_on_split) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); continue; } if(*jbuf) (void) strcat(jbuf, ","); (void) rb_strlcat(jbuf, name, sizeof(jbuf)); } for(name = rb_strtok_r(jbuf, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { /* JOIN 0 simply parts all channels the user is in */ if(*name == '0' && !atoi(name)) { if(target_p->user->channel.head == NULL) continue; do_join_0(&me, target_p); continue; } if((chptr = find_channel(name)) != NULL) { if(IsMember(target_p, chptr)) { /* debugging is fun... */ sendto_one_notice(source_p, ":*** Notice -- %s is already in %s", target_p->name, chptr->chname); return; } add_user_to_channel(chptr, target_p, CHFL_PEON); if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time) { chptr->join_count = 0; chptr->join_delta = rb_current_time(); } chptr->join_count++; sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); sendto_server(target_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", get_id(target_p, client_p), (long) chptr->channelts, chptr->chname); del_invite(chptr, target_p); if(chptr->topic != NULL) { sendto_one(target_p, form_str(RPL_TOPIC), me.name, target_p->name, chptr->chname, chptr->topic); sendto_one(target_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } channel_member_names(chptr, target_p, 1); } else { hook_data_channel_activity hook_info; char statusmodes[5] = ""; if(!check_channel_name(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) name); return; } /* channel name must begin with & or # */ if(!IsChannelName(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) name); return; } /* name can't be longer than CHANNELLEN */ if(strlen(name) > CHANNELLEN) { sendto_one_notice(source_p, ":Channel name is too long"); return; } chptr = get_or_create_channel(target_p, name, NULL); flags = CHFL_CHANOP; add_user_to_channel(chptr, target_p, flags); if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time) { chptr->join_count = 0; chptr->join_delta = rb_current_time(); } chptr->join_count++; sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; modes = channel_modes(chptr, &me); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s", me.name, chptr->chname, modes); strcat(statusmodes, "@"); sendto_server(target_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s %s :%s%s", me.id, (long) chptr->channelts, chptr->chname, modes, statusmodes, get_id(target_p, client_p)); target_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, target_p, 1); /* Call channel join hooks */ hook_info.client = source_p; hook_info.chptr = chptr; hook_info.key = chptr->mode.key; call_hook(h_channel_join, &hook_info); /* we do this to let the oper know that a channel was created, this will be * seen from the server handling the command instead of the server that * the oper is on. */ sendto_one_notice(source_p, ":*** Notice -- Creating channel %s", chptr->chname); } } return; }
/* * m_join * parv[0] = sender prefix * parv[1] = channel * parv[2] = channel password (key) */ static void m_join(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; char *name, *key = NULL; int i, flags = 0; char *p = NULL, *p2 = NULL; int successful_join_count = 0; /* Number of channels successfully joined */ if (*parv[1] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "JOIN"); return; } if (parc > 2) { key = strtoken(&p2, parv[2], ","); } for (name = strtoken(&p, parv[1], ","); name; key = (key) ? strtoken(&p2, NULL, ",") : NULL, name = strtoken(&p, NULL, ",")) { if(!check_channel_name(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char*)name); continue; } /* ** JOIN 0 sends out a part for all channels a user ** has joined. ** ** this should be either disabled or selectable in ** config file .. it's abused a lot more than it's ** used these days :/ --is */ if (*name == '0' && !atoi(name)) { if (source_p->user->channel.head == NULL) continue; do_join_0(&me,source_p); continue; } /* check it begins with # or & */ else if(!IsChannelName(name)) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); continue; } if(ConfigServerHide.disable_local_channels && (*name == '&')) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); continue; } /* check the length */ if (strlen(name) > CHANNELLEN) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, name); continue; } /* see if its resv'd */ if(find_channel_resv(name) && (!IsOper(source_p) || !ConfigChannel.no_oper_resvs)) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); sendto_realops_flags(UMODE_SPY, L_ALL, "User %s (%s@%s) is attempting to join locally juped channel %s", source_p->name, source_p->username, source_p->host, name); continue; } /* look for the channel */ if((chptr = hash_find_channel(name)) != NULL) { if(IsMember(source_p, chptr)) return; if(splitmode && !IsOper(source_p) && (*name != '&') && ConfigChannel.no_join_on_split) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); continue; } if (chptr->users == 0) flags = CHFL_CHANOP; else flags = 0; } else { if(splitmode && !IsOper(source_p) && (*name != '&') && (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split)) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); continue; } flags = CHFL_CHANOP; } if ((source_p->user->joined >= ConfigChannel.max_chans_per_user) && (!IsOper(source_p) || (source_p->user->joined >= ConfigChannel.max_chans_per_user*3))) { sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS), me.name, parv[0], name); if(successful_join_count) source_p->localClient->last_join_time = CurrentTime; return; } if(flags == 0) /* if channel doesn't exist, don't penalize */ successful_join_count++; if(chptr == NULL) /* If I already have a chptr, no point doing this */ { chptr = get_or_create_channel(source_p, name, NULL); } if(chptr == NULL) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, parv[0], name); if(successful_join_count > 0) successful_join_count--; continue; } if (!IsOper(source_p)) check_spambot_warning(source_p, name); /* can_join checks for +i key, bans etc */ if ( (i = can_join(source_p, chptr, key)) ) { sendto_one(source_p, form_str(i), me.name, parv[0], name); if(successful_join_count > 0) successful_join_count--; continue; } /* add the user to the channel */ add_user_to_channel(chptr, source_p, flags); /* we send the user their join here, because we could have to * send a mode out next. */ sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", source_p->name, source_p->username, source_p->host, chptr->chname); /* if theyre joining opped (ie, new chan or joining one thats * persisting) then set timestamp to current, set +nt and * broadcast the sjoin with its old modes, or +nt. */ if (flags & CHFL_CHANOP) { char mbuf[MODEBUFLEN]; char pbuf[MODEBUFLEN]; chptr->channelts = CurrentTime; chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s +nt", me.name, chptr->chname); if(*chptr->chname == '#') { channel_modes(chptr, source_p, mbuf, pbuf); strlcat(mbuf, " ", sizeof(mbuf)); if(pbuf[0] != '\0') strlcat(mbuf, pbuf, sizeof(mbuf)); /* note: mbuf here will have a trailing space. we add one above, * and channel_modes() will leave a trailing space on pbuf if * its used --fl */ sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s %s:@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, mbuf, parv[0]); } /* drop our +beI modes */ free_channel_list(&chptr->banlist); free_channel_list(&chptr->exceptlist); free_channel_list(&chptr->invexlist); } else { sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :%s", me.name, (unsigned long) chptr->channelts, chptr->chname, parv[0]); } del_invite(chptr, source_p); if (chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, parv[0], chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], chptr->chname, chptr->topic_info, chptr->topic_time); } channel_member_names(source_p, chptr, chptr->chname, 1); if(successful_join_count) source_p->localClient->last_join_time = CurrentTime; } }
/* Join a channel, ignoring forwards, +ib, etc. It notifes source_p of any errors joining * NB: this assumes a local user. */ void user_join_override(struct Client * client_p, struct Client * source_p, struct Client * target_p, const char * channels) { static char jbuf[BUFSIZE]; struct Channel *chptr = NULL; char *name; const char *modes; char *p = NULL; int flags; char *chanlist; jbuf[0] = '\0'; if(channels == NULL) return; /* rebuild the list of channels theyre supposed to be joining. * this code has a side effect of losing keys, but.. */ chanlist = LOCAL_COPY(channels); for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { /* check the length and name of channel is ok */ if(!check_channel_name_loc(target_p, name) || (strlen(name) > LOC_CHANNELLEN)) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), (unsigned char *) name); continue; } /* join 0 parts all channels */ if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist) { (void) strcpy(jbuf, "0"); continue; } /* check it begins with # or &, and local chans are disabled */ else if(!IsChannelName(name) || (!ConfigChannel.use_local_channels && name[0] == '&')) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); continue; } if(*jbuf) (void) strcat(jbuf, ","); (void) rb_strlcat(jbuf, name, sizeof(jbuf)); } for(name = rb_strtok_r(jbuf, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { /* JOIN 0 simply parts all channels the user is in */ if(*name == '0' && !atoi(name)) { if(target_p->user->channel.head == NULL) continue; do_join_0(&me, target_p); continue; } if((chptr = find_channel(name)) != NULL) { if(IsMember(target_p, chptr)) { /* debugging is fun... */ sendto_one_notice(source_p, ":*** Notice -- %s is already in %s", target_p->name, chptr->chname); return; } add_user_to_channel(chptr, target_p, CHFL_PEON); if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time) { chptr->join_count = 0; chptr->join_delta = rb_current_time(); } chptr->join_count++; sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); sendto_server(target_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", get_id(target_p, client_p), (long) chptr->channelts, chptr->chname); del_invite(chptr, target_p); if(chptr->topic != NULL) { sendto_one(target_p, form_str(RPL_TOPIC), me.name, target_p->name, chptr->chname, chptr->topic); sendto_one(target_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } channel_member_names(chptr, target_p, 1); } else { if(!check_channel_name(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) name); return; } /* channel name must begin with & or # */ if(!IsChannelName(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) name); return; } /* name can't be longer than CHANNELLEN */ if(strlen(name) > CHANNELLEN) { sendto_one_notice(source_p, ":Channel name is too long"); return; } chptr = get_or_create_channel(target_p, name, NULL); flags = CHFL_CHANOP; if(ConfigChannel.founder_on_channel_create && ConfigChannel.use_founder) flags |= CHFL_FOUNDER; if(ConfigChannel.admin_on_channel_create && ConfigChannel.use_admin) flags |= CHFL_ADMIN; add_user_to_channel(chptr, target_p, flags); if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time) { chptr->join_count = 0; chptr->join_delta = rb_current_time(); } chptr->join_count++; sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); /* autochanmodes stuff */ if(ConfigChannel.autochanmodes) { char * ch; for(ch = ConfigChannel.autochanmodes; *ch != '\0'; ch++) { chptr->mode.mode |= chmode_table[(unsigned int)*ch].mode_type; } } else { chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; } modes = channel_modes(chptr, &me); sendto_channel_local(ONLY_HALFOPSANDUP, chptr, ":%s MODE %s %s", me.name, chptr->chname, modes); sendto_server(target_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s %s :%s%s", me.id, (long) chptr->channelts, chptr->chname, modes, flags & CHFL_FOUNDER ? "~@" : "@", get_id(target_p, client_p)); target_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, target_p, 1); /* we do this to let the oper know that a channel was created, this will be * seen from the server handling the command instead of the server that * the oper is on. */ sendto_one_notice(source_p, ":*** Notice -- Creating channel %s", chptr->chname); } } return; }