void kick_list(struct Client *client_p, struct Client *source_p, struct Channel *chptr, dlink_list *list,char *chname) { struct Client *who; dlink_node *m; dlink_node *next_m; for (m = list->head; m; m = next_m) { next_m = m->next; who = m->data; sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :CLEARCHAN", source_p->name, chname, who->name); sendto_server(NULL, source_p, chptr, NOCAPS, NOCAPS, LL_ICLIENT, ":%s KICK %s %s :CLEARCHAN", source_p->name, chname, who->name); remove_user_from_channel(chptr, who); } /* Join the user themselves to the channel down here, so they dont see a nicklist * or people being kicked */ sendto_one(source_p, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chname); channel_member_names(source_p, chptr, chname, 1); }
/*! \brief NAMES command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = channel name */ static int m_names(struct Client *source_p, int parc, char *parv[]) { const char *const para = parc > 1 ? parv[1] : NULL; if (!EmptyString(para)) { struct Channel *chptr = hash_find_channel(para); if (chptr) channel_member_names(source_p, chptr, true); else sendto_one_numeric(source_p, &me, RPL_ENDOFNAMES, para); } else sendto_one_numeric(source_p, &me, RPL_ENDOFNAMES, "*"); return 0; }
/* mo_ojoin() * parv[0] = sender prefix * parv[1] = channels separated by commas (#ifdef OJOIN_MULTIJOIN) */ static void mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr; char *name = parv[1], modeletter; #ifdef OJOIN_MULTIJOIN char *t; #endif short move_me = 1; unsigned int tmp_flags; /* admins only */ if (!IsAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVILEGES), me.name, source_p->name); return; } #ifdef OJOIN_MULTIJOIN for (name = strtoken (&t, name, ","); name; name = strtoken (&t, NULL, ",")) { #endif move_me = 1; switch (*name) { #ifndef DISABLE_CHAN_OWNER case '!': tmp_flags = CHFL_CHANOWNER; modeletter = 'u'; name++; break; #endif case '@': tmp_flags = CHFL_CHANOP; modeletter = 'o'; name++; break; case '+': tmp_flags = CHFL_VOICE; modeletter = 'v'; name++; break; case '%': tmp_flags = CHFL_HALFOP; modeletter = 'h'; name++; break; case '#': case '&': tmp_flags = 0; modeletter = '\0'; break; /* We're not joining a channel, or we don't know the mode, * what ARE we joining? */ default: sendto_one (source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); #ifdef OJOIN_MULTIJOIN continue; #else return; #endif } /* Error checking here */ if ((chptr = hash_find_channel(name)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); } else if (IsMember(source_p, chptr)) { sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN", me.name, source_p->name, name); } else { if (move_me == 1) name--; add_user_to_channel(chptr, source_p, tmp_flags); if (chptr->chname[0] == '#') { sendto_server(client_p, CAP_TS6, NOCAPS, ":%s SJOIN %lu %s + :%c%s", me.id, (unsigned long)chptr->channelts, chptr->chname, (modeletter != '\0') ? *name : ' ', source_p->id); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s SJOIN %lu %s + :%c%s", me.name, (unsigned long)chptr->channelts, chptr->chname, (modeletter != '\0') ? *name : ' ', source_p->name); } sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, GET_CLIENT_HOST(source_p), chptr->chname); if (modeletter != '\0') { sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s", me.name, chptr->chname, modeletter, source_p->name); } /* send the topic... */ if (chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } source_p->localClient->last_join_time = CurrentTime; channel_member_names(source_p, chptr, 1); } #ifdef OJOIN_MULTIJOIN } #endif }
/* * m_lljoin * parv[0] = sender prefix * parv[1] = channel * parv[2] = nick ("!nick" == cjoin) * parv[3] = vchan/key (optional) * parv[4] = key (optional) * * If a lljoin is received, from our uplink, join * the requested client to the given channel, or ignore it * if there is an error. * * Ok, the way this works. Leaf client tries to join a channel, * it doesn't exist so the join does a cburst request on behalf of the * client, and aborts that join. The cburst sjoin's the channel if it * exists on the hub, and sends back an LLJOIN to the leaf. Thats where * this is now.. * */ static void ms_lljoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *chname = NULL; char *nick = NULL; char *key = NULL; char *vkey = NULL; int flags; int i; struct Client *target_p; struct Channel *chptr, *vchan_chptr, *root_vchan; #ifdef VCHANS int cjoin = 0; int vc_ts; char *pvc = NULL; #endif if(uplink && !IsCapable(uplink,CAP_LL)) { sendto_realops_flags(FLAGS_ALL, L_ALL, "*** LLJOIN requested from non LL server %s", client_p->name); return; } chname = parv[1]; if(chname == NULL) return; nick = parv[2]; if(nick == NULL) return; #ifdef VCHANS if (nick[0] == '!') { cjoin = 1; nick++; } if(parc > 4) { key = parv[4]; vkey = parv[3]; } #endif else if(parc >3) { key = vkey = parv[3]; } flags = 0; target_p = find_client(nick); if( !target_p || !target_p->user ) return; if( !MyClient(target_p) ) return; chptr = hash_find_channel(chname); #ifdef VCHANS if (cjoin) { if(!chptr) /* Uhm, bad! */ { sendto_realops_flags(FLAGS_ALL, L_ALL, "LLJOIN %s %s called by %s, but root chan doesn't exist!", chname, nick, client_p->name); return; } flags = CHFL_CHANOP; if(! (vchan_chptr = cjoin_channel(chptr, target_p, chname))) return; root_vchan = chptr; chptr = vchan_chptr; } else #endif { #ifdef VCHANS if (chptr) { vchan_chptr = select_vchan(chptr, target_p, vkey, chname); } else #endif { chptr = vchan_chptr = get_or_create_channel(target_p, chname, NULL); flags = CHFL_CHANOP; } #ifdef VCHANS if (vchan_chptr != chptr) { root_vchan = chptr; chptr = vchan_chptr; } else #endif root_vchan = chptr; if(!chptr || !root_vchan) return; if (chptr->users == 0) flags = CHFL_CHANOP; else flags = 0; /* XXX in m_join.c :( */ /* check_spambot_warning(target_p, chname); */ /* They _could_ join a channel twice due to lag */ if(chptr) { if (IsMember(target_p, chptr)) /* already a member, ignore this */ return; } else { sendto_one(target_p, form_str(ERR_UNAVAILRESOURCE), me.name, nick, root_vchan->chname); return; } if( (i = can_join(target_p, chptr, key)) ) { sendto_one(target_p, form_str(i), me.name, nick, root_vchan->chname); return; } } if ((target_p->user->joined >= ConfigChannel.max_chans_per_user) && (!IsOper(target_p) || (target_p->user->joined >= ConfigChannel.max_chans_per_user*3))) { sendto_one(target_p, form_str(ERR_TOOMANYCHANNELS), me.name, nick, root_vchan->chname ); return; } if(flags == CHFL_CHANOP) { chptr->channelts = CurrentTime; /* * XXX - this is a rather ugly hack. * * Unfortunately, there's no way to pass * the fact that it is a vchan through SJOIN... */ /* Prevent users creating a fake vchan */ #ifdef VCHANS if (chname[0] == '#' && chname[1] == '#') { if ((pvc = strrchr(chname+3, '_'))) { /* * OK, name matches possible vchan: * ##channel_blah */ pvc++; /* point pvc after last _ */ vc_ts = atol(pvc); /* * if blah is the same as the TS, up the TS * by one, to prevent this channel being * seen as a vchan */ if (vc_ts == CurrentTime) chptr->channelts++; } } #endif sendto_one(uplink, ":%s SJOIN %lu %s + :@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); } /* a user can create a channel with halfops..? */ #if 0 else if ((flags == CHFL_HALFOP) && (IsCapable(uplink, CAP_HOPS))) { sendto_one(uplink, ":%s SJOIN %lu %s + :%%%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); } #endif else { sendto_one(uplink, ":%s SJOIN %lu %s + :%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); } add_user_to_channel(chptr, target_p, flags); #ifdef VCHANS if ( chptr != root_vchan ) add_vchan_to_client_cache(target_p,root_vchan,chptr); #endif sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, root_vchan->chname); if( flags & CHFL_CHANOP ) { chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ALL_MEMBERS,chptr, ":%s MODE %s +nt", me.name, root_vchan->chname); sendto_one(uplink, ":%s MODE %s +nt", me.name, chptr->chname); } channel_member_names(target_p, chptr, chname, 1); }
/* ** mo_ojoin ** parv[1] = channel */ static int mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+' || *parv[1] == '!' || *parv[1] == '~') { parv[1]++; move_me = 1; } else { sendto_one_notice(source_p, ":Unrecognized op prefix '%c'", *parv[1]); return 0; } if((chptr = find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } if(IsMember(source_p, chptr)) { sendto_one_notice(source_p, ":Please part %s before using OJOIN", parv[1]); return 0; } if(move_me == 1) parv[1]--; /* only sends stuff for #channels remotely */ if(*parv[1] == '!') { if(!ConfigChannel.use_admin) { sendto_one_notice(source_p, ":This server's configuration file does not support admin prefix"); return 0; } add_user_to_channel(chptr, source_p, CHFL_ADMIN); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :!%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :@%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '%') { if(!ConfigChannel.use_halfop) { sendto_one_notice(source_p, ":This server's configuration file does not support halfop prefix"); return 0; } add_user_to_channel(chptr, source_p, CHFL_HALFOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :%s%s", me.id, (long) chptr->channelts, chptr->chname, "%", source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :+%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '~') { if(!ConfigChannel.use_founder) { sendto_one_notice(source_p, ":This server's configuration file does not support founder prefix"); return 0; } add_user_to_channel(chptr, source_p, CHFL_FOUNDER); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :~%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +u %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", source_p->id, (long) chptr->channelts, chptr->chname); send_channel_join(chptr, source_p); } /* send the topic... */ if(chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } source_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, source_p, 1); sendto_realops_snomask(SNO_GENERAL, L_ALL, "OJOIN called for %s by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OJOIN called for %s by %s", parv[1], get_oper_name(source_p)); return 0; }
/* * m_lljoin * parv[0] = sender prefix * parv[1] = channel * parv[2] = nick ("!nick" == cjoin) * parv[3] = key (optional) * * If a lljoin is received, from our uplink, join * the requested client to the given channel, or ignore it * if there is an error. * * Ok, the way this works. Leaf client tries to join a channel, * it doesn't exist so the join does a cburst request on behalf of the * client, and aborts that join. The cburst sjoin's the channel if it * exists on the hub, and sends back an LLJOIN to the leaf. Thats where * this is now.. * */ static void ms_lljoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *chname = NULL; char *nick = NULL; char *key = NULL; int flags; int i; struct Client *target_p; struct Channel *chptr; if (uplink && !IsCapable(uplink,CAP_LL)) { sendto_realops_flags(UMODE_ALL, L_ALL, "*** LLJOIN requested from non LL server %s", client_p->name); return; } chname = parv[1]; if(chname == NULL) return; nick = parv[2]; if(nick == NULL) return; if (parc >3) key = parv[3]; flags = 0; target_p = find_person(client_p, nick); if (!target_p) return; if (!MyClient(target_p)) return; if (!check_channel_name(chname, 0)) { sendto_gnotice_flags(UMODE_DEBUG, L_ALL, me.name, &me, NULL, "*** Too long or invalid channel name from %s: %s", target_p->name, chname); return; } chptr = make_channel(chname); flags = CHFL_CHANOP; if(!chptr) return; if (dlink_list_length(&chptr->members) == 0) flags = CHFL_CHANOP; else flags = 0; /* XXX in m_join.c :( */ /* check_spambot_warning(target_p, chname); */ /* They _could_ join a channel twice due to lag */ if(chptr) { if (IsMember(target_p, chptr)) /* already a member, ignore this */ return; } else { sendto_one(target_p, form_str(ERR_UNAVAILRESOURCE), me.name, nick, chptr->chname); return; } if ((i = can_join(target_p, chptr, key))) { sendto_one(target_p, form_str(i), me.name, nick, chptr->chname); return; } if ((dlink_list_length(&target_p->channel) >= ConfigChannel.max_chans_per_user) && (!IsOper(target_p) || (dlink_list_length(&target_p->channel) >= ConfigChannel.max_chans_per_user*3))) { sendto_one(target_p, form_str(ERR_TOOMANYCHANNELS), me.name, nick, chptr->chname ); return; } if (flags == CHFL_CHANOP) { chptr->channelts = CurrentTime; sendto_one(uplink, ":%s SJOIN %lu %s + :@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); } sendto_one(uplink, ":%s SJOIN %lu %s + :%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); add_user_to_channel(chptr, target_p, flags, YES); sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); if (flags & CHFL_CHANOP) { chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s MODE %s +nt", me.name, chptr->chname); sendto_one(uplink, ":%s MODE %s +nt", me.name, chptr->chname); } channel_member_names(target_p, chptr, 1); }
/* ** mo_ojoin ** parv[1] = channel */ static void mo_ojoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return; } if(*parv[1] == '@' || *parv[1] == '+') { parv[1]++; move_me = 1; } if((chptr = find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return; } if(IsMember(source_p, chptr)) { sendto_one_notice(source_p, ":Please part %s before using OJOIN", parv[1]); return; } if(move_me == 1) parv[1]--; sendto_wallops_flags(UMODE_WALLOP, &me, "OJOIN called for %s by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OJOIN called for %s by %s", parv[1], get_oper_name(source_p)); /* only sends stuff for #channels remotely */ sendto_server(NULL, chptr, NOCAPS, NOCAPS, ":%s WALLOPS :OJOIN called for %s by %s!%s@%s", me.name, parv[1], source_p->name, source_p->username, source_p->host); if(*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :@%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :+%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", source_p->id, (long) chptr->channelts, chptr->chname); send_channel_join(chptr, source_p); } /* send the topic... */ if(chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } source_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, source_p, 1); }
/* 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_forcejoin * parv[1] = user to force * parv[2] = channel to force them into */ static int mo_forcejoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; struct Channel *chptr; int type; char mode; char sjmode; char *newch; if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } if((hunt_server(client_p, source_p, ":%s FORCEJOIN %s %s", 1, parc, parv)) != HUNTED_ISME) return 0; /* if target_p is not existant, print message * to source_p and bail - scuzzy */ if((target_p = find_client(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return 0; } if(!IsPerson(target_p)) return 0; sendto_wallops_flags(UMODE_WALLOP, &me, "FORCEJOIN called for %s %s by %s!%s@%s", parv[1], parv[2], source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "FORCEJOIN called for %s %s by %s!%s@%s", parv[1], parv[2], source_p->name, source_p->username, source_p->host); sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s WALLOPS :FORCEJOIN called for %s %s by %s!%s@%s", me.name, parv[1], parv[2], source_p->name, source_p->username, source_p->host); /* select our modes from parv[2] if they exist... (chanop) */ if(*parv[2] == '@') { type = CHFL_CHANOP; mode = 'o'; sjmode = '@'; } else if(*parv[2] == '+') { type = CHFL_VOICE; mode = 'v'; sjmode = '+'; } else { type = CHFL_PEON; mode = sjmode = '\0'; } if(mode != '\0') parv[2]++; if((chptr = find_channel(parv[2])) != 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 0; } add_user_to_channel(chptr, target_p, type); sendto_server(target_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :%c%s", me.name, (long) chptr->channelts, chptr->chname, type ? sjmode : ' ', target_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); if(type) sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s", me.name, chptr->chname, mode, target_p->name); 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 { newch = LOCAL_COPY(parv[2]); if(!check_channel_name(newch)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) newch); return 0; } /* channel name must begin with & or # */ if(!IsChannelName(newch)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) newch); return 0; } /* newch can't be longer than CHANNELLEN */ if(strlen(newch) > CHANNELLEN) { sendto_one_notice(source_p, ":Channel name is too long"); return 0; } chptr = get_or_create_channel(target_p, newch, NULL); add_user_to_channel(chptr, target_p, CHFL_CHANOP); /* send out a join, make target_p join chptr */ sendto_server(target_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s +nt :@%s", me.name, (long) chptr->channelts, chptr->chname, target_p->name); 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; sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +nt", me.name, chptr->chname); 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 0; }
/* ** mo_ojoin ** parv[1] = channel */ static int mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "ojoin"); return 0; } /* XXX - we might not have CBURSTed this channel if we are a lazylink * yet. */ if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+') { parv[1]++; move_me = 1; } if((chptr = find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } if(IsMember(source_p, chptr)) { sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN", me.name, source_p->name, parv[1]); return 0; } if(move_me == 1) parv[1]--; if(*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :@%s", me.name, (long)chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :+%s", me.name, (long)chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :%s", me.name, (long)chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); } /* send the topic... */ if(chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic->topic_info, chptr->topic->topic_time); } source_p->localClient->last_join_time = rb_time(); channel_member_names(chptr, source_p, 1); return 0; }
/* ** mo_ojoin ** parv[0] = sender prefix ** parv[1] = channel */ static void mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if (!IsOperAdmin(source_p)) { sendto_one(source_p, ":%s NOTICE %s :You have no A flag", me.name, parv[0]); return; } if (*parv[1] == '@' || *parv[1] == '+') { parv[1]++; move_me = 1; } chptr = hash_find_channel(parv[1]); if(chptr == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } if(IsMember(source_p, chptr)) { sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN", me.name, source_p->name, parv[1]); return; } if (move_me == 1) parv[1]--; sendto_wallops_flags(UMODE_WALLOP, &me, "OJOIN called for [%s] by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_NOTICE, "OJOIN called for [%s] by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); if(*chptr->chname != '&') sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s WALLOPS :OJOIN called for [%s] by %s!%s@%s", me.name, parv[1], source_p->name, source_p->username, source_p->host); if (*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); if(*chptr->chname != '&') sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :@%s", me.name, chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if (*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); if(*chptr->chname != '&') sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :+%s", me.name, chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); if(*chptr->chname != '&') sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :%s", me.name, chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); } /* send the topic... */ if (chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } source_p->localClient->last_join_time = CurrentTime; channel_member_names(chptr, source_p, 1); }
/* * 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; } }
/* mo_ojoin() * parv[0] = sender prefix * parv[1] = channels separated by commas */ static void mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; const char *prefix = ""; char modeletter = '\0'; char *name = parv[1]; char *t = NULL; unsigned int flags = 0; /* admins only */ if(!IsAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVILEGES), me.name, source_p->name); return; } for(name = strtoken(&t, name, ","); name; name = strtoken(&t, NULL, ",")) { switch (*name) { case '@': prefix = "@"; flags = CHFL_CHANOP; modeletter = 'o'; ++name; break; #ifdef HALFOPS case '%': prefix = "%"; flags = CHFL_HALFOP; modeletter = 'h'; ++name; break; #endif case '+': prefix = "+"; flags = CHFL_VOICE; modeletter = 'v'; ++name; break; case '#': case '&': prefix = ""; flags = 0; modeletter = '\0'; break; default: sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); continue; } /* Error checking here */ if((chptr = hash_find_channel(name)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); } else if(IsMember(source_p, chptr)) { sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN", me.name, source_p->name, name); } else { add_user_to_channel(chptr, source_p, flags, NO); if(chptr->chname[0] == '#') { sendto_server(client_p, source_p, chptr, CAP_TS6, NOCAPS, LL_ICLIENT, ":%s SJOIN %lu %s + :%s%s", me.id, (unsigned long) chptr->channelts, chptr->chname, prefix, source_p->id); sendto_server(client_p, source_p, chptr, NOCAPS, CAP_TS6, LL_ICLIENT, ":%s SJOIN %lu %s + :%s%s", me.name, (unsigned long) chptr->channelts, chptr->chname, prefix, source_p->name); } sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); if(modeletter != '\0') sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s MODE %s +%c %s", me.name, chptr->chname, modeletter, source_p->name); /* send the topic... */ if(chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } source_p->localClient->last_join_time = CurrentTime; channel_member_names(source_p, chptr, 1); } } }
/* 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; }
/* ** m_cjoin ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = channel password (key) */ static void m_cjoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { static char jbuf[BUFSIZE]; struct Channel *chptr = NULL; struct Channel *vchan_chptr = NULL; struct Channel *root_vchan = NULL; char *name; char *p = NULL; if (!(source_p->user)) { /* something is *f****d* - bail */ return; } if(ConfigChannel.use_vchans == 0) { sendto_one(source_p, form_str(source_p,ERR_VCHANDISABLED), me.name, parv[0]); return; } if (ConfigChannel.vchans_oper_only && !IsOper(source_p)) { sendto_one(source_p, form_str(source_p,ERR_NOPRIVILEGES), me.name, parv[0]); return; } if (*parv[1] == '\0') { sendto_one(source_p, form_str(source_p,ERR_NEEDMOREPARAMS), me.name, parv[0], "CJOIN"); return; } /* Ok, only allowed to CJOIN already existing channels * so first part simply verifies the "root" channel exists first */ *jbuf = '\0'; name = parv[1]; while (*name == ',') name++; if ((p = strchr(name,',')) != NULL) *p = '\0'; if (!*name) return; if (!check_channel_name(name)) { sendto_one(source_p, form_str(source_p,ERR_BADCHANNAME), me.name, parv[0], (unsigned char*) name); return; } if (*name == '&') { sendto_one(source_p, form_str(source_p,ERR_BADCHANNAME), me.name, parv[0], (unsigned char*) name); return; } if (!IsChannelName(name)) { sendto_one(source_p, form_str(source_p,ERR_NOSUCHCHANNEL), me.name, parv[0], name); return; } strlcpy(jbuf, name, sizeof(jbuf)); if ((chptr = hash_find_channel(name)) == NULL) { /* if chptr isn't found locally, it =could= exist * on the uplink. So ask. */ if ( !ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL)) { /* cache the channel if it exists on uplink * If the channel as seen by the uplink, has vchans, * the uplink will have to SJOIN all of those. */ sendto_one(uplink, ":%s CBURST %s !%s", me.name, parv[1], source_p->name); return; } else { sendto_one(source_p, form_str(source_p,ERR_NOSUCHCHANNEL), me.name, source_p->name, name); } return; } if (! (vchan_chptr = cjoin_channel(chptr, source_p, name)) ) return; root_vchan = chptr; chptr = vchan_chptr; /* ** Complete user entry to the new channel */ add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", source_p->name, source_p->username, source_p->host, root_vchan->chname); sendto_server(client_p, NULL, chptr, NOCAPS, NOCAPS, NOFLAGS, ":%s SJOIN %lu %s + :@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, source_p->name); vchan_chptr->mode.mode |= MODE_TOPICLIMIT; vchan_chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ALL_MEMBERS,chptr, ":%s MODE %s +nt", me.name, root_vchan->chname); sendto_server(source_p, NULL, vchan_chptr, NOCAPS, NOCAPS, NOFLAGS, ":%s MODE %s +nt", me.name, vchan_chptr->chname); del_invite(vchan_chptr, source_p); channel_member_names(source_p, vchan_chptr, root_vchan->chname, 1); }