home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / s_misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  18.2 KB  |  683 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. #include <sys/time.h>
  30. #include "struct.h"
  31. #include "common.h"
  32. #include "sys.h"
  33. #include "numeric.h"
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36. #if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
  37.     !defined(__convex__)
  38. # include <sys/param.h>
  39. #endif
  40. #if defined(PCS) || defined(AIX) || defined(SVR3)
  41. # include <time.h>
  42. #endif
  43. #ifdef HPUX
  44. #include <unistd.h>
  45. #endif
  46. #ifdef DYNIXPTX
  47. #include <sys/types.h>
  48. #include <time.h>
  49. #endif
  50. #include "h.h"
  51.  
  52. static    void    exit_one_client PROTO((aClient *,aClient *,aClient *,char *));
  53.  
  54. static    char    *months[] = {
  55.     "January",    "February",    "March",    "April",
  56.     "May",            "June",            "July",            "August",
  57.     "September",    "October",    "November",    "December"
  58. };
  59.  
  60. static    char    *weekdays[] = {
  61.     "Sunday",    "Monday",    "Tuesday",    "Wednesday",
  62.     "Thursday",    "Friday",    "Saturday"
  63. };
  64.  
  65. /*
  66.  * stats stuff
  67.  */
  68. struct    stats    ircst, *ircstp = &ircst;
  69.  
  70. char    *date(clock) 
  71. time_t    clock;
  72. {
  73.     static    char    buf[80], plus;
  74.     Reg1    struct    tm *lt, *gm;
  75.     struct    tm    gmbuf;
  76.     int    minswest;
  77.  
  78.     if (!clock) 
  79.         time(&clock);
  80.     gm = gmtime(&clock);
  81.     bcopy((char *)gm, (char *)&gmbuf, sizeof(gmbuf));
  82.     gm = &gmbuf;
  83.     lt = localtime(&clock);
  84.  
  85.     if (lt->tm_yday == gm->tm_yday)
  86.         minswest = (gm->tm_hour - lt->tm_hour) * 60 +
  87.                (gm->tm_min - lt->tm_min);
  88.     else if (lt->tm_yday > gm->tm_yday)
  89.         minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
  90.     else
  91.         minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
  92.  
  93.     plus = (minswest > 0) ? '-' : '+';
  94.     if (minswest < 0)
  95.         minswest = -minswest;
  96.  
  97.     (void)sprintf(buf, "%s %s %d 19%02d -- %02d:%02d %c%02d:%02d",
  98.         weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday,
  99.         lt->tm_year, lt->tm_hour, lt->tm_min,
  100.         plus, minswest/60, minswest%60);
  101.  
  102.     return buf;
  103. }
  104.  
  105. /**
  106.  ** myctime()
  107.  **   This is like standard ctime()-function, but it zaps away
  108.  **   the newline from the end of that string. Also, it takes
  109.  **   the time value as parameter, instead of pointer to it.
  110.  **   Note that it is necessary to copy the string to alternate
  111.  **   buffer (who knows how ctime() implements it, maybe it statically
  112.  **   has newline there and never 'refreshes' it -- zapping that
  113.  **   might break things in other places...)
  114.  **
  115.  **/
  116.  
  117. char    *myctime(value)
  118. time_t    value;
  119. {
  120.     static    char    buf[28];
  121.     Reg1    char    *p;
  122.  
  123.     (void)strcpy(buf, ctime(&value));
  124.     if ((p = (char *)index(buf, '\n')) != NULL)
  125.         *p = '\0';
  126.  
  127.     return buf;
  128. }
  129.  
  130. /*
  131. ** check_registered_user is used to cancel message, if the
  132. ** originator is a server or not registered yet. In other
  133. ** words, passing this test, *MUST* guarantee that the
  134. ** sptr->user exists (not checked after this--let there
  135. ** be coredumps to catch bugs... this is intentional --msa ;)
  136. **
  137. ** There is this nagging feeling... should this NOT_REGISTERED
  138. ** error really be sent to remote users? This happening means
  139. ** that remote servers have this user registered, althout this
  140. ** one has it not... Not really users fault... Perhaps this
  141. ** error message should be restricted to local clients and some
  142. ** other thing generated for remotes...
  143. */
  144. int    check_registered_user(sptr)
  145. aClient    *sptr;
  146. {
  147.     if (!IsRegisteredUser(sptr))
  148.         {
  149.         sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
  150.         return -1;
  151.         }
  152.     return 0;
  153. }
  154.  
  155. /*
  156. ** check_registered user cancels message, if 'x' is not
  157. ** registered (e.g. we don't know yet whether a server
  158. ** or user)
  159. */
  160. int    check_registered(sptr)
  161. aClient    *sptr;
  162. {
  163.     if (!IsRegistered(sptr))
  164.         {
  165.         sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
  166.         return -1;
  167.         }
  168.     return 0;
  169. }
  170.  
  171. /*
  172. ** get_client_name
  173. **      Return the name of the client for various tracking and
  174. **      admin purposes. The main purpose of this function is to
  175. **      return the "socket host" name of the client, if that
  176. **    differs from the advertised name (other than case).
  177. **    But, this can be used to any client structure.
  178. **
  179. **    Returns:
  180. **      "name[user@ip#.port]" if 'showip' is true;
  181. **      "name[sockethost]", if name and sockhost are different and
  182. **      showip is false; else
  183. **      "name".
  184. **
  185. ** NOTE 1:
  186. **    Watch out the allocation of "nbuf", if either sptr->name
  187. **    or sptr->sockhost gets changed into pointers instead of
  188. **    directly allocated within the structure...
  189. **
  190. ** NOTE 2:
  191. **    Function return either a pointer to the structure (sptr) or
  192. **    to internal buffer (nbuf). *NEVER* use the returned pointer
  193. **    to modify what it points!!!
  194. */
  195. char    *get_client_name(sptr, showip)
  196. aClient *sptr;
  197. int    showip;
  198. {
  199.     static char nbuf[HOSTLEN * 2 + USERLEN + 5];
  200.  
  201.     if (MyConnect(sptr))
  202.         {
  203.         if (IsUnixSocket(sptr))
  204.             {
  205.             if (showip)
  206.                 (void) sprintf(nbuf, "%s[%s]",
  207.                     sptr->name, sptr->sockhost);
  208.             else
  209.                 (void) sprintf(nbuf, "%s[%s]",
  210.                     sptr->name, me.sockhost);
  211.             }
  212.         else
  213.             {
  214.             if (showip)
  215.                 (void)sprintf(nbuf, "%s[%s@%s.%u]",
  216.                     sptr->name,
  217.                     (!(sptr->flags & FLAGS_GOTID)) ? "" :
  218.                     sptr->username,
  219.                     inetntoa((char *)&sptr->ip),
  220.                     (unsigned int)sptr->port);
  221.             else
  222.                 {
  223.                 if (mycmp(sptr->name, sptr->sockhost))
  224.                     (void)sprintf(nbuf, "%s[%s]",
  225.                         sptr->name, sptr->sockhost);
  226.                 else
  227.                     return sptr->name;
  228.                 }
  229.             }
  230.         return nbuf;
  231.         }
  232.     return sptr->name;
  233. }
  234.  
  235. char    *get_client_host(cptr)
  236. aClient    *cptr;
  237. {
  238.     static char nbuf[HOSTLEN * 2 + USERLEN + 5];
  239.  
  240.     if (!MyConnect(cptr))
  241.         return cptr->name;
  242.     if (!cptr->hostp)
  243.         return get_client_name(cptr, FALSE);
  244.     if (IsUnixSocket(cptr))
  245.         (void) sprintf(nbuf, "%s[%s]", cptr->name, me.name);
  246.     else
  247.         (void)sprintf(nbuf, "%s[%-.*s@%-.*s]",
  248.             cptr->name, USERLEN,
  249.             (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->username,
  250.             HOSTLEN, cptr->hostp->h_name);
  251.     return nbuf;
  252. }
  253.  
  254. /*
  255.  * Form sockhost such that if the host is of form user@host, only the host
  256.  * portion is copied.
  257.  */
  258. void    get_sockhost(cptr, host)
  259. Reg1    aClient    *cptr;
  260. Reg2    char    *host;
  261. {
  262.     Reg3    char    *s;
  263.     if ((s = (char *)index(host, '@')))
  264.         s++;
  265.     else
  266.         s = host;
  267.     strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
  268. }
  269.  
  270. /*
  271.  * Return wildcard name of my server name according to given config entry
  272.  * --Jto
  273.  */
  274. char    *my_name_for_link(name, aconf)
  275. char    *name;
  276. aConfItem *aconf;
  277. {
  278.     static    char    namebuf[HOSTLEN];
  279.     register int    count = aconf->port;
  280.     register char    *start = name;
  281.  
  282.     if (count <= 0 || count > 5)
  283.         return start;
  284.  
  285.     while (count-- && name)
  286.         {
  287.         name++;
  288.         name = (char *)index(name, '.');
  289.         }
  290.     if (!name)
  291.         return start;
  292.  
  293.     namebuf[0] = '*';
  294.     (void)strncpy(&namebuf[1], name, HOSTLEN - 1);
  295.     namebuf[HOSTLEN - 1] = '\0';
  296.  
  297.     return namebuf;
  298. }
  299.  
  300. /*
  301. ** exit_client
  302. **    This is old "m_bye". Name  changed, because this is not a
  303. **    protocol function, but a general server utility function.
  304. **
  305. **    This function exits a client of *any* type (user, server, etc)
  306. **    from this server. Also, this generates all necessary prototol
  307. **    messages that this exit may cause.
  308. **
  309. **   1) If the client is a local client, then this implicitly
  310. **    exits all other clients depending on this connection (e.g.
  311. **    remote clients having 'from'-field that points to this.
  312. **
  313. **   2) If the client is a remote client, then only this is exited.
  314. **
  315. ** For convenience, this function returns a suitable value for
  316. ** m_funtion return value:
  317. **
  318. **    FLUSH_BUFFER    if (cptr == sptr)
  319. **    0        if (cptr != sptr)
  320. */
  321. int    exit_client(cptr, sptr, from, comment)
  322. aClient *cptr;    /*
  323.         ** The local client originating the exit or NULL, if this
  324.         ** exit is generated by this server for internal reasons.
  325.         ** This will not get any of the generated messages.
  326.         */
  327. aClient *sptr;    /* Client exiting */
  328. aClient *from;    /* Client firing off this Exit, never NULL! */
  329. char    *comment;    /* Reason for the exit */
  330.     {
  331.     Reg1    aClient    *acptr;
  332.     Reg2    aClient    *next;
  333. #ifdef    FNAME_USERLOG
  334.     time_t    on_for;
  335. #endif
  336.     char    comment1[HOSTLEN + HOSTLEN + 2];
  337.  
  338.     if (MyConnect(sptr))
  339.         {
  340.         sptr->flags |= FLAGS_CLOSING;
  341. #ifdef FNAME_USERLOG
  342.         on_for = time(NULL) - sptr->firsttime;
  343. # if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
  344.         if (IsPerson(sptr))
  345.             syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s@%s\n",
  346.                 myctime(sptr->firsttime),
  347.                 on_for / 3600, (on_for % 3600)/60,
  348.                 on_for % 60,
  349.                 sptr->user->username, sptr->user->host);
  350. # else
  351.         {
  352.         char    linebuf[160];
  353.         int    logfile;
  354.  
  355.         /*
  356.           * This conditional makes the logfile active only after
  357.          * it's been created - thus logging can be turned off by
  358.          * removing the file.
  359.          *
  360.          * stop NFS hangs...most systems should be able to open a
  361.          * file in 3 seconds. -avalon (curtesy of wumpus)
  362.          */
  363.         (void)alarm(3);
  364.         if (IsPerson(sptr) &&
  365.             (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1)
  366.             {
  367.             (void)alarm(0);
  368.             (void)sprintf(linebuf,
  369.                 "%s (%3d:%02d:%02d): %s@%s [%s]\n",
  370.                 myctime(sptr->firsttime),
  371.                 on_for / 3600, (on_for % 3600)/60,
  372.                 on_for % 60,
  373.                 sptr->user->username, sptr->user->host,
  374.                 sptr->username);
  375.             (void)alarm(3);
  376.             (void)write(logfile, linebuf, strlen(linebuf));
  377.             (void)alarm(0);
  378.             (void)close(logfile);
  379.             }
  380.         (void)alarm(0);
  381.         /* Modification by stealth@caen.engin.umich.edu */
  382.         }
  383. # endif
  384. #endif
  385.         if (sptr->fd >= 0)
  386.             {
  387.               if (cptr != NULL && sptr != cptr)
  388.             sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)",
  389.                    get_client_name(sptr,FALSE),
  390.                    cptr->name, comment);
  391.               else
  392.             sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
  393.                    get_client_name(sptr,FALSE), comment);
  394.             }
  395.         /*
  396.         ** Currently only server connections can have
  397.         ** depending remote clients here, but it does no
  398.         ** harm to check for all local clients. In
  399.         ** future some other clients than servers might
  400.         ** have remotes too...
  401.         **
  402.         ** Close the Client connection first and mark it
  403.         ** so that no messages are attempted to send to it.
  404.         ** (The following *must* make MyConnect(sptr) == FALSE!).
  405.         ** It also makes sptr->from == NULL, thus it's unnecessary
  406.         ** to test whether "sptr != acptr" in the following loops.
  407.         */
  408.         close_connection(sptr);
  409.         /*
  410.         ** First QUIT all NON-servers which are behind this link
  411.         **
  412.         ** Note    There is no danger of 'cptr' being exited in
  413.         **    the following loops. 'cptr' is a *local* client,
  414.         **    all dependants are *remote* clients.
  415.         */
  416.  
  417.         /* This next bit is a a bit ugly but all it does is take the
  418.         ** name of us.. me.name and tack it together with the name of
  419.         ** the server sptr->name that just broke off and puts this
  420.         ** together into exit_one_client() to provide some useful
  421.         ** information about where the net is broken.      Ian 
  422.         */
  423.         (void)strcpy(comment1, me.name);
  424.         (void)strcat(comment1," ");
  425.         (void)strcat(comment1, sptr->name);
  426.         for (acptr = client; acptr; acptr = next)
  427.             {
  428.             next = acptr->next;
  429.             if (!IsServer(acptr) && acptr->from == sptr)
  430.                 exit_one_client(NULL, acptr, &me, comment1);
  431.             }
  432.         /*
  433.         ** Second SQUIT all servers behind this link
  434.         */
  435.         for (acptr = client; acptr; acptr = next)
  436.             {
  437.             next = acptr->next;
  438.             if (IsServer(acptr) && acptr->from == sptr)
  439.                 exit_one_client(NULL, acptr, &me, me.name);
  440.             }
  441.         }
  442.  
  443.     exit_one_client(cptr, sptr, from, comment);
  444.     return cptr == sptr ? FLUSH_BUFFER : 0;
  445.     }
  446.  
  447. /*
  448. ** Exit one client, local or remote. Assuming all dependants have
  449. ** been already removed, and socket closed for local client.
  450. */
  451. static    void    exit_one_client(cptr, sptr, from, comment)
  452. aClient *sptr;
  453. aClient *cptr;
  454. aClient *from;
  455. char    *comment;
  456. {
  457.     Reg1    aClient *acptr;
  458.     Reg2    int    i;
  459.     Reg3    Link    *lp;
  460.  
  461.     /*
  462.     **  For a server or user quitting, propagage the information to
  463.     **  other servers (except to the one where is came from (cptr))
  464.     */
  465.     if (IsMe(sptr))
  466.         {
  467.         sendto_ops("ERROR: tried to exit me! : %s", comment);
  468.         return;    /* ...must *never* exit self!! */
  469.         }
  470.     else if (IsServer(sptr)) {
  471.      /*
  472.      ** Old sendto_serv_but_one() call removed because we now
  473.      ** need to send different names to different servers
  474.      ** (domain name matching)
  475.      */
  476.          for (i = 0; i <= highest_fd; i++)
  477.             {
  478.             Reg4    aConfItem *aconf;
  479.  
  480.             if (!(acptr = local[i]) || !IsServer(acptr) ||
  481.                 acptr == cptr || IsMe(acptr))
  482.                 continue;
  483.             if ((aconf = acptr->serv->nline) &&
  484.                 (matches(my_name_for_link(me.name, aconf),
  485.                      sptr->name) == 0))
  486.                 continue;
  487.             /*
  488.             ** SQUIT going "upstream". This is the remote
  489.             ** squit still hunting for the target. Use prefixed
  490.             ** form. "from" will be either the oper that issued
  491.             ** the squit or some server along the path that
  492.             ** didn't have this fix installed. --msa
  493.             */
  494.             if (sptr->from == acptr)
  495.                 {
  496.                 sendto_one(acptr, ":%s SQUIT %s :%s",
  497.                        from->name, sptr->name, comment);
  498. #ifdef    USE_SERVICES
  499.                 check_services_butone(SERVICE_WANT_SQUIT, sptr,
  500.                             ":%s SQUIT %s :%s",
  501.                             from->name,
  502.                             sptr->name, comment);
  503. #endif
  504.                 }
  505.             else
  506.                 {
  507.                 sendto_one(acptr, "SQUIT %s :%s",
  508.                        sptr->name, comment);
  509. #ifdef    USE_SERVICES
  510.                 check_services_butone(SERVICE_WANT_SQUIT, sptr,
  511.                             "SQUIT %s :%s",
  512.                             sptr->name, comment);
  513. #endif
  514.                 }
  515.         }
  516.     } else if (!(IsPerson(sptr) || IsService(sptr)))
  517.                     /* ...this test is *dubious*, would need
  518.                     ** some thougth.. but for now it plugs a
  519.                     ** nasty hole in the server... --msa
  520.                     */
  521.         ; /* Nothing */
  522.     else if (sptr->name[0]) /* ...just clean all others with QUIT... */
  523.         {
  524.         /*
  525.         ** If this exit is generated from "m_kill", then there
  526.         ** is no sense in sending the QUIT--KILL's have been
  527.         ** sent instead.
  528.         */
  529.         if ((sptr->flags & FLAGS_KILLED) == 0)
  530.             {
  531.             sendto_serv_butone(cptr,":%s QUIT :%s",
  532.                        sptr->name, comment);
  533. #ifdef    USE_SERVICES
  534.             check_services_butone(SERVICE_WANT_QUIT,
  535.                         ":%s QUIT :%s", sptr->name,
  536.                         comment);
  537. #endif
  538.             }
  539.         /*
  540.         ** If a person is on a channel, send a QUIT notice
  541.         ** to every client (person) on the same channel (so
  542.         ** that the client can show the "**signoff" message).
  543.         ** (Note: The notice is to the local clients *only*)
  544.         */
  545.         if (sptr->user)
  546.             {
  547.             sendto_common_channels(sptr, ":%s QUIT :%s",
  548.                         sptr->name, comment);
  549.  
  550.             while ((lp = sptr->user->channel))
  551.                 remove_user_from_channel(sptr,lp->value.chptr);
  552.  
  553.             /* Clean up invitefield */
  554.             while ((lp = sptr->user->invited))
  555.                 del_invite(sptr, lp->value.chptr);
  556.                 /* again, this is all that is needed */
  557.             }
  558.         }
  559.  
  560.     /* Remove sptr from the client list */
  561.     if (del_from_client_hash_table(sptr->name, sptr) != 1)
  562.         Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
  563.             sptr, sptr->name,
  564.             sptr->from ? sptr->from->sockhost : "??host",
  565.             sptr->from, sptr->next, sptr->prev, sptr->fd,
  566.             sptr->status, sptr->user));
  567.     remove_client_from_list(sptr);
  568.     return;
  569. }
  570.  
  571. void    checklist()
  572. {
  573.     Reg1    aClient    *acptr;
  574.     Reg2    int    i,j;
  575.  
  576.     if (!(bootopt & BOOT_AUTODIE))
  577.         return;
  578.     for (j = i = 0; i <= highest_fd; i++)
  579.         if (!(acptr = local[i]))
  580.             continue;
  581.         else if (IsClient(acptr))
  582.             j++;
  583.     if (!j)
  584.         {
  585. #ifdef    USE_SYSLOG
  586.         syslog(LOG_WARNING,"ircd exiting: autodie");
  587. #endif
  588.         exit(0);
  589.         }
  590.     return;
  591. }
  592.  
  593. void    initstats()
  594. {
  595.     bzero((char *)&ircst, sizeof(ircst));
  596. }
  597.  
  598. void    tstats(cptr, name)
  599. aClient    *cptr;
  600. char    *name;
  601. {
  602.     Reg1    aClient    *acptr;
  603.     Reg2    int    i;
  604.     Reg3    struct stats    *sp;
  605.     struct    stats    tmp;
  606.     time_t    now = time(NULL);
  607.  
  608.     sp = &tmp;
  609.     bcopy((char *)ircstp, (char *)sp, sizeof(*sp));
  610.     for (i = 0; i < MAXCONNECTIONS; i++)
  611.         {
  612.         if (!(acptr = local[i]))
  613.             continue;
  614.         if (IsServer(acptr))
  615.             {
  616.             sp->is_sbs += acptr->sendB;
  617.             sp->is_sbr += acptr->receiveB;
  618.             sp->is_sks += acptr->sendK;
  619.             sp->is_skr += acptr->receiveK;
  620.             sp->is_sti += now - acptr->firsttime;
  621.             sp->is_sv++;
  622.             if (sp->is_sbs > 1023)
  623.                 {
  624.                 sp->is_sks += (sp->is_sbs >> 10);
  625.                 sp->is_sbs &= 0x3ff;
  626.                 }
  627.             if (sp->is_sbr > 1023)
  628.                 {
  629.                 sp->is_skr += (sp->is_sbr >> 10);
  630.                 sp->is_sbr &= 0x3ff;
  631.                 }
  632.             }
  633.         else if (IsClient(acptr))
  634.             {
  635.             sp->is_cbs += acptr->sendB;
  636.             sp->is_cbr += acptr->receiveB;
  637.             sp->is_cks += acptr->sendK;
  638.             sp->is_ckr += acptr->receiveK;
  639.             sp->is_cti += now - acptr->firsttime;
  640.             sp->is_cl++;
  641.             if (sp->is_cbs > 1023)
  642.                 {
  643.                 sp->is_cks += (sp->is_cbs >> 10);
  644.                 sp->is_cbs &= 0x3ff;
  645.                 }
  646.             if (sp->is_cbr > 1023)
  647.                 {
  648.                 sp->is_ckr += (sp->is_cbr >> 10);
  649.                 sp->is_cbr &= 0x3ff;
  650.                 }
  651.             }
  652.         else if (IsUnknown(acptr))
  653.             sp->is_ni++;
  654.         }
  655.  
  656.     sendto_one(cptr, ":%s %d %s :accepts %u refused %u",
  657.            me.name, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
  658.     sendto_one(cptr, ":%s %d %s :unknown commands %u prefixes %u",
  659.            me.name, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
  660.     sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u",
  661.            me.name, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni);
  662.     sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u",
  663.            me.name, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
  664.     sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u",
  665.            me.name, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
  666.     sendto_one(cptr, ":%s %d %s :auth successes %u fails %u",
  667.            me.name, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
  668.     sendto_one(cptr, ":%s %d %s :local connections %u udp packets %u",
  669.            me.name, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udp);
  670.     sendto_one(cptr, ":%s %d %s :Client Server",
  671.            me.name, RPL_STATSDEBUG, name);
  672.     sendto_one(cptr, ":%s %d %s :connected %u %u",
  673.            me.name, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
  674.     sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK",
  675.            me.name, RPL_STATSDEBUG, name,
  676.            sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
  677.     sendto_one(cptr, ":%s %d %s :bytes recv %u.%uK %u.%uK",
  678.            me.name, RPL_STATSDEBUG, name,
  679.            sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
  680.     sendto_one(cptr, ":%s %d %s :time connected %u %u",
  681.            me.name, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
  682. }
  683.