/* * safelist_channel_named() * * inputs - client pointer, channel name, operspy * outputs - none * side effects - a named channel is listed */ static void safelist_channel_named(struct Client *source_p, const char *name, int operspy) { struct Channel *chptr; char *p; int visible; sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name); if ((p = strchr(name, ','))) *p = '\0'; if (*name == '\0') { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), name); sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name); return; } chptr = find_channel(name); if (chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), name); sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name); return; } visible = !SecretChannel(chptr) || IsMember(source_p, chptr); if (visible || operspy) list_one_channel(source_p, chptr, visible); sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name); return; }
/* * safelist_one_channel() * * inputs - client pointer and channel pointer * outputs - none * side effects - a channel is listed if it meets the * requirements */ static void safelist_one_channel(struct Client *source_p, struct Channel *chptr) { struct ListClient *safelist_data = source_p->localClient->safelist_data; int visible; visible = !SecretChannel(chptr) || IsMember(source_p, chptr); if (!visible && !safelist_data->operspy) return; if ((unsigned int)chptr->members.length < safelist_data->users_min || (unsigned int)chptr->members.length > safelist_data->users_max) return; if (safelist_data->topic_min && chptr->topic_time < safelist_data->topic_min) return; /* If a topic TS is provided, don't show channels without a topic set. */ if (safelist_data->topic_max && (chptr->topic_time > safelist_data->topic_max || chptr->topic_time == 0)) return; if (safelist_data->created_min && chptr->channelts < safelist_data->created_min) return; if (safelist_data->created_max && chptr->channelts > safelist_data->created_max) return; list_one_channel(source_p, chptr, visible); }
/** Handle a local user's attempt to get or set a channel topic. * * \a parv has the following elements: * \li \a parv[1] is the channel name * \li \a parv[\a parc - 1] is the topic (if \a parc > 2) * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; char *topic = 0, *name, *p = 0; if (parc < 2) return need_more_params(sptr, "TOPIC"); if (parc > 2) topic = parv[parc - 1]; for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0) { chptr = 0; /* Does the channel exist */ if (!IsChannelName(name) || !(chptr = FindChannel(name))) { send_reply(sptr,ERR_NOSUCHCHANNEL,name); continue; } /* Trying to check a topic outside a secret channel */ if ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); continue; } /* only asking for topic */ if (!topic) { if (chptr->topic[0] == '\0') send_reply(sptr, RPL_NOTOPIC, chptr->chname); else { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } } #if defined(DDB) || defined(SERVICES) else if ((chptr->mode.mode & MODE_TOPICLIMIT) && !(is_chan_owner(sptr, chptr) || is_chan_op(sptr, chptr))) #else else if ((chptr->mode.mode & MODE_TOPICLIMIT) && !is_chan_op(sptr, chptr)) #endif send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); else if (!client_can_send_to_channel(sptr, chptr, 1)) send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); else do_settopic(sptr,cptr,chptr,topic,0); } return 0; }
/* * list_all_channels * inputs - pointer to client requesting list * output - 0/1 * side effects - list all channels to source_p */ static int list_all_channels(struct Client *source_p) { struct Channel *chptr; sendto_one(source_p, form_str(source_p,RPL_LISTSTART), me.name, source_p->name); for ( chptr = GlobalChannelList; chptr; chptr = chptr->nextch ) { if ( !source_p->user || (SecretChannel(chptr) && !IsMember(source_p, chptr))) continue; list_one_channel(source_p,chptr); } sendto_one(source_p, form_str(source_p,RPL_LISTEND), me.name, source_p->name); return 0; }
/* ** m_who ** parv[0] = sender prefix ** parv[1] = nickname mask list ** parv[2] = additional selection flag, only 'o' for now. */ int m_who(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr; char *mask = parc > 1 ? parv[1] : NULL; Link *lp; struct Channel *chptr; struct Channel *mychannel = NULL; char *channame = NULL; int oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */ int member; int maxmatches = 500; mychannel = NullChn; if (sptr->user) if ((lp = sptr->user->channel)) mychannel = lp->value.chptr; /* ** Following code is some ugly hacking to preserve the ** functions of the old implementation. (Also, people ** will complain when they try to use masks like "12tes*" ** and get people on channel 12 ;) --msa */ if (mask) { if (!strcmp(mask, "**")) mask = NULL; else if (*mask == (char) 0) mask = NULL; else (void)collapse(mask); } if (!mask || (*mask == (char) 0)) { if (!HasUmode(sptr,UMODE_USER_AUSPEX)) { sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; } } else if ((*(mask+1) == (char) 0) && (*mask == '*')) { if (!mychannel) { sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; } channame = mychannel->chname; } else channame = mask; if (IsChannelName(channame)) { /* * List all users on a given channel */ if (!oper || SeesOpers(sptr)) /* If you're doing an oper search, you need SeesOpers() */ { chptr = hash_find_channel(channame, NULL); if (chptr) { member = IsMember(sptr, chptr) || IsLogger(sptr, chptr) || HasUmode(sptr,UMODE_USER_AUSPEX); if (member || !SecretChannel(chptr)) for (lp = chptr->members; lp; lp = lp->next) { if (oper && !HasUmode(lp->value.cptr,UMODE_OPER)) continue; if (IsInvisible(lp->value.cptr) && !member) continue; do_who(sptr, lp->value.cptr, chptr, lp); } } } } else if (mask && ((acptr = find_client(mask, NULL)) != NULL) && IsPerson(acptr) && (!oper || (HasUmode(acptr,UMODE_OPER) && SeesOpers(sptr)))) { int isinvis = 0; struct Channel *ch2ptr = NULL; isinvis = IsInvisible(acptr); for (lp = acptr->user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; member = IsMember(sptr, chptr) || HasUmode(sptr,UMODE_USER_AUSPEX); if (isinvis && !member) continue; if (member || (!isinvis && PubChannel(chptr))) { ch2ptr = chptr; break; } } do_who(sptr, acptr, ch2ptr, NULL); } else if (!oper || SeesOpers(sptr)) for (acptr = GlobalClientList; acptr; acptr = acptr->next) { struct Channel *ch2ptr = NULL; int showperson, isinvis; if (!IsPerson(acptr)) continue; if (oper && !HasUmode(acptr,UMODE_OPER)) continue; showperson = 0; /* * Show user if they are on the same channel, or not * invisible and on a non secret channel (if any). * Do this before brute force match on all relevant fields * since these are less cpu intensive (I hope :-) and should * provide better/more shortcuts - avalon */ isinvis = IsInvisible(acptr); for (lp = acptr->user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; member = IsMember(sptr, chptr) || HasUmode(sptr, UMODE_USER_AUSPEX); if (isinvis && !member) continue; if (member || (!isinvis && PubChannel(chptr))) { ch2ptr = chptr; showperson = 1; break; } if (HiddenChannel(chptr) && !SecretChannel(chptr) && !isinvis) showperson = 1; } if (!acptr->user->channel && !isinvis) showperson = 1; if ((HasUmode(sptr,UMODE_USER_AUSPEX) || showperson) && (!mask || match(mask, acptr->name) || match(mask, acptr->username) || match(mask, acptr->host) || (HasUmode(sptr, UMODE_AUSPEX) && match(mask, acptr->user->server)) || match(mask, acptr->info))) { do_who(sptr, acptr, ch2ptr, NULL); if (!HasUmode(sptr,UMODE_USER_AUSPEX) && !--maxmatches) { sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; } } } sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; }
/* m_topic() * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; char *p; struct Membership *ms; const char *from, *to; if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) { from = me.id; to = source_p->id; } else { from = me.name; to = source_p->name; } if ((p = strchr(parv[1], ',')) != NULL) *p = '\0'; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), from, to, "TOPIC"); return; } if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (IsChanPrefix(*parv[1])) { if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); return; } /* setting topic */ if (parc > 2) { if ((ms = find_channel_link(source_p, chptr)) == NULL && !IsService(source_p)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, parv[1]); return; } if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) || IsGod(source_p) || IsService(source_p)) { char topic_info[USERHOST_REPLYLEN]; if(!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) && IsGod(source_p) && MyClient(source_p) && (chptr->mode.mode & MODE_TOPICLIMIT) != 0) { char tmp[IRCD_BUFSIZE]; ircsprintf(tmp, "%s is using God mode: TOPIC %s %s", source_p->name, chptr->chname, parv[2]); sendto_gnotice_flags(UMODE_SERVNOTICE, L_ALL, me.name, &me, NULL, tmp); oftc_log(tmp); } ircsprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", ID(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), from, to, chptr->chname); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), from, to, chptr->chname); else { sendto_one(source_p, form_str(RPL_TOPIC), from, to, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), from, to, chptr->chname, chptr->topic_info, chptr->topic_time); } } else { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), from, to, chptr->chname); return; } } } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); } }
/* * m_topic * parv[1] = channel name * parv[2] = new topic, if setting topic */ static int m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char *p = NULL; const char *name; int operspy = 0; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; if(IsOperAuspex(source_p) && parv[1][0] == '!') { name++; operspy = 1; if(EmptyString(name)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return 0; } } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } /* setting topic */ if(parc > 2) { char topic_info[USERHOST_REPLYLEN]; char topic[BUFSIZE]; msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(MyClient(source_p) && !is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr)) { sendto_one(source_p, form_str(ERR_TARGCHANGE), me.name, source_p->name, chptr->chname); return 0; } if(MyClient(source_p) && !(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr)) && can_send(chptr, source_p, msptr))) { if(IsOverride(source_p)) sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is overriding TOPIC on [%s]", get_oper_name(source_p), chptr->chname); else { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } rb_strlcpy(topic, parv[2], BUFSIZE); strip_colour(topic); rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, topic, topic_info, rb_current_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else if(MyClient(source_p)) { if(operspy) report_operspy(source_p, "TOPIC", chptr->chname); if(!IsMember(source_p, chptr) && SecretChannel(chptr) && !operspy) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, name); else { 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); } } return 0; }
void _send_list(aClient *cptr, int numsend) { aChannel *chptr; LOpts *lopt = cptr->user->lopt; unsigned int hashnum; /* Begin of /list? then send official channels. */ if ((lopt->starthash == 0) && conf_offchans) { ConfigItem_offchans *x; for (x = conf_offchans; x; x = (ConfigItem_offchans *)x->next) { if (find_channel(x->chname, (aChannel *)NULL)) continue; /* exists, >0 users.. will be sent later */ sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name, x->chname, 0, #ifdef LIST_SHOW_MODES "", #endif x->topic ? x->topic : ""); } } for (hashnum = lopt->starthash; hashnum < CH_MAX; hashnum++) { if (numsend > 0) for (chptr = (aChannel *)hash_get_chan_bucket(hashnum); chptr; chptr = chptr->hnextch) { if (SecretChannel(chptr) && !IsMember(cptr, chptr) && !OPCanSeeSecret(cptr)) continue; /* Much more readable like this -- codemastr */ if ((!lopt->showall)) { /* User count must be in range */ if ((chptr->users < lopt->usermin) || ((lopt->usermax >= 0) && (chptr->users > lopt->usermax))) continue; /* Creation time must be in range */ if ((chptr->creationtime && (chptr->creationtime < lopt->chantimemin)) || (chptr->creationtime > lopt->chantimemax)) continue; /* Topic time must be in range */ if ((chptr->topic_time < lopt->topictimemin) || (chptr->topic_time > lopt->topictimemax)) continue; /* Must not be on nolist (if it exists) */ if (lopt->nolist && find_str_match_link(lopt->nolist, chptr->chname)) continue; /* Must be on yeslist (if it exists) */ if (lopt->yeslist && !find_str_match_link(lopt->yeslist, chptr->chname)) continue; } #ifdef LIST_SHOW_MODES modebuf[0] = '['; channel_modes(cptr, modebuf+1, parabuf, sizeof(modebuf)-1, sizeof(parabuf), chptr); if (modebuf[2] == '\0') modebuf[0] = '\0'; else strlcat(modebuf, "]", sizeof modebuf); #endif if (!OPCanSeeSecret(cptr)) sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name, ShowChannel(cptr, chptr) ? chptr->chname : "*", chptr->users, #ifdef LIST_SHOW_MODES ShowChannel(cptr, chptr) ? modebuf : "", #endif ShowChannel(cptr, chptr) ? (chptr->topic ? chptr->topic : "") : ""); else sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name, chptr->chname, chptr->users, #ifdef LIST_SHOW_MODES modebuf, #endif (chptr->topic ? chptr->topic : "")); numsend--; } else break; } /* All done */ if (hashnum == CH_MAX) { sendto_one(cptr, rpl_str(RPL_LISTEND), me.name, cptr->name); free_str_list(cptr->user->lopt->yeslist); free_str_list(cptr->user->lopt->nolist); MyFree(cptr->user->lopt); cptr->user->lopt = NULL; return; } /* * We've exceeded the limit on the number of channels to send back * at once. */ lopt->starthash = hashnum; return; }
/* ** m_list ** parv[0] = sender prefix ** parv[1] = channel */ int m_list(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr; char *name, *p = NULL; /* anti flooding code, * I did have this in parse.c with a table lookup * but I think this will be less inefficient doing it in each * function that absolutely needs it * * -Dianora */ static time_t last_used=0L; int i,j,minusers; minusers = HasUmode(sptr,UMODE_USER_AUSPEX) ? 0 : MIN_USERS_FOR_LIST; /* throw away non local list requests that do get here -Dianora */ if(!MyConnect(sptr)) return 0; if(!NoFloodProtection(sptr)) { if(IsHoneypot(sptr) || (((last_used + PACE_WAIT) > CurrentTime) && (!IsDoingList(sptr)))) { sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0],"LIST"); sendto_one(sptr,form_str(RPL_LISTEND),me.name,parv[0]); return 0; } else last_used = CurrentTime; } /* right.. if we are already involved in a "blocked" /list, we will simply continue where we left off */ if (IsDoingList(sptr)) { if (sptr->listprogress != -1) { for (i=sptr->listprogress; i<CH_MAX; i++) { int progress2 = sptr->listprogress2; for (j=0, chptr=(struct Channel*)(hash_get_channel_block(i).list); (chptr) && (j<hash_get_channel_block(i).links); chptr=chptr->hnextch, j++) { if (j<progress2) continue; /* wind up to listprogress2 */ /* Safety check */ if (!sptr->user) continue; /* If it's secret, and none of the overriding conditions are true, don't send it */ if (SecretChannel(chptr) && !HasUmode(sptr,UMODE_USER_AUSPEX) && !IsMember(sptr, chptr) && !IsLogger(sptr, chptr)) continue; if (chptr->users < minusers) continue; sendto_one(sptr, form_str(RPL_LIST), me.name, parv[0], chptr->chname, chptr->users, chptr->topic); if (IsSendqPopped(sptr)) { sptr->listprogress=i; sptr->listprogress2=j; return 0; } } sptr->listprogress2 = 0; } } sendto_one(sptr, form_str(RPL_LISTEND), me.name, parv[0]); if (IsSendqPopped(sptr)) { /* popped with the RPL_LISTEND code. d0h */ sptr->listprogress = -1; return 0; } ClearDoingList(sptr); /* yupo, its over */ return 0; } /* Grr, mIRC -- jilles */ if (parc == 2 && !strcmp(parv[1], "<10000")) { #if 0 /* discussed #hyperion 20050807, considered unnecessary and confusing */ sendto_one(sptr, ":%s NOTICE %s :Your client is buggy, it sends LIST <10000 even though we don't advertise ELIST=U in 005. Please upgrade or contact the developers.", me.name, parv[0]); #endif parc--; } sendto_one(sptr, form_str(RPL_LISTSTART), me.name, parv[0]); if (parc < 2 || BadPtr(parv[1])) { SetDoingList(sptr); /* only set if its a full list */ ClearSendqPop(sptr); /* just to make sure */ /* we'll do this by looking through each hash table bucket */ for (i=0; i<CH_MAX; i++) { for (j=0, chptr = (struct Channel*)(hash_get_channel_block(i).list); (chptr) && (j<hash_get_channel_block(i).links); chptr = chptr->hnextch, j++) { /* Safety check */ if (!sptr->user) continue; /* If it's secret, and none of the overriding conditions are true, don't send it */ if (SecretChannel(chptr) && !HasUmode(sptr,UMODE_USER_AUSPEX) && !IsMember(sptr, chptr) && !IsLogger(sptr, chptr)) continue; if (chptr->users < minusers) continue; sendto_one(sptr, form_str(RPL_LIST), me.name, parv[0], chptr->chname, chptr->users, chptr->topic); if (IsSendqPopped(sptr)) { sptr->listprogress=i; sptr->listprogress2=j; return 0; } } } sendto_one(sptr, form_str(RPL_LISTEND), me.name, parv[0]); if (IsSendqPopped(sptr)) { sptr->listprogress=-1; return 0; } ClearDoingList(sptr); /* yupo, its over */ return 0; } p = strchr(parv[1],','); if(p) *p = '\0'; name = parv[1]; /* strtoken(&p, parv[1], ","); */ /* while(name) */ if(name) { chptr = hash_find_channel(name, NullChn); if (chptr && ShowChannel(sptr, chptr) && sptr->user) sendto_one(sptr, form_str(RPL_LIST), me.name, parv[0], name, chptr->users, chptr->topic); /* name = strtoken(&p, (char *)NULL, ","); */ } sendto_one(sptr, form_str(RPL_LISTEND), me.name, parv[0]); return 0; }
DLLFUNC CMD_FUNC(m_names) { int uhnames = (MyConnect(sptr) && SupportUHNAMES(sptr)); // cache UHNAMES support int bufLen = NICKLEN + (!uhnames ? 0 : (1 + USERLEN + 1 + HOSTLEN)); int mlen = strlen(me.name) + bufLen + 7; aChannel *chptr; aClient *acptr; int member; Member *cm; int idx, flag = 1, spos; char *s, *para = parv[1]; char nuhBuffer[NICKLEN+USERLEN+HOSTLEN+3]; if (parc < 2 || !MyConnect(sptr)) { sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*"); return 0; } for (s = para; *s; s++) { if (*s == ',') { if (strlen(para) > TRUNCATED_NAMES) para[TRUNCATED_NAMES] = '\0'; sendto_realops("names abuser %s %s", get_client_name(sptr, FALSE), para); sendto_one(sptr, err_str(ERR_TOOMANYTARGETS), me.name, sptr->name, "NAMES"); return 0; } } chptr = find_channel(para, (aChannel *)NULL); if (!chptr || (!ShowChannel(sptr, chptr) && !OPCanSeeSecret(sptr))) { sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para); return 0; } /* cache whether this user is a member of this channel or not */ member = IsMember(sptr, chptr); if (PubChannel(chptr)) buf[0] = '='; else if (SecretChannel(chptr)) buf[0] = '@'; else buf[0] = '*'; idx = 1; buf[idx++] = ' '; for (s = chptr->chname; *s; s++) buf[idx++] = *s; buf[idx++] = ' '; buf[idx++] = ':'; /* If we go through the following loop and never add anything, we need this to be empty, otherwise spurious things from the LAST /names call get stuck in there.. - lucas */ buf[idx] = '\0'; spos = idx; /* starting point in buffer for names! */ for (cm = chptr->members; cm; cm = cm->next) { acptr = cm->cptr; if (IsInvisible(acptr) && !member && !IsNetAdmin(sptr)) continue; if (chptr->mode.mode & MODE_AUDITORIUM) if (!is_chan_op(sptr, chptr) && !is_chanprot(sptr, chptr) && !is_chanowner(sptr, chptr)) if (!(cm-> flags & (CHFL_CHANOP | CHFL_CHANPROT | CHFL_CHANOWNER)) && acptr != sptr) continue; if (!SupportNAMESX(sptr)) { /* Standard NAMES reply */ #ifdef PREFIX_AQ if (cm->flags & CHFL_CHANOWNER) buf[idx++] = '~'; else if (cm->flags & CHFL_CHANPROT) buf[idx++] = '&'; else #endif if (cm->flags & CHFL_CHANOP) buf[idx++] = '@'; else if (cm->flags & CHFL_HALFOP) buf[idx++] = '%'; else if (cm->flags & CHFL_VOICE) buf[idx++] = '+'; } else { /* NAMES reply with all rights included (NAMESX) */ #ifdef PREFIX_AQ if (cm->flags & CHFL_CHANOWNER) buf[idx++] = '~'; if (cm->flags & CHFL_CHANPROT) buf[idx++] = '&'; #endif if (cm->flags & CHFL_CHANOP) buf[idx++] = '@'; if (cm->flags & CHFL_HALFOP) buf[idx++] = '%'; if (cm->flags & CHFL_VOICE) buf[idx++] = '+'; } if (!uhnames) { s = acptr->name; } else { strlcpy(nuhBuffer, make_nick_user_host(acptr->name, acptr->user->username, GetHost(acptr)), bufLen + 1); s = nuhBuffer; } /* 's' is intialized above to point to either acptr->name (normal), * or to nuhBuffer (for UHNAMES). */ for (; *s; s++) buf[idx++] = *s; buf[idx++] = ' '; buf[idx] = '\0'; flag = 1; if (mlen + idx + bufLen > BUFSIZE - 7) { sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); idx = spos; flag = 0; } } if (flag) sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para); return 0; }
/*! \brief TOPIC 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 * - parv[2] = topic text, if setting topic */ static int m_topic(struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "TOPIC"); return 0; } if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]); return 0; } /* setting topic */ if (parc > 2) { const struct Membership *member = NULL; if ((member = find_channel_link(source_p, chptr)) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->name); return 0; } if (!(chptr->mode.mode & MODE_TOPICLIMIT) || has_member_flags(member, CHFL_CHANOP|CHFL_HALFOP)) { char topic_info[USERHOST_REPLYLEN]; snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name, source_p->username, source_p->host); channel_set_topic(chptr, parv[2], topic_info, CurrentTime, 1); sendto_server(source_p, 0, 0, ":%s TOPIC %s :%s", source_p->id, chptr->name, chptr->topic); sendto_channel_local(0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->name, chptr->topic); } else sendto_one_numeric(source_p, &me, ERR_CHANOPRIVSNEEDED, chptr->name); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic[0] == '\0') sendto_one_numeric(source_p, &me, RPL_NOTOPIC, chptr->name); else { sendto_one_numeric(source_p, &me, RPL_TOPIC, chptr->name, chptr->topic); sendto_one_numeric(source_p, &me, RPL_TOPICWHOTIME, chptr->name, chptr->topic_info, chptr->topic_time); } } else sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->name); } return 0; }
/* * m_topic * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; struct Channel *root_chan; char *p = NULL; #ifdef VCHANS struct Channel *vchan; #endif if ((p = strchr(parv[1],','))) *p = '\0'; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (parv[1] && IsChannelName(parv[1])) { chptr = hash_find_channel(parv[1]); if(chptr == NULL) { /* if chptr isn't found locally, it =could= exist * on the uplink. so forward reqeuest */ if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL)) { sendto_one(uplink, ":%s TOPIC %s %s", source_p->name, parv[1], ((parc > 2) ? parv[2] : "")); return; } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } } root_chan = chptr; #ifdef VCHANS if (HasVchans(chptr)) { vchan = map_vchan(chptr,source_p); if(vchan != NULL) chptr = vchan; } else if (IsVchan(chptr)) root_chan = RootChan(chptr); #endif /* setting topic */ if (parc > 2) { if (!IsMember(source_p, chptr)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[1]); return; } if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_any_op(chptr,source_p)) { char topic_info[USERHOST_REPLYLEN]; ircsprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime); sendto_server(client_p, NULL, chptr, NOCAPS, NOCAPS, NOFLAGS, ":%s TOPIC %s :%s", parv[0], chptr->chname, chptr->topic == NULL ? "" : chptr->topic); if(chptr->mode.mode & MODE_HIDEOPS) { sendto_channel_local(ONLY_CHANOPS_HALFOPS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, root_chan->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(NON_CHANOPS, chptr, ":%s TOPIC %s :%s", me.name, root_chan->chname, chptr->topic == NULL ? "" : chptr->topic); } else { sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, root_chan->chname, chptr->topic == NULL ? "" : chptr->topic); } } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0], parv[1]); } else /* only asking for topic */ { if (!IsMember(source_p, chptr) && SecretChannel(chptr)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[1]); return; } if (chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, parv[0], parv[1]); else { sendto_one(source_p, form_str(RPL_TOPIC), me.name, parv[0], root_chan->chname, chptr->topic); if(!(chptr->mode.mode & MODE_HIDEOPS) || is_any_op(chptr,source_p)) { sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], root_chan->chname, chptr->topic_info, chptr->topic_time); } /* client on LL needing the topic - if we have serverhide, say * its the actual LL server that set the topic, not us the * uplink -- fl_ */ else if(ConfigServerHide.hide_servers && !MyClient(source_p) && IsCapable(client_p, CAP_LL) && ServerInfo.hub) { sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], root_chan->chname, client_p->name, chptr->topic_time); } /* just normal topic hiding.. */ else { sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], root_chan->chname, me.name, chptr->topic_time); } } } } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); } }
/* ** m_whois ** parv[0] = sender prefix ** parv[1] = nickname masklist */ DLLFUNC int m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[]) { Membership *lp; anUser *user; aClient *acptr, *a2cptr; aChannel *chptr; char *nick, *tmp, *name; char *p = NULL; int found, len, mlen, cnt = 0; char querybuf[BUFSIZE]; if (IsServer(sptr)) return 0; if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if (parc > 2) { if (hunt_server(cptr, sptr, ":%s WHOIS %s :%s", 1, parc, parv) != HUNTED_ISME) return 0; parv[1] = parv[2]; } strcpy(querybuf, parv[1]); for (tmp = canonize(parv[1]); (nick = strtok_r(tmp, ",", &p)); tmp = NULL) { unsigned char invis, showchannel, member, wilds, hideoper; /* <- these are all boolean-alike */ if (++cnt > MAXTARGETS) break; found = 0; /* We do not support "WHOIS *" */ wilds = (index(nick, '?') || index(nick, '*')); if (wilds) continue; if ((acptr = find_client(nick, NULL))) { if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == NULL!! */ if (IsMe(acptr)) break; /* * 'Rules' established for sending a WHOIS reply: * - only send replies about common or public channels * the target user(s) are on; */ if (!IsPerson(acptr)) continue; user = acptr->user; name = (!*acptr->name) ? "?" : acptr->name; invis = acptr != sptr && IsInvisible(acptr); member = (user->channel) ? 1 : 0; a2cptr = find_server_quick(user->server); hideoper = 0; if (IsHideOper(acptr) && (acptr != sptr) && !IsAnOper(sptr)) hideoper = 1; if (IsWhois(acptr) && (sptr != acptr)) { sendnotice(acptr, "*** %s (%s@%s) did a /whois on you.", sptr->name, sptr->user->username, sptr->user->realhost); } sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name, parv[0], name, user->username, IsHidden(acptr) ? user->virthost : user->realhost, acptr->info); if (IsOper(sptr) || acptr == sptr) { char sno[512]; strcpy(sno, get_sno_str(acptr)); /* send the target user's modes */ sendto_one(sptr, rpl_str(RPL_WHOISMODES), me.name, parv[0], name, get_mode_str(acptr), sno[1] == 0 ? "" : sno); } if ((acptr == sptr) || IsAnOper(sptr)) { sendto_one(sptr, rpl_str(RPL_WHOISHOST), me.name, parv[0], acptr->name, (MyConnect(acptr) && strcmp(acptr->username, "unknown")) ? acptr->username : "******", user->realhost, user->ip_str ? user->ip_str : ""); } if (IsARegNick(acptr)) sendto_one(sptr, rpl_str(RPL_WHOISREGNICK), me.name, parv[0], name); found = 1; mlen = strlen(me.name) + strlen(parv[0]) + 10 + strlen(name); for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->chptr; showchannel = 0; if (ShowChannel(sptr, chptr)) showchannel = 1; if (OPCanSeeSecret(sptr)) showchannel = 1; if ((acptr->umodes & UMODE_HIDEWHOIS) && !IsMember(sptr, chptr) && !IsAnOper(sptr)) showchannel = 0; if (IsServices(acptr) && !IsNetAdmin(sptr) && !IsSAdmin(sptr)) showchannel = 0; if (acptr == sptr) showchannel = 1; /* Hey, if you are editting here... don't forget to change the webtv w_whois ;p. */ if (showchannel) { long access; if (len + strlen(chptr->chname) > (size_t)BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", me.name, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } #ifdef SHOW_SECRET if (IsAnOper(sptr) #else if (IsNetAdmin(sptr) #endif && SecretChannel(chptr) && !IsMember(sptr, chptr)) *(buf + len++) = '?'; if (acptr->umodes & UMODE_HIDEWHOIS && !IsMember(sptr, chptr) && IsAnOper(sptr)) *(buf + len++) = '!'; access = get_access(acptr, chptr); if (!SupportNAMESX(sptr)) { #ifdef PREFIX_AQ if (access & CHFL_CHANOWNER) *(buf + len++) = '~'; else if (access & CHFL_CHANPROT) *(buf + len++) = '&'; else #endif if (access & CHFL_CHANOP) *(buf + len++) = '@'; else if (access & CHFL_HALFOP) *(buf + len++) = '%'; else if (access & CHFL_VOICE) *(buf + len++) = '+'; } else { #ifdef PREFIX_AQ if (access & CHFL_CHANOWNER) *(buf + len++) = '~'; if (access & CHFL_CHANPROT) *(buf + len++) = '&'; #endif if (access & CHFL_CHANOP) *(buf + len++) = '@'; if (access & CHFL_HALFOP) *(buf + len++) = '%'; if (access & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS), me.name, parv[0], name, buf); if (!(IsULine(acptr) && !IsOper(sptr) && HIDE_ULINES)) sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0], name, user->server, a2cptr ? a2cptr->info : "*Not On This Net*"); if (user->away) sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0], name, user->away); /* makesure they aren't +H (we'll also check before we display a helpop or IRCD Coder msg) -- codemastr */ if ((IsAnOper(acptr) || IsServices(acptr)) && !hideoper) { buf[0] = '\0'; if (IsNetAdmin(acptr)) strlcat(buf, "a Network Administrator", sizeof buf); else if (IsSAdmin(acptr)) strlcat(buf, "a Services Administrator", sizeof buf); else if (IsAdmin(acptr) && !IsCoAdmin(acptr)) strlcat(buf, "a Server Administrator", sizeof buf); else if (IsCoAdmin(acptr)) strlcat(buf, "a Co Administrator", sizeof buf); else if (IsServices(acptr)) strlcat(buf, "a Network Service", sizeof buf); else if (IsOper(acptr)) strlcat(buf, "an IRC Operator", sizeof buf); else strlcat(buf, "a Local IRC Operator", sizeof buf); if (buf[0]) { if (IsOper(sptr) && MyClient(acptr)) sendto_one(sptr, ":%s 313 %s %s :is %s (%s)", me.name, parv[0], name, buf, acptr->user->operlogin); else sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR), me.name, parv[0], name, buf); } } if (IsHelpOp(acptr) && !hideoper && !user->away) sendto_one(sptr, rpl_str(RPL_WHOISHELPOP), me.name, parv[0], name); if (acptr->umodes & UMODE_BOT) sendto_one(sptr, rpl_str(RPL_WHOISBOT), me.name, parv[0], name, ircnetwork); if (acptr->umodes & UMODE_SECURE) sendto_one(sptr, rpl_str(RPL_WHOISSECURE), me.name, parv[0], name, "is using a Secure Connection"); if (!BadPtr(user->swhois) && !hideoper) sendto_one(sptr, ":%s %d %s %s :%s", me.name, RPL_WHOISSPECIAL, parv[0], name, acptr->user->swhois); /* * display services account name if it's actually a services account name and * not a legacy timestamp. --nenolod */ if (!isdigit(*user->svid)) sendto_one(sptr, rpl_str(RPL_WHOISLOGGEDIN), me.name, parv[0], name, user->svid); /* * Umode +I hides an oper's idle time from regular users. * -Nath. */ if (MyConnect(acptr) && (IsAnOper(sptr) || !(acptr->umodes & UMODE_HIDLE))) { sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name, parv[0], name, TStime() - acptr->last, acptr->firsttime); } } if (!found) sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick); } sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], querybuf); return 0; }
/* * Search and return as many people as matched by the wild 'nick'. * returns the number of people found (or, obviously, 0, if none where * found). */ static int do_wilds(struct Client* sptr, char *nick, int count, int parc) { struct Client *acptr; /* Current client we're considering */ struct User *user; /* the user portion of the client */ const char *name; /* the name of this client */ struct Membership* chan; int invis; /* does +i apply? */ int member; /* Is this user on any channels? */ int showperson; /* Should we show this person? */ int found = 0 ; /* How many were found? */ /* Ech! This is hideous! */ for (acptr = GlobalClientList; (acptr = next_client(acptr, nick)); acptr = cli_next(acptr)) { if (!IsRegistered(acptr)) continue; if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == 0!! * * Isomer: Does this strike anyone else as being a horrible hideous * hack? */ if (IsMe(acptr)) { assert(!cli_next(acptr)); break; } /* * 'Rules' established for sending a WHOIS reply: * * - if wildcards are being used don't send a reply if * the querier isn't any common channels and the * client in question is invisible. * * - only send replies about common or public channels * the target user(s) are on; */ user = cli_user(acptr); name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr); assert(user); invis = (acptr != sptr) && IsInvisible(acptr); member = (user && user->channel) ? 1 : 0; showperson = !invis && !member; /* Should we show this person now? */ if (showperson) { found++; do_whois(sptr, acptr, parc); if (count+found>MAX_WHOIS_LINES) return found; continue; } /* Step through the channels this user is on */ for (chan = user->channel; chan; chan = chan->next_channel) { struct Channel *chptr = chan->channel; /* If this is a public channel, show the person */ if (!invis && PubChannel(chptr)) { showperson = 1; break; } /* if this channel is +p and not +s, show them */ if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr)) { showperson = 1; break; } member = find_channel_member(sptr, chptr) ? 1 : 0; if (invis && !member) continue; /* If sptr isn't really on this channel, skip it */ if (IsZombie(chan)) continue; /* Is this a common channel? */ if (member) { showperson = 1; break; } } /* of for (chan in channels) */ /* Don't show this person */ if (!showperson) continue; do_whois(sptr, acptr, parc); found++; if (count+found>MAX_WHOIS_LINES) return found; } /* of global client list */ return found; }
/* * m_topic * parv[1] = channel name * parv[2] = new topic, if setting topic */ static int m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char *p = NULL; const char *name; int operspy = 0; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; if(IsOperSpy(source_p) && parv[1][0] == '!') { name++; operspy = 1; if(EmptyString(name)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return 0; } } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } /* setting topic */ if(parc > 2) { msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(MyClient(source_p) && !is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr)) { sendto_one(source_p, form_str(ERR_TARGCHANGE), me.name, source_p->name, chptr->chname); return 0; } if(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || get_channel_access(source_p, chptr, msptr, MODE_ADD, NULL) >= CHFL_CHANOP) && (!MyClient(source_p) || can_send(chptr, source_p, msptr))) { char topic[TOPICLEN + 1]; char topic_info[USERHOST_REPLYLEN]; rb_strlcpy(topic, parv[2], sizeof(topic)); rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); if (ConfigChannel.strip_topic_colors) strip_colour(topic); set_channel_topic(chptr, topic, topic_info, rb_current_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); } else if(MyClient(source_p)) { if(operspy) report_operspy(source_p, "TOPIC", chptr->chname); if(!IsMember(source_p, chptr) && SecretChannel(chptr) && !operspy) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, name); else { 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, (unsigned long)chptr->topic_time); } } return 0; }
void do_names(struct Client* sptr, struct Channel* chptr, int filter) { int mlen; int idx; int flag; int needs_space; int len; char buf[BUFSIZE]; struct Client *c2ptr; struct Membership* member; assert(chptr); assert(sptr); assert((filter&NAMES_ALL) != (filter&NAMES_VIS)); /* Tag Pub/Secret channels accordingly. */ strcpy(buf, "* "); if (PubChannel(chptr)) *buf = '='; else if (SecretChannel(chptr)) *buf = '@'; len = strlen(chptr->chname); strcpy(buf + 2, chptr->chname); strcpy(buf + 2 + len, " :"); idx = len + 4; flag = 1; needs_space = 0; if (!ShowChannel(sptr, chptr)) /* Don't list private channels unless we are on them. */ return; /* Iterate over all channel members, and build up the list. */ mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr)); for (member = chptr->members; member; member = member->next_member) { c2ptr = member->user; if (((filter&NAMES_VIS)!=0) && IsInvisible(c2ptr)) continue; if (IsZombie(member) && member->user != sptr) continue; if (IsDelayedJoin(member) && (member->user != sptr) && !(filter & NAMES_DEL)) continue; if ((!IsDelayedJoin(member) || (member->user == sptr)) && (filter & NAMES_DEL)) continue; if (needs_space) buf[idx++] = ' '; needs_space=1; if (IsZombie(member)) buf[idx++] = '!'; else if (IsChanOp(member)) buf[idx++] = '@'; else if (HasVoice(member)) buf[idx++] = '+'; strcpy(buf + idx, cli_name(c2ptr)); idx += strlen(cli_name(c2ptr)); flag = 1; if (mlen + idx + NICKLEN + 5 > BUFSIZE) /* space, modifier, nick, \r \n \0 */ { send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); idx = len + 4; flag = 0; needs_space=0; } } if (flag) send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); if (filter&NAMES_EON) send_reply(sptr, RPL_ENDOFNAMES, chptr->chname); }
int m_who(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *ac; chanMember *cm; Link *lp; int shown=0, i=0, showall=IsAnOper(sptr); char status[4]; /* drop nonlocal clients */ if(!MyClient(sptr)) return 0; if(!build_searchopts(sptr, parc-1, parv+1)) return 0; /* /who was no good */ if(wsopts.gcos!=NULL && (strchr(wsopts.gcos, '?'))==NULL && (strchr(wsopts.gcos, '*'))==NULL) gchkfn=mycmp; else gchkfn=match; if(wsopts.nick!=NULL && (strchr(wsopts.nick, '?'))==NULL && (strchr(wsopts.nick, '*'))==NULL) nchkfn=mycmp; else nchkfn=match; if(wsopts.user!=NULL && (strchr(wsopts.user, '?'))==NULL && (strchr(wsopts.user, '*'))==NULL) uchkfn=mycmp; else uchkfn=match; if(wsopts.host!=NULL && (strchr(wsopts.host, '?'))==NULL && (strchr(wsopts.host, '*'))==NULL) hchkfn=mycmp; else hchkfn=match; if(wsopts.ip!=NULL && (strchr(wsopts.ip, '?'))==NULL && (strchr(wsopts.ip, '*'))==NULL) ichkfn=mycmp; else ichkfn=match; if(wsopts.channel!=NULL) { if(IsMember(sptr,wsopts.channel) && (!(wsopts.channel->mode.mode & MODE_AUDITORIUM) || is_chan_opvoice(sptr, wsopts.channel))) showall=1; else if(SecretChannel(wsopts.channel) && IsAdmin(sptr)) showall=1; else if(!SecretChannel(wsopts.channel) && IsAnOper(sptr)) showall=1; else showall=0; if(showall || !SecretChannel(wsopts.channel)) { for(cm=wsopts.channel->members; cm; cm=cm->next) { ac=cm->cptr; i=0; if(!chk_who(ac,showall)) continue; /* If we have channel flags set, verify they match */ if(wsopts.channelflags && ((cm->flags & wsopts.channelflags) == 0)) continue; /* get rid of the pidly stuff first */ /* wow, they passed it all, give them the reply... * IF they haven't reached the max, or they're an oper */ status[i++]=(ac->user->away==NULL ? 'H' : 'G'); status[i]=(IsAnOper(ac) ? '*' : ((IsInvisible(ac) && IsOper(sptr)) ? '%' : 0)); status[((status[i]) ? ++i : i)]=((cm->flags&CHFL_CHANOP) ? '@' : ((cm->flags&CHFL_VOICE) ? '+' : 0)); status[++i]=0; sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name, wsopts.channel->chname, ac->user->username, WHO_HOST(ac), WHO_SERVER(sptr, ac), ac->name, status, WHO_HOPCOUNT(sptr, ac), ac->info); } } sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, wsopts.channel->chname, "WHO"); return 0; } /* if (for whatever reason) they gave us a nick with no * wildcards, just do a find_person, bewm! */ else if(nchkfn==mycmp) { ac=find_person(wsopts.nick,NULL); if(ac!=NULL) { if(!chk_who(ac,1)) { sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO"); return 0; } else { status[0]=(ac->user->away==NULL ? 'H' : 'G'); status[1]=(IsAnOper(ac) ? '*' : (IsInvisible(ac) && IsAnOper(sptr) ? '%' : 0)); status[2]=0; sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name, wsopts.show_chan ? first_visible_channel(ac, sptr) : "*", ac->user->username, WHO_HOST(ac), WHO_SERVER(sptr, ac), ac->name, status, WHO_HOPCOUNT(sptr, ac), ac->info); sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO"); return 0; } } sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO"); return 0; } if(wsopts.search_chan) { for(lp = sptr->user->channel; lp; lp = lp->next) { for(cm = lp->value.chptr->members; cm; cm = cm->next) { ac = cm->cptr; if(!chk_who(ac, 1)) continue; if(shown==MAXWHOREPLIES && !IsAnOper(sptr)) { sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name, sptr->name, MAXWHOREPLIES, "WHO"); break; } i = 0; status[i++]=(ac->user->away==NULL ? 'H' : 'G'); status[i]=(IsAnOper(ac) ? '*' : ((IsInvisible(ac) && IsOper(sptr)) ? '%' : 0)); status[((status[i]) ? ++i : i)]=((cm->flags&CHFL_CHANOP) ? '@' : ((cm->flags&CHFL_VOICE) ? '+' : 0)); status[++i]=0; sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name, lp->value.chptr->chname, ac->user->username, WHO_HOST(ac),WHO_SERVER(sptr, ac), ac->name, status, WHO_HOPCOUNT(sptr, ac), ac->info); shown++; } } } else { for(ac=client;ac;ac=ac->next) { if(!chk_who(ac,showall)) continue; /* wow, they passed it all, give them the reply... * IF they haven't reached the max, or they're an oper */ if(shown==MAXWHOREPLIES && !IsAnOper(sptr)) { sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name, sptr->name, MAXWHOREPLIES, "WHO"); break; /* break out of loop so we can send end of who */ } status[0]=(ac->user->away==NULL ? 'H' : 'G'); status[1]=(IsAnOper(ac) ? '*' : (IsInvisible(ac) && IsAnOper(sptr) ? '%' : 0)); status[2]=0; sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name, wsopts.show_chan ? first_visible_channel(ac, sptr) : "*", ac->user->username, WHO_HOST(ac), WHO_SERVER(sptr, ac), ac->name, status, WHO_HOPCOUNT(sptr, ac), ac->info); shown++; } } sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, (wsopts.host!=NULL ? wsopts.host : (wsopts.nick!=NULL ? wsopts.nick : (wsopts.user!=NULL ? wsopts.user : (wsopts.gcos!=NULL ? wsopts.gcos : (wsopts.server!=NULL ? wsopts.server->name : "*"))))), "WHO"); return 0; }
static int can_see(aClient *sptr, aClient *acptr, aChannel *channel) { int ret = 0; char has_common_chan = 0; do { /* can only see people */ if (!IsPerson(acptr)) return WHO_CANTSEE; /* can only see opers if thats what they want */ if (who_flags & WF_OPERONLY) { if (!IsAnOper(acptr)) return ret | WHO_CANTSEE; if (IsHideOper(acptr)) { if (IsAnOper(sptr)) ret |= WHO_OPERSEE; else return ret | WHO_CANTSEE; } } /* if they only want people who are away */ if ((wfl.want_away == WHO_WANT && !acptr->user->away) || (wfl.want_away == WHO_DONTWANT && acptr->user->away)) return WHO_CANTSEE; /* if they only want people on a certain channel. */ if (wfl.want_channel != WHO_DONTCARE) { aChannel *chan = find_channel(wfl.channel, NULL); if (!chan && wfl.want_channel == WHO_WANT) return WHO_CANTSEE; if ((wfl.want_channel == WHO_WANT) && !IsMember(acptr, chan)) return WHO_CANTSEE; if ((wfl.want_channel == WHO_DONTWANT) && IsMember(acptr, chan)) return WHO_CANTSEE; } /* if they only want people with a certain gecos */ if (wfl.want_gecos != WHO_DONTCARE) { if (((wfl.want_gecos == WHO_WANT) && match(wfl.gecos, acptr->info)) || ((wfl.want_gecos == WHO_DONTWANT) && !match(wfl.gecos, acptr->info))) { return WHO_CANTSEE; } } /* if they only want people with a certain server */ if (wfl.want_server != WHO_DONTCARE) { if (((wfl.want_server == WHO_WANT) && stricmp(wfl.server, acptr->user->server)) || ((wfl.want_server == WHO_DONTWANT) && !stricmp(wfl.server, acptr->user->server))) { return WHO_CANTSEE; } } /* if they only want people with a certain host */ if (wfl.want_host != WHO_DONTCARE) { char *host; if (IsAnOper(sptr)) host = acptr->user->realhost; else host = GetHost(acptr); if (((wfl.want_host == WHO_WANT) && match(wfl.host, host)) || ((wfl.want_host == WHO_DONTWANT) && !match(wfl.host, host))) { return WHO_CANTSEE; } } /* if they only want people with a certain IP */ if (wfl.want_ip != WHO_DONTCARE) { char *ip; ip = acptr->user->ip_str; if (!ip) return WHO_CANTSEE; if (((wfl.want_ip == WHO_WANT) && match(wfl.ip, ip)) || ((wfl.want_ip == WHO_DONTWANT) && !match(wfl.ip, ip))) { return WHO_CANTSEE; } } /* if they only want people with a certain nick.. */ if (wfl.want_nick != WHO_DONTCARE) { if (((wfl.want_nick == WHO_WANT) && match(wfl.nick, acptr->name)) || ((wfl.want_nick == WHO_DONTWANT) && !match(wfl.nick, acptr->name))) { return WHO_CANTSEE; } } /* if they only want people with a certain username */ if (wfl.want_user != WHO_DONTCARE) { if (((wfl.want_user == WHO_WANT) && match(wfl.user, acptr->user->username)) || ((wfl.want_user == WHO_DONTWANT) && !match(wfl.user, acptr->user->username))) { return WHO_CANTSEE; } } /* if they only want people with a certain umode */ if (wfl.umodes_want) { if (!(acptr->umodes & wfl.umodes_want) || (!IsAnOper(sptr) && (acptr->umodes & UMODE_HIDEOPER))) return WHO_CANTSEE; } if (wfl.umodes_dontwant) { if ((acptr->umodes & wfl.umodes_dontwant) && (!(acptr->umodes & UMODE_HIDEOPER) || IsAnOper(sptr))) return WHO_CANTSEE; } /* if they only want common channels */ if (wfl.common_channels_only) { if (!has_common_channels(sptr, acptr)) return WHO_CANTSEE; has_common_chan = 1; } if (channel) { int member = who_flags & WF_ONCHANNEL; if (SecretChannel(channel) || HiddenChannel(channel)) { /* if they aren't on it.. they can't see it */ if (!(who_flags & WF_ONCHANNEL)) break; } if (IsInvisible(acptr) && !member) break; if ((channel->mode.mode & MODE_AUDITORIUM) && !is_chan_op(acptr, channel) && !is_chan_op(sptr, channel)) break; } else { /* a user/mask who */ /* If the common channel info hasn't been set, set it now */ if (!wfl.common_channels_only) has_common_chan = has_common_channels(sptr, acptr); if (IsInvisible(acptr) && !has_common_chan) { /* don't show them unless it's an exact match or it is the user requesting the /who */ if ((who_flags & WF_WILDCARD) && sptr != acptr) break; } } /* phew.. show them. */ return WHO_CANSEE; } while (0); /* if we get here, it's oper-dependant. */ if (IsAnOper(sptr)) return ret | WHO_OPERSEE | WHO_CANSEE; else { if (sptr == acptr) return ret | WHO_CANSEE; else return ret | WHO_CANTSEE; } }
/* * m_topic * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static int m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char *p = NULL; if((p = strchr(parv[1], ','))) *p = '\0'; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsChannelName(parv[1])) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } chptr = find_channel(parv[1]); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } /* setting topic */ if(parc > 2) { msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), parv[1]); return 0; } if((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr) || !MyClient(source_p)) { char topic_info[USERHOST_REPLYLEN]; ircsprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, parv[1]); } else if(MyClient(source_p)) { if(!IsMember(source_p, chptr) && SecretChannel(chptr)) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), parv[1]); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, parv[1]); else { 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); } } return 0; }
/* m_topic() * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return; } if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, parv[1]); return; } /* setting topic */ if (parc > 2) { struct Membership *ms; if ((ms = find_channel_link(source_p, chptr)) == NULL) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, parv[1]); return; } if (!(chptr->mode.mode & MODE_TOPICLIMIT) || has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP)) { char topic_info[USERHOST_REPLYLEN]; snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime, 1); sendto_server(client_p, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", ID(source_p), chptr->chname, chptr->topic); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic); sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, chptr->chname); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic[0] == '\0') sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, chptr->chname); else { 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); } } else sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, chptr->chname); } }