"Fossies" - the Fresh Open Source Software Archive

Member "bahamut-2.1.5/src/m_who.c" (28 May 2020, 26311 Bytes) of package /linux/privat/bahamut-2.1.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "m_who.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.1.4_vs_2.1.5.

    1 /* m_who.c - Because s_user.c was just crazy.
    2  *   Copyright (C) 1990 Jarkko Oikarinen and
    3  *                      University of Oulu, Computing Center
    4  *
    5  *   See file AUTHORS in IRC package for additional names of
    6  *   the programmers.
    7  *
    8  *   This program is free softwmare; you can redistribute it and/or modify
    9  *   it under the terms of the GNU General Public License as published by
   10  *   the Free Software Foundation; either version 1, or (at your option)
   11  *   any later version.
   12  *
   13  *   This program is distributed in the hope that it will be useful,
   14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  *   GNU General Public License for more details.
   17  *
   18  *   You should have received a copy of the GNU General Public License
   19  *   along with this program; if not, write to the Free Software
   20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   21  */
   22 
   23 #include "struct.h"
   24 #include "common.h"
   25 #include "sys.h"
   26 #include "numeric.h"
   27 #include "inet.h"
   28 #include "msg.h"
   29 #include "channel.h"
   30 #include <sys/stat.h>
   31 #include <fcntl.h>
   32 #include "h.h"
   33 
   34 /* Internally defined stuffs */
   35 SOpts wsopts;
   36 int build_searchopts(aClient *, int, char **);
   37 int chk_who(aClient *, aClient *, int);
   38 
   39 /* Externally defined stuffs */
   40 extern int user_modes[];
   41 
   42 extern Link *find_channel_link(Link *, aChannel *);
   43 
   44 int build_searchopts(aClient *sptr, int parc, char *parv[])
   45 {
   46   static char *who_oper_help[] =
   47   {
   48 #ifdef USER_HOSTMASKING
   49       "/WHO [+|-][acghilmnstuCHIMR] [args]",
   50 #else
   51       "/WHO [+|-][acghilmnstuCIM] [args]",
   52 #endif
   53       "Flags are specified like channel modes,",
   54       "The flags cghimnsu all have arguments",
   55       "Flags are set to a positive check by +, a negative check by -",
   56       "The flags work as follows:",
   57       "Flag a: user is away",
   58       "Flag c <channel>: user is on <channel>,",
   59       "                  no wildcards accepted",
   60       "Flag g <gcos/realname>: user has string <gcos> in their GCOS,",
   61       "                        wildcards accepted, oper only",
   62       "Flag h <host>: user has string <host> in their hostname,",
   63       "               wildcards accepted",
   64       "Flag i <ip>: user is from <ip>, wildcards and cidr accepted,",
   65       "Flag m <usermodes>: user has <usermodes> set on them",
   66       "Flag n <nick>: user has string <nick> in their nickname,",
   67       "               wildcards accepted",
   68       "Flag s <server>: user is on server <server>,",
   69       "                 wildcards not accepted",
   70       "Flag t <seconds>: (+t) show nicks in use for more than or equal to <seconds> seconds",
   71       "                  (-t) show nicks in use for less than <seconds> seconds",
   72       "Flag u <user>: user has string <user> in their username,",
   73       "               wildcards accepted",
   74       "Flag T <type>: user is of type <type>, where type is assigned",
   75       "               by services.",
   76       "Behavior flags:",
   77       "Flag C: show first visible channel user is in",
   78       "Flag M: check for user in channels I am a member of",
   79       "Flag I: always show IPs instead of hosts",
   80 #ifdef USER_HOSTMASKING
   81       "Flag H: show the masked host even if the user's host is not masked (umode -H)",
   82       "Flag R: show the real host even if the user's host is masked (umode +H)",
   83 #endif
   84       NULL
   85   };
   86 
   87   static char *who_user_help[] =
   88   {
   89       "/WHO [+|-][achmnsuCM] [args]",
   90       "Flags are specified like channel modes,",
   91       "The flags cghimnsu all have arguments",
   92       "Flags are set to a positive check by +, a negative check by -",
   93       "The flags work as follows:",
   94       "Flag a: user is away",
   95       "Flag c <channel>: user is on <channel>,",
   96       "                  no wildcards accepted",
   97       "Flag h <host>: user has string <host> in their hostname,",
   98       "               wildcards accepted",
   99       "Flag m <usermodes>: user has <usermodes> set on them,",
  100       "                    only usermodes o/O/a/A will return a result",
  101       "Flag n <nick>: user has string <nick> in their nickname,",
  102       "               wildcards accepted",
  103       "Flag s <server>: user is on server <server>,",
  104       "                 wildcards not accepted",
  105       "Flag u <user>: user has string <user> in their username,",
  106       "               wildcards accepted",
  107       "Behavior flags:",
  108       "Flag C: show first visible channel user is in",
  109       "Flag M: check for user in channels I am a member of",
  110       NULL
  111   };
  112 
  113   char *flags, change=1, *s, *err;
  114   int args=1, i, rval;
  115 
  116   memset((char *)&wsopts, '\0', sizeof(SOpts));
  117   /* if we got no extra arguments, send them the help. yeech. */
  118   /* if it's /who ?, send them the help */
  119   if(parc < 1 || parv[0][0]=='?')
  120   {
  121       /* So we don't confuse users with flags they cannot use,
  122          a different /who ? output will be given to users and
  123          opers -srd */
  124 
  125       char **ptr = NULL;
  126 
  127       if (!IsAnOper(sptr))
  128        ptr = who_user_help;
  129       else
  130        ptr = who_oper_help;
  131 
  132       for (; *ptr; ptr++)
  133       sendto_one(sptr, getreply(RPL_COMMANDSYNTAX), me.name,
  134              sptr->name, *ptr);
  135       sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, "?","WHO");
  136       return 0;
  137   }
  138   /* backwards compatibility */
  139   else if(parv[0][0]=='0' && parv[0][1]==0)
  140   {
  141       if(parc>1 && *parv[1]=='o')
  142       {
  143       wsopts.check_umode=1;
  144       wsopts.umode_plus=1;
  145       wsopts.umodes=UMODE_o;
  146       }
  147       wsopts.host_plus=1;
  148       wsopts.host="*";
  149       return 1;
  150   }
  151   /* if the first argument isn't a list of stuff */
  152   else if(parv[0][0]!='+' && parv[0][0]!='-')
  153   {
  154       if(parv[0][0]=='#' || parv[0][0]=='&')
  155       {
  156       wsopts.channel=find_channel(parv[0],NullChn);
  157       if(wsopts.channel==NULL)
  158       {
  159           sendto_one(sptr, getreply(ERR_NOSUCHCHANNEL), me.name,
  160              sptr->name, parv[0]);
  161           return 0;
  162       }
  163       }
  164       else if (IsAnOper(sptr))
  165       {
  166       int bits;
  167 
  168       bits = inet_parse_cidr(AF_INET, parv[0],
  169                  &wsopts.cidr_ip, sizeof(wsopts.cidr_ip));
  170       if (bits > 0)
  171       {
  172           wsopts.cidr_family = AF_INET;
  173           wsopts.cidr_bits = bits;
  174           wsopts.cidr_plus = 1;
  175       }
  176       else
  177       {
  178           bits = inet_parse_cidr(AF_INET6, parv[0],
  179                      &wsopts.cidr_ip, sizeof(wsopts.cidr_ip));
  180           if (bits > 0)
  181           {
  182           wsopts.cidr_family = AF_INET6;
  183           wsopts.cidr_bits = bits;
  184           wsopts.cidr_plus = 1;
  185           }
  186           else
  187           {
  188           /*
  189            * The argument could be an IPv6 address with a wildcard, a
  190            * hostname, or a nickname.
  191            */
  192           if (strchr(parv[0], ':'))
  193           {
  194               wsopts.ip_plus = 1;
  195               wsopts.ip = parv[0];
  196           }
  197           else if (strchr(parv[0], '.'))
  198           {
  199               wsopts.host_plus = 1;
  200               wsopts.host = parv[0];
  201           }
  202           else
  203           {
  204               wsopts.nick_plus = 1;
  205               wsopts.nick = parv[0];
  206           }
  207           }
  208       }
  209       }
  210       else
  211       {
  212       /* The argument could be either a hostname or a nickname. */
  213       if (strchr(parv[0], '.'))
  214       {
  215           wsopts.host_plus = 1;
  216           wsopts.host = parv[0];
  217       }
  218       else
  219       {
  220           wsopts.nick_plus = 1;
  221           wsopts.nick = parv[0];
  222       }
  223       }
  224       return 1;
  225   }
  226   /* now walk the list (a lot like set_mode) and set arguments
  227    * as appropriate. */
  228   flags=parv[0];
  229   while(*flags)
  230   {
  231       switch(*flags)
  232       {
  233       case '+':
  234       case '-':
  235       change=(*flags=='+' ? 1 : 0);
  236       break;
  237       case 'a':
  238       if(change)
  239           wsopts.away_plus=1; /* they want here people */
  240       else
  241           wsopts.away_plus=0;
  242       wsopts.check_away=1;
  243       break;
  244       case 'C':
  245       wsopts.show_chan = change;
  246       break;
  247       case 'M':
  248       wsopts.search_chan = change;
  249       break;
  250       case 'c':
  251       if(parv[args]==NULL || !change)
  252       {
  253           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  254              sptr->name, "WHO", "who");
  255           return 0;
  256       }
  257       if(*parv[args] == '@' || *parv[args] == '+')
  258       {
  259           char *cname = parv[args] + 1;
  260 
  261               if(*parv[args] == '@')
  262           {
  263           wsopts.channelflags = CHFL_CHANOP;
  264           if(*cname == '+')
  265           {
  266               wsopts.channelflags |= CHFL_VOICE;
  267               cname++;
  268           }
  269           }
  270           else
  271           wsopts.channelflags = CHFL_VOICE;
  272 
  273           wsopts.channel=find_channel(cname, NullChn);
  274       }
  275       else
  276       {
  277           wsopts.channelflags = 0;
  278           wsopts.channel=find_channel(parv[args],NullChn);
  279       }
  280  
  281       if(wsopts.channel==NULL)
  282       {
  283           sendto_one(sptr, getreply(ERR_NOSUCHCHANNEL), me.name,
  284              sptr->name, parv[args]);
  285           return 0;
  286       }
  287       wsopts.chan_plus=change;
  288       args++;
  289       break;
  290       case 'g':
  291           if(parv[args]==NULL)
  292           {
  293               sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  294                          sptr->name, "WHO", "who");
  295               return 0;
  296           }
  297           else if(!IsAnOper(sptr))
  298           {
  299               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  300               return 0;
  301           }
  302           wsopts.gcos=parv[args];
  303           wsopts.gcos_plus=change;
  304           args++;
  305           break;
  306       case 'h':
  307       if(parv[args]==NULL)
  308       {
  309           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  310              sptr->name, "WHO", "who");
  311           return 0;
  312       }
  313       wsopts.host=parv[args];
  314       wsopts.host_plus=change;
  315       args++;
  316       break;
  317        case 't':
  318           if(parv[args]==NULL || (rval = strtol(parv[args], &err, 0)) == 0 || *err != '\0')
  319           {
  320               sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  321                          sptr->name, "WHO", "who");
  322               return 0;
  323           }
  324           else if(!IsAnOper(sptr))
  325           {
  326               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  327               return 0;
  328           }
  329           wsopts.ts = rval;
  330           wsopts.ts_value = change ? 2 : 1;
  331           args++;
  332           break; 
  333        case 'T':
  334           if(parv[args]==NULL || (rval = strtol(parv[args], &err, 0)) == 0 || *err != '\0')
  335           {
  336               sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  337                          sptr->name, "WHO", "who");
  338               return 0;
  339           }
  340           else if(!IsAnOper(sptr))
  341           {
  342               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  343               return 0;
  344           }
  345           wsopts.client_type = rval;
  346           wsopts.client_type_plus = change ? 1 : 0;
  347           args++;
  348           break;
  349       case 'I':
  350           if(!IsAnOper(sptr))
  351           {
  352               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  353               return 0;
  354           }
  355           wsopts.ip_show = change;
  356           break; 
  357 #ifdef USER_HOSTMASKING
  358       case 'H':
  359           if(!IsAnOper(sptr))
  360           {
  361               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  362               return 0;
  363           }
  364           wsopts.maskhost_show = change;
  365           break;
  366       case 'R':
  367           if(!IsAnOper(sptr))
  368           {
  369               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  370               return 0;
  371           }
  372           wsopts.realhost_show = change;
  373           break; 
  374 #endif
  375       case 'i':
  376           if(parv[args]==NULL)
  377           {
  378               sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  379                          sptr->name, "WHO", "who");
  380               return 0;
  381           }
  382           else if(!IsAnOper(sptr))
  383           {
  384               sendto_one(sptr, getreply(ERR_NOPRIVILEGES), me.name, parv[0]);
  385               return 0;
  386           }
  387           else
  388           {
  389           if (strchr(parv[args], '/'))
  390           {
  391           int bits;
  392 
  393           bits = inet_parse_cidr(AF_INET, parv[args],
  394                      &wsopts.cidr_ip,
  395                      sizeof(wsopts.cidr_ip));
  396           if (bits > 0)
  397               wsopts.cidr_family = AF_INET;
  398           else
  399           {
  400               bits = inet_parse_cidr(AF_INET6, parv[args],
  401                          &wsopts.cidr_ip,
  402                          sizeof(wsopts.cidr_ip));
  403               if (bits > 0)
  404               wsopts.cidr_family = AF_INET6;
  405           }
  406           if (bits > 0)
  407           {
  408               wsopts.cidr_bits = bits;
  409               wsopts.cidr_plus = change;
  410           }
  411           else
  412                   {
  413                       sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name,
  414                          "WHO", "who");
  415                       return 0;
  416                   }
  417           args++;
  418           }
  419               else
  420               {
  421                   wsopts.ip=parv[args];
  422                   wsopts.ip_plus=change;
  423                   args++;
  424               }
  425           }
  426           break;
  427       case 'm':
  428       if(parv[args]==NULL)
  429       {
  430           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  431              sptr->name, "WHO", "who");
  432           return 0;
  433       }
  434       s=parv[args];
  435       while(*s)
  436       {
  437           for(i=1;user_modes[i]!=0x0;i+=2)
  438           {
  439           if(*s==(char)user_modes[i])
  440           {
  441               wsopts.umodes|=user_modes[i-1];
  442               break;
  443           }
  444           }
  445               if(!user_modes[i])
  446               {
  447                   sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  448                              sptr->name, "WHO", "who");
  449                   return 0;
  450               }
  451           s++;
  452       }
  453       if(!IsAnOper(sptr)) /* only let users search for +/-oOaA */
  454           wsopts.umodes=(wsopts.umodes&(UMODE_o|UMODE_O|UMODE_a|UMODE_A));
  455       wsopts.umode_plus=change;
  456       if(wsopts.umodes)
  457           wsopts.check_umode=1;
  458       args++;
  459       break;
  460       case 'n':
  461       if(parv[args]==NULL)
  462       {
  463           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  464              sptr->name, "WHO", "who");
  465           return 0;
  466       }
  467       wsopts.nick=parv[args];
  468       wsopts.nick_plus=change;
  469       args++;
  470       break;
  471       case 's':
  472       if(parv[args]==NULL || !change)
  473       {
  474           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  475              sptr->name, "WHO", "who");
  476           return 0;
  477       }
  478       wsopts.server=find_server(parv[args],NULL);
  479       if(wsopts.server==NULL)
  480       {
  481           sendto_one(sptr, getreply(ERR_NOSUCHSERVER), me.name,
  482              sptr->name, parv[args]);
  483           return 0;
  484       }
  485       wsopts.serv_plus=change;
  486       args++;
  487       break;
  488       case 'u':
  489       if(parv[args]==NULL)
  490       {
  491           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  492              sptr->name, "WHO", "who");
  493           return 0;
  494       }
  495       wsopts.user=parv[args];
  496       wsopts.user_plus=change;
  497       args++;
  498       break;
  499       default:
  500       sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name,
  501              sptr->name, "WHO", "who");
  502       return 0;
  503 
  504       }
  505       flags++;
  506   }
  507   
  508   /* if we specified search_chan, we _must_ specify something useful 
  509    * to go with it. Specifying a channel makes no sense, and no params make no 
  510    * sense either, as does specifying a nick.
  511    */
  512   
  513   if(wsopts.search_chan && !(wsopts.check_away || wsopts.gcos_plus || 
  514                  wsopts.host_plus || wsopts.check_umode || 
  515                  wsopts.serv_plus || wsopts.nick_plus || 
  516                  wsopts.user_plus || wsopts.ts_value || 
  517                  wsopts.client_type_plus || wsopts.ip_plus))
  518   {
  519       if(parv[args]==NULL || wsopts.channel || wsopts.nick ||
  520      parv[args][0] == '#' || parv[args][0] == '&')
  521       {
  522       sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
  523                  "who");
  524       return 0;
  525       }
  526 
  527       if (strchr(parv[args], '.'))
  528       {
  529       wsopts.host_plus=1;
  530       wsopts.host=parv[args];
  531       }
  532       else
  533       {
  534       sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
  535                  "who");
  536       return 0;
  537       }
  538   } 
  539   else /* can't show_chan if nothing else is set! */
  540       if(wsopts.show_chan && !(wsopts.check_away || wsopts.gcos_plus || 
  541                    wsopts.host_plus || wsopts.check_umode || 
  542                    wsopts.serv_plus || wsopts.nick_plus || 
  543                    wsopts.user_plus || wsopts.ts_value || 
  544                    wsopts.client_type_plus || wsopts.ip_plus || 
  545                    wsopts.chan_plus || wsopts.cidr_bits))
  546       {
  547       if(parv[args]==NULL)
  548       {
  549           sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
  550                      "who");
  551           return 0;
  552       }
  553       
  554       if (strchr(parv[args], '.'))
  555       {
  556           wsopts.host_plus=1;
  557           wsopts.host=parv[args];
  558       }
  559       else
  560       {
  561           wsopts.nick_plus=1;
  562           wsopts.nick=parv[args];
  563       }
  564       }
  565 
  566   if(parc > args)
  567   {
  568       /* Too many arguments */
  569       sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO",
  570              "who");
  571       return 0;
  572   }
  573 
  574   /* hey cool, it all worked! */
  575   return 1;
  576 }
  577 
  578 /* these four are used by chk_who to check gcos/nick/user/host
  579  * respectively 
  580  * as well as ip -srd */
  581 
  582 int (*gchkfn)(char *, char *);
  583 int (*nchkfn)(char *, char *);
  584 int (*uchkfn)(char *, char *);
  585 int (*hchkfn)(char *, char *);
  586 int (*ichkfn)(char *, char *);
  587 
  588 int chk_who(aClient *ac, aClient *sptr, int showall)
  589 {
  590     if(!IsClient(ac))
  591     return 0;
  592     if(IsInvisible(ac) && !showall)
  593     return 0;
  594 
  595     if(wsopts.client_type_plus &&
  596     wsopts.client_type != ac->user->servicetype)
  597     return 0;
  598 
  599     if(wsopts.check_umode)
  600     if((wsopts.umode_plus && 
  601         !((ac->umode&wsopts.umodes)==wsopts.umodes)) ||
  602        (!wsopts.umode_plus && ((ac->umode&wsopts.umodes)==wsopts.umodes)))
  603         return 0;
  604 
  605     if(wsopts.check_away)
  606     if((wsopts.away_plus && ac->user->away==NULL) ||
  607        (!wsopts.away_plus && ac->user->away!=NULL))
  608         return 0;
  609 
  610     /* while this is wasteful now, in the future
  611      * when clients contain pointers to their servers
  612      * of origin, this'll become a 4 byte check instead of a mycmp
  613      * -wd */
  614     /* welcome to the future... :) - lucas */
  615     if(wsopts.serv_plus)
  616     {
  617     if(wsopts.server != ac->uplink)
  618         return 0;
  619     /* don't let people find hidden opers via /who +s server */
  620     if(IsUmodeI(ac) && !showall)
  621         return 0;
  622     }
  623     /* we only call match once, since if the first condition
  624      * isn't true, most (all?) compilers will never try the
  625      * second...phew :) */
  626     if(wsopts.user!=NULL)
  627     if((wsopts.user_plus && uchkfn(wsopts.user, ac->user->username)) ||
  628        (!wsopts.user_plus && !uchkfn(wsopts.user, ac->user->username)))
  629         return 0;
  630 
  631     if(wsopts.host!=NULL)
  632     {
  633 #ifdef USER_HOSTMASKING
  634         if(IsAnOper(sptr))
  635         {
  636         if((wsopts.host_plus && hchkfn(wsopts.host, ac->user->host) && hchkfn(wsopts.host, ac->user->mhost)) ||
  637            (!wsopts.host_plus && (!hchkfn(wsopts.host, ac->user->host) || !hchkfn(wsopts.host, ac->user->mhost))))
  638             return 0;
  639         }
  640         else
  641         {
  642         if((wsopts.host_plus && hchkfn(wsopts.host, IsUmodeH(ac)?ac->user->mhost:ac->user->host)) ||
  643            (!wsopts.host_plus && !hchkfn(wsopts.host, IsUmodeH(ac)?ac->user->mhost:ac->user->host)))
  644             return 0;
  645         }
  646 #else
  647         if((wsopts.host_plus && hchkfn(wsopts.host, ac->user->host)) ||
  648            (!wsopts.host_plus && !hchkfn(wsopts.host, ac->user->host)))
  649             return 0;
  650 #endif
  651     }
  652     
  653     if(wsopts.host!=NULL)
  654     if((wsopts.host_plus && hchkfn(wsopts.host, ac->user->host)) ||
  655        (!wsopts.host_plus && !hchkfn(wsopts.host, ac->user->host)))
  656         return 0;
  657 
  658     if(wsopts.cidr_plus)
  659     if(ac->ip_family != wsopts.cidr_family ||
  660        bitncmp(&ac->ip, &wsopts.cidr_ip, wsopts.cidr_bits) != 0)
  661         return 0;
  662     
  663     if(wsopts.ip_plus)
  664     if(ichkfn(wsopts.ip, ac->hostip))
  665         return 0;
  666     
  667     if(wsopts.gcos!=NULL)
  668     if((wsopts.gcos_plus && gchkfn(wsopts.gcos, ac->info)) ||
  669        (!wsopts.gcos_plus && !gchkfn(wsopts.gcos, ac->info)))
  670         return 0;
  671 
  672     /*
  673      * For the below options, a value of two means '+', 
  674      * a value of 1 means '-', and a value of 0 means
  675      * not specified.
  676      */
  677 
  678     if(wsopts.ts_value == 2 && /* +t */
  679         NOW - ac->tsinfo < wsopts.ts)
  680         return 0;
  681     else if(wsopts.ts_value == 1 && /* -t */
  682         NOW - ac->tsinfo >= wsopts.ts)
  683         return 0;
  684 
  685     return 1;
  686 }
  687 
  688 inline char *first_visible_channel(aClient *cptr, aClient *sptr)
  689 {
  690     Link *lp;
  691     int secret = 0;
  692     aChannel *chptr = NULL;
  693     static char chnbuf[CHANNELLEN + 2];
  694 
  695     if(cptr->user->channel)
  696     {
  697     if(IsAdmin(sptr))
  698     {
  699         chptr = cptr->user->channel->value.chptr;
  700         if(!(ShowChannel(sptr, chptr)))
  701         secret = 1;
  702     }
  703     else
  704     {
  705         for(lp = cptr->user->channel; lp; lp = lp->next)
  706         {
  707         if(ShowChannel(sptr, lp->value.chptr))
  708             break;
  709         }
  710         if(lp)
  711         chptr = lp->value.chptr;
  712     }
  713 
  714     if(chptr)
  715     {
  716         if(!secret)
  717         return chptr->chname;
  718         ircsprintf(chnbuf, "%%%s", chptr->chname);
  719         return chnbuf;
  720     }
  721     }
  722     return "*";
  723 }
  724 
  725 /* allow lusers only 200 replies from /who */
  726 #define MAXWHOREPLIES 200
  727 #define WHO_HOPCOUNT(s, a) ( ( (IsULine((a)) || IsUmodeI((a))) && !IsAnOper((s)) ) ? 0 : a->hopcount)
  728 #define WHO_SERVER(s ,a) ((IsUmodeI((a)) && !IsAnOper((s))) ? HIDDEN_SERVER_NAME : a->user->server)
  729 #ifdef USER_HOSTMASKING
  730 #define WHO_HOST(s, a) ((wsopts.ip_show) ? (a)->hostip : ((IsUmodeH((a)) && !wsopts.realhost_show) || wsopts.maskhost_show) ? (a)->user->mhost : (a)->user->host)
  731 #else
  732 #define WHO_HOST(s, a) ((wsopts.ip_show) ? (a)->hostip : (a)->user->host)
  733 #endif
  734 int m_who(aClient *cptr, aClient *sptr, int parc, char *parv[])
  735 {
  736     aClient *ac;
  737     chanMember *cm;
  738     Link *lp;
  739     int shown=0, i=0, showall=IsAnOper(sptr);
  740     char status[4];
  741 
  742     /* drop nonlocal clients */
  743     if(!MyClient(sptr))
  744     return 0;
  745     
  746     if(!build_searchopts(sptr, parc-1, parv+1))
  747     return 0; /* /who was no good */
  748     
  749     if(wsopts.gcos!=NULL && (strchr(wsopts.gcos, '?'))==NULL &&
  750        (strchr(wsopts.gcos, '*'))==NULL)
  751     gchkfn=mycmp;
  752     else
  753     gchkfn=match;
  754     if(wsopts.nick!=NULL && (strchr(wsopts.nick, '?'))==NULL &&
  755        (strchr(wsopts.nick, '*'))==NULL)
  756     nchkfn=mycmp;
  757     else
  758     nchkfn=match;
  759     if(wsopts.user!=NULL && (strchr(wsopts.user, '?'))==NULL &&
  760        (strchr(wsopts.user, '*'))==NULL)
  761     uchkfn=mycmp;
  762     else
  763     uchkfn=match;
  764     if(wsopts.host!=NULL && (strchr(wsopts.host, '?'))==NULL &&
  765        (strchr(wsopts.host, '*'))==NULL)
  766     hchkfn=mycmp;
  767     else
  768     hchkfn=match;
  769 
  770     if(wsopts.ip!=NULL && (strchr(wsopts.ip, '?'))==NULL &&
  771        (strchr(wsopts.ip, '*'))==NULL)
  772     ichkfn=mycmp;
  773     else
  774     ichkfn=match;
  775 
  776     if(wsopts.channel!=NULL)
  777     {
  778     if(IsMember(sptr,wsopts.channel) && (!(wsopts.channel->mode.mode & MODE_AUDITORIUM) ||
  779            is_chan_opvoice(sptr, wsopts.channel) || IsAnOper(sptr)))
  780         showall=1;
  781     else if(SecretChannel(wsopts.channel) && IsAdmin(sptr))
  782         showall=1;
  783     else if(!SecretChannel(wsopts.channel) && IsAnOper(sptr))
  784         showall=1;
  785     else
  786         showall=0;
  787     if(showall || !SecretChannel(wsopts.channel))
  788     {
  789         for(cm=wsopts.channel->members; cm; cm=cm->next)
  790         {
  791         ac=cm->cptr;
  792         i=0;
  793         if(!chk_who(ac,sptr,showall))
  794             continue;
  795         /* If we have channel flags set, verify they match */
  796         if(wsopts.channelflags && ((cm->flags & wsopts.channelflags) == 0))
  797             continue;
  798         /* get rid of the pidly stuff first */
  799         /* wow, they passed it all, give them the reply...
  800          * IF they haven't reached the max, or they're an oper */
  801         status[i++]=(ac->user->away==NULL ? 'H' : 'G');
  802         status[i]=(IsAnOper(ac) ? '*' : ((IsInvisible(ac) &&
  803                           IsOper(sptr)) ? '%' : 0));
  804         status[((status[i]) ? ++i : i)]=((cm->flags&CHFL_CHANOP) ? '@'
  805                          : ((cm->flags&CHFL_VOICE) ? 
  806                             '+' : 0));
  807         status[++i]=0;
  808         sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
  809                wsopts.channel->chname, ac->user->username,
  810                WHO_HOST(sptr,ac), WHO_SERVER(sptr, ac), ac->name, status,
  811                WHO_HOPCOUNT(sptr, ac),
  812                ac->info);
  813         }
  814     }
  815     sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
  816            wsopts.channel->chname, "WHO");
  817     return 0;
  818     }
  819     /* if (for whatever reason) they gave us a nick with no
  820      * wildcards, just do a find_person, bewm! */
  821     else if(nchkfn==mycmp)
  822     {
  823     ac=find_person(wsopts.nick,NULL);
  824     if(ac!=NULL)
  825     {
  826         if(!chk_who(ac,sptr,1))
  827         {
  828         sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
  829                wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO");
  830         return 0;
  831         }
  832         else
  833         {
  834         status[0]=(ac->user->away==NULL ? 'H' : 'G');
  835         status[1]=(IsAnOper(ac) ? '*' : (IsInvisible(ac) &&
  836                          IsAnOper(sptr) ? '%' : 0));
  837         status[2]=0;
  838         sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
  839                wsopts.show_chan ? first_visible_channel(ac, sptr)
  840                : "*", ac->user->username, WHO_HOST(sptr,ac),
  841                WHO_SERVER(sptr, ac), ac->name, status,
  842                WHO_HOPCOUNT(sptr, ac),
  843                ac->info);
  844         sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
  845                wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO");
  846         return 0;
  847         }
  848     }
  849     sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
  850            wsopts.host!=NULL ? wsopts.host : wsopts.nick, "WHO");
  851     return 0;
  852     }
  853     
  854     if(wsopts.search_chan)
  855     {
  856     for(lp = sptr->user->channel; lp; lp = lp->next)
  857     {
  858         for(cm = lp->value.chptr->members; cm; cm = cm->next)
  859         {
  860         ac = cm->cptr;
  861         if(!chk_who(ac, sptr, 1))
  862             continue;
  863         
  864         if(shown==MAXWHOREPLIES && !IsAnOper(sptr))
  865         {
  866             sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name,
  867                    sptr->name, MAXWHOREPLIES, "WHO");
  868             break;
  869         }
  870         
  871         i = 0;
  872         status[i++]=(ac->user->away==NULL ? 'H' : 'G');
  873         status[i]=(IsAnOper(ac) ? '*' : ((IsInvisible(ac) &&
  874                           IsOper(sptr)) ? '%' : 0));
  875         status[((status[i]) ? ++i : i)]=((cm->flags&CHFL_CHANOP) ? 
  876                          '@' : ((cm->flags&CHFL_VOICE)
  877                             ? '+' : 0));
  878         status[++i]=0;
  879         sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
  880                lp->value.chptr->chname, ac->user->username,
  881                WHO_HOST(sptr,ac),WHO_SERVER(sptr, ac), ac->name,
  882                status, WHO_HOPCOUNT(sptr, ac), ac->info);
  883         shown++;
  884         }
  885     }
  886     }
  887     else
  888     {
  889     for(ac=client;ac;ac=ac->next)
  890     {
  891         if(!chk_who(ac,sptr,showall))
  892         continue;
  893         /* wow, they passed it all, give them the reply...
  894          * IF they haven't reached the max, or they're an oper */
  895         if(shown==MAXWHOREPLIES && !IsAnOper(sptr))
  896         {
  897         sendto_one(sptr, getreply(ERR_WHOLIMEXCEED), me.name, 
  898                sptr->name, MAXWHOREPLIES, "WHO");
  899         break; /* break out of loop so we can send end of who */
  900         }
  901         status[0]=(ac->user->away==NULL ? 'H' : 'G');
  902         status[1]=(IsAnOper(ac) ? '*' : (IsInvisible(ac) && 
  903                          IsAnOper(sptr) ? '%' : 0));
  904         status[2]=0;
  905         sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
  906                wsopts.show_chan ? first_visible_channel(ac, sptr) :
  907                "*", ac->user->username, WHO_HOST(sptr,ac),
  908                WHO_SERVER(sptr, ac), ac->name, status,
  909                WHO_HOPCOUNT(sptr, ac), ac->info);
  910         shown++;
  911     }
  912     }
  913     sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name,
  914            (wsopts.host!=NULL ? wsopts.host :
  915         (wsopts.nick!=NULL ? wsopts.nick :
  916          (wsopts.user!=NULL ? wsopts.user :
  917           (wsopts.gcos!=NULL ? wsopts.gcos :
  918            (wsopts.server!=NULL ? wsopts.server->name :
  919             "*"))))), "WHO");
  920     return 0;
  921 }