2 * IRC - Internet Relay Chat, ircd/m_whois.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * m_functions execute protocol messages on this server:
29 * cptr is always NON-NULL, pointing to a *LOCAL* client
30 * structure (with an open socket connected!). This
31 * identifies the physical socket where the message
32 * originated (or which caused the m_function to be
33 * executed--some m_functions may call others...).
35 * sptr is the source of the message, defined by the
36 * prefix part of the message if present. If not
37 * or prefix not found, then sptr==cptr.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
63 * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64 * *cannot* be a local connection, unless it's
65 * actually cptr!). [MyConnect(x) should probably
66 * be defined as (x == x->from) --msa ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
73 * parv[0], sender (prefix string), if not present
74 * this points to an empty string.
75 * parv[1]...parv[parc-1]
76 * pointers to additional parameters
77 * parv[parc] == NULL, *always*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
84 * No need to include handlers.h here the signatures must match
85 * and we don't need to force a rebuild of all the handlers everytime
86 * we add a new one to the list. --Bleep
94 #include "ircd_reply.h"
95 #include "ircd_string.h"
108 * m_whois - generic message handler
110 * parv[0] = sender prefix
111 * parv[1] = nickname masklist
115 * parv[1] = target server
116 * parv[2] = nickname masklist
118 int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
121 struct Client* acptr;
122 struct Client* a2cptr;
123 struct Channel* chptr;
132 static char buf[512];
136 sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
142 struct Client *acptr;
143 /* For convenience: Accept a nickname as first parameter, by replacing
144 it with the correct servername - as is needed by hunt_server() */
145 if (MyUser(sptr) && (acptr = FindUser(parv[1])))
146 parv[1] = acptr->user->server->name;
147 if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
154 for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
156 int invis, showperson, member, wilds;
160 wilds = (strchr(nick, '?') || strchr(nick, '*'));
161 /* Do a hash lookup if the nick does not contain wilds */
165 * We're no longer allowing remote users to generate requests with wildcards.
167 if (!MyConnect(sptr))
169 for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
172 if (!IsRegistered(acptr) || IsServer(acptr))
175 * I'm always last :-) and acptr->next == 0!!
180 * 'Rules' established for sending a WHOIS reply:
182 * - if wildcards are being used dont send a reply if
183 * the querier isnt any common channels and the
184 * client in question is invisible and wildcards are
185 * in use (allow exact matches only);
187 * - only send replies about common or public channels
188 * the target user(s) are on;
191 name = (!*acptr->name) ? "?" : acptr->name;
193 invis = acptr != sptr && IsInvisible(acptr);
194 member = (user && user->channel) ? 1 : 0;
195 showperson = (wilds && !invis && !member) || !wilds;
197 struct Membership* chan;
198 for (chan = user->channel; chan; chan = chan->next_channel)
200 chptr = chan->channel;
201 member = find_channel_member(sptr, chptr) ? 1 : 0;
202 if (invis && !member)
206 if (member || (!invis && PubChannel(chptr)))
211 if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
220 a2cptr = user->server;
221 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
222 parv[0], name, user->username, user->host, acptr->info);
227 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
228 parv[0], name, "<unknown>", "<unknown>", "<unknown>");
234 if (user && !IsChannelService(acptr))
236 struct Membership* chan;
237 mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
240 for (chan = user->channel; chan; chan = chan->next_channel)
242 chptr = chan->channel;
243 if (ShowChannel(sptr, chptr) &&
244 (acptr == sptr || !IsZombie(chan)))
246 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
248 sendto_one(sptr, ":%s %d %s %s :%s",
249 me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
254 *(buf + len++) = '-';
255 if (is_chan_op(acptr, chptr))
256 *(buf + len++) = '@';
257 else if (has_voice(acptr, chptr))
258 *(buf + len++) = '+';
259 else if (IsZombie(chan))
260 *(buf + len++) = '!';
263 strcpy(buf + len, chptr->chname);
264 len += strlen(chptr->chname);
265 strcat(buf + len, " ");
270 sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
271 me.name, parv[0], name, buf);
274 sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
275 parv[0], name, a2cptr->name, a2cptr->info);
280 sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
281 parv[0], name, user->away);
284 sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
285 me.name, parv[0], name);
287 if (MyConnect(acptr))
288 sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
289 parv[0], name, CurrentTime - user->last, acptr->firsttime);
291 if (found == 2 || total++ >= MAX_WHOIS_LINES)
298 if ((acptr = FindUser(nick)))
300 found = 2; /* Make sure we exit the loop after passing it once */
302 name = (!*acptr->name) ? "?" : acptr->name;
303 a2cptr = user->server;
304 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
305 parv[0], name, user->username, user->host, acptr->info);
310 sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
313 if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
316 sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
322 * ms_whois - server message handler
324 * parv[0] = sender prefix
325 * parv[1] = nickname masklist
329 * parv[1] = target server
330 * parv[2] = nickname masklist
332 int ms_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
335 struct Client* acptr;
336 struct Client* a2cptr;
337 struct Channel* chptr;
346 static char buf[512];
350 sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
356 struct Client *acptr;
357 /* For convenience: Accept a nickname as first parameter, by replacing
358 it with the correct servername - as is needed by hunt_server() */
359 if (MyUser(sptr) && (acptr = FindUser(parv[1])))
360 parv[1] = acptr->user->server->name;
361 if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
368 for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
370 int invis, showperson, member, wilds;
374 wilds = (strchr(nick, '?') || strchr(nick, '*'));
375 /* Do a hash lookup if the nick does not contain wilds */
379 * We're no longer allowing remote users to generate requests with wildcards.
381 if (!MyConnect(sptr))
383 for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
386 if (!IsRegistered(acptr) || IsServer(acptr))
389 * I'm always last :-) and acptr->next == 0!!
394 * 'Rules' established for sending a WHOIS reply:
396 * - if wildcards are being used dont send a reply if
397 * the querier isnt any common channels and the
398 * client in question is invisible and wildcards are
399 * in use (allow exact matches only);
401 * - only send replies about common or public channels
402 * the target user(s) are on;
405 name = (!*acptr->name) ? "?" : acptr->name;
407 invis = acptr != sptr && IsInvisible(acptr);
408 member = (user && user->channel) ? 1 : 0;
409 showperson = (wilds && !invis && !member) || !wilds;
411 struct Membership* chan;
412 for (chan = user->channel; chan; chan = chan->next_channel)
414 chptr = chan->channel;
415 member = find_channel_member(sptr, chptr) ? 1 : 0;
416 if (invis && !member)
420 if (member || (!invis && PubChannel(chptr)))
425 if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
434 a2cptr = user->server;
435 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
436 parv[0], name, user->username, user->host, acptr->info);
441 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
442 parv[0], name, "<unknown>", "<unknown>", "<unknown>");
448 if (user && !IsChannelService(acptr))
450 struct Membership* chan;
451 mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
454 for (chan = user->channel; chan; chan = chan->next_channel)
456 chptr = chan->channel;
457 if (ShowChannel(sptr, chptr) &&
458 (acptr == sptr || !IsZombie(chan)))
460 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
462 sendto_one(sptr, ":%s %d %s %s :%s",
463 me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
468 *(buf + len++) = '-';
469 if (is_chan_op(acptr, chptr))
470 *(buf + len++) = '@';
471 else if (has_voice(acptr, chptr))
472 *(buf + len++) = '+';
473 else if (IsZombie(chan))
474 *(buf + len++) = '!';
477 strcpy(buf + len, chptr->chname);
478 len += strlen(chptr->chname);
479 strcat(buf + len, " ");
484 sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
485 me.name, parv[0], name, buf);
488 sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
489 parv[0], name, a2cptr->name, a2cptr->info);
494 sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
495 parv[0], name, user->away);
498 sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
499 me.name, parv[0], name);
501 if (MyConnect(acptr))
502 sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
503 parv[0], name, CurrentTime - user->last, acptr->firsttime);
505 if (found == 2 || total++ >= MAX_WHOIS_LINES)
512 if ((acptr = FindUser(nick)))
514 found = 2; /* Make sure we exit the loop after passing it once */
516 name = (!*acptr->name) ? "?" : acptr->name;
517 a2cptr = user->server;
518 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
519 parv[0], name, user->username, user->host, acptr->info);
524 sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
527 if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
530 sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
536 * mo_whois - oper message handler
538 * parv[0] = sender prefix
539 * parv[1] = nickname masklist
543 * parv[1] = target server
544 * parv[2] = nickname masklist
546 int mo_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
549 struct Client* acptr;
550 struct Client* a2cptr;
551 struct Channel* chptr;
560 static char buf[512];
564 sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
570 struct Client *acptr;
571 /* For convenience: Accept a nickname as first parameter, by replacing
572 it with the correct servername - as is needed by hunt_server() */
573 if (MyUser(sptr) && (acptr = FindUser(parv[1])))
574 parv[1] = acptr->user->server->name;
575 if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
582 for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
584 int invis, showperson, member, wilds;
588 wilds = (strchr(nick, '?') || strchr(nick, '*'));
589 /* Do a hash lookup if the nick does not contain wilds */
593 * We're no longer allowing remote users to generate requests with wildcards.
595 if (!MyConnect(sptr))
597 for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
600 if (!IsRegistered(acptr) || IsServer(acptr))
603 * I'm always last :-) and acptr->next == 0!!
608 * 'Rules' established for sending a WHOIS reply:
610 * - if wildcards are being used dont send a reply if
611 * the querier isnt any common channels and the
612 * client in question is invisible and wildcards are
613 * in use (allow exact matches only);
615 * - only send replies about common or public channels
616 * the target user(s) are on;
619 name = (!*acptr->name) ? "?" : acptr->name;
621 invis = acptr != sptr && IsInvisible(acptr);
622 member = (user && user->channel) ? 1 : 0;
623 showperson = (wilds && !invis && !member) || !wilds;
625 struct Membership* chan;
626 for (chan = user->channel; chan; chan = chan->next_channel)
628 chptr = chan->channel;
629 member = find_channel_member(sptr, chptr) ? 1 : 0;
630 if (invis && !member)
634 if (member || (!invis && PubChannel(chptr)))
639 if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
648 a2cptr = user->server;
649 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
650 parv[0], name, user->username, user->host, acptr->info);
655 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
656 parv[0], name, "<unknown>", "<unknown>", "<unknown>");
662 if (user && !IsChannelService(acptr))
664 struct Membership* chan;
665 mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
668 for (chan = user->channel; chan; chan = chan->next_channel)
670 chptr = chan->channel;
671 if (ShowChannel(sptr, chptr) &&
672 (acptr == sptr || !IsZombie(chan)))
674 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
676 sendto_one(sptr, ":%s %d %s %s :%s",
677 me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
682 *(buf + len++) = '-';
683 if (is_chan_op(acptr, chptr))
684 *(buf + len++) = '@';
685 else if (has_voice(acptr, chptr))
686 *(buf + len++) = '+';
687 else if (IsZombie(chan))
688 *(buf + len++) = '!';
691 strcpy(buf + len, chptr->chname);
692 len += strlen(chptr->chname);
693 strcat(buf + len, " ");
698 sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
699 me.name, parv[0], name, buf);
702 sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
703 parv[0], name, a2cptr->name, a2cptr->info);
708 sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
709 parv[0], name, user->away);
712 sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
713 me.name, parv[0], name);
715 if (MyConnect(acptr))
716 sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
717 parv[0], name, CurrentTime - user->last, acptr->firsttime);
719 if (found == 2 || total++ >= MAX_WHOIS_LINES)
726 if ((acptr = FindUser(nick)))
728 found = 2; /* Make sure we exit the loop after passing it once */
730 name = (!*acptr->name) ? "?" : acptr->name;
731 a2cptr = user->server;
732 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
733 parv[0], name, user->username, user->host, acptr->info);
738 sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
741 if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
744 sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
755 * parv[0] = sender prefix
756 * parv[1] = nickname masklist
760 * parv[1] = target server
761 * parv[2] = nickname masklist
763 int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
766 struct Client* acptr;
767 struct Client* a2cptr;
768 struct Channel* chptr;
777 static char buf[512];
781 sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
787 struct Client *acptr;
788 /* For convenience: Accept a nickname as first parameter, by replacing
789 it with the correct servername - as is needed by hunt_server() */
790 if (MyUser(sptr) && (acptr = FindUser(parv[1])))
791 parv[1] = acptr->user->server->name;
792 if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
799 for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
801 int invis, showperson, member, wilds;
805 wilds = (strchr(nick, '?') || strchr(nick, '*'));
806 /* Do a hash lookup if the nick does not contain wilds */
810 * We're no longer allowing remote users to generate requests with wildcards.
812 if (!MyConnect(sptr))
814 for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
817 if (!IsRegistered(acptr) || IsServer(acptr))
820 * I'm always last :-) and acptr->next == NULL!!
825 * 'Rules' established for sending a WHOIS reply:
827 * - if wildcards are being used dont send a reply if
828 * the querier isnt any common channels and the
829 * client in question is invisible and wildcards are
830 * in use (allow exact matches only);
832 * - only send replies about common or public channels
833 * the target user(s) are on;
836 name = (!*acptr->name) ? "?" : acptr->name;
838 invis = acptr != sptr && IsInvisible(acptr);
839 member = (user && user->channel) ? 1 : 0;
840 showperson = (wilds && !invis && !member) || !wilds;
842 struct Membership* chan;
843 for (chan = user->channel; chan; chan = chan->next_channel)
845 chptr = chan->channel;
846 member = find_channel_member(sptr, chptr) ? 1 : 0;
847 if (invis && !member)
851 if (member || (!invis && PubChannel(chptr)))
856 if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
865 a2cptr = user->server;
866 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
867 parv[0], name, user->username, user->host, acptr->info);
872 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
873 parv[0], name, "<unknown>", "<unknown>", "<unknown>");
879 if (user && !IsChannelService(acptr))
881 struct Membership* chan;
882 mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
885 for (chan = user->channel; chan; chan = chan->next_channel)
887 chptr = chan->channel;
888 if (ShowChannel(sptr, chptr) &&
889 (acptr == sptr || !IsZombie(chan)))
891 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
893 sendto_one(sptr, ":%s %d %s %s :%s",
894 me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
899 *(buf + len++) = '-';
900 if (is_chan_op(acptr, chptr))
901 *(buf + len++) = '@';
902 else if (has_voice(acptr, chptr))
903 *(buf + len++) = '+';
904 else if (IsZombie(chan))
905 *(buf + len++) = '!';
908 strcpy(buf + len, chptr->chname);
909 len += strlen(chptr->chname);
910 strcat(buf + len, " ");
915 sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
916 me.name, parv[0], name, buf);
919 sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
920 parv[0], name, a2cptr->name, a2cptr->info);
925 sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
926 parv[0], name, user->away);
929 sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
930 me.name, parv[0], name);
932 if (MyConnect(acptr))
933 sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
934 parv[0], name, CurrentTime - user->last, acptr->firsttime);
936 if (found == 2 || total++ >= MAX_WHOIS_LINES)
943 if ((acptr = FindUser(nick)))
945 found = 2; /* Make sure we exit the loop after passing it once */
947 name = (!*acptr->name) ? "?" : acptr->name;
948 a2cptr = user->server;
949 sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
950 parv[0], name, user->username, user->host, acptr->info);
955 sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
958 if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
961 sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);