/* * list_named_channel * inputs - pointer to client requesting list * output - 0/1 * side effects - list all channels to source_p */ static int list_named_channel(struct Client *source_p,char *name) { struct Channel *chptr; char id_and_topic[TOPICLEN+NICKLEN+6]; /* <!!>, space and null */ char *p; #ifdef VCHANS dlink_node *ptr; struct Channel *root_chptr; struct Channel *tmpchptr; #endif sendto_one(source_p, form_str(source_p,RPL_LISTSTART), me.name, source_p->name); while (*name == ',') name++; if ((p = strchr(name,',')) != NULL) *p = '\0'; if (!*name) return; chptr = hash_find_channel(name); if (chptr == NULL) { sendto_one(source_p, form_str(source_p,ERR_NOSUCHNICK),me.name, source_p->name, name); sendto_one(source_p, form_str(source_p,RPL_LISTEND), me.name, source_p->name); return 0; } #ifdef VCHANS if (HasVchans(chptr)) ircsprintf(id_and_topic, "<!%s> %s", pick_vchan_id(chptr), chptr->topic == NULL ? "" : chptr->topic ); else #endif ircsprintf(id_and_topic, "%s", chptr->topic == NULL ? "" : chptr->topic); if (ShowChannel(source_p, chptr)) sendto_one(source_p, form_str(source_p,RPL_LIST), me.name, source_p->name, chptr->chname, chptr->users, id_and_topic); /* Deal with subvchans */ #ifdef VCHANS for (ptr = chptr->vchan_list.head; ptr; ptr = ptr->next) { tmpchptr = ptr->data; if (ShowChannel(source_p, tmpchptr)) { root_chptr = find_bchan(tmpchptr); ircsprintf(id_and_topic, "<!%s> %s", pick_vchan_id(tmpchptr), tmpchptr->topic == NULL ? "" : chptr->topic); sendto_one(source_p, form_str(source_p,RPL_LIST), me.name, source_p->name, root_chptr->chname, tmpchptr->users, id_and_topic); } } #endif sendto_one(source_p, form_str(source_p,RPL_LISTEND), me.name, source_p->name); return 0; }
static char *first_visible_channel(aClient *sptr, aClient *acptr, int *flg) { Membership *lp; *flg = 0; for (lp = acptr->user->channel; lp; lp = lp->next) { aChannel *chptr = lp->chptr; int cansee = ShowChannel(sptr, chptr); if (cansee && (acptr->umodes & UMODE_HIDEWHOIS) && !IsMember(sptr, chptr)) cansee = 0; if (!cansee) { if (OPCanSeeSecret(sptr)) *flg |= FVC_HIDDEN; else continue; } return chptr->chname; } /* no channels that they can see */ return "*"; }
inline char *first_visible_channel(aClient *cptr, aClient *sptr) { Link *lp; int secret = 0; aChannel *chptr = NULL; static char chnbuf[CHANNELLEN + 2]; if(cptr->user->channel) { if(IsAdmin(sptr)) { chptr = cptr->user->channel->value.chptr; if(!(ShowChannel(sptr, chptr))) secret = 1; } else { for(lp = cptr->user->channel; lp; lp = lp->next) { if(ShowChannel(sptr, lp->value.chptr)) break; } if(lp) chptr = lp->value.chptr; } if(chptr) { if(!secret) return chptr->chname; ircsprintf(chnbuf, "%%%s", chptr->chname); return chnbuf; } } return "*"; }
void ShowTopFlag(void) { #define BTM_LIN_START (BTM_LINE_ROW * 20) struct wr_slines_t { unsigned short x; unsigned short len; unsigned char *buffer; }; unsigned int i; //struct wr_slines_t wrconf; for(i = 0;i < 20;i++) lcd_buffer[BTM_LIN_START+i] = 0xff; ScreenSetHeadFlag(SCRHEAD_FLAG_SIG, GprsSigQuality()); //ScreenSetHeadFlag(SCRHEAD_FLAG_BAT, BatCapacity()); ShowChannel(); ShowTime(); #if 0 /* if(AlarmFlagErc) ShowAlarmFlag(1); else ShowAlarmFlag(0); wrconf.x = 0; wrconf.len = 16*20; wrconf.buffer = lcd_buffer; ioctl(fd_lcd, 20, &wrconf); if(HaveAlarmInfo) { ShowAlarmInfo(); wrconf.x = BTM_LINE_ROW+1; wrconf.len = 16*20; wrconf.buffer = lcd_buffer + (BTM_LINE_ROW+1)*20; ioctl(fd_lcd, 20, &wrconf); AlarmInfoCount++; if(AlarmInfoCount > 666) { // 10 min AlarmInfoCount = 0; HaveAlarmInfo = 0; memset(lcd_buffer+(BTM_LINE_ROW+1)*20, 0, 16*20); } } */ //write(fd_lcd,lcd_buffer_tmp, LCD_BUFFER_SIZE); #endif DisplayLcdBuffer(); }
/* ** 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; }
/* * * m_list * parv[0] = sender prefix * parv[1] = channel */ DLLFUNC CMD_FUNC(m_list) { aChannel *chptr; TS currenttime = TStime(); char *name, *p = NULL; LOpts *lopt = NULL; Link *lp; int usermax, usermin, error = 0, doall = 0; TS chantimemin, chantimemax; TS topictimemin, topictimemax; Link *yeslist = NULL, *nolist = NULL; static char *usage[] = { " Usage: /LIST <options>", "", "If you don't include any options, the default is to send you the", "entire unfiltered list of channels. Below are the options you can", "use, and what channels LIST will return when you use them.", ">number List channels with more than <number> people.", "<number List channels with less than <number> people.", "C>number List channels created between now and <number> minutes ago.", "C<number List channels created earlier than <number> minutes ago.", "T>number List channels whose topics are older than <number> minutes", " (Ie, they have not changed in the last <number> minutes.", "T<number List channels whose topics are not older than <number> minutes.", "*mask* List channels that match *mask*", "!*mask* List channels that do not match *mask*", NULL }; /* Some starting san checks -- No interserver lists allowed. */ if (cptr != sptr || !sptr->user) return 0; /* If a /list is in progress, then another one will cancel it */ if ((lopt = sptr->user->lopt) != NULL) { sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]); free_str_list(sptr->user->lopt->yeslist); free_str_list(sptr->user->lopt->nolist); MyFree(sptr->user->lopt); sptr->user->lopt = NULL; return 0; } if (parc < 2 || BadPtr(parv[1])) { sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]); lopt = sptr->user->lopt = (LOpts *) MyMalloc(sizeof(LOpts)); memset(lopt, '\0', sizeof(LOpts)); lopt->showall = 1; if (DBufLength(&cptr->sendQ) < 2048) send_list(cptr, 64); return 0; } if ((parc == 2) && (parv[1][0] == '?') && (parv[1][1] == '\0')) { char **ptr = usage; for (; *ptr; ptr++) sendto_one(sptr, rpl_str(RPL_LISTSYNTAX), me.name, cptr->name, *ptr); return 0; } sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]); chantimemax = topictimemax = currenttime + 86400; chantimemin = topictimemin = 0; usermin = 1; /* Minimum of 1 */ usermax = -1; /* No maximum */ for (name = strtok_r(parv[1], ",", &p); name && !error; name = strtok_r(NULL, ",", &p)) { switch (*name) { case '<': usermax = atoi(name + 1) - 1; doall = 1; break; case '>': usermin = atoi(name + 1) + 1; doall = 1; break; case 'C': case 'c': /* Channel TS time -- creation time? */ ++name; switch (*name++) { case '<': chantimemax = currenttime - 60 * atoi(name); doall = 1; break; case '>': chantimemin = currenttime - 60 * atoi(name); doall = 1; break; default: sendto_one(sptr, err_str(ERR_LISTSYNTAX), me.name, cptr->name); error = 1; } break; #ifdef LIST_USE_T case 'T': case 't': ++name; switch (*name++) { case '<': topictimemax = currenttime - 60 * atoi(name); doall = 1; break; case '>': topictimemin = currenttime - 60 * atoi(name); doall = 1; break; default: sendto_one(sptr, err_str(ERR_LISTSYNTAX), me.name, cptr->name, "Bad list syntax, type /list ?"); error = 1; } break; #endif default: /* A channel, possibly with wildcards. * Thought for the future: Consider turning wildcard * processing on the fly. * new syntax: !channelmask will tell ircd to ignore * any channels matching that mask, and then * channelmask will tell ircd to send us a list of * channels only masking channelmask. Note: Specifying * a channel without wildcards will return that * channel even if any of the !channelmask masks * matches it. */ if (*name == '!') { doall = 1; lp = make_link(); lp->next = nolist; nolist = lp; DupString(lp->value.cp, name + 1); } else if (strchr(name, '*') || strchr(name, '?')) { doall = 1; lp = make_link(); lp->next = yeslist; yeslist = lp; DupString(lp->value.cp, name); } else /* Just a normal channel */ { chptr = find_channel(name, NullChn); if (chptr && (ShowChannel(sptr, chptr) || OPCanSeeSecret(sptr))) { #ifdef LIST_SHOW_MODES modebuf[0] = '['; channel_modes(sptr, modebuf+1, parabuf, sizeof(modebuf)-1, sizeof(parabuf), chptr); if (modebuf[2] == '\0') modebuf[0] = '\0'; else strlcat(modebuf, "]", sizeof modebuf); #endif sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0], name, chptr->users, #ifdef LIST_SHOW_MODES modebuf, #endif (chptr->topic ? chptr->topic : "")); } } } /* switch */ } /* while */ if (doall) { lopt = sptr->user->lopt = (LOpts *) MyMalloc(sizeof(LOpts)); memset(lopt, '\0', sizeof(LOpts)); lopt->usermin = usermin; lopt->usermax = usermax; lopt->topictimemax = topictimemax; lopt->topictimemin = topictimemin; lopt->chantimemax = chantimemax; lopt->chantimemin = chantimemin; lopt->nolist = nolist; lopt->yeslist = yeslist; if (DBufLength(&cptr->sendQ) < 2048) send_list(cptr, 64); return 0; } sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]); 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; }
int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; struct Channel *ch2ptr; struct Client *c2ptr; struct Membership* member; char* s; char* para = parc > 1 ? parv[1] : 0; int showingdelayed = 0; if (parc > 1 && !ircd_strcmp(parv[1], "-D")) { para = (parc > 2) ? parv[2] : 0; showingdelayed = NAMES_DEL; if (parc > 3 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %s %C", 3, parc, parv)) return 0; } else if (parc > 2 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %C", 2, parc, parv)) return 0; if (EmptyString(para)) { send_reply(sptr, RPL_ENDOFNAMES, "*"); return 0; } do { s = strchr(para, ','); if (s) *s++ = '\0'; /* * Special Case 1: "/names 0". * Full list as per RFC. */ if ((*para == '0') || (*para == '\0')) { int idx; int mlen; int flag; struct Channel *ch3ptr; char buf[BUFSIZE]; mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr)); /* List all visible channels/visible members */ for (ch2ptr = GlobalChannelList; ch2ptr; ch2ptr = ch2ptr->next) { if (!ShowChannel(sptr, ch2ptr)) continue; /* Don't show secret chans. */ else if (find_channel_member(sptr, ch2ptr)) do_names(sptr, ch2ptr, showingdelayed|NAMES_ALL); /* Full list if we're in this chan. */ else do_names(sptr, ch2ptr, showingdelayed|NAMES_VIS); } /* List all remaining users on channel '*' */ strcpy(buf, "* * :"); idx = 5; flag = 0; for (c2ptr = GlobalClientList; c2ptr; c2ptr = cli_next(c2ptr)) { int showflag = 0; if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr))) continue; member = cli_user(c2ptr)->channel; while (member) { ch3ptr = member->channel; if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr)) showflag = 1; member = member->next_channel; } if (showflag) /* Have we already shown them? */ continue; strcpy(buf + idx, cli_name(c2ptr)); idx += strlen(cli_name(c2ptr)); buf[idx++] = ' '; flag = 1; if (mlen + idx + NICKLEN + 3 > BUFSIZE) /* space, \r\n\0 */ { send_reply(sptr, RPL_NAMREPLY, buf); strcpy(buf, "* * :"); idx = 5; flag = 0; } } if (flag) send_reply(sptr, RPL_NAMREPLY, buf); send_reply(sptr, RPL_ENDOFNAMES, "*"); } else if ((chptr = FindChannel(para)) != NULL) { member = find_member_link(chptr, sptr); if (member) { /* * Special Case 2: User is on this channel, requesting full names list. * (As performed with each /join) - ** High frequency usage ** */ do_names(sptr, chptr, showingdelayed|NAMES_ALL|NAMES_EON); } else { /* * Special Case 3: User isn't on this channel, show all visible users, in * non secret channels. */ do_names(sptr, chptr, showingdelayed|NAMES_VIS|NAMES_EON); } } else send_reply(sptr, RPL_ENDOFNAMES, para); } while ((para = s) != NULL); return 1; }
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); }
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; }
signed int checkHostmask(struct Client *sptr, char *hoststr, int flags) { struct Client *acptr; struct Channel *chptr; struct Membership *lp; int count = 0, found = 0, cidr_check_bits = 0; char outbuf[BUFSIZE]; char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3]; char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1]; char *p = NULL; struct in_addr cidr_check; strcpy(nickm,"*"); strcpy(userm,"*"); strcpy(hostm,"*"); if (!strchr(hoststr, '!') && !strchr(hoststr, '@')) ircd_strncpy(hostm,hoststr,HOSTLEN); else { if ((p = strchr(hoststr, '@'))) { *p++ = '\0'; if (*p) ircd_strncpy(hostm,p, HOSTLEN); } /* Get the nick!user mask */ if ((p = strchr(hoststr, '!'))) { *p++ = '\0'; if (*p) ircd_strncpy(userm,p,USERLEN); if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN); } else if (*hoststr) { /* Durz: We should only do the following *IF* the hoststr has not already been * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com */ ircd_strncpy(userm,hoststr,USERLEN); } } if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) { if (p) *p = '\0'; if (inet_aton(hostm, &cidr_check)) { cidr_check_bits = p ? atoi(p + 1) : 32; if ((cidr_check_bits >= 0) && (cidr_check_bits <= 32)) { flags |= CHECK_CIDRMASK; cidr_check.s_addr &= NETMASK(cidr_check_bits); } } if (p) *p = '/'; } /* Copy formatted string into "targhost" buffer */ ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm); targhost[sizeof(targhost) - 1] = '\0'; /* Note: we have to exclude the last client struct as it is not a real client * structure, and therefore any attempt to access elements in it would cause * a segfault. */ for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { /* Dont process if acptr is a unregistered client, a server or a ping */ if (!IsRegistered(acptr) || IsServer(acptr)) continue; if (IsMe(acptr)) /* Always the last acptr record */ break; if(count > feature_int(FEAT_MAX_CHECK_OUTPUT)) { /* sanity stuff */ ircd_snprintf(0, outbuf, sizeof(outbuf), "More than %d results, truncating...", count); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_ENDOFCHECK, " "); break; } /* Copy host info into buffer */ curhost[0] = '\0'; ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->realusername, acptr->cli_user->realhost); if (flags & CHECK_CIDRMASK) { if (((cli_ip(acptr).s_addr & NETMASK(cidr_check_bits)) == cidr_check.s_addr) && !match(nickm, acptr->cli_name) && (!match(userm, acptr->cli_user->realusername) || !match(userm, acptr->cli_user->username))) found = 1; } else { if(match((const char*)targhost,(const char*)curhost) == 0) found = 1; else { curhost[0] = '\0'; ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->username, acptr->cli_user->host); if(match((const char*)targhost,(const char*)curhost) == 0) found = 1; } } if (found == 1) { found = 0; /* reset that so it doesn't get crazy go nuts */ /* Show header if we've found at least 1 record */ if (count == 0) { /* Output header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "host", targhost); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), "%s %-*s%-*s%s", "No.", (NICKLEN + 2 ), "Nick", (USERLEN + 2), "User", "Host"); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d %-*s%-*s%s", (count+1), (NICKLEN + 2), acptr->cli_name, (USERLEN + 2), acptr->cli_user->realusername, (flags & CHECK_SHOWIPS) ? ircd_ntoa((const char*)&(cli_ip(acptr))) : acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); /* Show channel output (if applicable) - the 50 channel limit sanity check * is specifically to prevent coredumping when someone lamely tries to /check * Q or some other channel service... */ if (flags & CHECK_CHECKCHAN) { if (acptr->cli_user->joined > 0 && acptr->cli_user->joined <= 50) { char chntext[BUFSIZE]; int len = strlen(" on channels: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " on channels: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " on channels: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; else if (has_voice(acptr, chptr)) *(chntext + len++) = '+'; else if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); send_reply(sptr, RPL_DATASTR, " "); } } count++; } } if (count > 0) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_ENDOFCHECK, " "); } return count; }
void checkClient(struct Client *sptr, struct Client *acptr) { struct Channel *chptr; struct Membership *lp; char outbuf[BUFSIZE]; char *privs; time_t nowr; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s", myctime(acptr->cli_firsttime)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host, ircd_ntoa((const char*) &(cli_ip(acptr)))); send_reply(sptr, RPL_DATASTR, outbuf); if (((feature_int(FEAT_HOST_HIDING_STYLE) == 1) ? HasHiddenHost(acptr) : IsHiddenHost(acptr)) || IsSetHost(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF); send_reply(sptr, RPL_DATASTR, outbuf); if (IsService(cli_user(acptr)->server)) { if (acptr) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsAdmin(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator (service)"); else if (IsAnOper(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator (service)"); else send_reply(sptr, RPL_DATASTR, " Status:: Client (service)"); } else if (IsAdmin(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator"); } else if (IsAnOper(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator"); } else { send_reply(sptr, RPL_DATASTR, " Status:: Client"); } if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } privs = client_print_privs(acptr); if (strlen(privs) > 1) client_check_privs(acptr, sptr); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s", cli_name(acptr->cli_user->server)); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_version(acptr)) { if (strlen(cli_version(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " CTCP Version:: %s", cli_version(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_user(acptr) && !EmptyString(cli_user(acptr)->swhois)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " SWHOIS:: %s", cli_user(acptr)->swhois); send_reply(sptr, RPL_DATASTR, outbuf); } if (cli_webirc(acptr)) { if (strlen(cli_webirc(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " WebIRC:: %s", cli_webirc(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (MyUser(acptr)) get_eflags(sptr, acptr); /* +s (SERV_NOTICE) is not relayed to us from remote servers, * so we cannot tell if a remote client has that mode set. * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG * (and breaks if the user is +r) so we won't do that either. */ if (strlen(umode_str(acptr)) < 1) strcpy(outbuf, " Umode(s):: <none>"); else ircd_snprintf(0, outbuf, sizeof(outbuf), " Umode(s):: +%s", umode_str(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (acptr->cli_user->joined == 0) send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>"); else if (acptr->cli_user->joined > 50) { /* NB. As a sanity check, we DO NOT show the individual channels the * client is on if it is on > 50 channels. This is to prevent the ircd * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine * an Oper would want to see every single channel 'x' client is on anyway if * they are on *that* many). */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", acptr->cli_user->joined); send_reply(sptr, RPL_DATASTR, outbuf); } else { char chntext[BUFSIZE]; int len = strlen(" Channel(s):: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); } /* If client processing command ISN'T target (or a registered * Network Service), show idle time since the last time we * parsed something. */ if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) { nowr = CurrentTime - acptr->cli_user->last; ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld", nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60); send_reply(sptr, RPL_DATASTR, outbuf); } /* Away message (if applicable) */ if (acptr->cli_user->away) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", acptr->cli_user->away); send_reply(sptr, RPL_DATASTR, outbuf); } /* If local user.. */ if (MyUser(acptr)) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)", cli_port(acptr), cli_listener(acptr)->port); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { /* Note: sendq = receiveq for a client (it makes sense really) */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %u.%0.3u Kb (%u protocol messages)", cli_receiveK(acptr), cli_receiveB(acptr), cli_receiveM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %u.%0.3u Kb (%u protocol messages)", cli_sendK(acptr), cli_sendB(acptr), cli_sendM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
/* ** 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; }
/* * m_list - generic message handler * * parv[0] = sender prefix * parv[1] = channel list or user/time limit * parv[2...] = more user/time limits */ int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; char *name, *p = 0; int show_channels = 0, param; struct ListingArgs args; if (cli_listing(sptr)) /* Already listing ? */ { if (cli_listing(sptr)) MyFree(cli_listing(sptr)); cli_listing(sptr) = 0; send_reply(sptr, RPL_LISTEND); update_write(sptr); if (parc < 2 || 0 == ircd_strcmp("STOP", parv[1])) return 0; /* Let LIST or LIST STOP abort a listing. */ } if (parc < 2) /* No arguments given to /LIST ? */ args = la_default; else { args = la_init; /* initialize argument to blank slate */ for (param = 1; parv[param]; param++) { /* process each parameter */ switch (param_parse(sptr, parv[param], &args, parc == 2)) { case LPARAM_ERROR: /* error encountered, usage already sent, return */ return 0; break; case LPARAM_CHANNEL: /* show channel instead */ show_channels++; break; case LPARAM_SUCCESS: /* parse succeeded */ break; } } } send_reply(sptr, RPL_LISTSTART); if (!show_channels) { if (args.max_users > args.min_users + 1 && args.max_time > args.min_time && args.max_topic_time > args.min_topic_time) /* Sanity check */ { cli_listing(sptr) = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs)); assert(0 != cli_listing(sptr)); memcpy(cli_listing(sptr), &args, sizeof(struct ListingArgs)); list_next_channels(sptr); return 0; } send_reply(sptr, RPL_LISTEND); return 0; } for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0) { chptr = FindChannel(name); if (!chptr) continue; if (ShowChannel(sptr, chptr) || (IsAnOper(sptr) && HasPriv(sptr, PRIV_LIST_CHAN))) send_reply(sptr, RPL_LIST, chptr->chname, chptr->users - number_of_zombies(chptr), chptr->topic); } send_reply(sptr, RPL_LISTEND); return 0; }
/* * Send whois information for acptr to sptr */ static void do_whois(struct Client* sptr, struct Client *acptr, int parc) { struct Client *a2cptr=0; struct Channel *chptr=0; int mlen; int len; static char buf[512]; const struct User* user = cli_user(acptr); const char* name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr); a2cptr = feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr) && sptr != acptr ? &his : user->server; assert(user); send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host, cli_info(acptr)); /* Display the channels this user is on. */ if (!IsChannelService(acptr)) { struct Membership* chan; mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name); len = 0; *buf = '\0'; for (chan = user->channel; chan; chan = chan->next_channel) { chptr = chan->channel; if (!ShowChannel(sptr, chptr) && !(IsOper(sptr) && IsLocalChannel(chptr->chname))) continue; if (acptr != sptr && IsZombie(chan)) continue; /* Don't show local channels when HIS is defined, unless it's a * remote WHOIS --ULtimaTe_ */ if (IsLocalChannel(chptr->chname) && (acptr != sptr) && (parc == 2) && feature_bool(FEAT_HIS_WHOIS_LOCALCHAN) && !IsAnOper(sptr)) continue; if (len+strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS, "%s :%s", name, buf); *buf = '\0'; len = 0; } if (IsDeaf(acptr)) *(buf + len++) = '-'; if (!ShowChannel(sptr, chptr)) *(buf + len++) = '*'; if (IsDelayedJoin(chan) && (sptr != acptr)) *(buf + len++) = '<'; else if (IsChanOp(chan)) *(buf + len++) = '@'; else if (HasVoice(chan)) *(buf + len++) = '+'; else if (IsZombie(chan)) *(buf + len++) = '!'; if (len) *(buf + len) = '\0'; strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); strcat(buf + len, " "); len++; } if (buf[0] != '\0') send_reply(sptr, RPL_WHOISCHANNELS, name, buf); } send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr), cli_info(a2cptr)); if (user) { if (user->away) send_reply(sptr, RPL_AWAY, name, user->away); if (SeeOper(sptr,acptr)) send_reply(sptr, RPL_WHOISOPERATOR, name); if (IsAccount(acptr)) send_reply(sptr, RPL_WHOISACCOUNT, name, user->account); if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr)) send_reply(sptr, RPL_WHOISACTUALLY, name, user->username, user->realhost, ircd_ntoa(&cli_ip(acptr))); /* Hint: if your looking to add more flags to a user, eg +h, here's * probably a good place to add them :) */ if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) || (sptr == acptr || IsAnOper(sptr) || parc >= 3))) send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last, cli_firsttime(acptr)); } }
/* ** m_whois ** parv[0] = sender prefix ** parv[1] = nickname masklist */ int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { static anUser UnknownUser = { NULL, /* next */ NULL, /* channel */ NULL, /* invited */ NULL, /* silence */ NULL, /* away */ 0, /* last */ 1, /* refcount */ 0, /* joined */ "<Unknown>" /* server */ }; static char rpl_oper[] = "an IRC Operator"; static char rpl_locop[] = "an IRC Operator - Local IRC Operator"; static char rpl_sadmin[] = "an IRC Operator - Services Administrator"; static char rpl_admin[] = "an IRC Operator - Server Administrator"; static char rpl_tadmin[] = "an IRC Operator - Technical Administrator"; static char rpl_nadmin[] = "an IRC Operator - Network Administrator"; Link *lp; anUser *user; struct Client *acptr, *a2cptr; aChannel *chptr; char *nick, *name; /* char *tmp; */ char *p = NULL; int found, len, mlen; static time_t last_used=0L; char *nick_match=NULL, *user_match=NULL, *host_match=NULL, *server_match=NULL; char *name_match=NULL; int found_mode; int hits = 0; char *mename = me.name; if(sptr->user && sptr->user->vlink) mename = sptr->user->vlink->name; if (parc < 2) { sendto_one(sptr, form_str(ERR_NONICKNAMEGIVEN), mename, 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]; } if(!IsAnOper(sptr) && !MyConnect(sptr)) /* pace non local requests */ { if((last_used + WHOIS_WAIT) > CurrentTime) { /* Unfortunately, returning anything to a non local * request =might= increase sendq to be usable in a split hack * Sorry gang ;-( - Dianora */ return 0; } else { last_used = CurrentTime; } } /* Multiple whois from remote hosts, can be used * to flood a server off. One could argue that multiple whois on * local server could remain. Lets think about that, for now * removing it totally. * -Dianora */ /* for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL) */ nick = parv[1]; p = strchr(parv[1],','); if(p) *p = '\0'; { int invis, member, wilds; found = 0; (void)collapse(nick); wilds = (nick[0]=='$' || strchr(nick, '?') || strchr(nick, '*')); /* ** We're no longer allowing remote users to generate ** requests with wildcards. */ if (wilds && !IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; } /* continue; */ /* If the nick doesn't have any wild cards in it, * then just pick it up from the hash table * - Dianora */ if(!wilds) { acptr = hash_find_client(nick,(struct Client *)NULL); if(!acptr) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } if(IsStealth(acptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; // Add by ^Stinger^ after the idea of Soldier (: } if(!IsPerson(acptr)) { sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; } /* continue; */ user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; invis = IsInvisible(acptr); member = (user->channel) ? 1 : 0; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, acptr->host, acptr->info); if((IsOper(sptr) || (acptr == sptr)) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISREALHOST), mename, parv[0], name, acptr->realhost); } mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); *buf = '\0'; if (IsSsl(acptr)) { sendto_one(sptr, form_str(RPL_WHOISSECURE), mename, parv[0], parv[1]); } if(((!IsPrivate(acptr) || IsOper(sptr)) || (acptr==sptr)) && !IsStealth(acptr)) for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if(found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & 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, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); if(IsAnOper(sptr) || !HideServerOnWhois) { #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif if(acptr->user && acptr->user->vlink) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->vlink->name, user->vlink->passwd); else { if(!IsService(acptr) || IsAnOper(sptr) || !HideServicesServer) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); } } /* if(IsAnOper(sptr) || HideServerOnWhois) */ if (IsIdentified(acptr)) sendto_one(sptr, form_str(RPL_WHOISIDENTIFIED), mename, parv[0], name); if (IsHelper(acptr)) sendto_one(sptr, form_str(RPL_WHOISHELPOP), mename, parv[0], name); if(IsOper(sptr) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISMODE), mename, parv[0], name, get_mode_string(acptr)); } if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if(!IsHideOper(acptr) || IsOper(sptr)) { if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); else if (IsLocOp(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_locop); } #ifdef WHOIS_NOTICE if ((IsOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr) && !is_silenced(sptr, acptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", me.name, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } /* wild is true so here we go */ if(nick[0]==':') /* real name match */ { name_match = &nick[1]; nick_match = NULL; } else if(nick[0]=='$') /* server name match */ { server_match = &nick[1]; nick_match = NULL; } else { host_match = strchr(nick,'@'); if(host_match) { if(*host_match) *(host_match++) = '\0'; user_match=nick; if(host_match=='\0') host_match="*"; if(user_match=='\0') user_match="*"; } else nick_match = nick; } for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == NULL!! */ if (IsMe(acptr)) break; /* * 'Rules' established for sending a WHOIS reply: * * * - if wildcards are being used dont send a reply if * the querier isnt any common channels and the * client in question is invisible and wildcards are * in use (allow exact matches only); * * - only send replies about common or public channels * the target user(s) are on; */ /* If its an unregistered client, ignore it, it can be "seen" on a /trace anyway -Dianora */ if(!IsRegistered(acptr)) continue; user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; if( (server_match && !match(server_match, user->server)) || (nick_match && !match(nick, name)) || (host_match && !match(host_match, acptr->realhost) && !match(host_match, acptr->host)) || (user_match && !match(user_match, acptr->username)) || (name_match && !match(name_match, acptr->info)) ) continue; ++hits; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, IsOper(sptr) ? acptr->realhost : acptr->host, acptr->info); found = 1; mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if (found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & 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, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); #ifdef WHOIS_NOTICE if ((MyOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", mename, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); if(hits>50) { sendto_one(sptr,":%s NOTICE %s :Aborting /whois output as flood prevention", mename, sptr->name); break; } } if (!found) sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); else sendto_one(sptr,":%s NOTICE %s :This /whois matched \2%i\2 user(s)", mename, sptr->name,hits); /* if (p) p[-1] = ','; */ } sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; }