home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ircd4652.zip / ircd-df-4.6.5-os2 / src / s_misc.c < prev    next >
C/C++ Source or Header  |  1997-12-28  |  23KB  |  839 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.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_misc.c    2.42 3/1/94 (C) 1988 University of Oulu, \
  26. Computing Center and Jarkko Oikarinen";
  27. #endif
  28.  
  29. #ifndef _WIN32
  30. #include <sys/time.h>
  31. #endif
  32. #include "struct.h"
  33. #include "common.h"
  34. #include "sys.h"
  35. #include "numeric.h"
  36. #include "userload.h"
  37. #include <sys/stat.h>
  38. #include <fcntl.h>
  39. #if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
  40.     !defined(__convex__) && !defined(_WIN32)
  41. # include <sys/param.h>
  42. #endif
  43. #if defined(PCS) || defined(AIX) || defined(SVR3)
  44. # include <time.h>
  45. #endif
  46. #ifdef HPUX
  47. #include <unistd.h>
  48. #endif
  49. #ifdef DYNIXPTX
  50. #include <sys/types.h>
  51. #include <time.h>
  52. #endif
  53. #ifdef _WIN32
  54. # include <io.h>
  55. #endif
  56. #include "h.h"
  57.  
  58. static    void    exit_one_client PROTO((aClient *,aClient *,aClient *,char *));
  59. static    void    exit_one_client_in_split PROTO((aClient *,aClient *,aClient *,char *));
  60.  
  61. static    char    *months[] = {
  62.     "January",    "February",    "March",    "April",
  63.     "May",            "June",            "July",            "August",
  64.     "September",    "October",    "November",    "December"
  65. };
  66.  
  67. static    char    *weekdays[] = {
  68.     "Sunday",    "Monday",    "Tuesday",    "Wednesday",
  69.     "Thursday",    "Friday",    "Saturday"
  70. };
  71.  
  72. /*
  73.  * stats stuff
  74.  */
  75. struct    stats    ircst, *ircstp = &ircst;
  76.  
  77. char    *date(clock) 
  78. time_t    clock;
  79. {
  80.     static    char    buf[80], plus;
  81.     Reg1    struct    tm *lt, *gm;
  82.     struct    tm    gmbuf;
  83.     int    minswest;
  84.  
  85.     if (!clock) 
  86.         time(&clock);
  87.     gm = gmtime(&clock);
  88.     bcopy((char *)gm, (char *)&gmbuf, sizeof(gmbuf));
  89.     gm = &gmbuf;
  90.     lt = localtime(&clock);
  91.  
  92.     if (lt->tm_yday == gm->tm_yday)
  93.         minswest = (gm->tm_hour - lt->tm_hour) * 60 +
  94.                (gm->tm_min - lt->tm_min);
  95.     else if (lt->tm_yday > gm->tm_yday)
  96.         minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
  97.     else
  98.         minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
  99.  
  100.     plus = (minswest > 0) ? '-' : '+';
  101.     if (minswest < 0)
  102.         minswest = -minswest;
  103.  
  104.     (void)sprintf(buf, "%s %s %d 19%02d -- %02d:%02d %c%02d:%02d",
  105.         weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday,
  106.         lt->tm_year, lt->tm_hour, lt->tm_min,
  107.         plus, minswest/60, minswest%60);
  108.  
  109.     return buf;
  110. }
  111.  
  112. /*
  113.  *  Fixes a string so that the first white space found becomes an end of
  114.  * string marker (`\-`).  returns the 'fixed' string or "*" if the string
  115.  * was NULL length or a NULL pointer.
  116.  */
  117. char    *check_string(s)
  118. Reg1    char *s;
  119. {
  120.     static    char    star[2] = "*";
  121.     char    *str = s;
  122.  
  123.     if (BadPtr(s))
  124.         return star;
  125.  
  126.     for ( ;*s; s++)
  127.         if (isspace(*s))
  128.             {
  129.             *s = '\0';
  130.             break;
  131.             }
  132.  
  133.     return (BadPtr(str)) ? star : str;
  134. }
  135.  
  136. /*
  137.  * create a string of form "foo!bar@fubar" given foo, bar and fubar
  138.  * as the parameters.  If NULL, they become "*".
  139.  */
  140. char *make_nick_user_host(nick, name, host)
  141. Reg1    char    *nick, *name, *host;
  142. {
  143.     static    char    namebuf[NICKLEN+USERLEN+HOSTLEN+6];
  144.     Reg2    char    *s = namebuf;
  145.  
  146.     bzero(namebuf, sizeof(namebuf));
  147.     nick = check_string(nick);
  148.     strncpyzt(namebuf, nick, NICKLEN + 1);
  149.     s += strlen(s);
  150.     *s++ = '!';
  151.     name = check_string(name);
  152.     strncpyzt(s, name, USERLEN + 1);
  153.     s += strlen(s);
  154.     *s++ = '@';
  155.     host = check_string(host);
  156.     strncpyzt(s, host, HOSTLEN + 1);
  157.     s += strlen(s);
  158.     *s = '\0';
  159.     return (namebuf);
  160. }
  161.  
  162. /**
  163.  ** myctime()
  164.  **   This is like standard ctime()-function, but it zaps away
  165.  **   the newline from the end of that string. Also, it takes
  166.  **   the time value as parameter, instead of pointer to it.
  167.  **   Note that it is necessary to copy the string to alternate
  168.  **   buffer (who knows how ctime() implements it, maybe it statically
  169.  **   has newline there and never 'refreshes' it -- zapping that
  170.  **   might break things in other places...)
  171.  **
  172.  **/
  173.  
  174. char    *myctime(value)
  175. time_t    value;
  176. {
  177.     static    char    buf[28];
  178.     Reg1    char    *p;
  179.  
  180.     (void)strcpy(buf, ctime(&value));
  181.     if ((p = (char *)index(buf, '\n')) != NULL)
  182.         *p = '\0';
  183.  
  184.     return buf;
  185. }
  186.  
  187. /*
  188. ** check_registered_user is used to cancel message, if the
  189. ** originator is a server or not registered yet. In other
  190. ** words, passing this test, *MUST* guarantee that the
  191. ** sptr->user exists (not checked after this--let there
  192. ** be coredumps to catch bugs... this is intentional --msa ;)
  193. **
  194. ** There is this nagging feeling... should this NOT_REGISTERED
  195. ** error really be sent to remote users? This happening means
  196. ** that remote servers have this user registered, althout this
  197. ** one has it not... Not really users fault... Perhaps this
  198. ** error message should be restricted to local clients and some
  199. ** other thing generated for remotes...
  200. */
  201. int    check_registered_user(sptr)
  202. aClient    *sptr;
  203. {
  204.     if (!IsRegisteredUser(sptr))
  205.         {
  206.         sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
  207.         return -1;
  208.         }
  209.     return 0;
  210. }
  211.  
  212. /*
  213. ** check_registered user cancels message, if 'x' is not
  214. ** registered (e.g. we don't know yet whether a server
  215. ** or user)
  216. */
  217. int    check_registered(sptr)
  218. aClient    *sptr;
  219. {
  220.     if (!IsRegistered(sptr))
  221.         {
  222.         sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
  223.         return -1;
  224.         }
  225.     return 0;
  226. }
  227.  
  228. /*
  229. ** get_client_name
  230. **      Return the name of the client for various tracking and
  231. **      admin purposes. The main purpose of this function is to
  232. **      return the "socket host" name of the client, if that
  233. **    differs from the advertised name (other than case).
  234. **    But, this can be used to any client structure.
  235. **
  236. **    Returns:
  237. **      "name[user@ip#.port]" if 'showip' is true;
  238. **      "name[sockethost]", if name and sockhost are different and
  239. **      showip is false; else
  240. **      "name".
  241. **
  242. ** NOTE 1:
  243. **    Watch out the allocation of "nbuf", if either sptr->name
  244. **    or sptr->sockhost gets changed into pointers instead of
  245. **    directly allocated within the structure...
  246. **
  247. ** NOTE 2:
  248. **    Function return either a pointer to the structure (sptr) or
  249. **    to internal buffer (nbuf). *NEVER* use the returned pointer
  250. **    to modify what it points!!!
  251. */
  252. char    *get_client_name(sptr, showip)
  253. aClient *sptr;
  254. int    showip;
  255. {
  256.     static char nbuf[HOSTLEN * 2 + USERLEN + 5];
  257.  
  258.     if (MyConnect(sptr))
  259.         {
  260.         if (IsUnixSocket(sptr))
  261.             {
  262.             if (showip)
  263.                 (void) sprintf(nbuf, "%s[%s]",
  264.                     sptr->name, sptr->sockhost);
  265.             else
  266.                 (void) sprintf(nbuf, "%s[%s]",
  267.                     sptr->name, me.sockhost);
  268.             }
  269.         else
  270.             {
  271.             if (showip)
  272.                 (void)sprintf(nbuf, "%s[%s@%s.%u]",
  273.                     sptr->name,
  274.                     (!(sptr->flags & FLAGS_GOTID)) ? "" :
  275.                     sptr->username,
  276.                     inetntoa((char *)&sptr->ip),
  277.                     (unsigned int)sptr->port);
  278.             else
  279.                 {
  280.                 if (mycmp(sptr->name, sptr->sockhost))
  281.                     (void)sprintf(nbuf, "%s[%s]",
  282.                         sptr->name, sptr->sockhost);
  283.                 else
  284.                     return sptr->name;
  285.                 }
  286.             }
  287.         return nbuf;
  288.         }
  289.     return sptr->name;
  290. }
  291.  
  292. char    *get_client_host(cptr)
  293. aClient    *cptr;
  294. {
  295.     static char nbuf[HOSTLEN * 2 + USERLEN + 5];
  296.  
  297.     if (!MyConnect(cptr))
  298.         return cptr->name;
  299.     if (!cptr->hostp)
  300.         return get_client_name(cptr, FALSE);
  301.     if (IsUnixSocket(cptr))
  302.         (void) sprintf(nbuf, "%s[%s]", cptr->name, me.name);
  303.     else
  304.         (void)sprintf(nbuf, "%s[%-.*s@%-.*s]",
  305.             cptr->name, USERLEN,
  306.             (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->username,
  307.             HOSTLEN, cptr->hostp->h_name);
  308.     return nbuf;
  309. }
  310.  
  311. /*
  312.  * Form sockhost such that if the host is of form user@host, only the host
  313.  * portion is copied.
  314.  */
  315. void    get_sockhost(cptr, host)
  316. Reg1    aClient    *cptr;
  317. Reg2    char    *host;
  318. {
  319.     Reg3    char    *s;
  320.     if ((s = (char *)index(host, '@')))
  321.         s++;
  322.     else
  323.         s = host;
  324.     strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
  325. }
  326.  
  327. /*
  328.  * Return wildcard name of my server name according to given config entry
  329.  * --Jto
  330.  */
  331. char    *my_name_for_link(name, aconf)
  332. char    *name;
  333. aConfItem *aconf;
  334. {
  335.     static    char    namebuf[HOSTLEN];
  336.     register int    count = aconf->port;
  337.     register char    *start = name;
  338.  
  339.     if (count <= 0 || count > 5)
  340.         return start;
  341.  
  342.     while (count-- && name)
  343.         {
  344.         name++;
  345.         name = (char *)index(name, '.');
  346.         }
  347.     if (!name)
  348.         return start;
  349.  
  350.     namebuf[0] = '*';
  351.     (void)strncpy(&namebuf[1], name, HOSTLEN - 1);
  352.     namebuf[HOSTLEN - 1] = '\0';
  353.  
  354.     return namebuf;
  355. }
  356.  
  357. /*
  358. ** exit_client
  359. **    This is old "m_bye". Name  changed, because this is not a
  360. **    protocol function, but a general server utility function.
  361. **
  362. **    This function exits a client of *any* type (user, server, etc)
  363. **    from this server. Also, this generates all necessary prototol
  364. **    messages that this exit may cause.
  365. **
  366. **   1) If the client is a local client, then this implicitly
  367. **    exits all other clients depending on this connection (e.g.
  368. **    remote clients having 'from'-field that points to this.
  369. **
  370. **   2) If the client is a remote client, then only this is exited.
  371. **
  372. ** For convenience, this function returns a suitable value for
  373. ** m_funtion return value:
  374. **
  375. **    FLUSH_BUFFER    if (cptr == sptr)
  376. **    0        if (cptr != sptr)
  377. */
  378. int    exit_client(cptr, sptr, from, comment)
  379. aClient *cptr;    /*
  380.         ** The local client originating the exit or NULL, if this
  381.         ** exit is generated by this server for internal reasons.
  382.         ** This will not get any of the generated messages.
  383.         */
  384. aClient *sptr;    /* Client exiting */
  385. aClient *from;    /* Client firing off this Exit, never NULL! */
  386. char    *comment;    /* Reason for the exit */
  387.     {
  388.     Reg1    aClient    *acptr;
  389.     Reg2    aClient    *next;
  390. #ifdef    FNAME_USERLOG
  391.     time_t    on_for;
  392. #endif
  393.     static    char    comment1[HOSTLEN + HOSTLEN + 2];
  394.     static    int    recurse=0;
  395.  
  396.  
  397.     if (MyConnect(sptr))
  398.         {
  399.         sptr->flags |= FLAGS_CLOSING;
  400.                 if (IsPerson(sptr))
  401.                  sendto_umode(UMODE_OPER|UMODE_CLIENT,"*** Notice -- Client exiting: %s (%s@%s) [%s]", 
  402.                   sptr->name, sptr->user->username, sptr->user->host, comment);
  403.         current_load_data.conn_count--;
  404.         if (IsPerson(sptr)) {
  405.           char mydom_mask[HOSTLEN + 1];
  406.           mydom_mask[0] = '*';
  407.           strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1);
  408.           current_load_data.client_count--;
  409.           if (match(mydom_mask, sptr->sockhost) == 0)
  410.             current_load_data.local_count--;
  411.           /* Clean out list and watch structures -Donwulff */
  412.           hash_del_notify_list(sptr);
  413.           if (sptr->lopt) {
  414.             free_str_list(sptr->lopt->yeslist);
  415.             free_str_list(sptr->lopt->nolist);
  416.             MyFree(sptr->lopt);
  417.           }
  418.         }
  419.         update_load();
  420. #ifdef FNAME_USERLOG
  421.         on_for = time(NULL) - sptr->firsttime;
  422. # if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
  423.         if (IsPerson(sptr))
  424.             syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s@%s (%s)\n",
  425.                    myctime(sptr->firsttime),
  426.                    on_for / 3600, (on_for % 3600)/60,
  427.                    on_for % 60, sptr->user->username,
  428.                    sptr->sockhost, sptr->name);
  429. # else
  430.         {
  431.         char    linebuf[160];
  432.         int    logfile;
  433.  
  434.         /*
  435.           * This conditional makes the logfile active only after
  436.          * it's been created - thus logging can be turned off by
  437.          * removing the file.
  438.          *
  439.          * stop NFS hangs...most systems should be able to open a
  440.          * file in 3 seconds. -avalon (curtesy of wumpus)
  441.          */
  442.         if (IsPerson(sptr) &&
  443.             (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1)
  444.             {
  445.             (void)sprintf(linebuf,
  446.                 "%s (%3d:%02d:%02d): %s@%s [%s]\n",
  447.                 myctime(sptr->firsttime),
  448.                 on_for / 3600, (on_for % 3600)/60,
  449.                 on_for % 60,
  450.                 sptr->user->username, sptr->user->host,
  451.                 sptr->username);
  452.             (void)write(logfile, linebuf, strlen(linebuf));
  453.             (void)close(logfile);
  454.             }
  455.         /* Modification by stealth@caen.engin.umich.edu */
  456.         }
  457. # endif
  458. #endif
  459.         if (sptr->fd >= 0 && !IsConnecting(sptr))
  460.             {
  461.               if (cptr != NULL && sptr != cptr)
  462.             sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)",
  463.                    get_client_name(sptr,FALSE),
  464.                    cptr->name, comment);
  465.               else
  466.             sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
  467.                    get_client_name(sptr,FALSE), comment);
  468.             }
  469.         /*
  470.         ** Currently only server connections can have
  471.         ** depending remote clients here, but it does no
  472.         ** harm to check for all local clients. In
  473.         ** future some other clients than servers might
  474.         ** have remotes too...
  475.         **
  476.         ** Close the Client connection first and mark it
  477.         ** so that no messages are attempted to send to it.
  478.         ** (The following *must* make MyConnect(sptr) == FALSE!).
  479.         ** It also makes sptr->from == NULL, thus it's unnecessary
  480.         ** to test whether "sptr != acptr" in the following loops.
  481.         */
  482.         close_connection(sptr);
  483.         }
  484.  
  485.     /*
  486.      * Recurse down the client list and get rid of clients who are no
  487.      * longer connected to the network (from my point of view)
  488.      * Only do this expensive stuff if exited==server -Donwulff
  489.      */
  490.  
  491.     if (IsServer(sptr)) {
  492.         /*
  493.          * Is this right? Not recreateing the split message if
  494.          * we have been called recursivly? I hope so, cuz thats
  495.          * the only way I could make this give the right servers
  496.          * in the quit msg. -Cabal95
  497.          */
  498.         if (cptr && !recurse) {
  499.             (void)strcpy(comment1, sptr->srvptr->name);
  500.             (void)strcat(comment1, " ");
  501.             (void)strcat(comment1, sptr->name);
  502.         }
  503.         /*
  504.          * First, remove the clients on the server itself.
  505.          */
  506.         for (acptr = client; acptr; acptr=next) {
  507.             next = acptr->next;
  508.             if (IsClient(acptr) && (acptr->srvptr == sptr))
  509.                 exit_one_client_in_split(NULL, acptr,
  510.                     &me, comment1);
  511. #ifdef DEBUGMODE
  512.             else if (IsClient(acptr) &&
  513.                 (find_server(acptr->user->server,NULL)==sptr)) {
  514.                 sendto_ops("WARNING, srvptr!=sptr but "
  515.                     "find_server did!  User %s on %s "
  516.                     "thought it was on %s while "
  517.                     "loosing %s.  Tell coding team.",
  518.                     acptr->name, acptr->user->server,
  519.                     acptr->srvptr?acptr->srvptr->name:"<noserver>",
  520.                     sptr->name);
  521.                 exit_one_client_in_split(NULL, acptr,
  522.                     &me, comment1);
  523.             }
  524. #endif
  525.         }
  526.  
  527.         /*
  528.          * Now, go SQUIT off the servers which are down-stream of
  529.          * the one we just lost.
  530.          */
  531.         recurse++;
  532.         for (acptr = client; acptr; acptr=next) {
  533.             next = acptr->next;
  534.             if (IsServer(acptr) && acptr->srvptr == sptr)
  535.                 exit_client(sptr, acptr, /* RECURSION */
  536.                         sptr, comment1);
  537.             /*
  538.              * I am not masking SQUITS like I do QUITs.  This
  539.              * is probobly something we could easily do, but
  540.              * how much savings is there really in something
  541.              * like that?
  542.              */
  543. #ifdef DEBUGMODE
  544.             else if (IsServer(acptr) &&
  545.                 (find_server(acptr->serv->up, NULL)==sptr)) {
  546.                 sendto_ops("WARNING, srvptr!=sptr but "
  547.                     "find_server did!  Server %s on "
  548.                     "%s thought it was on %s while "
  549.                     "loosing %s.  Tell coding team.",
  550.                     acptr->name, acptr->serv->up,
  551.                     acptr->srvptr?acptr->srvptr->name:"<noserver>",
  552.                     sptr->name);
  553.                 exit_client(sptr, acptr, sptr, comment1);
  554.             }
  555. #endif
  556.         }
  557.         recurse--;
  558.     }
  559.  
  560.     /*
  561.      * Finally, clear out the server we lost itself
  562.      */
  563.     exit_one_client(cptr, sptr, from, comment);
  564.     return cptr == sptr ? FLUSH_BUFFER : 0;
  565.     }
  566.  
  567. /*
  568. ** Exit one client, local or remote. Assuming all dependants have
  569. ** been already removed, and socket closed for local client.
  570. */
  571. /* DANGER: Ugly hack follows. */
  572. /* Yeah :/ */
  573. static    void    exit_one_client_backend(cptr, sptr, from, comment, split)
  574. aClient *sptr;
  575. aClient *cptr;
  576. aClient *from;
  577. char    *comment;
  578. int    split;
  579. {
  580.     Reg1    aClient *acptr;
  581.     Reg2    int    i;
  582.     Reg3    Link    *lp;
  583.  
  584.     /*
  585.     **  For a server or user quitting, propagage the information to
  586.     **  other servers (except to the one where is came from (cptr))
  587.     */
  588.     if (IsMe(sptr))
  589.         {
  590.         sendto_ops("ERROR: tried to exit me! : %s", comment);
  591.         return;    /* ...must *never* exit self!! */
  592.         }
  593.     else if (IsServer(sptr)) {
  594.      /*
  595.      ** Old sendto_serv_but_one() call removed because we now
  596.      ** need to send different names to different servers
  597.      ** (domain name matching)
  598.      */
  599.          for (i = 0; i <= highest_fd; i++)
  600.             {
  601.             Reg4    aConfItem *aconf;
  602.  
  603.             if (!(acptr = local[i]) || !IsServer(acptr) ||
  604.                 acptr == cptr || IsMe(acptr))
  605.                 continue;
  606.             if ((aconf = acptr->serv->nline) &&
  607.                 (match(my_name_for_link(me.name, aconf),
  608.                      sptr->name) == 0))
  609.                 continue;
  610.             /*
  611.             ** SQUIT going "upstream". This is the remote
  612.             ** squit still hunting for the target. Use prefixed
  613.             ** form. "from" will be either the oper that issued
  614.             ** the squit or some server along the path that
  615.             ** didn't have this fix installed. --msa
  616.             */
  617.             if (sptr->from == acptr)
  618.                 {
  619.                 sendto_one(acptr, ":%s SQUIT %s :%s",
  620.                        from->name, sptr->name, comment);
  621. #ifdef    USE_SERVICES
  622.                 check_services_butone(SERVICE_WANT_SQUIT, sptr,
  623.                             ":%s SQUIT %s :%s",
  624.                             from->name,
  625.                             sptr->name, comment);
  626. #endif
  627.                 }
  628.             else
  629.                 {
  630.                 sendto_one(acptr, "SQUIT %s :%s",
  631.                        sptr->name, comment);
  632. #ifdef    USE_SERVICES
  633.                 check_services_butone(SERVICE_WANT_SQUIT, sptr,
  634.                             "SQUIT %s :%s",
  635.                             sptr->name, comment);
  636. #endif
  637.                 }
  638.         }
  639.     } else if (!(IsPerson(sptr) || IsService(sptr)))
  640.                     /* ...this test is *dubious*, would need
  641.                     ** some thougth.. but for now it plugs a
  642.                     ** nasty hole in the server... --msa
  643.                     */
  644.         ; /* Nothing */
  645.     else if (sptr->name[0]) /* ...just clean all others with QUIT... */
  646.         {
  647.         /*
  648.         ** If this exit is generated from "m_kill", then there
  649.         ** is no sense in sending the QUIT--KILL's have been
  650.         ** sent instead.
  651.         */
  652.         if ((sptr->flags & FLAGS_KILLED) == 0)
  653.             {
  654.             if (split == 0)
  655.             sendto_serv_butone(cptr,":%s QUIT :%s",
  656.                        sptr->name, comment);
  657.             else
  658.                 /*
  659.                  * Then this is a split, only old (stupid)
  660.                  * clients need to get quit messages
  661.                  */
  662.                 sendto_serv_butone_quit(cptr, ":%s QUIT :%s",
  663.                     sptr->name, comment);
  664. #ifdef    USE_SERVICES
  665.             check_services_butone(SERVICE_WANT_QUIT,
  666.                         ":%s QUIT :%s", sptr->name,
  667.                         comment);
  668. #endif
  669.             }
  670.         /*
  671.         ** If a person is on a channel, send a QUIT notice
  672.         ** to every client (person) on the same channel (so
  673.         ** that the client can show the "**signoff" message).
  674.         ** (Note: The notice is to the local clients *only*)
  675.         */
  676.         if (sptr->user)
  677.             {
  678.             sendto_common_channels(sptr, ":%s QUIT :%s",
  679.                         sptr->name, comment);
  680.  
  681.             while ((lp = sptr->user->channel))
  682.                 remove_user_from_channel(sptr,lp->value.chptr);
  683.  
  684.             /* Clean up invitefield */
  685.             while ((lp = sptr->user->invited))
  686.                 del_invite(sptr, lp->value.chptr);
  687.                 /* again, this is all that is needed */
  688.  
  689.             /* Clean up silencefield */
  690.             while ((lp = sptr->user->silence))
  691.                 (void)del_silence(sptr, lp->value.cp);
  692.             }
  693.         }
  694.  
  695.     /* Remove sptr from the client list */
  696.     if (del_from_client_hash_table(sptr->name, sptr) != 1)
  697.         Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
  698.             sptr, sptr->name,
  699.             sptr->from ? sptr->from->sockhost : "??host",
  700.             sptr->from, sptr->next, sptr->prev, sptr->fd,
  701.             sptr->status, sptr->user));
  702.     if (IsRegisteredUser(sptr))
  703.         hash_check_notify(sptr, RPL_LOGOFF);
  704.     remove_client_from_list(sptr);
  705.     return;
  706. }
  707.  
  708. static    void    exit_one_client(cptr, sptr, from, comment)
  709. aClient    *sptr, *cptr, *from;
  710. char    *comment;
  711. {
  712.     exit_one_client_backend(cptr, sptr, from, comment, 0);
  713. }
  714.  
  715. static    void    exit_one_client_in_split(cptr, sptr, from, comment)
  716. aClient    *sptr, *cptr, *from;
  717. char    *comment;
  718. {
  719.     exit_one_client_backend(cptr, sptr, from, comment, 1);
  720. }
  721.  
  722.  
  723. void    checklist()
  724. {
  725.     Reg1    aClient    *acptr;
  726.     Reg2    int    i,j;
  727.  
  728.     if (!(bootopt & BOOT_AUTODIE))
  729.         return;
  730.     for (j = i = 0; i <= highest_fd; i++)
  731.         if (!(acptr = local[i]))
  732.             continue;
  733.         else if (IsClient(acptr))
  734.             j++;
  735.     if (!j)
  736.         {
  737. #ifdef    USE_SYSLOG
  738.         syslog(LOG_WARNING,"ircd exiting: autodie");
  739. #endif
  740.         exit(0);
  741.         }
  742.     return;
  743. }
  744.  
  745. void    initstats()
  746. {
  747.     bzero((char *)&ircst, sizeof(ircst));
  748. }
  749.  
  750. void    tstats(cptr, name)
  751. aClient    *cptr;
  752. char    *name;
  753. {
  754.     Reg1    aClient    *acptr;
  755.     Reg2    int    i;
  756.     Reg3    struct stats    *sp;
  757.     struct    stats    tmp;
  758.     time_t    now = time(NULL);
  759.  
  760.     sp = &tmp;
  761.     bcopy((char *)ircstp, (char *)sp, sizeof(*sp));
  762. #ifndef _WIN32
  763.     for (i = 0; i < MAXCONNECTIONS; i++)
  764. #else
  765.     for (i = 0; i < highest_fd; i++)
  766. #endif
  767.         {
  768.         if (!(acptr = local[i]))
  769.             continue;
  770.         if (IsServer(acptr))
  771.             {
  772.             sp->is_sbs += acptr->sendB;
  773.             sp->is_sbr += acptr->receiveB;
  774.             sp->is_sks += acptr->sendK;
  775.             sp->is_skr += acptr->receiveK;
  776.             sp->is_sti += now - acptr->firsttime;
  777.             sp->is_sv++;
  778.             if (sp->is_sbs > 1023)
  779.                 {
  780.                 sp->is_sks += (sp->is_sbs >> 10);
  781.                 sp->is_sbs &= 0x3ff;
  782.                 }
  783.             if (sp->is_sbr > 1023)
  784.                 {
  785.                 sp->is_skr += (sp->is_sbr >> 10);
  786.                 sp->is_sbr &= 0x3ff;
  787.                 }
  788.             }
  789.         else if (IsClient(acptr))
  790.             {
  791.             sp->is_cbs += acptr->sendB;
  792.             sp->is_cbr += acptr->receiveB;
  793.             sp->is_cks += acptr->sendK;
  794.             sp->is_ckr += acptr->receiveK;
  795.             sp->is_cti += now - acptr->firsttime;
  796.             sp->is_cl++;
  797.             if (sp->is_cbs > 1023)
  798.                 {
  799.                 sp->is_cks += (sp->is_cbs >> 10);
  800.                 sp->is_cbs &= 0x3ff;
  801.                 }
  802.             if (sp->is_cbr > 1023)
  803.                 {
  804.                 sp->is_ckr += (sp->is_cbr >> 10);
  805.                 sp->is_cbr &= 0x3ff;
  806.                 }
  807.             }
  808.         else if (IsUnknown(acptr))
  809.             sp->is_ni++;
  810.         }
  811.  
  812.     sendto_one(cptr, ":%s %d %s :accepts %u refused %u",
  813.            me.name, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
  814.     sendto_one(cptr, ":%s %d %s :unknown commands %u prefixes %u",
  815.            me.name, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
  816.     sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u",
  817.            me.name, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni);
  818.     sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u",
  819.            me.name, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
  820.     sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u",
  821.            me.name, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
  822.     sendto_one(cptr, ":%s %d %s :auth successes %u fails %u",
  823.            me.name, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
  824.     sendto_one(cptr, ":%s %d %s :local connections %u udp packets %u",
  825.            me.name, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udp);
  826.     sendto_one(cptr, ":%s %d %s :Client Server",
  827.            me.name, RPL_STATSDEBUG, name);
  828.     sendto_one(cptr, ":%s %d %s :connected %u %u",
  829.            me.name, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
  830.     sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK",
  831.            me.name, RPL_STATSDEBUG, name,
  832.            sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
  833.     sendto_one(cptr, ":%s %d %s :bytes recv %u.%uK %u.%uK",
  834.            me.name, RPL_STATSDEBUG, name,
  835.            sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
  836.     sendto_one(cptr, ":%s %d %s :time connected %u %u",
  837.            me.name, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
  838. }
  839.