home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / s_user.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  56.4 KB  |  2,239 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
  3.  *   Copyright (C) 1990 Jarkko Oikarinen and
  4.  *                      University of Oulu, Computing Center
  5.  *
  6.  *   See file AUTHORS in IRC package for additional names of
  7.  *   the programmers. 
  8.  *
  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)
  12.  *   any later version.
  13.  *
  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.
  18.  *
  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.
  22.  */
  23.  
  24. #ifndef lint
  25. static  char sccsid[] = "@(#)s_user.c    2.74 2/8/94 (C) 1988 University of Oulu, \
  26. Computing Center and Jarkko Oikarinen";
  27. #endif
  28.  
  29. #include "struct.h"
  30. #include "common.h"
  31. #include "sys.h"
  32. #include "numeric.h"
  33. #include "msg.h"
  34. #include "channel.h"
  35. #include <sys/stat.h>
  36. #include <utmp.h>
  37. #include <fcntl.h>
  38. #include "h.h"
  39.  
  40. void    send_umode_out PROTO((aClient*, aClient *, int));
  41. void    send_umode PROTO((aClient *, aClient *, int, int, char *));
  42.  
  43. static char buf[BUFSIZE], buf2[BUFSIZE];
  44.  
  45. /*
  46. ** m_functions execute protocol messages on this server:
  47. **
  48. **    cptr    is always NON-NULL, pointing to a *LOCAL* client
  49. **        structure (with an open socket connected!). This
  50. **        identifies the physical socket where the message
  51. **        originated (or which caused the m_function to be
  52. **        executed--some m_functions may call others...).
  53. **
  54. **    sptr    is the source of the message, defined by the
  55. **        prefix part of the message if present. If not
  56. **        or prefix not found, then sptr==cptr.
  57. **
  58. **        (!IsServer(cptr)) => (cptr == sptr), because
  59. **        prefixes are taken *only* from servers...
  60. **
  61. **        (IsServer(cptr))
  62. **            (sptr == cptr) => the message didn't
  63. **            have the prefix.
  64. **
  65. **            (sptr != cptr && IsServer(sptr) means
  66. **            the prefix specified servername. (?)
  67. **
  68. **            (sptr != cptr && !IsServer(sptr) means
  69. **            that message originated from a remote
  70. **            user (not local).
  71. **
  72. **        combining
  73. **
  74. **        (!IsServer(sptr)) means that, sptr can safely
  75. **        taken as defining the target structure of the
  76. **        message in this server.
  77. **
  78. **    *Always* true (if 'parse' and others are working correct):
  79. **
  80. **    1)    sptr->from == cptr  (note: cptr->from == cptr)
  81. **
  82. **    2)    MyConnect(sptr) <=> sptr == cptr (e.g. sptr
  83. **        *cannot* be a local connection, unless it's
  84. **        actually cptr!). [MyConnect(x) should probably
  85. **        be defined as (x == x->from) --msa ]
  86. **
  87. **    parc    number of variable parameter strings (if zero,
  88. **        parv is allowed to be NULL)
  89. **
  90. **    parv    a NULL terminated list of parameter pointers,
  91. **
  92. **            parv[0], sender (prefix string), if not present
  93. **                this points to an empty string.
  94. **            parv[1]...parv[parc-1]
  95. **                pointers to additional parameters
  96. **            parv[parc] == NULL, *always*
  97. **
  98. **        note:    it is guaranteed that parv[0]..parv[parc-1] are all
  99. **            non-NULL pointers.
  100. */
  101.  
  102. /*
  103. ** next_client
  104. **    Local function to find the next matching client. The search
  105. **    can be continued from the specified client entry. Normal
  106. **    usage loop is:
  107. **
  108. **    for (x = client; x = next_client(x,mask); x = x->next)
  109. **        HandleMatchingClient;
  110. **          
  111. */
  112. aClient *next_client(next, ch)
  113. Reg1    aClient *next;    /* First client to check */
  114. Reg2    char    *ch;    /* search string (may include wilds) */
  115. {
  116.     Reg3    aClient    *tmp = next;
  117.  
  118.     next = find_client(ch, tmp);
  119.     if (tmp && tmp->prev == next)
  120.         return NULL;
  121.     if (next != tmp)
  122.         return next;
  123.     for ( ; next; next = next->next)
  124.         {
  125.         if (IsService(next))
  126.             continue;
  127.         if (!match(ch, next->name) || !matches(next->name, ch))
  128.             break;
  129.         }
  130.     return next;
  131. }
  132.  
  133. /*
  134. ** hunt_server
  135. **
  136. **    Do the basic thing in delivering the message (command)
  137. **    across the relays to the specific server (server) for
  138. **    actions.
  139. **
  140. **    Note:    The command is a format string and *MUST* be
  141. **        of prefixed style (e.g. ":%s COMMAND %s ...").
  142. **        Command can have only max 8 parameters.
  143. **
  144. **    server    parv[server] is the parameter identifying the
  145. **        target server.
  146. **
  147. **    *WARNING*
  148. **        parv[server] is replaced with the pointer to the
  149. **        real servername from the matched client (I'm lazy
  150. **        now --msa).
  151. **
  152. **    returns: (see #defines)
  153. */
  154. int    hunt_server(cptr, sptr, command, server, parc, parv)
  155. aClient    *cptr, *sptr;
  156. char    *command, *parv[];
  157. int    server, parc;
  158.     {
  159.     aClient *acptr;
  160.  
  161.     /*
  162.     ** Assume it's me, if no server
  163.     */
  164.     if (parc <= server || BadPtr(parv[server]) ||
  165.         matches(me.name, parv[server]) == 0 ||
  166.         matches(parv[server], me.name) == 0)
  167.         return (HUNTED_ISME);
  168.     /*
  169.     ** These are to pickup matches that would cause the following
  170.     ** message to go in the wrong direction while doing quick fast
  171.     ** non-matching lookups.
  172.     */
  173.     if ((acptr = find_client(parv[server], NULL)))
  174.         if (acptr->from == sptr->from && !MyConnect(acptr))
  175.             acptr = NULL;
  176.     if (!acptr && (acptr = find_server(parv[server], NULL)))
  177.         if (acptr->from == sptr->from && !MyConnect(acptr))
  178.             acptr = NULL;
  179.     if (!acptr)
  180.         for (acptr = client, (void)collapse(parv[server]);
  181.              (acptr = next_client(acptr, parv[server]));
  182.              acptr = acptr->next)
  183.             {
  184.             if (acptr->from == sptr->from && !MyConnect(acptr))
  185.                 continue;
  186.             /*
  187.              * Fix to prevent looping in case the parameter for
  188.              * some reason happens to match someone from the from
  189.              * link --jto
  190.              */
  191.             if (IsRegistered(acptr) && (acptr != cptr))
  192.                 break;
  193.             }
  194.      if (acptr)
  195.         {
  196.         if (IsMe(acptr) || MyClient(acptr))
  197.             return HUNTED_ISME;
  198.         if (matches(acptr->name, parv[server]))
  199.             parv[server] = acptr->name;
  200.         sendto_one(acptr, command, parv[0],
  201.                parv[1], parv[2], parv[3], parv[4],
  202.                parv[5], parv[6], parv[7], parv[8]);
  203.         return(HUNTED_PASS);
  204.         } 
  205.     sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name,
  206.            parv[0], parv[server]);
  207.     return(HUNTED_NOSUCH);
  208.     }
  209.  
  210. /*
  211. ** 'do_nick_name' ensures that the given parameter (nick) is
  212. ** really a proper string for a nickname (note, the 'nick'
  213. ** may be modified in the process...)
  214. **
  215. **    RETURNS the length of the final NICKNAME (0, if
  216. **    nickname is illegal)
  217. **
  218. **  Nickname characters are in range
  219. **    'A'..'}', '_', '-', '0'..'9'
  220. **  anything outside the above set will terminate nickname.
  221. **  In addition, the first character cannot be '-'
  222. **  or a Digit.
  223. **
  224. **  Note:
  225. **    '~'-character should be allowed, but
  226. **    a change should be global, some confusion would
  227. **    result if only few servers allowed it...
  228. */
  229.  
  230. static    int do_nick_name(nick)
  231. char    *nick;
  232. {
  233.     Reg1 char *ch;
  234.  
  235.     if (*nick == '-' || isdigit(*nick)) /* first character in [0..9-] */
  236.         return 0;
  237.  
  238.     for (ch = nick; *ch && (ch - nick) < NICKLEN; ch++)
  239.         if (!isvalid(*ch) || isspace(*ch))
  240.             break;
  241.  
  242.     *ch = '\0';
  243.  
  244.     return (ch - nick);
  245. }
  246.  
  247.  
  248. /*
  249. ** canonize
  250. **
  251. ** reduce a string of duplicate list entries to contain only the unique
  252. ** items.  Unavoidably O(n^2).
  253. */
  254. char    *canonize(buffer)
  255. char    *buffer;
  256. {
  257.     static    char    cbuf[BUFSIZ];
  258.     register char    *s, *t, *cp = cbuf;
  259.     register int    l = 0;
  260.     char    *p = NULL, *p2;
  261.  
  262.     *cp = '\0';
  263.  
  264.     for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ","))
  265.         {
  266.         if (l)
  267.             {
  268.             for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
  269.                  t = strtoken(&p2, NULL, ","))
  270.                 if (!mycmp(s, t))
  271.                     break;
  272.                 else if (p2)
  273.                     p2[-1] = ',';
  274.             }
  275.         else
  276.             t = NULL;
  277.         if (!t)
  278.             {
  279.             if (l)
  280.                 *(cp-1) = ',';
  281.             else
  282.                 l = 1;
  283.             (void)strcpy(cp, s);
  284.             if (p)
  285.                 cp += (p - s);
  286.             }
  287.         else if (p2)
  288.             p2[-1] = ',';
  289.         }
  290.     return cbuf;
  291. }
  292.  
  293.  
  294. /*
  295. ** register_user
  296. **    This function is called when both NICK and USER messages
  297. **    have been accepted for the client, in whatever order. Only
  298. **    after this the USER message is propagated.
  299. **
  300. **    NICK's must be propagated at once when received, although
  301. **    it would be better to delay them too until full info is
  302. **    available. Doing it is not so simple though, would have
  303. **    to implement the following:
  304. **
  305. **    1) user telnets in and gives only "NICK foobar" and waits
  306. **    2) another user far away logs in normally with the nick
  307. **       "foobar" (quite legal, as this server didn't propagate
  308. **       it).
  309. **    3) now this server gets nick "foobar" from outside, but
  310. **       has already the same defined locally. Current server
  311. **       would just issue "KILL foobar" to clean out dups. But,
  312. **       this is not fair. It should actually request another
  313. **       nick from local user or kill him/her...
  314. */
  315.  
  316. static    int    register_user(cptr, sptr, nick, username)
  317. aClient    *cptr;
  318. aClient    *sptr;
  319. char    *nick, *username;
  320. {
  321.     Reg1    aConfItem *aconf;
  322.         char    *parv[3];
  323.     short    oldstatus = sptr->status;
  324.     anUser    *user = sptr->user;
  325.     int    i;
  326.  
  327.     user->last = time(NULL);
  328.     parv[0] = sptr->name;
  329.     parv[1] = parv[2] = NULL;
  330.  
  331.     if (MyConnect(sptr))
  332.         {
  333.         if ((i = check_client(sptr)))
  334.             {
  335.             sendto_ops("%s from %s.", i == -3 ?
  336.                           "Too many connections" :
  337.                            "Unauthorized connection",
  338.                    get_client_host(sptr));
  339.             ircstp->is_ref++;
  340.             return exit_client(cptr, sptr, &me, i == -3 ?
  341.                          "No more connections" :
  342.                          "No Authorization");
  343.               } 
  344.         if (IsUnixSocket(sptr))
  345.             strncpyzt(user->host, me.sockhost, HOSTLEN+1);
  346.         else
  347.             strncpyzt(user->host, sptr->sockhost, HOSTLEN+1);
  348.         aconf = sptr->confs->value.aconf;
  349.         if (sptr->flags & FLAGS_DOID && !(sptr->flags & FLAGS_GOTID))
  350.             {
  351.             /* because username may point to user->username */
  352.             char    temp[USERLEN+1];
  353.  
  354.             strncpyzt(temp, username, USERLEN+1);
  355.             *user->username = '~';
  356.             (void)strncpy(&user->username[1], temp, USERLEN);
  357.             user->username[USERLEN] = '\0';
  358.             
  359.             }
  360.         else if (sptr->flags & FLAGS_GOTID)
  361.             strncpyzt(user->username, sptr->username, USERLEN+1);
  362.         else
  363.             strncpyzt(user->username, username, USERLEN+1);
  364.  
  365.         if (!BadPtr(aconf->passwd) &&
  366.             !StrEq(sptr->passwd, aconf->passwd))
  367.             {
  368.             ircstp->is_ref++;
  369.             sendto_one(sptr, err_str(ERR_PASSWDMISMATCH),
  370.                    me.name, parv[0]);
  371.             return exit_client(cptr, sptr, &me, "Bad Password");
  372.             }
  373.         bzero(sptr->passwd, sizeof(sptr->passwd));
  374.         /*
  375.          * following block for the benefit of time-dependent K:-lines
  376.          */
  377.         if (find_kill(sptr))
  378.             {
  379.             ircstp->is_ref++;
  380.             return exit_client(cptr, sptr, &me, "K-lined");
  381.             }
  382. #ifdef R_LINES
  383.         if (find_restrict(sptr))
  384.             {
  385.             ircstp->is_ref++;
  386.             return exit_client(cptr, sptr, &me , "R-lined");
  387.             }
  388. #endif
  389.         if (oldstatus == STAT_MASTER && MyConnect(sptr))
  390.             (void)m_oper(&me, sptr, 1, parv);
  391.         }
  392.     else
  393.         strncpyzt(user->username, username, USERLEN+1);
  394.     SetClient(sptr);
  395.     if (MyConnect(sptr))
  396.         {
  397.         sendto_one(sptr, rpl_str(RPL_WELCOME), me.name, nick, nick);
  398.         /* This is a duplicate of the NOTICE but see below...*/
  399.         sendto_one(sptr, rpl_str(RPL_YOURHOST), me.name, nick,
  400.                get_client_name(&me, FALSE), version);
  401. #ifdef    IRCII_KLUDGE
  402.         /*
  403.         ** Don't mess with this one - IRCII needs it! -Avalon
  404.         */
  405.         sendto_one(sptr,
  406.             "NOTICE %s :*** Your host is %s, running version %s",
  407.             nick, get_client_name(&me, FALSE), version);
  408. #endif
  409.         sendto_one(sptr, rpl_str(RPL_CREATED),me.name,nick,creation);
  410.         sendto_one(sptr, rpl_str(RPL_MYINFO), me.name, parv[0],
  411.                me.name, version);
  412.         (void)m_lusers(sptr, sptr, 1, parv);
  413.         (void)m_motd(sptr, sptr, 1, parv);
  414.         nextping = time(NULL);
  415.         }
  416.     else if (IsServer(cptr))
  417.         {
  418.         aClient    *acptr;
  419.  
  420.         if ((acptr = find_server(user->server, NULL)) &&
  421.             acptr->from != sptr->from)
  422.            {
  423.             sendto_ops("Bad User [%s] :%s USER %s %s, != %s[%s]",
  424.                 cptr->name, nick, user->username, user->server,
  425.                 acptr->name, acptr->from->name);
  426.             sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])",
  427.                    me.name, sptr->name, me.name, user->server,
  428.                    acptr->from->name, acptr->from->sockhost);
  429.             sptr->flags |= FLAGS_KILLED;
  430.             return exit_client(sptr, sptr, &me,
  431.                        "USER server wrong direction");
  432.            }
  433.         }
  434.  
  435.     sendto_serv_butone(cptr, "NICK %s :%d", nick, sptr->hopcount+1);
  436.     sendto_serv_butone(cptr, ":%s USER %s %s %s :%s", nick,
  437.                user->username, user->host,
  438.                user->server, sptr->info);
  439.     if (MyConnect(sptr))
  440.         send_umode_out(cptr, sptr, 0);
  441. #ifdef    USE_SERVICES
  442.     check_services_butone(SERVICE_WANT_NICK, sptr, "NICK %s :%d",
  443.                 nick, sptr->hopcount);
  444.     check_services_butone(SERVICE_WANT_USER, sptr, ":%s USER %s %s %s :%s",
  445.                 nick, user->username, user->host,
  446.                 user->server, sptr->info);
  447. #endif
  448.  
  449.     return 0;
  450.     }
  451.  
  452. /*
  453. ** m_nick
  454. **    parv[0] = sender prefix
  455. **    parv[1] = nickname
  456. */
  457. int    m_nick(cptr, sptr, parc, parv)
  458. aClient *cptr, *sptr;
  459. int    parc;
  460. char    *parv[];
  461. {
  462.     aClient *acptr;
  463.     char    nick[NICKLEN+2], *s;
  464.     
  465.     if (parc < 2)
  466.         {
  467.         sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
  468.                me.name, parv[0]);
  469.         return 0;
  470.         }
  471.     if (MyConnect(sptr) && (s = (char *)index(parv[1], '~')))
  472.         *s = '\0';
  473.     strncpyzt(nick, parv[1], NICKLEN+1);
  474.     /*
  475.      * if do_nick_name() returns a null name OR if the server sent a nick
  476.      * name and do_nick_name() changed it in some way (due to rules of nick
  477.      * creation) then reject it. If from a server and we reject it,
  478.      * and KILL it. -avalon 4/4/92
  479.      */
  480.     if (do_nick_name(nick) == 0 ||
  481.         (IsServer(cptr) && strcmp(nick, parv[1])))
  482.         {
  483.         sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME),
  484.                me.name, parv[0], parv[1]);
  485.  
  486.         if (IsServer(cptr))
  487.             {
  488.             ircstp->is_kill++;
  489.             sendto_ops("Bad Nick: %s From: %s %s",
  490.                    parv[1], parv[0],
  491.                    get_client_name(cptr, FALSE));
  492.             sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])",
  493.                    me.name, parv[1], me.name, parv[1],
  494.                    nick, cptr->name);
  495.             if (sptr != cptr) /* bad nick change */
  496.                 {
  497.                 sendto_serv_butone(cptr,
  498.                     ":%s KILL %s :%s (%s <- %s!%s@%s)",
  499.                     me.name, parv[0], me.name,
  500.                     get_client_name(cptr, FALSE),
  501.                     parv[0],
  502.                     sptr->user ? sptr->username : "",
  503.                     sptr->user ? sptr->user->server :
  504.                              cptr->name);
  505.                 sptr->flags |= FLAGS_KILLED;
  506.                 return exit_client(cptr,sptr,&me,"BadNick");
  507.                 }
  508.             }
  509.         return 0;
  510.         }
  511.  
  512.     /*
  513.     ** Check against nick name collisions.
  514.     **
  515.     ** Put this 'if' here so that the nesting goes nicely on the screen :)
  516.     ** We check against server name list before determining if the nickname
  517.     ** is present in the nicklist (due to the way the below for loop is
  518.     ** constructed). -avalon
  519.     */
  520.     if ((acptr = find_server(nick, NULL)))
  521.         if (MyConnect(sptr))
  522.             {
  523.             sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
  524.                    BadPtr(parv[0]) ? "*" : parv[0], nick);
  525.             return 0; /* NICK message ignored */
  526.             }
  527.     /*
  528.     ** acptr already has result from previous find_server()
  529.     */
  530.     if (acptr)
  531.         {
  532.         /*
  533.         ** We have a nickname trying to use the same name as
  534.         ** a server. Send out a nick collision KILL to remove
  535.         ** the nickname. As long as only a KILL is sent out,
  536.         ** there is no danger of the server being disconnected.
  537.         ** Ultimate way to jupiter a nick ? >;-). -avalon
  538.         */
  539.         sendto_ops("Nick collision on %s(%s <- %s)",
  540.                sptr->name, acptr->from->name,
  541.                get_client_name(cptr, FALSE));
  542.         ircstp->is_kill++;
  543.         sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)",
  544.                me.name, sptr->name, me.name, acptr->from->name,
  545.                /* NOTE: Cannot use get_client_name
  546.                ** twice here, it returns static
  547.                ** string pointer--the other info
  548.                ** would be lost
  549.                */
  550.                get_client_name(cptr, FALSE));
  551.         sptr->flags |= FLAGS_KILLED;
  552.         return exit_client(cptr, sptr, &me, "Nick/Server collision");
  553.         }
  554.     if (!(acptr = find_client(nick, NULL)))
  555.         goto nickkilldone;  /* No collisions, all clear... */
  556.     /*
  557.     ** If acptr == sptr, then we have a client doing a nick
  558.     ** change between *equivalent* nicknames as far as server
  559.     ** is concerned (user is changing the case of his/her
  560.     ** nickname or somesuch)
  561.     */
  562.     if (acptr == sptr)
  563.         if (strcmp(acptr->name, nick) != 0)
  564.             /*
  565.             ** Allows change of case in his/her nick
  566.             */
  567.             goto nickkilldone; /* -- go and process change */
  568.         else
  569.             /*
  570.             ** This is just ':old NICK old' type thing.
  571.             ** Just forget the whole thing here. There is
  572.             ** no point forwarding it to anywhere,
  573.             ** especially since servers prior to this
  574.             ** version would treat it as nick collision.
  575.             */
  576.             return 0; /* NICK Message ignored */
  577.     /*
  578.     ** Note: From this point forward it can be assumed that
  579.     ** acptr != sptr (point to different client structures).
  580.     */
  581.     /*
  582.     ** If the older one is "non-person", the new entry is just
  583.     ** allowed to overwrite it. Just silently drop non-person,
  584.     ** and proceed with the nick. This should take care of the
  585.     ** "dormant nick" way of generating collisions...
  586.     */
  587.     if (IsUnknown(acptr) && MyConnect(acptr))
  588.         {
  589.         exit_client(NULL, acptr, &me, "Overridden");
  590.         goto nickkilldone;
  591.         }
  592.     /*
  593.     ** Decide, we really have a nick collision and deal with it
  594.     */
  595.     if (!IsServer(cptr))
  596.         {
  597.         /*
  598.         ** NICK is coming from local client connection. Just
  599.         ** send error reply and ignore the command.
  600.         */
  601.         sendto_one(sptr, err_str(ERR_NICKNAMEINUSE),
  602.                /* parv[0] is empty when connecting */
  603.                me.name, BadPtr(parv[0]) ? "*" : parv[0], nick);
  604.         return 0; /* NICK message ignored */
  605.         }
  606.     /*
  607.     ** NICK was coming from a server connection. Means that the same
  608.     ** nick is registerd for different users by different server.
  609.     ** This is either a race condition (two users coming online about
  610.     ** same time, or net reconnecting) or just two net fragmens becoming
  611.     ** joined and having same nicks in use. We cannot have TWO users with
  612.     ** same nick--purge this NICK from the system with a KILL... >;)
  613.     **
  614.     ** The client indicated by 'acptr' is dead meat, give at least some
  615.     ** indication of the reason why we are just dropping it cold.
  616.     */
  617.     sendto_one(acptr, err_str(ERR_NICKCOLLISION),
  618.            me.name, acptr->name, acptr->name);
  619.     /*
  620.     ** This seemingly obscure test (sptr == cptr) differentiates
  621.     ** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms.
  622.     */
  623.     if (sptr == cptr)
  624.         {
  625.         sendto_ops("Nick collision on %s(%s <- %s)",
  626.                acptr->name, acptr->from->name,
  627.                get_client_name(cptr, FALSE));
  628.         /*
  629.         ** A new NICK being introduced by a neighbouring
  630.         ** server (e.g. message type "NICK new" received)
  631.         */
  632.         ircstp->is_kill++;
  633.         sendto_serv_butone(NULL, /* all servers */
  634.                    ":%s KILL %s :%s (%s <- %s)",
  635.                    me.name, acptr->name, me.name,
  636.                    acptr->from->name,
  637.                    /* NOTE: Cannot use get_client_name twice
  638.                    ** here, it returns static string pointer:
  639.                    ** the other info would be lost
  640.                    */
  641.                    get_client_name(cptr, FALSE));
  642.         acptr->flags |= FLAGS_KILLED;
  643.         return exit_client(cptr, acptr, &me, "Nick collision");
  644.         }
  645.     /*
  646.     ** A NICK change has collided (e.g. message type
  647.     ** ":old NICK new". This requires more complex cleanout.
  648.     ** Both clients must be purged from this server, the "new"
  649.     ** must be killed from the incoming connection, and "old" must
  650.     ** be purged from all outgoing connections.
  651.     */
  652.     sendto_ops("Nick change collision from %s to %s(%s <- %s)",
  653.            sptr->name, acptr->name, acptr->from->name,
  654.            get_client_name(cptr, FALSE));
  655.     ircstp->is_kill++;
  656.     sendto_serv_butone(NULL, /* KILL old from outgoing servers */
  657.                ":%s KILL %s :%s (%s(%s) <- %s)",
  658.                me.name, sptr->name, me.name, acptr->from->name,
  659.                acptr->name, get_client_name(cptr, FALSE));
  660.     ircstp->is_kill++;
  661.     sendto_serv_butone(NULL, /* Kill new from incoming link */
  662.            ":%s KILL %s :%s (%s <- %s(%s))",
  663.            me.name, acptr->name, me.name, acptr->from->name,
  664.            get_client_name(cptr, FALSE), sptr->name);
  665.     acptr->flags |= FLAGS_KILLED;
  666.     (void)exit_client(NULL, acptr, &me, "Nick collision(new)");
  667.     sptr->flags |= FLAGS_KILLED;
  668.     return exit_client(cptr, sptr, &me, "Nick collision(old)");
  669.  
  670. nickkilldone:
  671.     if (IsServer(sptr))
  672.         {
  673.         /* A server introducing a new client, change source */
  674.  
  675.         sptr = make_client(cptr);
  676.         add_client_to_list(sptr);
  677.         if (parc > 2)
  678.             sptr->hopcount = atoi(parv[2]);
  679.         }
  680.     else if (sptr->name[0])
  681.         {
  682.         /*
  683.         ** Client just changing his/her nick. If he/she is
  684.         ** on a channel, send note of change to all clients
  685.         ** on that channel. Propagate notice to other servers.
  686.         */
  687.         sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
  688.         if (sptr->user)
  689.             add_history(sptr);
  690.         sendto_serv_butone(cptr, ":%s NICK :%s", parv[0], nick);
  691. #ifdef    USE_SERVICES
  692.         check_services_butone(SERVICE_WANT_NICK, sptr, ":%s NICK :%s",
  693.                     parv[0], nick);
  694. #endif
  695.         }
  696.     else
  697.         {
  698.         /* Client setting NICK the first time */
  699.  
  700.         /* This had to be copied here to avoid problems.. */
  701.         (void)strcpy(sptr->name, nick);
  702.         if (sptr->user)
  703.             /*
  704.             ** USER already received, now we have NICK.
  705.             ** *NOTE* For servers "NICK" *must* precede the
  706.             ** user message (giving USER before NICK is possible
  707.             ** only for local client connection!). register_user
  708.             ** may reject the client and call exit_client for it
  709.             ** --must test this and exit m_nick too!!!
  710.             */
  711.             if (register_user(cptr, sptr, nick,
  712.                       sptr->user->username)
  713.                 == FLUSH_BUFFER)
  714.                 return FLUSH_BUFFER;
  715.         }
  716.     /*
  717.     **  Finally set new nick name.
  718.     */
  719.     if (sptr->name[0])
  720.         (void)del_from_client_hash_table(sptr->name, sptr);
  721.     (void)strcpy(sptr->name, nick);
  722.     (void)add_to_client_hash_table(nick, sptr);
  723.     return 0;
  724. }
  725.  
  726. /*
  727. ** m_message (used in m_private() and m_notice())
  728. ** the general function to deliver MSG's between users/channels
  729. **
  730. **    parv[0] = sender prefix
  731. **    parv[1] = receiver list
  732. **    parv[2] = message text
  733. **
  734. ** massive cleanup
  735. ** rev argv 6/91
  736. **
  737. */
  738.  
  739. static    int    m_message(cptr, sptr, parc, parv, notice)
  740. aClient *cptr, *sptr;
  741. int    parc;
  742. char    *parv[];
  743. int    notice;
  744. {
  745.     Reg1    aClient    *acptr;
  746.     Reg2    char    *s;
  747.     aChannel *chptr;
  748.     char    *nick, *server, *p, *cmd, *host;
  749.  
  750.     if (notice)
  751.         {
  752.         if (check_registered(sptr))
  753.             return 0;
  754.         }
  755.     else if (check_registered_user(sptr))
  756.         return 0;
  757.  
  758.     cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
  759.  
  760.     if (parc < 2 || *parv[1] == '\0')
  761.         {
  762.         sendto_one(sptr, err_str(ERR_NORECIPIENT),
  763.                me.name, parv[0], cmd);
  764.         return -1;
  765.         }
  766.  
  767.     if (parc < 3 || *parv[2] == '\0')
  768.         {
  769.         sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
  770.         return -1;
  771.         }
  772.  
  773.     if (MyConnect(sptr))
  774.         parv[1] = canonize(parv[1]);
  775.     for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
  776.          nick = strtoken(&p, NULL, ","))
  777.         {
  778.         /*
  779.         ** nickname addressed?
  780.         */
  781.         if ((acptr = find_person(nick, NULL)))
  782.             {
  783.             if (!notice && MyConnect(sptr) &&
  784.                 acptr->user && acptr->user->away)
  785.                 sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
  786.                        parv[0], acptr->name,
  787.                        acptr->user->away);
  788.             sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
  789.                       parv[0], cmd, nick, parv[2]);
  790.             continue;
  791.             }
  792.         /*
  793.         ** channel msg?
  794.         */
  795.         if ((chptr = find_channel(nick, NullChn)))
  796.             {
  797.             if (can_send(sptr, chptr) == 0)
  798.                 sendto_channel_butone(cptr, sptr, chptr,
  799.                               ":%s %s %s :%s",
  800.                               parv[0], cmd, nick,
  801.                               parv[2]);
  802.             else if (!notice)
  803.                 sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
  804.                        me.name, parv[0], nick);
  805.             continue;
  806.             }
  807.     
  808.         /*
  809.         ** the following two cases allow masks in NOTICEs
  810.         ** (for OPERs only)
  811.         **
  812.         ** Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
  813.         */
  814.         if ((*nick == '$' || *nick == '#') && IsAnOper(sptr))
  815.             {
  816.             if (!(s = (char *)rindex(nick, '.')))
  817.                 {
  818.                 sendto_one(sptr, err_str(ERR_NOTOPLEVEL),
  819.                        me.name, parv[0], nick);
  820.                 continue;
  821.                 }
  822.             while (*++s)
  823.                 if (*s == '.' || *s == '*' || *s == '?')
  824.                     break;
  825.             if (*s == '*' || *s == '?')
  826.                 {
  827.                 sendto_one(sptr, err_str(ERR_WILDTOPLEVEL),
  828.                        me.name, parv[0], nick);
  829.                 continue;
  830.                 }
  831.             sendto_match_butone(IsServer(cptr) ? cptr : NULL, 
  832.                         sptr, nick + 1,
  833.                         (*nick == '#') ? MATCH_HOST :
  834.                                  MATCH_SERVER,
  835.                         ":%s %s %s :%s", parv[0],
  836.                         cmd, nick, parv[2]);
  837.             continue;
  838.             }
  839.     
  840.         /*
  841.         ** user[%host]@server addressed?
  842.         */
  843.         if ((server = (char *)index(nick, '@')) &&
  844.             (acptr = find_server(server + 1, NULL)))
  845.             {
  846.             int count = 0;
  847.  
  848.             /*
  849.             ** Not destined for a user on me :-(
  850.             */
  851.             if (!IsMe(acptr))
  852.                 {
  853.                 sendto_one(acptr,":%s %s %s :%s", parv[0],
  854.                        cmd, nick, parv[2]);
  855.                 continue;
  856.                 }
  857.             *server = '\0';
  858.  
  859.             if ((host = (char *)index(nick, '%')))
  860.                 *host++ = '\0';
  861.  
  862.             /*
  863.             ** Look for users which match the destination host
  864.             ** (no host == wildcard) and if one and one only is
  865.             ** found connected to me, deliver message!
  866.             */
  867.             acptr = find_userhost(nick, host, NULL, &count);
  868.             if (server)
  869.                 *server = '@';
  870.             if (host)
  871.                 *--host = '%';
  872.             if (acptr)
  873.                 {
  874.                 if (count == 1)
  875.                     sendto_prefix_one(acptr, sptr,
  876.                               ":%s %s %s :%s",
  877.                                parv[0], cmd,
  878.                               nick, parv[2]);
  879.                 else if (!notice)
  880.                     sendto_one(sptr,
  881.                            err_str(ERR_TOOMANYTARGETS),
  882.                            me.name, parv[0], nick);
  883.                 }
  884.             if (acptr)
  885.                 continue;
  886.             }
  887.         sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
  888.                parv[0], nick);
  889.             }
  890.     return 0;
  891. }
  892.  
  893. /*
  894. ** m_private
  895. **    parv[0] = sender prefix
  896. **    parv[1] = receiver list
  897. **    parv[2] = message text
  898. */
  899.  
  900. int    m_private(cptr, sptr, parc, parv)
  901. aClient *cptr, *sptr;
  902. int    parc;
  903. char    *parv[];
  904. {
  905.     return m_message(cptr, sptr, parc, parv, 0);
  906. }
  907.  
  908. /*
  909. ** m_notice
  910. **    parv[0] = sender prefix
  911. **    parv[1] = receiver list
  912. **    parv[2] = notice text
  913. */
  914.  
  915. int    m_notice(cptr, sptr, parc, parv)
  916. aClient *cptr, *sptr;
  917. int    parc;
  918. char    *parv[];
  919. {
  920.     return m_message(cptr, sptr, parc, parv, 1);
  921. }
  922.  
  923. static    void    do_who(sptr, acptr, repchan)
  924. aClient *sptr, *acptr;
  925. aChannel *repchan;
  926. {
  927.     char    status[5];
  928.     int    i = 0;
  929.  
  930.     if (acptr->user->away)
  931.         status[i++] = 'G';
  932.     else
  933.         status[i++] = 'H';
  934.     if (IsAnOper(acptr))
  935.         status[i++] = '*';
  936.     if (repchan && is_chan_op(acptr, repchan))
  937.         status[i++] = '@';
  938.     else if (repchan && has_voice(acptr, repchan))
  939.         status[i++] = '+';
  940.     status[i] = '\0';
  941.     sendto_one(sptr, rpl_str(RPL_WHOREPLY), me.name, sptr->name,
  942.            (repchan) ? (repchan->chname) : "*", acptr->user->username,
  943.            acptr->user->host, acptr->user->server, acptr->name,
  944.            status, acptr->hopcount, acptr->info);
  945. }
  946.  
  947.  
  948. /*
  949. ** m_who
  950. **    parv[0] = sender prefix
  951. **    parv[1] = nickname mask list
  952. **    parv[2] = additional selection flag, only 'o' for now.
  953. */
  954. int    m_who(cptr, sptr, parc, parv)
  955. aClient *cptr, *sptr;
  956. int    parc;
  957. char    *parv[];
  958. {
  959.     Reg1    aClient *acptr;
  960.     Reg2    char    *mask = parc > 1 ? parv[1] : NULL;
  961.     Reg3    Link    *lp;
  962.     aChannel *chptr;
  963.     aChannel *mychannel;
  964.     char    *channame = NULL, *s;
  965.     int    oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
  966.     int    member;
  967.  
  968.     if (!BadPtr(mask))
  969.         {
  970.         if ((s = (char *)index(mask, ',')))
  971.             {
  972.             parv[1] = ++s;
  973.             (void)m_who(cptr, sptr, parc, parv);
  974.             }
  975.         clean_channelname(mask);
  976.         }
  977.  
  978.     mychannel = NullChn;
  979.     if (sptr->user)
  980.         if ((lp = sptr->user->channel))
  981.             mychannel = lp->value.chptr;
  982.  
  983.     /* Allow use of m_who without registering */
  984.     
  985.     /*
  986.     **  Following code is some ugly hacking to preserve the
  987.     **  functions of the old implementation. (Also, people
  988.     **  will complain when they try to use masks like "12tes*"
  989.     **  and get people on channel 12 ;) --msa
  990.     */
  991.     if (!mask || *mask == '\0')
  992.         mask = NULL;
  993.     else if (mask[1] == '\0' && mask[0] == '*')
  994.         {
  995.         mask = NULL;
  996.         if (mychannel)
  997.             channame = mychannel->chname;
  998.         }
  999.     else if (mask[1] == '\0' && mask[0] == '0') /* "WHO 0" for irc.el */
  1000.         mask = NULL;
  1001.     else
  1002.         channame = mask;
  1003.     (void)collapse(mask);
  1004.  
  1005.     if (IsChannelName(channame))
  1006.         {
  1007.         /*
  1008.          * List all users on a given channel
  1009.          */
  1010.         chptr = find_channel(channame, NULL);
  1011.         if (chptr)
  1012.           {
  1013.             member = IsMember(sptr, chptr);
  1014.             if (member || !SecretChannel(chptr))
  1015.             for (lp = chptr->members; lp; lp = lp->next)
  1016.                 {
  1017.                 if (oper && !IsAnOper(lp->value.cptr))
  1018.                     continue;
  1019.                 if (IsInvisible(lp->value.cptr) && !member)
  1020.                     continue;
  1021.                 do_who(sptr, lp->value.cptr, chptr);
  1022.                 }
  1023.           }
  1024.         }
  1025.     else for (acptr = client; acptr; acptr = acptr->next)
  1026.         {
  1027.         aChannel *ch2ptr = NULL;
  1028.         int    showperson, isinvis;
  1029.  
  1030.         if (!IsPerson(acptr))
  1031.             continue;
  1032.         if (oper && !IsAnOper(acptr))
  1033.             continue;
  1034.         showperson = 0;
  1035.         /*
  1036.          * Show user if they are on the same channel, or not
  1037.          * invisible and on a non secret channel (if any).
  1038.          * Do this before brute force match on all relevant fields
  1039.          * since these are less cpu intensive (I hope :-) and should
  1040.          * provide better/more shortcuts - avalon
  1041.          */
  1042.         isinvis = IsInvisible(acptr);
  1043.         for (lp = acptr->user->channel; lp; lp = lp->next)
  1044.             {
  1045.             chptr = lp->value.chptr;
  1046.             member = IsMember(sptr, chptr);
  1047.             if (isinvis && !member)
  1048.                 continue;
  1049.             if (member || (!isinvis && ShowChannel(sptr, chptr)))
  1050.                 {
  1051.                 ch2ptr = chptr;
  1052.                 showperson = 1;
  1053.                 break;
  1054.                 }
  1055.             if (HiddenChannel(chptr) && !SecretChannel(chptr) &&
  1056.                 !isinvis)
  1057.                 showperson = 1;
  1058.             }
  1059.         if (!acptr->user->channel && !isinvis)
  1060.             showperson = 1;
  1061.         /*
  1062.         ** This is brute force solution, not efficient...? ;( 
  1063.         ** Show entry, if no mask or any of the fields match
  1064.         ** the mask. --msa
  1065.         */
  1066.         if (showperson &&
  1067.             (!mask ||
  1068.              match(mask, acptr->name) == 0 ||
  1069.              match(mask, acptr->user->username) == 0 ||
  1070.              match(mask, acptr->user->host) == 0 ||
  1071.              match(mask, acptr->user->server) == 0 ||
  1072.              match(mask, acptr->info) == 0))
  1073.             do_who(sptr, acptr, ch2ptr);
  1074.         }
  1075.     sendto_one(sptr, rpl_str(RPL_ENDOFWHO), me.name, parv[0],
  1076.            BadPtr(mask) ?  "*" : mask);
  1077.     return 0;
  1078. }
  1079.  
  1080. /*
  1081. ** m_whois
  1082. **    parv[0] = sender prefix
  1083. **    parv[1] = nickname masklist
  1084. */
  1085. int    m_whois(cptr, sptr, parc, parv)
  1086. aClient *cptr, *sptr;
  1087. int    parc;
  1088. char    *parv[];
  1089. {
  1090.     static anUser UnknownUser =
  1091.         {
  1092.         NULL,    /* next */
  1093.         NULL,    /* channel */
  1094.         NULL,   /* invited */
  1095.         NULL,    /* away */
  1096.         0,    /* last */
  1097.         1,      /* refcount */
  1098.         0,    /* joined */
  1099.         "<Unknown>",    /* user */
  1100.         "<Unknown>",    /* host */
  1101.         "<Unknown>"    /* server */
  1102.         };
  1103.     Reg2    Link    *lp;
  1104.     Reg3    anUser    *user;
  1105.     aClient *acptr, *a2cptr;
  1106.     aChannel *chptr;
  1107.     char    *nick, *tmp, *name;
  1108.     char    *p = NULL;
  1109.     int    found, len, mlen;
  1110.  
  1111.     if (check_registered_user(sptr))
  1112.         return 0;
  1113.  
  1114.         if (parc < 2)
  1115.         {
  1116.         sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
  1117.                me.name, parv[0]);
  1118.         return 0;
  1119.         }
  1120.  
  1121.     if (parc > 2)
  1122.         {
  1123.         if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) !=
  1124.             HUNTED_ISME)
  1125.             return 0;
  1126.         parv[1] = parv[2];
  1127.         }
  1128.  
  1129.     for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL)
  1130.         {
  1131.         int    invis, showperson, member, wilds;
  1132.  
  1133.         found = 0;
  1134.         (void)collapse(nick);
  1135.         wilds = (index(nick, '?') || index(nick, '*'));
  1136.         for (acptr = client; (acptr = next_client(acptr, nick));
  1137.              acptr = acptr->next)
  1138.             {
  1139.             if (IsServer(acptr))
  1140.                 continue;
  1141.             /*
  1142.              * I'm always last :-) and acptr->next == NULL!!
  1143.              */
  1144.             if (IsMe(acptr))
  1145.                 break;
  1146.             /*
  1147.              * 'Rules' established for sending a WHOIS reply:
  1148.              *
  1149.              * - only allow a remote client to get replies for
  1150.              *   local clients if wildcards are being used;
  1151.              *
  1152.              * - if wildcards are being used dont send a reply if
  1153.              *   the querier isnt any common channels and the
  1154.              *   client in question is invisible and wildcards are
  1155.              *   in use (allow exact matches only);
  1156.              *
  1157.              * - only send replies about common or public channels
  1158.              *   the target user(s) are on;
  1159.              */
  1160.             if (!MyConnect(sptr) && !MyConnect(acptr) && wilds)
  1161.                 continue;
  1162.             user = acptr->user ? acptr->user : &UnknownUser;
  1163.             name = (!*acptr->name) ? "?" : acptr->name;
  1164.  
  1165.             invis = IsInvisible(acptr);
  1166.             member = (user->channel) ? 1 : 0;
  1167.             showperson = (wilds && !invis && !member) || !wilds;
  1168.             for (lp = user->channel; lp; lp = lp->next)
  1169.                 {
  1170.                 chptr = lp->value.chptr;
  1171.                 member = IsMember(sptr, chptr);
  1172.                 if (invis && !member)
  1173.                     continue;
  1174.                 if (member || (!invis && PubChannel(chptr)))
  1175.                     {
  1176.                     showperson = 1;
  1177.                     break;
  1178.                     }
  1179.                 if (!invis && HiddenChannel(chptr) &&
  1180.                     !SecretChannel(chptr))
  1181.                     showperson = 1;
  1182.                 }
  1183.             if (!showperson)
  1184.                 continue;
  1185.  
  1186.             a2cptr = find_server(user->server, NULL);
  1187.  
  1188.             sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
  1189.                    parv[0], name,
  1190.                    user->username, user->host, acptr->info);
  1191.             found = 1;
  1192.             mlen = strlen(me.name) + strlen(parv[0]) + 6 +
  1193.                 strlen(name);
  1194.             for (len = 0, *buf = '\0', lp = user->channel; lp;
  1195.                  lp = lp->next)
  1196.                 {
  1197.                 chptr = lp->value.chptr;
  1198.                 if (ShowChannel(sptr, chptr))
  1199.                     {
  1200.                     if (len + strlen(chptr->chname)
  1201.                                             > (size_t) BUFSIZE - 4 - mlen)
  1202.                         {
  1203.                         sendto_one(sptr,
  1204.                                ":%s %d %s %s :%s",
  1205.                                me.name,
  1206.                                RPL_WHOISCHANNELS,
  1207.                                parv[0], name, buf);
  1208.                         *buf = '\0';
  1209.                         len = 0;
  1210.                         }
  1211.                     if (is_chan_op(acptr, chptr))
  1212.                         *(buf + len++) = '@';
  1213.                     else if (has_voice(acptr, chptr))
  1214.                         *(buf + len++) = '+';
  1215.                     if (len)
  1216.                         *(buf + len) = '\0';
  1217.                     (void)strcpy(buf + len, chptr->chname);
  1218.                     len += strlen(chptr->chname);
  1219.                     (void)strcat(buf + len, " ");
  1220.                     len++;
  1221.                     }
  1222.                 }
  1223.             if (buf[0] != '\0')
  1224.                 sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
  1225.                        me.name, parv[0], name, buf);
  1226.  
  1227.             sendto_one(sptr, rpl_str(RPL_WHOISSERVER),
  1228.                    me.name, parv[0], name, user->server,
  1229.                    a2cptr?a2cptr->info:"*Not On This Net*");
  1230.  
  1231.             if (user->away)
  1232.                 sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
  1233.                        parv[0], name, user->away);
  1234.  
  1235.             if (IsAnOper(acptr))
  1236.                 sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
  1237.                        me.name, parv[0], name);
  1238.  
  1239.             if (acptr->user && MyConnect(acptr))
  1240.                 sendto_one(sptr, rpl_str(RPL_WHOISIDLE),
  1241.                        me.name, parv[0], name,
  1242.                        time(NULL) - user->last);
  1243.             }
  1244.         if (!found)
  1245.             sendto_one(sptr, err_str(ERR_NOSUCHNICK),
  1246.                    me.name, parv[0], nick);
  1247.         if (p)
  1248.             p[-1] = ',';
  1249.         }
  1250.     sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
  1251.  
  1252.     return 0;
  1253. }
  1254.  
  1255. /*
  1256. ** m_user
  1257. **    parv[0] = sender prefix
  1258. **    parv[1] = username (login name, account)
  1259. **    parv[2] = client host name (used only from other servers)
  1260. **    parv[3] = server host name (used only from other servers)
  1261. **    parv[4] = users real name info
  1262. */
  1263. int    m_user(cptr, sptr, parc, parv)
  1264. aClient    *cptr, *sptr;
  1265. int    parc;
  1266. char    *parv[];
  1267. {
  1268. #define    UFLAGS    (FLAGS_INVISIBLE|FLAGS_WALLOP|FLAGS_SERVNOTICE)
  1269.     char    *username, *host, *server, *realname;
  1270.     anUser    *user;
  1271.  
  1272.     if (parc > 2 && (username = (char *)index(parv[1],'@')))
  1273.         *username = '\0'; 
  1274.     if (parc < 5 || *parv[1] == '\0' || *parv[2] == '\0' ||
  1275.         *parv[3] == '\0' || *parv[4] == '\0')
  1276.         {
  1277.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1278.                    me.name, parv[0], "USER");
  1279.         if (IsServer(cptr))
  1280.             sendto_ops("bad USER param count for %s from %s",
  1281.                    parv[0], get_client_name(cptr, FALSE));
  1282.         else
  1283.             return 0;
  1284.         }
  1285.  
  1286.     /* Copy parameters into better documenting variables */
  1287.  
  1288.     username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1];
  1289.     host     = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2];
  1290.     server   = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3];
  1291.     realname = (parc < 5 || BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
  1292.  
  1293.      user = make_user(sptr);
  1294.  
  1295.     if (!MyConnect(sptr))
  1296.         {
  1297.         strncpyzt(user->server, server, sizeof(user->server));
  1298.         strncpyzt(user->host, host, sizeof(user->host));
  1299.         goto user_finish;
  1300.         }
  1301.  
  1302.     if (!IsUnknown(sptr))
  1303.         {
  1304.         sendto_one(sptr, err_str(ERR_ALREADYREGISTRED),
  1305.                me.name, parv[0]);
  1306.         return 0;
  1307.         }
  1308. #ifndef    NO_DEFAULT_INVISIBLE
  1309.     sptr->flags |= FLAGS_INVISIBLE;
  1310. #endif
  1311.     sptr->flags |= (UFLAGS & atoi(host));
  1312.     strncpyzt(user->host, host, sizeof(user->host));
  1313.     strncpyzt(user->server, me.name, sizeof(user->server));
  1314. user_finish:
  1315.     strncpyzt(sptr->info, realname, sizeof(sptr->info));
  1316.     if (sptr->name[0]) /* NICK already received, now we have USER... */
  1317.         return register_user(cptr, sptr, sptr->name, username);
  1318.     else
  1319.         strncpyzt(sptr->user->username, username, USERLEN+1);
  1320.     return 0;
  1321. }
  1322.  
  1323. /*
  1324. ** m_quit
  1325. **    parv[0] = sender prefix
  1326. **    parv[1] = comment
  1327. */
  1328. int    m_quit(cptr, sptr, parc, parv)
  1329. aClient *cptr, *sptr;
  1330. int    parc;
  1331. char    *parv[];
  1332.     {
  1333.     register char *comment = (parc > 1 && parv[1]) ? parv[1] : cptr->name;
  1334.  
  1335.     if (MyClient(sptr))
  1336.         if (!strncmp("Local Kill", comment, 10) ||
  1337.             !strncmp(comment, "Killed", 6))
  1338.             comment = parv[0];
  1339.     if (strlen(comment) > (size_t) TOPICLEN)
  1340.         comment[TOPICLEN] = '\0';
  1341.     return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, comment);
  1342.     }
  1343.  
  1344. /*
  1345. ** m_kill
  1346. **    parv[0] = sender prefix
  1347. **    parv[1] = kill victim
  1348. **    parv[2] = kill path
  1349. */
  1350. int    m_kill(cptr, sptr, parc, parv)
  1351. aClient *cptr, *sptr;
  1352. int    parc;
  1353. char    *parv[];
  1354. {
  1355.     aClient *acptr;
  1356.     char    *inpath = get_client_name(cptr,FALSE);
  1357.     char    *user, *path, *killer;
  1358.     int    chasing = 0;
  1359.  
  1360.     if (parc < 2 || *parv[1] == '\0')
  1361.         {
  1362.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1363.                me.name, parv[0], "KILL");
  1364.         return 0;
  1365.         }
  1366.  
  1367.     user = parv[1];
  1368.     path = parv[2]; /* Either defined or NULL (parc >= 2!!) */
  1369.  
  1370. #ifdef    OPER_KILL
  1371.     if (!IsPrivileged(cptr))
  1372.         {
  1373.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1374.         return 0;
  1375.         }
  1376. #else
  1377.     if (!IsServer(cptr))
  1378.         {
  1379.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1380.         return 0;
  1381.         }
  1382. #endif
  1383.     if (IsAnOper(cptr))
  1384.         {
  1385.         if (BadPtr(path))
  1386.             {
  1387.             sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1388.                    me.name, parv[0], "KILL");
  1389.             return 0;
  1390.             }
  1391.         if (strlen(path) > (size_t) TOPICLEN)
  1392.             path[TOPICLEN] = '\0';
  1393.         }
  1394.  
  1395.     if (!(acptr = find_client(user, NULL)))
  1396.         {
  1397.         /*
  1398.         ** If the user has recently changed nick, we automaticly
  1399.         ** rewrite the KILL for this new nickname--this keeps
  1400.         ** servers in synch when nick change and kill collide
  1401.         */
  1402.         if (!(acptr = get_history(user, (long)KILLCHASETIMELIMIT)))
  1403.             {
  1404.             sendto_one(sptr, err_str(ERR_NOSUCHNICK),
  1405.                    me.name, parv[0], user);
  1406.             return 0;
  1407.             }
  1408.         sendto_one(sptr,":%s NOTICE %s :KILL changed from %s to %s",
  1409.                me.name, parv[0], user, acptr->name);
  1410.         chasing = 1;
  1411.         }
  1412.     if (!MyConnect(acptr) && IsLocOp(cptr))
  1413.         {
  1414.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1415.         return 0;
  1416.         }
  1417.     if (IsServer(acptr) || IsMe(acptr))
  1418.         {
  1419.         sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
  1420.                me.name, parv[0]);
  1421.         return 0;
  1422.         }
  1423.  
  1424. #ifdef    LOCAL_KILL_ONLY
  1425.     if (MyConnect(sptr) && !MyConnect(acptr))
  1426.         {
  1427.         sendto_one(sptr, ":%s NOTICE %s :Nick %s isnt on your server",
  1428.                me.name, parv[0], acptr->name);
  1429.         return 0;
  1430.         }
  1431. #endif
  1432.     if (!IsServer(cptr))
  1433.         {
  1434.         /*
  1435.         ** The kill originates from this server, initialize path.
  1436.         ** (In which case the 'path' may contain user suplied
  1437.         ** explanation ...or some nasty comment, sigh... >;-)
  1438.         **
  1439.         **    ...!operhost!oper
  1440.         **    ...!operhost!oper (comment)
  1441.         */
  1442.         if (IsUnixSocket(cptr)) /* Don't use get_client_name syntax */
  1443.             inpath = me.sockhost;
  1444.         else
  1445.             inpath = cptr->sockhost;
  1446.         if (!BadPtr(path))
  1447.             {
  1448.             (void)sprintf(buf, "%s%s (%s)",
  1449.                 cptr->name, IsOper(sptr) ? "" : "(L)", path);
  1450.             path = buf;
  1451.             }
  1452.         else
  1453.             path = cptr->name;
  1454.         }
  1455.     else if (BadPtr(path))
  1456.          path = "*no-path*"; /* Bogus server sending??? */
  1457.     /*
  1458.     ** Notify all *local* opers about the KILL (this includes the one
  1459.     ** originating the kill, if from this server--the special numeric
  1460.     ** reply message is not generated anymore).
  1461.     **
  1462.     ** Note: "acptr->name" is used instead of "user" because we may
  1463.     **     have changed the target because of the nickname change.
  1464.     */
  1465.     if (IsLocOp(sptr) && !MyConnect(acptr))
  1466.         {
  1467.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1468.         return 0;
  1469.         }
  1470.     sendto_ops("Received KILL message for %s. From %s Path: %s!%s",
  1471.            acptr->name, parv[0], inpath, path);
  1472. #if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
  1473.     if (IsOper(sptr))
  1474.         syslog(LOG_DEBUG,"KILL From %s For %s Path %s!%s",
  1475.             parv[0], acptr->name, inpath, path);
  1476. #endif
  1477.     /*
  1478.     ** And pass on the message to other servers. Note, that if KILL
  1479.     ** was changed, the message has to be sent to all links, also
  1480.     ** back.
  1481.     ** Suicide kills are NOT passed on --SRB
  1482.     */
  1483.     if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
  1484.         {
  1485.         sendto_serv_butone(cptr, ":%s KILL %s :%s!%s",
  1486.                    parv[0], acptr->name, inpath, path);
  1487.         if (chasing)
  1488.             sendto_one(cptr, ":%s KILL %s :%s!%s",
  1489.                    me.name, acptr->name, inpath, path);
  1490.         acptr->flags |= FLAGS_KILLED;
  1491.         }
  1492. #ifdef    USE_SERVICES
  1493.     check_services_butone(SERVICE_WANT_KILL, sptr, ":%s KILL %s :%s!%s",
  1494.                 parv[0], acptr->name, inpath, path);
  1495. #endif
  1496.  
  1497.     /*
  1498.     ** Tell the victim she/he has been zapped, but *only* if
  1499.     ** the victim is on current server--no sense in sending the
  1500.     ** notification chasing the above kill, it won't get far
  1501.     ** anyway (as this user don't exist there any more either)
  1502.     */
  1503.     if (MyConnect(acptr))
  1504.         sendto_prefix_one(acptr, sptr,":%s KILL %s :%s!%s",
  1505.                   parv[0], acptr->name, inpath, path);
  1506.     /*
  1507.     ** Set FLAGS_KILLED. This prevents exit_one_client from sending
  1508.     ** the unnecessary QUIT for this. (This flag should never be
  1509.     ** set in any other place)
  1510.     */
  1511.     if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
  1512.         (void)sprintf(buf2, "Local kill by %s (%s)", sptr->name,
  1513.             BadPtr(parv[2]) ? sptr->name : parv[2]);
  1514.     else
  1515.         {
  1516.         if ((killer = index(path, ' ')))
  1517.             {
  1518.             while (*killer && *killer != '!')
  1519.                 killer--;
  1520.             if (!*killer)
  1521.                 killer = path;
  1522.             else
  1523.                 killer++;
  1524.             }
  1525.         else
  1526.             killer = path;
  1527.         (void)sprintf(buf2, "Killed (%s)", killer);
  1528.         }
  1529.     return exit_client(cptr, acptr, sptr, buf2);
  1530. }
  1531.  
  1532. /***********************************************************************
  1533.  * m_away() - Added 14 Dec 1988 by jto. 
  1534.  *            Not currently really working, I don't like this
  1535.  *            call at all...
  1536.  *
  1537.  *            ...trying to make it work. I don't like it either,
  1538.  *          but perhaps it's worth the load it causes to net.
  1539.  *          This requires flooding of the whole net like NICK,
  1540.  *          USER, MODE, etc messages...  --msa
  1541.  ***********************************************************************/
  1542.  
  1543. /*
  1544. ** m_away
  1545. **    parv[0] = sender prefix
  1546. **    parv[1] = away message
  1547. */
  1548. int    m_away(cptr, sptr, parc, parv)
  1549. aClient *cptr, *sptr;
  1550. int    parc;
  1551. char    *parv[];
  1552. {
  1553.     Reg1    char    *away, *awy2 = parv[1];
  1554.  
  1555.     if (check_registered_user(sptr))
  1556.         return 0;
  1557.  
  1558.     away = sptr->user->away;
  1559.  
  1560.     if (parc < 2 || !*awy2)
  1561.         {
  1562.         /* Marking as not away */
  1563.  
  1564.         if (away)
  1565.             {
  1566.             MyFree(away);
  1567.             sptr->user->away = NULL;
  1568.             }
  1569.         sendto_serv_butone(cptr, ":%s AWAY", parv[0]);
  1570.         if (MyConnect(sptr))
  1571.             sendto_one(sptr, rpl_str(RPL_UNAWAY),
  1572.                    me.name, parv[0]);
  1573. #ifdef    USE_SERVICES
  1574.         check_services_butonee(SERVICE_WANT_AWAY, ":%s AWAY", parv[0]);
  1575. #endif
  1576.         return 0;
  1577.         }
  1578.  
  1579.     /* Marking as away */
  1580.  
  1581.     if (strlen(awy2) > (size_t) TOPICLEN)
  1582.         awy2[TOPICLEN] = '\0';
  1583.     sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2);
  1584. #ifdef    USE_SERVICES
  1585.     check_services_butonee(SERVICE_WANT_AWAY, ":%s AWAY :%s",
  1586.                 parv[0], parv[1]);
  1587. #endif
  1588.  
  1589.     if (away)
  1590.         away = (char *)MyRealloc(away, strlen(awy2)+1);
  1591.     else
  1592.         away = (char *)MyMalloc(strlen(awy2)+1);
  1593.  
  1594.     sptr->user->away = away;
  1595.     (void)strcpy(away, awy2);
  1596.     if (MyConnect(sptr))
  1597.         sendto_one(sptr, rpl_str(RPL_NOWAWAY), me.name, parv[0]);
  1598.     return 0;
  1599. }
  1600.  
  1601. /*
  1602. ** m_ping
  1603. **    parv[0] = sender prefix
  1604. **    parv[1] = origin
  1605. **    parv[2] = destination
  1606. */
  1607. int    m_ping(cptr, sptr, parc, parv)
  1608. aClient *cptr, *sptr;
  1609. int    parc;
  1610. char    *parv[];
  1611. {
  1612.     aClient *acptr;
  1613.     char    *origin, *destination;
  1614.  
  1615.     if (parc < 2 || *parv[1] == '\0')
  1616.         {
  1617.         sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
  1618.         return 0;
  1619.         }
  1620.     origin = parv[1];
  1621.     destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
  1622.  
  1623.     acptr = find_client(origin, NULL);
  1624.     if (!acptr)
  1625.         acptr = find_server(origin, NULL);
  1626.     if (acptr && acptr != sptr)
  1627.         origin = cptr->name;
  1628.     if (!BadPtr(destination) && mycmp(destination, me.name) != 0)
  1629.         {
  1630.         if ((acptr = find_server(destination, NULL)))
  1631.             sendto_one(acptr,":%s PING %s :%s", parv[0],
  1632.                    origin, destination);
  1633.             else
  1634.             {
  1635.             sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
  1636.                    me.name, parv[0], destination);
  1637.             return 0;
  1638.             }
  1639.         }
  1640.     else
  1641.         sendto_one(sptr,":%s PONG %s :%s", me.name,
  1642.                (destination) ? destination : me.name, origin);
  1643.     return 0;
  1644.     }
  1645.  
  1646. /*
  1647. ** m_pong
  1648. **    parv[0] = sender prefix
  1649. **    parv[1] = origin
  1650. **    parv[2] = destination
  1651. */
  1652. int    m_pong(cptr, sptr, parc, parv)
  1653. aClient *cptr, *sptr;
  1654. int    parc;
  1655. char    *parv[];
  1656. {
  1657.     aClient *acptr;
  1658.     char    *origin, *destination;
  1659.  
  1660.     if (parc < 2 || *parv[1] == '\0')
  1661.         {
  1662.         sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
  1663.         return 0;
  1664.         }
  1665.  
  1666.     origin = parv[1];
  1667.     destination = parv[2];
  1668.     cptr->flags &= ~FLAGS_PINGSENT;
  1669.     sptr->flags &= ~FLAGS_PINGSENT;
  1670.  
  1671.     if (!BadPtr(destination) && mycmp(destination, me.name) != 0)
  1672.         {
  1673.         if ((acptr = find_client(destination, NULL)) ||
  1674.             (acptr = find_server(destination, NULL)))
  1675.             sendto_one(acptr,":%s PONG %s %s",
  1676.                    parv[0], origin, destination);
  1677.         else
  1678.             {
  1679.             sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
  1680.                    me.name, parv[0], destination);
  1681.             return 0;
  1682.             }
  1683.         }
  1684. #ifdef    DEBUGMODE
  1685.     else
  1686.         Debug((DEBUG_NOTICE, "PONG: %s %s", origin,
  1687.               destination ? destination : "*"));
  1688. #endif
  1689.     return 0;
  1690.     }
  1691.  
  1692.  
  1693. /*
  1694. ** m_oper
  1695. **    parv[0] = sender prefix
  1696. **    parv[1] = oper name
  1697. **    parv[2] = oper password
  1698. */
  1699. int    m_oper(cptr, sptr, parc, parv)
  1700. aClient *cptr, *sptr;
  1701. int    parc;
  1702. char    *parv[];
  1703.     {
  1704.     aConfItem *aconf;
  1705.     char    *name, *password, *encr;
  1706. #ifdef CRYPT_OPER_PASSWORD
  1707.     char    salt[3];
  1708.     extern    char *crypt();
  1709. #endif /* CRYPT_OPER_PASSWORD */
  1710.  
  1711.     if (check_registered_user(sptr))
  1712.         return 0;
  1713.  
  1714.     name = parc > 1 ? parv[1] : NULL;
  1715.     password = parc > 2 ? parv[2] : NULL;
  1716.  
  1717.     if (!IsServer(cptr) && (BadPtr(name) || BadPtr(password)))
  1718.         {
  1719.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1720.                me.name, parv[0], "OPER");
  1721.         return 0;
  1722.         }
  1723.     
  1724.     /* if message arrived from server, trust it, and set to oper */
  1725.         
  1726.     if ((IsServer(cptr) || IsMe(cptr)) && !IsOper(sptr))
  1727.         {
  1728.         sptr->flags |= FLAGS_OPER;
  1729.         sendto_serv_butone(cptr, ":%s MODE %s :+o", parv[0], parv[0]);
  1730.         if (IsMe(cptr))
  1731.             sendto_one(sptr, rpl_str(RPL_YOUREOPER),
  1732.                    me.name, parv[0]);
  1733. #ifdef    USE_SERVICES
  1734.         check_services_butone(SERVICE_WANT_OPER, sptr,
  1735.                       ":%s MODE %s :+o", parv[0], parv[0]);
  1736. #endif
  1737.         return 0;
  1738.         }
  1739.     else if (IsOper(sptr))
  1740.         {
  1741.         if (MyConnect(sptr))
  1742.             sendto_one(sptr, rpl_str(RPL_YOUREOPER),
  1743.                    me.name, parv[0]);
  1744.         return 0;
  1745.         }
  1746.     if (!(aconf = find_conf_exact(name, sptr->username, sptr->sockhost,
  1747.                       CONF_OPS)) &&
  1748.         !(aconf = find_conf_exact(name, sptr->username,
  1749.                       inetntoa((char *)&cptr->ip), CONF_OPS)))
  1750.         {
  1751.         sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
  1752.         return 0;
  1753.         }
  1754. #ifdef CRYPT_OPER_PASSWORD
  1755.         /* use first two chars of the password they send in as salt */
  1756.  
  1757.         /* passwd may be NULL. Head it off at the pass... */
  1758.         salt[0] = '\0';
  1759.         if (password && aconf->passwd)
  1760.         {
  1761.             salt[0] = aconf->passwd[0];
  1762.         salt[1] = aconf->passwd[1];
  1763.         salt[2] = '\0';
  1764.         encr = crypt(password, salt);
  1765.         }
  1766.     else
  1767.         encr = "";
  1768. #else
  1769.     encr = password;
  1770. #endif  /* CRYPT_OPER_PASSWORD */
  1771.  
  1772.     if ((aconf->status & CONF_OPS) &&
  1773.         StrEq(encr, aconf->passwd) && !attach_conf(sptr, aconf))
  1774.         {
  1775.         int old = (sptr->flags & ALL_UMODES);
  1776.         char *s;
  1777.  
  1778.         s = index(aconf->host, '@');
  1779.         *s++ = '\0';
  1780. #ifdef    OPER_REMOTE
  1781.         if (aconf->status == CONF_LOCOP)
  1782. #else
  1783.         if ((matches(s,me.sockhost) && !IsLocal(sptr)) ||
  1784.             aconf->status == CONF_LOCOP)
  1785. #endif
  1786.             SetLocOp(sptr);
  1787.         else
  1788.             SetOper(sptr);
  1789.         *--s =  '@';
  1790.         sendto_ops("%s (%s@%s) is now operator (%c)", parv[0],
  1791.                sptr->user->username, sptr->user->host,
  1792.                IsOper(sptr) ? 'O' : 'o');
  1793.         sptr->flags |= (FLAGS_SERVNOTICE|FLAGS_WALLOP);
  1794.         send_umode_out(cptr, sptr, old);
  1795.          sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
  1796. #if !defined(CRYPT_OPER_PASSWORD) && (defined(FNAME_OPERLOG) ||\
  1797.     (defined(USE_SYSLOG) && defined(SYSLOG_OPER)))
  1798.         encr = "";
  1799. #endif
  1800. #if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
  1801.         syslog(LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s)",
  1802.             name, encr,
  1803.             parv[0], sptr->user->username, sptr->sockhost);
  1804. #endif
  1805. #ifdef FNAME_OPERLOG
  1806.           {
  1807.                 int     logfile;
  1808.  
  1809.                 /*
  1810.                  * This conditional makes the logfile active only after
  1811.                  * it's been created - thus logging can be turned off by
  1812.                  * removing the file.
  1813.                  *
  1814.                  * stop NFS hangs...most systems should be able to open a
  1815.                  * file in 3 seconds. -avalon (curtesy of wumpus)
  1816.                  */
  1817.                 (void)alarm(3);
  1818.                 if (IsPerson(sptr) &&
  1819.                     (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND)) != -1)
  1820.         {
  1821.           (void)alarm(0);
  1822.                         (void)sprintf(buf, "%s OPER (%s) (%s) by (%s!%s@%s)\n",
  1823.                       myctime(time(NULL)), name, encr,
  1824.                       parv[0], sptr->user->username,
  1825.                       sptr->sockhost);
  1826.           (void)alarm(3);
  1827.           (void)write(logfile, buf, strlen(buf));
  1828.           (void)alarm(0);
  1829.           (void)close(logfile);
  1830.         }
  1831.                 (void)alarm(0);
  1832.                 /* Modification by pjg */
  1833.           }
  1834. #endif
  1835. #ifdef    USE_SERVICES
  1836.         check_services_butone(SERVICE_WANT_OPER, sptr,
  1837.                       ":%s MODE %s :+o", parv[0], parv[0]);
  1838. #endif
  1839.         }
  1840.     else
  1841.         {
  1842.         (void)detach_conf(sptr, aconf);
  1843.         sendto_one(sptr,err_str(ERR_PASSWDMISMATCH),me.name, parv[0]);
  1844.         }
  1845.     return 0;
  1846.     }
  1847.  
  1848. /***************************************************************************
  1849.  * m_pass() - Added Sat, 4 March 1989
  1850.  ***************************************************************************/
  1851.  
  1852. /*
  1853. ** m_pass
  1854. **    parv[0] = sender prefix
  1855. **    parv[1] = password
  1856. */
  1857. int    m_pass(cptr, sptr, parc, parv)
  1858. aClient *cptr, *sptr;
  1859. int    parc;
  1860. char    *parv[];
  1861.     {
  1862.     char *password = parc > 1 ? parv[1] : NULL;
  1863.  
  1864.     if (BadPtr(password))
  1865.         {
  1866.         sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS),
  1867.                me.name, parv[0], "PASS");
  1868.         return 0;
  1869.         }
  1870.     if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
  1871.         {
  1872.         sendto_one(cptr, err_str(ERR_ALREADYREGISTRED),
  1873.                me.name, parv[0]);
  1874.         return 0;
  1875.         }
  1876.     strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
  1877.     return 0;
  1878.     }
  1879.  
  1880. /*
  1881.  * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
  1882.  * the need for complicated requests like WHOIS. It returns user/host
  1883.  * information only (no spurious AWAY labels or channels).
  1884.  */
  1885. int    m_userhost(cptr, sptr, parc, parv)
  1886. aClient *cptr, *sptr;
  1887. int    parc;
  1888. char    *parv[];
  1889. {
  1890.     char    *p = NULL;
  1891.     aClient    *acptr;
  1892.     Reg1    char    *s;
  1893.     Reg2    int    i, len;
  1894.  
  1895.     if (check_registered(sptr))
  1896.         return 0;
  1897.  
  1898.     if (parc > 2)
  1899.         (void)m_userhost(cptr, sptr, parc-1, parv+1);
  1900.  
  1901.     if (parc < 2)
  1902.         {
  1903.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1904.                me.name, parv[0], "USERHOST");
  1905.         return 0;
  1906.         }
  1907.  
  1908.     (void)sprintf(buf, rpl_str(RPL_USERHOST), me.name, parv[0]);
  1909.     len = strlen(buf);
  1910.     *buf2 = '\0';
  1911.  
  1912.     for (i = 5, s = strtoken(&p, parv[1], " "); i && s;
  1913.          s = strtoken(&p, (char *)NULL, " "), i--)
  1914.         if ((acptr = find_person(s, NULL)))
  1915.             {
  1916.             if (*buf2)
  1917.                 (void)strcat(buf, " ");
  1918.             (void)sprintf(buf2, "%s%s=%c%s@%s",
  1919.                 acptr->name,
  1920.                 IsAnOper(acptr) ? "*" : "",
  1921.                 (acptr->user->away) ? '-' : '+',
  1922.                 acptr->user->username,
  1923.                 acptr->user->host);
  1924.             (void)strncat(buf, buf2, sizeof(buf) - len);
  1925.             len += strlen(buf2);
  1926.             }
  1927.     sendto_one(sptr, "%s", buf);
  1928.     return 0;
  1929. }
  1930.  
  1931. /*
  1932.  * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator
  1933.  * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in
  1934.  * clients. Designed to reduce number of whois requests. Can process
  1935.  * nicknames in batches as long as the maximum buffer length.
  1936.  *
  1937.  * format:
  1938.  * ISON :nicklist
  1939.  */
  1940.  
  1941. int    m_ison(cptr, sptr, parc, parv)
  1942. aClient *cptr, *sptr;
  1943. int    parc;
  1944. char    *parv[];
  1945. {
  1946.     Reg1    aClient *acptr;
  1947.     Reg2    char    *s, **pav = parv;
  1948.     Reg3    int    len;
  1949.     char    *p = NULL;
  1950.  
  1951.     if (check_registered(sptr))
  1952.         return 0;
  1953.  
  1954.     if (parc < 2)
  1955.         {
  1956.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1957.                me.name, parv[0], "ISON");
  1958.         return 0;
  1959.         }
  1960.  
  1961.     (void)sprintf(buf, rpl_str(RPL_ISON), me.name, *parv);
  1962.     len = strlen(buf);
  1963.  
  1964.     for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " "))
  1965.         if ((acptr = find_person(s, NULL)))
  1966.             {
  1967.             (void)strncat(buf, acptr->name, sizeof(buf) - len);
  1968.             len += strlen(acptr->name);
  1969.             (void)strncat(buf, " ", sizeof(buf) - len);
  1970.             len++;
  1971.             }
  1972.     sendto_one(sptr, "%s", buf);
  1973.     return 0;
  1974. }
  1975.  
  1976. #if defined(NPATH)
  1977. int    m_note(cptr, sptr, parc, parv)
  1978. aClient    *cptr, *sptr;
  1979. int    parc;
  1980. char    *parv[];
  1981. {
  1982.     Reg1    aClient *acptr;
  1983.     Reg2    int    i = 0;
  1984.     int    wilds = 0;
  1985.     char    *c, nbuf[50];
  1986.  
  1987.     if (parc < 2)
  1988.         return 0;
  1989.  
  1990.     c = parv[1];
  1991.  
  1992.     while (*c && *c != ' ' && i < 49)
  1993.         {
  1994.             if (*c == '*' || *c == '?')
  1995.             wilds = 1;
  1996.           nbuf[i++] = *c++;
  1997.         }
  1998.  
  1999.     nbuf[i] = 0;
  2000.  
  2001.     if (IsOper(sptr) && wilds)
  2002.         for (i = highest_fd; i >= 0; i--)
  2003.             {
  2004.             if (!(acptr = local[i]))
  2005.                 continue;
  2006.                 if (IsServer(acptr) && acptr != cptr)
  2007.                 sendto_one(acptr, ":%s NOTE :%s",
  2008.                        parv[0], parv[1]);
  2009.             }
  2010.     else
  2011.         for (acptr = client; acptr; acptr = acptr->next)
  2012.             if (IsServer(acptr) && acptr != cptr
  2013.                 && !mycmp(nbuf, acptr->name))
  2014.                 {
  2015.                 sendto_one(acptr, ":%s NOTE :%s",
  2016.                        parv[0], parv[1]);
  2017.                 break;
  2018.                 }
  2019.     return 0;
  2020. }
  2021. #endif
  2022.  
  2023. static int user_modes[]         = { FLAGS_OPER, 'o',
  2024.                  FLAGS_LOCOP, 'O',
  2025.                  FLAGS_INVISIBLE, 'i',
  2026.                  FLAGS_WALLOP, 'w',
  2027.                  FLAGS_SERVNOTICE, 's',
  2028.                  0, 0 };
  2029.  
  2030. /*
  2031.  * m_umode() added 15/10/91 By Darren Reed.
  2032.  * parv[0] - sender
  2033.  * parv[1] - username to change mode for
  2034.  * parv[2] - modes to change
  2035.  */
  2036. int    m_umode(cptr, sptr, parc, parv)
  2037. aClient *cptr, *sptr;
  2038. int    parc;
  2039. char    *parv[];
  2040. {
  2041.     Reg1    int    flag;
  2042.     Reg2    int    *s;
  2043.     Reg3    char    **p, *m;
  2044.     aClient    *acptr;
  2045.     int    what, setflags;
  2046.  
  2047.     if (check_registered_user(sptr))
  2048.         return 0;
  2049.  
  2050.     what = MODE_ADD;
  2051.  
  2052.     if (parc < 2)
  2053.         {
  2054.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  2055.                me.name, parv[0], "MODE");
  2056.         return 0;
  2057.         }
  2058.  
  2059.     if (!(acptr = find_person(parv[1], NULL)))
  2060.         {
  2061.         if (MyConnect(sptr))
  2062.             sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
  2063.                    me.name, parv[0], parv[1]);
  2064.         return 0;
  2065.         }
  2066.  
  2067.     if (IsServer(sptr) || sptr != acptr || acptr->from != sptr->from)
  2068.         {
  2069.         if (IsServer(cptr))
  2070.             sendto_ops_butone(NULL, &me,
  2071.                   ":%s WALLOPS :MODE for User %s From %s!%s",
  2072.                   me.name, parv[1],
  2073.                   get_client_name(cptr, FALSE), sptr->name);
  2074.         else
  2075.             sendto_one(sptr, err_str(ERR_USERSDONTMATCH),
  2076.                    me.name, parv[0]);
  2077.             return 0;
  2078.         }
  2079.  
  2080.     if (parc < 3)
  2081.         {
  2082.         m = buf;
  2083.         *m++ = '+';
  2084.         for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4);
  2085.              s += 2)
  2086.             if (sptr->flags & flag)
  2087.                 *m++ = (char)(*(s+1));
  2088.         *m = '\0';
  2089.         sendto_one(sptr, rpl_str(RPL_UMODEIS),
  2090.                me.name, parv[0], buf);
  2091.         return 0;
  2092.         }
  2093.  
  2094.     /* find flags already set for user */
  2095.     setflags = 0;
  2096.     for (s = user_modes; (flag = *s); s += 2)
  2097.         if (sptr->flags & flag)
  2098.             setflags |= flag;
  2099.  
  2100.     /*
  2101.      * parse mode change string(s)
  2102.      */
  2103.     for (p = &parv[2]; p && *p; p++ )
  2104.         for (m = *p; *m; m++)
  2105.             switch(*m)
  2106.             {
  2107.             case '+' :
  2108.                 what = MODE_ADD;
  2109.                 break;
  2110.             case '-' :
  2111.                 what = MODE_DEL;
  2112.                 break;    
  2113.             /* we may not get these,
  2114.              * but they shouldnt be in default
  2115.              */
  2116.             case ' ' :
  2117.             case '\n' :
  2118.             case '\r' :
  2119.             case '\t' :
  2120.                 break;
  2121.             default :
  2122.                 for (s = user_modes; (flag = *s); s += 2)
  2123.                     if (*m == (char)(*(s+1)))
  2124.                     {
  2125.                     if (what == MODE_ADD)
  2126.                         sptr->flags |= flag;
  2127.                     else
  2128.                         sptr->flags &= ~flag;    
  2129.                     break;
  2130.                     }
  2131.                 if (flag == 0 && MyConnect(sptr))
  2132.                     sendto_one(sptr,
  2133.                         err_str(ERR_UMODEUNKNOWNFLAG),
  2134.                         me.name, parv[0]);
  2135.                 break;
  2136.             }
  2137.     /*
  2138.      * stop users making themselves operators too easily
  2139.      */
  2140.     if (!(setflags & FLAGS_OPER) && IsOper(sptr) && !IsServer(cptr))
  2141.         ClearOper(sptr);
  2142.     if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr) && !IsServer(cptr))
  2143.         sptr->flags &= ~FLAGS_LOCOP;
  2144.     if ((setflags & (FLAGS_OPER|FLAGS_LOCOP)) && !IsAnOper(sptr) &&
  2145.         MyConnect(sptr))
  2146.         det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPS);
  2147. #ifdef    USE_SERVICES
  2148.     if (IsOper(sptr) && !(setflags & FLAGS_OPER))
  2149.         check_services_butone(SERVICE_WANT_OPER, sptr,
  2150.                       ":%s MODE %s :+o", parv[0], parv[0]);
  2151.     else if (!IsOper(sptr) && (setflags & FLAGS_OPER))
  2152.         check_services_butone(SERVICE_WANT_OPER, sptr,
  2153.                       ":%s MODE %s :-o", parv[0], parv[0]);
  2154. #endif
  2155.     /*
  2156.      * compare new flags with old flags and send string which
  2157.      * will cause servers to update correctly.
  2158.      */
  2159.     send_umode_out(cptr, sptr, setflags);
  2160.  
  2161.     return 0;
  2162. }
  2163.     
  2164. /*
  2165.  * send the MODE string for user (user) to connection cptr
  2166.  * -avalon
  2167.  */
  2168. void    send_umode(cptr, sptr, old, sendmask, umode_buf)
  2169. aClient *cptr, *sptr;
  2170. int    old, sendmask;
  2171. char    *umode_buf;
  2172. {
  2173.     Reg1    int    *s, flag;
  2174.     Reg2    char    *m;
  2175.     int    what = MODE_NULL;
  2176.  
  2177.     /*
  2178.      * build a string in umode_buf to represent the change in the user's
  2179.      * mode between the new (sptr->flag) and 'old'.
  2180.      */
  2181.     m = umode_buf;
  2182.     *m = '\0';
  2183.     for (s = user_modes; (flag = *s); s += 2)
  2184.         {
  2185.         if (MyClient(sptr) && !(flag & sendmask))
  2186.             continue;
  2187.         if ((flag & old) && !(sptr->flags & flag))
  2188.             {
  2189.             if (what == MODE_DEL)
  2190.                 *m++ = *(s+1);
  2191.             else
  2192.                 {
  2193.                 what = MODE_DEL;
  2194.                 *m++ = '-';
  2195.                 *m++ = *(s+1);
  2196.                 }
  2197.             }
  2198.         else if (!(flag & old) && (sptr->flags & flag))
  2199.             {
  2200.             if (what == MODE_ADD)
  2201.                 *m++ = *(s+1);
  2202.             else
  2203.                 {
  2204.                 what = MODE_ADD;
  2205.                 *m++ = '+';
  2206.                 *m++ = *(s+1);
  2207.                 }
  2208.             }
  2209.         }
  2210.     *m = '\0';
  2211.     if (*umode_buf && cptr)
  2212.         sendto_one(cptr, ":%s MODE %s :%s",
  2213.                sptr->name, sptr->name, umode_buf);
  2214. }
  2215.  
  2216. /*
  2217.  * added Sat Jul 25 07:30:42 EST 1992
  2218.  */
  2219. void    send_umode_out(cptr, sptr, old)
  2220. aClient *cptr, *sptr;
  2221. int    old;
  2222. {
  2223.     Reg1    int     i;
  2224.     Reg2    aClient *acptr;
  2225.  
  2226.     send_umode(NULL, sptr, old, SEND_UMODES, buf);
  2227. # ifdef NPATH
  2228.         check_command((long)4, ":%s MODE %s :%s", sptr->name, sptr->name, buf);
  2229. # endif
  2230.     for (i = highest_fd; i >= 0; i--)
  2231.         if ((acptr = local[i]) && IsServer(acptr) &&
  2232.             (acptr != cptr) && (acptr != sptr) && *buf)
  2233.             sendto_one(acptr, ":%s MODE %s :%s",
  2234.                    sptr->name, sptr->name, buf);
  2235.  
  2236.     if (cptr && MyClient(cptr))
  2237.         send_umode(cptr, sptr, old, ALL_UMODES, buf);
  2238. }
  2239.