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

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/s_serv.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_serv.c    2.55 2/7/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. #if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
  36. #include <time.h>
  37. #endif
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #include <utmp.h>
  41. #include "h.h"
  42.  
  43. static    char    buf[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. ** m_version
  104. **    parv[0] = sender prefix
  105. **    parv[1] = remote server
  106. */
  107. int    m_version(cptr, sptr, parc, parv)
  108. aClient *sptr, *cptr;
  109. int    parc;
  110. char    *parv[];
  111. {
  112.     extern    char    serveropts[];
  113.  
  114.     if (check_registered(sptr))
  115.         return 0;
  116.  
  117.     if (hunt_server(cptr,sptr,":%s VERSION :%s",1,parc,parv)==HUNTED_ISME)
  118.         sendto_one(sptr, rpl_str(RPL_VERSION), me.name,
  119.                parv[0], version, debugmode, me.name, serveropts);
  120.     return 0;
  121. }
  122.  
  123. /*
  124. ** m_squit
  125. **    parv[0] = sender prefix
  126. **    parv[1] = server name
  127. **    parv[2] = comment
  128. */
  129. int    m_squit(cptr, sptr, parc, parv)
  130. aClient *cptr, *sptr;
  131. int    parc;
  132. char    *parv[];
  133.     {
  134.     Reg1    aConfItem *aconf;
  135.     char    *server;
  136.     Reg2    aClient    *acptr;
  137.     char    *comment = (parc > 2 && parv[2]) ? parv[2] : cptr->name;
  138.  
  139.     if (!IsPrivileged(sptr))
  140.         {
  141.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  142.         return 0;
  143.         }
  144.  
  145.     if (parc > 1)
  146.         {
  147.         server = parv[1];
  148.         /*
  149.         ** To accomodate host masking, a squit for a masked server
  150.         ** name is expanded if the incoming mask is the same as
  151.         ** the server name for that link to the name of link.
  152.         */
  153.         while ((*server == '*') && IsServer(cptr))
  154.             {
  155.             aconf = cptr->serv->nline;
  156.             if (!aconf)
  157.                 break;
  158.             if (!mycmp(server, my_name_for_link(me.name, aconf)))
  159.                 server = cptr->name;
  160.             break; /* WARNING is normal here */
  161.             }
  162.         /*
  163.         ** The following allows wild cards in SQUIT. Only usefull
  164.         ** when the command is issued by an oper.
  165.         */
  166.         for (acptr = client; (acptr = next_client(acptr, server));
  167.              acptr = acptr->next)
  168.             if (IsServer(acptr) || IsMe(acptr))
  169.                 break;
  170.         if (acptr && IsMe(acptr))
  171.             {
  172.             acptr = cptr;
  173.             server = cptr->sockhost;
  174.             }
  175.         }
  176.     else
  177.         {
  178.         /*
  179.         ** This is actually protocol error. But, well, closing
  180.         ** the link is very proper answer to that...
  181.         */
  182.         server = cptr->sockhost;
  183.         acptr = cptr;
  184.         }
  185.  
  186.     /*
  187.     ** SQUIT semantics is tricky, be careful...
  188.     **
  189.     ** The old (irc2.2PL1 and earlier) code just cleans away the
  190.     ** server client from the links (because it is never true
  191.     ** "cptr == acptr".
  192.     **
  193.     ** This logic here works the same way until "SQUIT host" hits
  194.     ** the server having the target "host" as local link. Then it
  195.     ** will do a real cleanup spewing SQUIT's and QUIT's to all
  196.     ** directions, also to the link from which the orinal SQUIT
  197.     ** came, generating one unnecessary "SQUIT host" back to that
  198.     ** link.
  199.     **
  200.     ** One may think that this could be implemented like
  201.     ** "hunt_server" (e.g. just pass on "SQUIT" without doing
  202.     ** nothing until the server having the link as local is
  203.     ** reached). Unfortunately this wouldn't work in the real life,
  204.     ** because either target may be unreachable or may not comply
  205.     ** with the request. In either case it would leave target in
  206.     ** links--no command to clear it away. So, it's better just
  207.     ** clean out while going forward, just to be sure.
  208.     **
  209.     ** ...of course, even better cleanout would be to QUIT/SQUIT
  210.     ** dependant users/servers already on the way out, but
  211.     ** currently there is not enough information about remote
  212.     ** clients to do this...   --msa
  213.     */
  214.     if (!acptr)
  215.         {
  216.         sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
  217.                me.name, parv[0], server);
  218.         return 0;
  219.         }
  220.     if (IsLocOp(sptr) && !MyConnect(acptr))
  221.         {
  222.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  223.         return 0;
  224.         }
  225.     /*
  226.     **  Notify all opers, if my local link is remotely squitted
  227.     */
  228.     if (MyConnect(acptr) && !IsAnOper(cptr))
  229.       {
  230.         sendto_ops_butone(NULL, &me,
  231.         ":%s WALLOPS :Received SQUIT %s from %s (%s)",
  232.         me.name, server, get_client_name(sptr,FALSE), comment);
  233. #if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
  234.         syslog(LOG_DEBUG,"SQUIT From %s : %s (%s)",
  235.            parv[0], server, comment);
  236. #endif
  237.       }
  238.     else if (MyConnect(acptr))
  239.         sendto_ops("Received SQUIT %s from %s (%s)",
  240.                acptr->name, get_client_name(sptr,FALSE), comment);
  241.  
  242.     return exit_client(cptr, acptr, sptr, comment);
  243.     }
  244.  
  245. /*
  246. ** m_server
  247. **    parv[0] = sender prefix
  248. **    parv[1] = servername
  249. **    parv[2] = serverinfo/hopcount
  250. **      parv[3] = serverinfo
  251. */
  252. int    m_server(cptr, sptr, parc, parv)
  253. aClient *cptr, *sptr;
  254. int    parc;
  255. char    *parv[];
  256. {
  257.     Reg1    char    *ch;
  258.     Reg2    int    i;
  259.     char    info[REALLEN+1], *inpath, *host;
  260.     aClient *acptr, *bcptr;
  261.     aConfItem *aconf;
  262.     int    hop;
  263.  
  264.     info[0] = '\0';
  265.     inpath = get_client_name(cptr,FALSE);
  266.     if (parc < 2 || *parv[1] == '\0')
  267.         {
  268.             sendto_one(cptr,"ERROR :No servername");
  269.             return 0;
  270.         }
  271.     hop = 0;
  272.     host = parv[1];
  273.     if (parc > 3 && atoi(parv[2]))
  274.         {
  275.         hop = atoi(parv[2]);
  276.         (void)strncpy(info, parv[3], REALLEN);
  277.         }
  278.     else if (parc > 2)
  279.         {
  280.         (void)strncpy(info, parv[2], REALLEN);
  281.         if (parc > 3)
  282.             {
  283.                 i = strlen(info);
  284.                 (void)strncat(info, " ", REALLEN - i - 1);
  285.                 (void)strncat(info, parv[3], REALLEN - i - 2);
  286.             }
  287.         }
  288.     /*
  289.     ** Check for "FRENCH " infection ;-) (actually this should
  290.     ** be replaced with routine to check the hostname syntax in
  291.     ** general). [ This check is still needed, even after the parse
  292.     ** is fixed, because someone can send "SERVER :foo bar " ].
  293.     ** Also, changed to check other "difficult" characters, now
  294.     ** that parse lets all through... --msa
  295.     */
  296.     if (strlen(host) > HOSTLEN)
  297.         host[HOSTLEN] = '\0';
  298.     for (ch = host; *ch; ch++)
  299.         if (*ch <= ' ' || *ch > '~')
  300.             break;
  301.     if (*ch || !index(host, '.'))
  302.         {
  303.         sendto_one(sptr,"ERROR :Bogus server name (%s)",
  304.                sptr->name, host);
  305.         sendto_ops("Bogus server name (%s) from %s", host,
  306.                get_client_name(cptr, TRUE));
  307.         return 0;
  308.         }
  309.  
  310.     if (IsPerson(cptr))
  311.         {
  312.         /*
  313.         ** A local link that has been identified as a USER
  314.         ** tries something fishy... ;-)
  315.         */
  316.         sendto_one(cptr, err_str(ERR_ALREADYREGISTRED),
  317.                me.name, parv[0]);
  318.         sendto_ops("User %s trying to become a server %s",
  319.                get_client_name(cptr, TRUE),host);
  320.         return 0;
  321.         }
  322.     /* *WHEN* can it be that "cptr != sptr" ????? --msa */
  323.     /* When SERVER command (like now) has prefix. -avalon */
  324.     
  325.     if ((acptr = find_name(host, NULL)))
  326.         {
  327.         /*
  328.         ** This link is trying feed me a server that I already have
  329.         ** access through another path -- multiple paths not accepted
  330.         ** currently, kill this link immeatedly!!
  331.         **
  332.         ** Rather than KILL the link which introduced it, KILL the
  333.         ** youngest of the two links. -avalon
  334.         */
  335.         acptr = acptr->from;
  336.         acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr;
  337.         sendto_one(acptr,"ERROR :Server %s already exists", host);
  338.         sendto_ops("Link %s cancelled, server %s already exists",
  339.                get_client_name(acptr, TRUE), host);
  340.         return exit_client(acptr, acptr, acptr, "Server Exists");
  341.         }
  342.     if ((acptr = find_client(host, NULL)) && acptr != cptr)
  343.         {
  344.         /*
  345.         ** Server trying to use the same name as a person. Would
  346.         ** cause a fair bit of confusion. Enough to make it hellish
  347.         ** for a while and servers to send stuff to the wrong place.
  348.         */
  349.         sendto_one(cptr,"ERROR :Nickname %s already exists!", host);
  350.         sendto_ops("Link %s cancelled: Server/nick collision on %s",
  351.                inpath, host);
  352.         return exit_client(cptr, cptr, cptr, "Nick as Server");
  353.         }
  354.  
  355.     if (IsServer(cptr))
  356.         {
  357.         /*
  358.         ** Server is informing about a new server behind
  359.         ** this link. Create REMOTE server structure,
  360.         ** add it to list and propagate word to my other
  361.         ** server links...
  362.         */
  363.         if (parc == 1 || info[0] == '\0')
  364.             {
  365.               sendto_one(cptr,
  366.                    "ERROR :No server info specified for %s",
  367.                    host);
  368.               return 0;
  369.             }
  370.  
  371.         /*
  372.         ** See if the newly found server is behind a guaranteed
  373.         ** leaf (L-line). If so, close the link.
  374.         */
  375.         if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
  376.             (!aconf->port || (hop > aconf->port)))
  377.             {
  378.                   sendto_ops("Leaf-only link %s->%s - Closing",
  379.                    get_client_name(cptr,  TRUE),
  380.                    aconf->host ? aconf->host : "*");
  381.                   sendto_one(cptr, "ERROR :Leaf-only link, sorry.");
  382.                   return exit_client(cptr, cptr, cptr, "Leaf Only");
  383.             }
  384.         /*
  385.         **
  386.         */
  387.         if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
  388.             (aconf->port && (hop > aconf->port)) )
  389.             {
  390.             sendto_ops("Non-Hub link %s introduced %s(%s).",
  391.                    get_client_name(cptr,  TRUE), host,
  392.                    aconf ? (aconf->host ? aconf->host : "*") :
  393.                    "!");
  394.             return exit_client(cptr, cptr, cptr,
  395.                        "Too many servers");
  396.             }
  397.         /*
  398.         ** See if the newly found server has a Q line for it in
  399.         ** our conf. If it does, lose the link that brought it
  400.         ** into our network. Format:
  401.         **
  402.         ** Q:<unused>:<reason>:<servername>
  403.         **
  404.         ** Example:  Q:*:for the hell of it:eris.Berkeley.EDU
  405.         */
  406.         if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER)))
  407.             {
  408.             sendto_ops_butone(NULL, &me,
  409.                 ":%s WALLOPS * :%s brought in %s, %s %s",
  410.                 me.name, me.name, get_client_name(cptr,FALSE),
  411.                 host, "closing link because",
  412.                 BadPtr(aconf->passwd) ? "reason unspecified" :
  413.                 aconf->passwd);
  414.  
  415.             sendto_one(cptr,
  416.                    "ERROR :%s is not welcome: %s. %s",
  417.                    host, BadPtr(aconf->passwd) ?
  418.                    "reason unspecified" : aconf->passwd,
  419.                    "Go away and get a life");
  420.  
  421.             return exit_client(cptr, cptr, cptr, "Q-Lined Server");
  422.             }
  423.  
  424.         acptr = make_client(cptr);
  425.         (void)make_server(acptr);
  426.         acptr->hopcount = hop;
  427.         strncpyzt(acptr->name, host, sizeof(acptr->name));
  428.         strncpyzt(acptr->info, info, sizeof(acptr->info));
  429.         strncpyzt(acptr->serv->up, parv[0], sizeof(acptr->serv->up));
  430.         SetServer(acptr);
  431.         add_client_to_list(acptr);
  432.         (void)add_to_client_hash_table(acptr->name, acptr);
  433.         /*
  434.         ** Old sendto_serv_but_one() call removed because we now
  435.         ** need to send different names to different servers
  436.         ** (domain name matching)
  437.         */
  438.         for (i = 0; i <= highest_fd; i++)
  439.             {
  440.             if (!(bcptr = local[i]) || !IsServer(bcptr) ||
  441.                 bcptr == cptr || IsMe(bcptr))
  442.                 continue;
  443.             if (!(aconf = bcptr->serv->nline))
  444.                 {
  445.                 sendto_ops("Lost N-line for %s on %s. Closing",
  446.                        get_client_name(cptr, TRUE), host);
  447.                 return exit_client(cptr, cptr, cptr,
  448.                            "Lost N line");
  449.                 }
  450.             if (matches(my_name_for_link(me.name, aconf),
  451.                     acptr->name) == 0)
  452.                 continue;
  453.             sendto_one(bcptr, ":%s SERVER %s %d :%s",
  454.                    parv[0], acptr->name, hop+1, acptr->info);
  455.             }
  456. #ifdef    USE_SERVICES
  457.         check_services_butone(SERVICE_WANT_SERVER, sptr,
  458.                     ":%s SERVER %s %d :%s", parv[0],
  459.                     acptr->name, hop+1, acptr->info);
  460. #endif
  461.         return 0;
  462.         }
  463.  
  464.     if (!IsUnknown(cptr) && !IsHandshake(cptr))
  465.         return 0;
  466.     /*
  467.     ** A local link that is still in undefined state wants
  468.     ** to be a SERVER. Check if this is allowed and change
  469.     ** status accordingly...
  470.     */
  471.     strncpyzt(cptr->name, host, sizeof(cptr->name));
  472.     strncpyzt(cptr->info, info[0] ? info:me.name, sizeof(cptr->info));
  473.     cptr->hopcount = hop;
  474.  
  475.     switch (check_server_init(cptr))
  476.     {
  477.     case 0 :
  478.         return m_server_estab(cptr);
  479.     case 1 :
  480.         sendto_ops("Access check for %s in progress",
  481.                get_client_name(cptr,TRUE));
  482.         return 1;
  483.     default :
  484.         ircstp->is_ref++;
  485.         sendto_ops("Received unauthorized connection from %s.",
  486.                    get_client_host(cptr));
  487.         return exit_client(cptr, cptr, cptr, "No C/N conf lines");
  488.     }
  489.  
  490. }
  491.  
  492. int    m_server_estab(cptr)
  493. Reg1    aClient    *cptr;
  494. {
  495.     Reg2    aClient    *acptr;
  496.     Reg3    aConfItem    *aconf, *bconf;
  497.     char    *inpath, *host, *s, *encr;
  498.     int    split, i;
  499.  
  500.     inpath = get_client_name(cptr,TRUE); /* "refresh" inpath with host */
  501.     split = mycmp(cptr->name, cptr->sockhost);
  502.     host = cptr->name;
  503.  
  504.     if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
  505.         {
  506.         ircstp->is_ref++;
  507.         sendto_one(cptr,
  508.                "ERROR :Access denied. No N line for server %s",
  509.                inpath);
  510.         sendto_ops("Access denied. No N line for server %s", inpath);
  511.         return exit_client(cptr, cptr, cptr, "No N line for server");
  512.         }
  513.     if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
  514.         {
  515.         ircstp->is_ref++;
  516.         sendto_one(cptr, "ERROR :Only N (no C) field for server %s",
  517.                inpath);
  518.         sendto_ops("Only N (no C) field for server %s",inpath);
  519.         return exit_client(cptr, cptr, cptr, "No C line for server");
  520.         }
  521.  
  522. #ifdef CRYPT_LINK_PASSWORD
  523.     /* use first two chars of the password they send in as salt */
  524.  
  525.     /* passwd may be NULL. Head it off at the pass... */
  526.     if(*cptr->passwd)
  527.         {
  528.         char    salt[3];
  529.         extern  char *crypt();
  530.  
  531.         salt[0]=aconf->passwd[0];
  532.         salt[1]=aconf->passwd[1];
  533.         salt[2]='\0';
  534.         encr = crypt(cptr->passwd, salt);
  535.         }
  536.     else
  537.         encr = "";
  538. #else
  539.     encr = cptr->passwd;
  540. #endif  /* CRYPT_LINK_PASSWORD */
  541.     if (*aconf->passwd && !StrEq(aconf->passwd, encr))
  542.         {
  543.         ircstp->is_ref++;
  544.         sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
  545.                inpath);
  546.         sendto_ops("Access denied (passwd mismatch) %s", inpath);
  547.         return exit_client(cptr, cptr, cptr, "Bad Password");
  548.         }
  549.     bzero(cptr->passwd, sizeof(cptr->passwd));
  550.  
  551. #ifndef    HUB
  552.     for (i = 0; i <= highest_fd; i++)
  553.         if (local[i] && IsServer(local[i]))
  554.             {
  555.             ircstp->is_ref++;
  556.             sendto_one(cptr, "ERROR :I'm a leaf not a hub");
  557.             return exit_client(cptr, cptr, cptr, "I'm a leaf");
  558.             }
  559. #endif
  560.     if (IsUnknown(cptr))
  561.         {
  562.         if (bconf->passwd[0])
  563.             sendto_one(cptr,"PASS :%s",bconf->passwd);
  564.         /*
  565.         ** Pass my info to the new server
  566.         */
  567.         sendto_one(cptr, "SERVER %s 1 :%s",
  568.                my_name_for_link(me.name, aconf), 
  569.                (me.info[0]) ? (me.info) : "IRCers United");
  570.         }
  571.     else
  572.         {
  573.         s = (char *)index(aconf->host, '@');
  574.         *s = '\0'; /* should never be NULL */
  575.         Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
  576.             aconf->host, cptr->username));
  577.         if (matches(aconf->host, cptr->username))
  578.             {
  579.             *s = '@';
  580.             ircstp->is_ref++;
  581.             sendto_ops("Username mismatch [%s]v[%s] : %s",
  582.                    aconf->host, cptr->username,
  583.                    get_client_name(cptr, TRUE));
  584.             sendto_one(cptr, "ERROR :No Username Match");
  585.             return exit_client(cptr, cptr, cptr, "Bad User");
  586.             }
  587.         *s = '@';
  588.         }
  589.  
  590.     det_confs_butmask(cptr, CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER);
  591.     /*
  592.     ** *WARNING*
  593.     **     In the following code in place of plain server's
  594.     **    name we send what is returned by get_client_name
  595.     **    which may add the "sockhost" after the name. It's
  596.     **    *very* *important* that there is a SPACE between
  597.     **    the name and sockhost (if present). The receiving
  598.     **    server will start the information field from this
  599.     **    first blank and thus puts the sockhost into info.
  600.     **    ...a bit tricky, but you have been warned, besides
  601.     **    code is more neat this way...  --msa
  602.     */
  603.     SetServer(cptr);
  604.     nextping = time(NULL);
  605.     sendto_ops("Link with %s established.", inpath);
  606.     (void)add_to_client_hash_table(cptr->name, cptr);
  607.     /* doesnt duplicate cptr->serv if allocted this struct already */
  608.     (void)make_server(cptr);
  609.     (void)strcpy(cptr->serv->up, me.name);
  610.     cptr->serv->nline = aconf;
  611. #ifdef    USE_SERVICES
  612.     check_services_butone(SERVICE_WANT_SERVER, sptr,
  613.                 ":%s SERVER %s %d :%s", parv[0],
  614.                 cptr->name, hop+1, cptr->info);
  615. #endif
  616.     /*
  617.     ** Old sendto_serv_but_one() call removed because we now
  618.     ** need to send different names to different servers
  619.     ** (domain name matching) Send new server to other servers.
  620.     */
  621.     for (i = 0; i <= highest_fd; i++) 
  622.         {
  623.         if (!(acptr = local[i]) || !IsServer(acptr) ||
  624.             acptr == cptr || IsMe(acptr))
  625.             continue;
  626.         if ((aconf = acptr->serv->nline) &&
  627.             !matches(my_name_for_link(me.name, aconf), cptr->name))
  628.             continue;
  629.         if (split)
  630.             sendto_one(acptr,":%s SERVER %s 2 :[%s] %s",
  631.                    me.name, cptr->name,
  632.                    cptr->sockhost, cptr->info);
  633.         else
  634.             sendto_one(acptr,":%s SERVER %s 2 :%s",
  635.                    me.name, cptr->name, cptr->info);
  636.         }
  637.  
  638.     /*
  639.     ** Pass on my client information to the new server
  640.     **
  641.     ** First, pass only servers (idea is that if the link gets
  642.     ** cancelled beacause the server was already there,
  643.     ** there are no NICK's to be cancelled...). Of course,
  644.     ** if cancellation occurs, all this info is sent anyway,
  645.     ** and I guess the link dies when a read is attempted...? --msa
  646.     ** 
  647.     ** Note: Link cancellation to occur at this point means
  648.     ** that at least two servers from my fragment are building
  649.     ** up connection this other fragment at the same time, it's
  650.     ** a race condition, not the normal way of operation...
  651.     **
  652.     ** ALSO NOTE: using the get_client_name for server names--
  653.     **    see previous *WARNING*!!! (Also, original inpath
  654.     **    is destroyed...)
  655.     */
  656.  
  657.     aconf = cptr->serv->nline;
  658.     for (acptr = &me; acptr; acptr = acptr->prev)
  659.         {
  660.         /* acptr->from == acptr for acptr == cptr */
  661.         if (acptr->from == cptr)
  662.             continue;
  663.         if (IsServer(acptr))
  664.             {
  665.             if (matches(my_name_for_link(me.name, aconf),
  666.                     acptr->name) == 0)
  667.                 continue;
  668.             split = (MyConnect(acptr) &&
  669.                  mycmp(acptr->name, acptr->sockhost));
  670.             if (split)
  671.                 sendto_one(cptr, ":%s SERVER %s %d :[%s] %s",
  672.                           acptr->serv->up, acptr->name,
  673.                        acptr->hopcount+1,
  674.                           acptr->sockhost, acptr->info);
  675.             else
  676.                 sendto_one(cptr, ":%s SERVER %s %d :%s",
  677.                           acptr->serv->up, acptr->name,
  678.                        acptr->hopcount+1, acptr->info);
  679.             }
  680.         }
  681.  
  682.     for (acptr = &me; acptr; acptr = acptr->prev)
  683.         {
  684.         /* acptr->from == acptr for acptr == cptr */
  685.         if (acptr->from == cptr)
  686.             continue;
  687.         if (IsPerson(acptr))
  688.             {
  689.             /*
  690.             ** IsPerson(x) is true only when IsClient(x) is true.
  691.             ** These are only true when *BOTH* NICK and USER have
  692.             ** been received. -avalon
  693.             */
  694.             sendto_one(cptr,"NICK %s :%d",acptr->name,
  695.                    acptr->hopcount + 1);
  696.             sendto_one(cptr,":%s USER %s %s %s :%s", acptr->name,
  697.                    acptr->user->username, acptr->user->host,
  698.                    acptr->user->server, acptr->info);
  699.             send_umode(cptr, acptr, 0, SEND_UMODES, buf);
  700.             send_user_joins(cptr, acptr);
  701.             }
  702.         else if (IsService(acptr))
  703.             {
  704.             sendto_one(cptr,"NICK %s :%d",
  705.                    acptr->name, acptr->hopcount + 1);
  706.             sendto_one(cptr,":%s SERVICE * * :%s",
  707.                    acptr->name, acptr->info);
  708.             }
  709.         }
  710.     /*
  711.     ** Last, pass all channels plus statuses
  712.     */
  713.     {
  714.         Reg1 aChannel *chptr;
  715.         for (chptr = channel; chptr; chptr = chptr->nextch)
  716.             send_channel_modes(cptr, chptr);
  717.     }
  718.     return 0;
  719. }
  720.  
  721. /*
  722. ** m_info
  723. **    parv[0] = sender prefix
  724. **    parv[1] = servername
  725. */
  726. int    m_info(cptr, sptr, parc, parv)
  727. aClient *cptr, *sptr;
  728. int    parc;
  729. char    *parv[];
  730. {
  731.     char **text = infotext;
  732.  
  733.     if (check_registered(sptr))
  734.         return 0;
  735.  
  736.     if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME)
  737.         {
  738.         while (*text)
  739.             sendto_one(sptr, rpl_str(RPL_INFO),
  740.                    me.name, parv[0], *text++);
  741.  
  742.         sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
  743.         sendto_one(sptr,
  744.                ":%s %d %s :Birth Date: %s, compile # %s",
  745.                me.name, RPL_INFO, parv[0], creation, generation);
  746.         sendto_one(sptr, ":%s %d %s :On-line since %s",
  747.                me.name, RPL_INFO, parv[0],
  748.                myctime(me.firsttime));
  749.         sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
  750.         }
  751.  
  752.     return 0;
  753. }
  754.  
  755. /*
  756. ** m_links
  757. **    parv[0] = sender prefix
  758. **    parv[1] = servername mask
  759. ** or
  760. **    parv[0] = sender prefix
  761. **    parv[1] = server to query 
  762. **      parv[2] = servername mask
  763. */
  764. int    m_links(cptr, sptr, parc, parv)
  765. aClient *cptr, *sptr;
  766. int    parc;
  767. char    *parv[];
  768. {
  769.     char *mask;
  770.     aClient *acptr;
  771.  
  772.     if (check_registered_user(sptr))
  773.         return 0;
  774.     
  775.     if (parc > 2)
  776.         {
  777.         if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv)
  778.                 != HUNTED_ISME)
  779.             return 0;
  780.         mask = parv[2];
  781.         }
  782.     else
  783.         mask = parc < 2 ? NULL : parv[1];
  784.  
  785.     for (acptr = client, (void)collapse(mask); acptr; acptr = acptr->next) 
  786.         {
  787.         if (!IsServer(acptr) && !IsMe(acptr))
  788.             continue;
  789.         if (!BadPtr(mask) && match(mask, acptr->name))
  790.             continue;
  791.         sendto_one(sptr, rpl_str(RPL_LINKS),
  792.                me.name, parv[0], acptr->name, acptr->serv->up,
  793.                acptr->hopcount, (acptr->info[0] ? acptr->info :
  794.                "(Unknown Location)"));
  795.         }
  796.  
  797.     sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
  798.            BadPtr(mask) ? "*" : mask);
  799.     return 0;
  800. }
  801.  
  802. /*
  803. ** m_summon should be redefined to ":prefix SUMMON host user" so
  804. ** that "hunt_server"-function could be used for this too!!! --msa
  805. ** As of 2.7.1e, this was the case. -avalon
  806. **
  807. **    parv[0] = sender prefix
  808. **    parv[1] = user
  809. **    parv[2] = server
  810. **    parv[3] = channel (optional)
  811. */
  812. int    m_summon(cptr, sptr, parc, parv)
  813. aClient *sptr, *cptr;
  814. int    parc;
  815. char    *parv[];
  816. {
  817.     char    *host, *user, *chname;
  818. #ifdef    ENABLE_SUMMON
  819.     char    hostbuf[17], namebuf[10], linebuf[10];
  820. #  ifdef LEAST_IDLE
  821.         char    linetmp[10], ttyname[15]; /* Ack */
  822.         struct    stat stb;
  823.         time_t    ltime = (time_t)0;
  824. #  endif
  825.     int    fd, flag = 0;
  826. #endif
  827.  
  828.     if (check_registered_user(sptr))
  829.         return 0;
  830.     if (parc < 2 || *parv[1] == '\0')
  831.         {
  832.         sendto_one(sptr, err_str(ERR_NORECIPIENT),
  833.                me.name, parv[0], "SUMMON");
  834.         return 0;
  835.         }
  836.     user = parv[1];
  837.     host = (parc < 3 || BadPtr(parv[2])) ? me.name : parv[2];
  838.     chname = (parc > 3) ? parv[3] : "*";
  839.     /*
  840.     ** Summoning someone on remote server, find out which link to
  841.     ** use and pass the message there...
  842.     */
  843.     parv[1] = user;
  844.     parv[2] = host;
  845.     parv[3] = chname;
  846.     parv[4] = NULL;
  847.     if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) ==
  848.         HUNTED_ISME)
  849.         {
  850. #ifdef ENABLE_SUMMON
  851.         if ((fd = utmp_open()) == -1)
  852.             {
  853.             sendto_one(sptr, err_str(ERR_FILEERROR),
  854.                    me.name, parv[0], "open", UTMP);
  855.             return 0;
  856.             }
  857. #  ifndef LEAST_IDLE
  858.         while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf,
  859.                      sizeof(hostbuf))) == 0) 
  860.             if (StrEq(namebuf,user))
  861.                 break;
  862. #  else
  863.                 /* use least-idle tty, not the first
  864.                  * one we find in utmp. 10/9/90 Spike@world.std.com
  865.                  * (loosely based on Jim Frost jimf@saber.com code)
  866.                  */
  867.         
  868.                 while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf,
  869.                      sizeof(hostbuf))) == 0)
  870.             {
  871.             if (StrEq(namebuf,user))
  872.                 {
  873.                 (void)sprintf(ttyname,"/dev/%s",linetmp);
  874.                 if (stat(ttyname,&stb) == -1)
  875.                     {
  876.                     sendto_one(sptr,
  877.                            err_str(ERR_FILEERROR),
  878.                            me.name, sptr->name,
  879.                            "stat", ttyname);
  880.                     return 0;
  881.                     }
  882.                 if (!ltime)
  883.                     {
  884.                     ltime= stb.st_mtime;
  885.                     (void)strcpy(linebuf,linetmp);
  886.                     }
  887.                 else if (stb.st_mtime > ltime) /* less idle */
  888.                     {
  889.                     ltime= stb.st_mtime;
  890.                     (void)strcpy(linebuf,linetmp);
  891.                     }
  892.                 }
  893.             }
  894. #  endif
  895.         (void)utmp_close(fd);
  896. #  ifdef LEAST_IDLE
  897.                 if (ltime == 0)
  898. #  else
  899.         if (flag == -1)
  900. #  endif
  901.             sendto_one(sptr, err_str(ERR_NOLOGIN),
  902.                    me.name, parv[0], user);
  903.         else
  904.             summon(sptr, user, linebuf, chname);
  905. #else
  906.         sendto_one(sptr, err_str(ERR_SUMMONDISABLED),
  907.                me.name, parv[0]);
  908. #endif /* ENABLE_SUMMON */
  909.         }
  910.     return 0;
  911. }
  912.  
  913.  
  914. /*
  915. ** m_stats
  916. **    parv[0] = sender prefix
  917. **    parv[1] = statistics selector (defaults to Message frequency)
  918. **    parv[2] = server name (current server defaulted, if omitted)
  919. **
  920. **    Currently supported are:
  921. **        M = Message frequency (the old stat behaviour)
  922. **        L = Local Link statistics
  923. **              C = Report C and N configuration lines
  924. */
  925. /*
  926. ** m_stats/stats_conf
  927. **    Report N/C-configuration lines from this server. This could
  928. **    report other configuration lines too, but converting the
  929. **    status back to "char" is a bit akward--not worth the code
  930. **    it needs...
  931. **
  932. **    Note:   The info is reported in the order the server uses
  933. **            it--not reversed as in ircd.conf!
  934. */
  935.  
  936. static int report_array[11][3] = {
  937.         { CONF_CONNECT_SERVER,    RPL_STATSCLINE, 'C'},
  938.         { CONF_NOCONNECT_SERVER,  RPL_STATSNLINE, 'N'},
  939.         { CONF_CLIENT,            RPL_STATSILINE, 'I'},
  940.         { CONF_KILL,              RPL_STATSKLINE, 'K'},
  941.         { CONF_QUARANTINED_SERVER,RPL_STATSQLINE, 'Q'},
  942.         { CONF_LEAF,          RPL_STATSLLINE, 'L'},
  943.         { CONF_OPERATOR,      RPL_STATSOLINE, 'O'},
  944.         { CONF_HUB,          RPL_STATSHLINE, 'H'},
  945.         { CONF_LOCOP,          RPL_STATSOLINE, 'o'},
  946.         { CONF_SERVICE,          RPL_STATSSLINE, 'S'},
  947.         { 0, 0}
  948.                 };
  949.  
  950. static    void    report_configured_links(sptr, mask)
  951. aClient *sptr;
  952. int    mask;
  953. {
  954.     static    char    null[] = "<NULL>";
  955.     aConfItem *tmp;
  956.     int    *p, port;
  957.     char    c, *host, *pass, *name;
  958.     
  959.     for (tmp = conf; tmp; tmp = tmp->next)
  960.         if (tmp->status & mask)
  961.             {
  962.             for (p = &report_array[0][0]; *p; p += 3)
  963.                 if (*p == tmp->status)
  964.                     break;
  965.             if (!*p)
  966.                 continue;
  967.             c = (char)*(p+2);
  968.             host = BadPtr(tmp->host) ? null : tmp->host;
  969.             pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
  970.             name = BadPtr(tmp->name) ? null : tmp->name;
  971.             port = (int)tmp->port;
  972.             /*
  973.              * On K line the passwd contents can be
  974.             /* displayed on STATS reply.     -Vesa
  975.              */
  976.             if (tmp->status == CONF_KILL)
  977.                 sendto_one(sptr, rpl_str(p[1]), me.name,
  978.                        sptr->name, c, host, pass,
  979.                        name, port, get_conf_class(tmp));
  980.             else
  981.                 sendto_one(sptr, rpl_str(p[1]), me.name,
  982.                        sptr->name, c, host, name, port,
  983.                        get_conf_class(tmp));
  984.             }
  985.     return;
  986. }
  987.  
  988. int    m_stats(cptr, sptr, parc, parv)
  989. aClient *cptr, *sptr;
  990. int    parc;
  991. char    *parv[];
  992.     {
  993.     static    char    Lformat[]  = ":%s %d %s %s %u %u %u %u %u :%u";
  994.     struct    Message    *mptr;
  995.     aClient    *acptr;
  996.     char    stat = parc > 1 ? parv[1][0] : '\0';
  997.     Reg1    int    i;
  998.     int    doall = 0, wilds = 0;
  999.     char    *name;
  1000.  
  1001.     if (check_registered(sptr))
  1002.         return 0;
  1003.  
  1004.     if (hunt_server(cptr,sptr,":%s STATS %s :%s",2,parc,parv)!=HUNTED_ISME)
  1005.         return 0;
  1006.  
  1007.     if (parc > 2)
  1008.         {
  1009.         name = parv[2];
  1010.         if (!mycmp(name, me.name))
  1011.             doall = 2;
  1012.         else if (matches(name, me.name) == 0)
  1013.             doall = 1;
  1014.         if (index(name, '*') || index(name, '?'))
  1015.             wilds = 1;
  1016.         }
  1017.     else
  1018.         name = me.name;
  1019.  
  1020.     switch (stat)
  1021.     {
  1022.     case 'L' : case 'l' :
  1023.         /*
  1024.          * send info about connections which match, or all if the
  1025.          * mask matches me.name.  Only restrictions are on those who
  1026.          * are invisible not being visible to 'foreigners' who use
  1027.          * a wild card based search to list it.
  1028.          */
  1029.         for (i = 0; i <= highest_fd; i++)
  1030.             {
  1031.             if (!(acptr = local[i]))
  1032.                 continue;
  1033.             if (IsInvisible(acptr) && (doall || wilds) &&
  1034.                 !(MyConnect(sptr) && IsOper(sptr)) &&
  1035.                 !IsAnOper(acptr) && (acptr != sptr))
  1036.                 continue;
  1037.             if (!doall && wilds && matches(name, acptr->name))
  1038.                 continue;
  1039.             if (!(doall || wilds) && mycmp(name, acptr->name))
  1040.                 continue;
  1041.             sendto_one(sptr, Lformat, me.name,
  1042.                    RPL_STATSLINKINFO, parv[0],
  1043.                    (isupper(stat)) ?
  1044.                    get_client_name(acptr, TRUE) :
  1045.                    get_client_name(acptr, FALSE),
  1046.                    (int)DBufLength(&acptr->sendQ),
  1047.                    (int)acptr->sendM, (int)acptr->sendK,
  1048.                    (int)acptr->receiveM, (int)acptr->receiveK,
  1049.                    time(NULL) - acptr->firsttime);
  1050.             }
  1051.         break;
  1052.     case 'C' : case 'c' :
  1053.                 report_configured_links(sptr, CONF_CONNECT_SERVER|
  1054.                     CONF_NOCONNECT_SERVER);
  1055.         break;
  1056.     case 'H' : case 'h' :
  1057.                 report_configured_links(sptr, CONF_HUB|CONF_LEAF);
  1058.         break;
  1059.     case 'I' : case 'i' :
  1060.         report_configured_links(sptr, CONF_CLIENT);
  1061.         break;
  1062.     case 'K' : case 'k' :
  1063.         report_configured_links(sptr, CONF_KILL);
  1064.         break;
  1065.     case 'M' : case 'm' :
  1066.         for (mptr = msgtab; mptr->cmd; mptr++)
  1067.             if (mptr->count)
  1068.                 sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
  1069.                        me.name, parv[0], mptr->cmd,
  1070.                        mptr->count, mptr->bytes);
  1071.         break;
  1072.     case 'o' : case 'O' :
  1073.         report_configured_links(sptr, CONF_OPS);
  1074.         break;
  1075.     case 'Q' : case 'q' :
  1076.         report_configured_links(sptr, CONF_QUARANTINED_SERVER);
  1077.         break;
  1078.     case 'R' : case 'r' :
  1079. #ifdef DEBUGMODE
  1080.         send_usage(sptr,parv[0]);
  1081. #endif
  1082.         break;
  1083.     case 'S' : case 's' :
  1084.         report_configured_links(sptr, CONF_SERVICE);
  1085.         break;
  1086.     case 'T' : case 't' :
  1087.         tstats(sptr, parv[0]);
  1088.         break;
  1089.     case 'U' : case 'u' :
  1090.         {
  1091.         register time_t now;
  1092.  
  1093.         now = time(NULL) - me.since;
  1094.         sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
  1095.                now/86400, (now/3600)%24, (now/60)%60, now%60);
  1096.         break;
  1097.         }
  1098.     case 'X' : case 'x' :
  1099. #ifdef    DEBUGMODE
  1100.         send_listinfo(sptr, parv[0]);
  1101. #endif
  1102.         break;
  1103.     case 'Y' : case 'y' :
  1104.         report_classes(sptr);
  1105.         break;
  1106.     case 'Z' : case 'z' :
  1107.         count_memory(sptr, parv[0]);
  1108.         break;
  1109.     default :
  1110.         stat = '*';
  1111.         break;
  1112.     }
  1113.     sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
  1114.     return 0;
  1115.     }
  1116.  
  1117. /*
  1118. ** m_users
  1119. **    parv[0] = sender prefix
  1120. **    parv[1] = servername
  1121. */
  1122. int    m_users(cptr, sptr, parc, parv)
  1123. aClient *cptr, *sptr;
  1124. int    parc;
  1125. char    *parv[];
  1126. {
  1127. #ifdef ENABLE_USERS
  1128.     char    namebuf[10],linebuf[10],hostbuf[17];
  1129.     int    fd, flag = 0;
  1130. #endif
  1131.  
  1132.     if (check_registered_user(sptr))
  1133.         return 0;
  1134.  
  1135.     if (hunt_server(cptr,sptr,":%s USERS :%s",1,parc,parv) == HUNTED_ISME)
  1136.         {
  1137. #ifdef ENABLE_USERS
  1138.         if ((fd = utmp_open()) == -1)
  1139.             {
  1140.             sendto_one(sptr, err_str(ERR_FILEERROR),
  1141.                    me.name, parv[0], "open", UTMP);
  1142.             return 0;
  1143.             }
  1144.  
  1145.         sendto_one(sptr, rpl_str(RPL_USERSSTART), me.name, parv[0]);
  1146.         while (utmp_read(fd, namebuf, linebuf,
  1147.                  hostbuf, sizeof(hostbuf)) == 0)
  1148.             {
  1149.             flag = 1;
  1150.             sendto_one(sptr, rpl_str(RPL_USERS), me.name, parv[0],
  1151.                    namebuf, linebuf, hostbuf);
  1152.             }
  1153.         if (flag == 0) 
  1154.             sendto_one(sptr, rpl_str(RPL_NOUSERS),
  1155.                    me.name, parv[0]);
  1156.  
  1157.         sendto_one(sptr, rpl_str(RPL_ENDOFUSERS), me.name, parv[0]);
  1158.         (void)utmp_close(fd);
  1159. #else
  1160.         sendto_one(sptr, err_str(ERR_USERSDISABLED), me.name, parv[0]);
  1161. #endif
  1162.         }
  1163.     return 0;
  1164. }
  1165.  
  1166. /*
  1167. ** Note: At least at protocol level ERROR has only one parameter,
  1168. ** although this is called internally from other functions
  1169. ** --msa
  1170. **
  1171. **    parv[0] = sender prefix
  1172. **    parv[*] = parameters
  1173. */
  1174. int    m_error(cptr, sptr, parc, parv)
  1175. aClient *cptr, *sptr;
  1176. int    parc;
  1177. char    *parv[];
  1178.     {
  1179.     Reg1    char    *para;
  1180.  
  1181.     para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
  1182.  
  1183.     Debug((DEBUG_ERROR,"Received ERROR message from %s: %s",
  1184.           sptr->name, para));
  1185.     /*
  1186.     ** Ignore error messages generated by normal user clients
  1187.     ** (because ill-behaving user clients would flood opers
  1188.     ** screen otherwise). Pass ERROR's from other sources to
  1189.     ** the local operator...
  1190.     */
  1191.     if (IsPerson(cptr) || IsUnknown(cptr) || IsService(cptr))
  1192.         return 0;
  1193.     if (cptr == sptr)
  1194.         sendto_ops("ERROR :from %s -- %s",
  1195.                get_client_name(cptr, FALSE), para);
  1196.     else
  1197.         sendto_ops("ERROR :from %s via %s -- %s", sptr->name,
  1198.                get_client_name(cptr,FALSE), para);
  1199.     return 0;
  1200.     }
  1201.  
  1202. /*
  1203. ** m_help
  1204. **    parv[0] = sender prefix
  1205. */
  1206. int    m_help(cptr, sptr, parc, parv)
  1207. aClient *cptr, *sptr;
  1208. int    parc;
  1209. char    *parv[];
  1210.     {
  1211.     int i;
  1212.  
  1213.     for (i = 0; msgtab[i].cmd; i++)
  1214.         sendto_one(sptr,":%s NOTICE %s :%s",
  1215.                me.name, parv[0], msgtab[i].cmd);
  1216.     return 0;
  1217.     }
  1218.  
  1219. /*
  1220.  * parv[0] = sender
  1221.  * parv[1] = host/server mask.
  1222.  * parv[2] = server to query
  1223.  */
  1224. int     m_lusers(cptr, sptr, parc, parv)
  1225. aClient *cptr, *sptr;
  1226. int    parc;
  1227. char    *parv[];
  1228.     {
  1229.     int    s_count = 0, c_count = 0, u_count = 0, i_count = 0;
  1230.     int    o_count = 0, m_client = 0, m_server = 0;
  1231.     aClient *acptr;
  1232.  
  1233.     if (check_registered_user(sptr))
  1234.         return 0;
  1235.  
  1236.     if (parc > 2)
  1237.         if(hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
  1238.                 != HUNTED_ISME)
  1239.             return 0;
  1240.  
  1241.     (void)collapse(parv[1]);
  1242.     for (acptr = client; acptr; acptr = acptr->next)
  1243.         {
  1244.         if (parc>1)
  1245.             if (!IsServer(acptr) && acptr->user)
  1246.                 {
  1247.                 if (match(parv[1], acptr->user->server))
  1248.                     continue;
  1249.                 }
  1250.             else
  1251.                       if (match(parv[1], acptr->name))
  1252.                     continue;
  1253.  
  1254.         switch (acptr->status)
  1255.         {
  1256.         case STAT_SERVER:
  1257.             if (MyConnect(acptr))
  1258.                 m_server++;
  1259.         case STAT_ME:
  1260.             s_count++;
  1261.             break;
  1262.         case STAT_CLIENT:
  1263.             if (IsOper(acptr))
  1264.                     o_count++;
  1265. #ifdef    SHOW_INVISIBLE_LUSERS
  1266.             if (MyConnect(acptr))
  1267.                   m_client++;
  1268.             if (!IsInvisible(acptr))
  1269.                 c_count++;
  1270.             else
  1271.                 i_count++;
  1272. #else
  1273.             if (MyConnect(acptr))
  1274.                 {
  1275.                 if (IsInvisible(acptr))
  1276.                     {
  1277.                     if (IsAnOper(sptr))
  1278.                         m_client++;
  1279.                     }
  1280.                 else
  1281.                     m_client++;
  1282.                 }
  1283.              if (!IsInvisible(acptr))
  1284.                 c_count++;
  1285.             else
  1286.                 i_count++;
  1287. #endif
  1288.             break;
  1289.         default:
  1290.             u_count++;
  1291.             break;
  1292.          }
  1293.          }
  1294. #ifndef    SHOW_INVISIBLE_LUSERS
  1295.     if (IsAnOper(sptr) && i_count)
  1296. #endif
  1297.     sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
  1298.            c_count, i_count, s_count);
  1299. #ifndef    SHOW_INVISIBLE_LUSERS
  1300.     else
  1301.         sendto_one(sptr,
  1302.             ":%s %d %s :There are %d users on %d servers", me.name,
  1303.                 RPL_LUSERCLIENT, parv[0], c_count, s_count);
  1304. #endif
  1305.     if (o_count)
  1306.         sendto_one(sptr, rpl_str(RPL_LUSEROP),
  1307.                me.name, parv[0], o_count);
  1308.     if (u_count > 0)
  1309.         sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN),
  1310.                me.name, parv[0], u_count);
  1311.     if ((c_count = count_channels(sptr))>0)
  1312.         sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS),
  1313.                me.name, parv[0], count_channels(sptr));
  1314.     sendto_one(sptr, rpl_str(RPL_LUSERME),
  1315.            me.name, parv[0], m_client, m_server);
  1316.     return 0;
  1317.     }
  1318.  
  1319.   
  1320. /***********************************************************************
  1321.  * m_connect() - Added by Jto 11 Feb 1989
  1322.  ***********************************************************************/
  1323.  
  1324. /*
  1325. ** m_connect
  1326. **    parv[0] = sender prefix
  1327. **    parv[1] = servername
  1328. **    parv[2] = port number
  1329. **    parv[3] = remote server
  1330. */
  1331. int    m_connect(cptr, sptr, parc, parv)
  1332. aClient *cptr, *sptr;
  1333. int    parc;
  1334. char    *parv[];
  1335.     {
  1336.     int    port, tmpport, retval;
  1337.     aConfItem *aconf;
  1338.     aClient *acptr;
  1339.  
  1340.     if (!IsPrivileged(sptr))
  1341.         {
  1342.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1343.         return -1;
  1344.         }
  1345.  
  1346.     if (IsLocOp(sptr) && parc > 3)    /* Only allow LocOps to make */
  1347.         return 0;        /* local CONNECTS --SRB      */
  1348.  
  1349.     if (hunt_server(cptr,sptr,":%s CONNECT %s %s :%s",
  1350.                3,parc,parv) != HUNTED_ISME)
  1351.         return 0;
  1352.  
  1353.     if (parc < 2 || *parv[1] == '\0')
  1354.         {
  1355.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1356.                me.name, parv[0], "CONNECT");
  1357.         return -1;
  1358.         }
  1359.  
  1360.     if ((acptr = find_server(parv[1], NULL)))
  1361.         {
  1362.         sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
  1363.                me.name, parv[0], parv[1], "already exists from",
  1364.                acptr->from->name);
  1365.         return 0;
  1366.         }
  1367.  
  1368.     for (aconf = conf; aconf; aconf = aconf->next)
  1369.         if (aconf->status == CONF_CONNECT_SERVER &&
  1370.             matches(parv[1], aconf->name) == 0)
  1371.           break;
  1372.     /* Checked first servernames, then try hostnames. */
  1373.     if (!aconf)
  1374.             for (aconf = conf; aconf; aconf = aconf->next)
  1375.                     if (aconf->status == CONF_CONNECT_SERVER &&
  1376.                             (matches(parv[1], aconf->host) == 0 ||
  1377.                              matches(parv[1], index(aconf->host, '@')+1) == 0))
  1378.                           break;
  1379.  
  1380.     if (!aconf)
  1381.         {
  1382.           sendto_one(sptr,
  1383.              "NOTICE %s :Connect: Host %s not listed in irc.conf",
  1384.              parv[0], parv[1]);
  1385.           return 0;
  1386.         }
  1387.     /*
  1388.     ** Get port number from user, if given. If not specified,
  1389.     ** use the default form configuration structure. If missing
  1390.     ** from there, then use the precompiled default.
  1391.     */
  1392.     tmpport = port = aconf->port;
  1393.     if (parc > 2 && !BadPtr(parv[2]))
  1394.         {
  1395.         if ((port = atoi(parv[2])) <= 0)
  1396.             {
  1397.             sendto_one(sptr,
  1398.                    "NOTICE %s :Connect: Illegal port number",
  1399.                    parv[0]);
  1400.             return 0;
  1401.             }
  1402.         }
  1403.     else if (port <= 0 && (port = PORTNUM) <= 0)
  1404.         {
  1405.         sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
  1406.                me.name, parv[0]);
  1407.         return 0;
  1408.         }
  1409.     /*
  1410.     ** Notify all operators about remote connect requests
  1411.     */
  1412.     if (!IsAnOper(cptr))
  1413.         {
  1414.         sendto_ops_butone(NULL, &me,
  1415.                   ":%s WALLOPS :Remote CONNECT %s %s from %s",
  1416.                    me.name, parv[1], parv[2] ? parv[2] : "",
  1417.                    get_client_name(sptr,FALSE));
  1418. #if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
  1419.         syslog(LOG_DEBUG, "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
  1420. #endif
  1421.         }
  1422.     aconf->port = port;
  1423.     switch (retval = connect_server(aconf, sptr, NULL))
  1424.     {
  1425.     case 0:
  1426.         sendto_one(sptr,
  1427.                ":%s NOTICE %s :*** Connecting to %s[%s].",
  1428.                me.name, parv[0], aconf->host, aconf->name);
  1429.         break;
  1430.     case -1:
  1431.         sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
  1432.                me.name, parv[0], aconf->host);
  1433.         break;
  1434.     case -2:
  1435.         sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
  1436.                me.name, parv[0], aconf->host);
  1437.         break;
  1438.     default:
  1439.         sendto_one(sptr,
  1440.                ":%s NOTICE %s :*** Connection to %s failed: %s",
  1441.                me.name, parv[0], aconf->host, strerror(retval));
  1442.     }
  1443.     aconf->port = tmpport;
  1444.     return 0;
  1445.     }
  1446.  
  1447. /*
  1448. ** m_wallops (write to *all* opers currently online)
  1449. **    parv[0] = sender prefix
  1450. **    parv[1] = message text
  1451. */
  1452. int    m_wallops(cptr, sptr, parc, parv)
  1453. aClient *cptr, *sptr;
  1454. int    parc;
  1455. char    *parv[];
  1456.     {
  1457.     char    *message, *pv[4];
  1458.  
  1459.     message = parc > 1 ? parv[1] : NULL;
  1460.  
  1461.     if (BadPtr(message))
  1462.         {
  1463.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1464.                me.name, parv[0], "WALLOPS");
  1465.         return 0;
  1466.         }
  1467.  
  1468.     if (!IsServer(sptr))
  1469.         {
  1470.         pv[0] = parv[0];
  1471.         pv[1] = "#wallops";
  1472.         pv[2] = message;
  1473.         pv[3] = NULL;
  1474.         return m_private(cptr, sptr, 3, pv);
  1475.         }
  1476.     sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
  1477.             ":%s WALLOPS :%s", parv[0], message);
  1478. #ifdef    USE_SERVICES
  1479.     check_services_butone(SERVICE_WANT_WALLOP, sptr, ":%s WALLOP :%s",
  1480.                 parv[0], message);
  1481. #endif
  1482.     return 0;
  1483.     }
  1484.  
  1485. /*
  1486. ** m_time
  1487. **    parv[0] = sender prefix
  1488. **    parv[1] = servername
  1489. */
  1490. int    m_time(cptr, sptr, parc, parv)
  1491. aClient *cptr, *sptr;
  1492. int    parc;
  1493. char    *parv[];
  1494.     {
  1495.     if (check_registered_user(sptr))
  1496.         return 0;
  1497.     if (hunt_server(cptr,sptr,":%s TIME :%s",1,parc,parv) == HUNTED_ISME)
  1498.         sendto_one(sptr, rpl_str(RPL_TIME), me.name,
  1499.                parv[0], me.name, date((long)0));
  1500.     return 0;
  1501.     }
  1502.  
  1503.  
  1504. /*
  1505. ** m_admin
  1506. **    parv[0] = sender prefix
  1507. **    parv[1] = servername
  1508. */
  1509. int    m_admin(cptr, sptr, parc, parv)
  1510. aClient *cptr, *sptr;
  1511. int    parc;
  1512. char    *parv[];
  1513.     {
  1514.     aConfItem *aconf;
  1515.  
  1516.     if (check_registered(sptr))
  1517.         return 0;
  1518.  
  1519.     if (hunt_server(cptr,sptr,":%s ADMIN :%s",1,parc,parv) != HUNTED_ISME)
  1520.         return 0;
  1521.     if ((aconf = find_admin()))
  1522.         {
  1523.         sendto_one(sptr, rpl_str(RPL_ADMINME),
  1524.                me.name, parv[0], me.name);
  1525.         sendto_one(sptr, rpl_str(RPL_ADMINLOC1),
  1526.                me.name, parv[0], aconf->host);
  1527.         sendto_one(sptr, rpl_str(RPL_ADMINLOC2),
  1528.                me.name, parv[0], aconf->passwd);
  1529.         sendto_one(sptr, rpl_str(RPL_ADMINEMAIL),
  1530.                me.name, parv[0], aconf->name);
  1531.         }
  1532.     else
  1533.         sendto_one(sptr, err_str(ERR_NOADMININFO),
  1534.                me.name, parv[0], me.name);
  1535.     return 0;
  1536.     }
  1537.  
  1538. #if defined(OPER_REHASH) || defined(LOCOP_REHASH)
  1539. /*
  1540. ** m_rehash
  1541. **
  1542. */
  1543. int    m_rehash(cptr, sptr, parc, parv)
  1544. aClient    *cptr, *sptr;
  1545. int    parc;
  1546. char    *parv[];
  1547. {
  1548. #ifndef    LOCOP_REHASH
  1549.     if (!MyClient(sptr) || !IsOper(sptr))
  1550. #else
  1551. # ifdef    OPER_REHASH
  1552.     if (!MyClient(sptr) || !IsAnOper(sptr))
  1553. # else
  1554.     if (!MyClient(sptr) || !IsLocOp(sptr))
  1555. # endif
  1556. #endif
  1557.         {
  1558.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1559.         return 0;
  1560.         }
  1561.     sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
  1562.     sendto_ops("%s is rehashing Server config file", parv[0]);
  1563. #ifdef USE_SYSLOG
  1564.     syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
  1565. #endif
  1566.     return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q')?2:0) : 0);
  1567. }
  1568. #endif
  1569.  
  1570. #if defined(OPER_RESTART) || defined(LOCOP_RESTART)
  1571. /*
  1572. ** m_restart
  1573. **
  1574. */
  1575. int    m_restart(cptr, sptr, parc, parv)
  1576. aClient *cptr, *sptr;
  1577. int    parc;
  1578. char    *parv[];
  1579. {
  1580. #ifndef    LOCOP_RESTART
  1581.     if (!MyClient(sptr) || !IsOper(sptr))
  1582. #else
  1583. # ifdef    OPER_RESTART
  1584.     if (!MyClient(sptr) || !IsAnOper(sptr))
  1585. # else
  1586.     if (!MyClient(sptr) || !IsLocOp(sptr))
  1587. # endif
  1588. #endif
  1589.         {
  1590.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1591.         return 0;
  1592.         }
  1593. #ifdef USE_SYSLOG
  1594.     syslog(LOG_WARNING, "Server RESTART by %s\n",
  1595.         get_client_name(sptr,FALSE));
  1596. #endif
  1597.     server_reboot();
  1598.     return 0;
  1599. }
  1600. #endif
  1601.  
  1602. /*
  1603. ** m_trace
  1604. **    parv[0] = sender prefix
  1605. **    parv[1] = servername
  1606. */
  1607. int    m_trace(cptr, sptr, parc, parv)
  1608. aClient *cptr, *sptr;
  1609. int    parc;
  1610. char    *parv[];
  1611. {
  1612.     Reg1    int    i;
  1613.     Reg2    aClient    *acptr;
  1614.     aClass    *cltmp;
  1615.     char    *tname;
  1616.     int    doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
  1617.     int    cnt = 0, wilds, dow;
  1618.  
  1619.     if (check_registered(sptr))
  1620.         return 0;
  1621.  
  1622.     if (parc > 2)
  1623.         if (hunt_server(cptr, sptr, ":%s TRACE %s :%s",
  1624.                 2, parc, parv))
  1625.             return 0;
  1626.  
  1627.     if (parc > 1)
  1628.         tname = parv[1];
  1629.     else
  1630.         tname = me.name;
  1631.  
  1632.     switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv))
  1633.     {
  1634.     case HUNTED_PASS: /* note: gets here only if parv[1] exists */
  1635.         {
  1636.         aClient    *ac2ptr;
  1637.  
  1638.         ac2ptr = next_client(client, tname);
  1639.         sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
  1640.                version, debugmode, tname, ac2ptr->from->name);
  1641.         return 0;
  1642.         }
  1643.     case HUNTED_ISME:
  1644.         break;
  1645.     default:
  1646.         return 0;
  1647.     }
  1648.  
  1649.     doall = (parv[1] && (parc > 1)) ? !matches(tname, me.name): TRUE;
  1650.     wilds = !parv[1] || index(tname, '*') || index(tname, '?');
  1651.     dow = wilds || doall;
  1652.  
  1653.     for (i = 0; i < MAXCONNECTIONS; i++)
  1654.         link_s[i] = 0, link_u[i] = 0;
  1655.  
  1656.     if (doall)
  1657.         for (acptr = client; acptr; acptr = acptr->next)
  1658. #ifdef    SHOW_INVISIBLE_LUSERS
  1659.             if (IsPerson(acptr))
  1660.                 link_u[acptr->from->fd]++;
  1661. #else
  1662.             if (IsPerson(acptr) &&
  1663.                 (!IsInvisible(acptr) || IsOper(sptr)))
  1664.                 link_u[acptr->from->fd]++;
  1665. #endif
  1666.             else if (IsServer(acptr))
  1667.                 link_s[acptr->from->fd]++;
  1668.  
  1669.     /* report all direct connections */
  1670.     
  1671.     for (i = 0; i <= highest_fd; i++)
  1672.         {
  1673.         char    *name;
  1674.         int    class;
  1675.  
  1676.         if (!(acptr = local[i])) /* Local Connection? */
  1677.             continue;
  1678.         if (IsInvisible(acptr) && dow &&
  1679.             !(MyConnect(sptr) && IsOper(sptr)) &&
  1680.             !IsAnOper(acptr) && (acptr != sptr))
  1681.             continue;
  1682.         if (!doall && wilds && matches(tname, acptr->name))
  1683.             continue;
  1684.         if (!dow && mycmp(tname, acptr->name))
  1685.             continue;
  1686.         name = get_client_name(acptr,FALSE);
  1687.         class = get_client_class(acptr);
  1688.  
  1689.         switch(acptr->status)
  1690.         {
  1691.         case STAT_CONNECTING:
  1692.             sendto_one(sptr, rpl_str(RPL_TRACECONNECTING), me.name,
  1693.                    parv[0], class, name);
  1694.             cnt++;
  1695.             break;
  1696.         case STAT_HANDSHAKE:
  1697.             sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE), me.name,
  1698.                    parv[0], class, name);
  1699.             cnt++;
  1700.             break;
  1701.         case STAT_ME:
  1702.             break;
  1703.         case STAT_UNKNOWN:
  1704.             sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
  1705.                    me.name, parv[0], class, name);
  1706.             cnt++;
  1707.             break;
  1708.         case STAT_CLIENT:
  1709.             /* Only opers see users if there is a wildcard
  1710.              * but anyone can see all the opers.
  1711.              */
  1712.             if (IsOper(sptr)  &&
  1713.                 (MyClient(sptr) || !(dow && IsInvisible(acptr)))
  1714.                 || !dow || IsAnOper(acptr))
  1715.                 {
  1716.                 if (IsAnOper(acptr))
  1717.                     sendto_one(sptr,
  1718.                            rpl_str(RPL_TRACEOPERATOR),
  1719.                            me.name,
  1720.                            parv[0], class, name);
  1721.                 else
  1722.                     sendto_one(sptr,rpl_str(RPL_TRACEUSER),
  1723.                            me.name, parv[0],
  1724.                            class, name);
  1725.                 cnt++;
  1726.                 }
  1727.             break;
  1728.         case STAT_SERVER:
  1729.             if (acptr->serv->user)
  1730.                 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
  1731.                        me.name, parv[0], class, link_s[i],
  1732.                        link_u[i], name, acptr->serv->by,
  1733.                        acptr->serv->user->username,
  1734.                        acptr->serv->user->host);
  1735.             else
  1736.                 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
  1737.                        me.name, parv[0], class, link_s[i],
  1738.                        link_u[i], name, *(acptr->serv->by) ?
  1739.                        acptr->serv->by : "*", "*", me.name);
  1740.             cnt++;
  1741.             break;
  1742.         case STAT_SERVICE:
  1743.             sendto_one(sptr, rpl_str(RPL_TRACESERVICE),
  1744.                    me.name, parv[0], class, name);
  1745.             cnt++;
  1746.             break;
  1747.         case STAT_LOG:
  1748.             sendto_one(sptr, rpl_str(RPL_TRACELOG), me.name,
  1749.                    parv[0], LOGFILE, acptr->port);
  1750.             cnt++;
  1751.             break;
  1752.         default: /* ...we actually shouldn't come here... --msa */
  1753.             sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name,
  1754.                    parv[0], name);
  1755.             cnt++;
  1756.             break;
  1757.         }
  1758.         }
  1759.     /*
  1760.      * Add these lines to summarize the above which can get rather long
  1761.          * and messy when done remotely - Avalon
  1762.          */
  1763.            if (!IsAnOper(sptr) || !cnt)
  1764.         {
  1765.         if (cnt)
  1766.             return 0;
  1767.         /* let the user have some idea that its at the end of the
  1768.          * trace
  1769.          */
  1770.         sendto_one(sptr, rpl_str(RPL_TRACESERVER),
  1771.                me.name, parv[0], 0, link_s[me.fd],
  1772.                link_u[me.fd], me.name, "*", "*", me.name);
  1773.         return 0;
  1774.         }
  1775.     for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
  1776.         if (Links(cltmp) > 0)
  1777.             sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
  1778.                    parv[0], Class(cltmp), Links(cltmp));
  1779.     return 0;
  1780.     }
  1781.  
  1782. /*
  1783. ** m_motd
  1784. **    parv[0] = sender prefix
  1785. **    parv[1] = servername
  1786. */
  1787. int    m_motd(cptr, sptr, parc, parv)
  1788. aClient *cptr, *sptr;
  1789. int    parc;
  1790. char    *parv[];
  1791. {
  1792.     int    fd;
  1793.     char    line[80];
  1794.     Reg1    char     *tmp;
  1795.     struct    stat    sb;
  1796.     struct    tm    *tm;
  1797.  
  1798.     if (check_registered(sptr))
  1799.         return 0;
  1800.  
  1801.     if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1,parc,parv)!=HUNTED_ISME)
  1802.         return 0;
  1803.     /*
  1804.      * stop NFS hangs...most systems should be able to open a file in
  1805.      * 3 seconds. -avalon (curtesy of wumpus)
  1806.      */
  1807.     (void)alarm(3);
  1808.     fd = open(MOTD, O_RDONLY);
  1809.     (void)alarm(0);
  1810.     if (fd == -1)
  1811.         {
  1812.         sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
  1813.         return 0;
  1814.         }
  1815.     (void)fstat(fd, &sb);
  1816.     sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
  1817.     tm = localtime(&sb.st_mtime);
  1818.     sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
  1819.            parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
  1820.            tm->tm_hour, tm->tm_min);
  1821.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  1822.     while (dgets(fd, line, sizeof(line)-1) > 0)
  1823.         {
  1824.         if ((tmp = (char *)index(line,'\n')))
  1825.             *tmp = '\0';
  1826.         if ((tmp = (char *)index(line,'\r')))
  1827.             *tmp = '\0';
  1828.         sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
  1829.         }
  1830.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  1831.     sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
  1832.     (void)close(fd);
  1833.     return 0;
  1834.     }
  1835.  
  1836. /*
  1837. ** m_close - added by Darren Reed Jul 13 1992.
  1838. */
  1839. int    m_close(cptr, sptr, parc, parv)
  1840. aClient    *cptr, *sptr;
  1841. int    parc;
  1842. char    *parv[];
  1843. {
  1844.     Reg1    aClient    *acptr;
  1845.     Reg2    int    i;
  1846.     int    closed = 0;
  1847.  
  1848.     if (!MyOper(sptr))
  1849.         {
  1850.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1851.         return 0;
  1852.         }
  1853.  
  1854.     for (i = highest_fd; i; i--)
  1855.         {
  1856.         if (!(acptr = local[i]))
  1857.             continue;
  1858.         if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
  1859.             !IsHandshake(acptr))
  1860.             continue;
  1861.         sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
  1862.                get_client_name(acptr, TRUE), acptr->status);
  1863.         (void)exit_client(acptr, acptr, acptr, "Oper Closing");
  1864.         closed++;
  1865.         }
  1866.     sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
  1867.     return 0;
  1868. }
  1869.  
  1870. #if defined(OPER_DIE) || defined(LOCOP_DIE)
  1871. int    m_die(cptr, sptr, parc, parv)
  1872. aClient    *cptr, *sptr;
  1873. int    parc;
  1874. char    *parv[];
  1875. {
  1876.     Reg1    aClient    *acptr;
  1877.     Reg2    int    i;
  1878.  
  1879. #ifndef    LOCOP_DIE
  1880.     if (!MyClient(sptr) || !IsOper(sptr))
  1881. #else
  1882. # ifdef    OPER_DIE
  1883.     if (!MyClient(sptr) || !IsAnOper(sptr))
  1884. # else
  1885.     if (!MyClient(sptr) || !IsLocOp(sptr))
  1886. # endif
  1887. #endif
  1888.         {
  1889.         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1890.         return 0;
  1891.         }
  1892.  
  1893.     for (i = 0; i <= highest_fd; i++)
  1894.         {
  1895.         if (!(acptr = local[i]))
  1896.             continue;
  1897.         if (IsClient(acptr))
  1898.             sendto_one(acptr,
  1899.                    ":%s NOTICE %s :Server Terminating. %s",
  1900.                    me.name, acptr->name,
  1901.                    get_client_name(sptr, TRUE));
  1902.         else if (IsServer(acptr))
  1903.             sendto_one(acptr, ":%s ERROR :Terminated by %s",
  1904.                    me.name, get_client_name(sptr, TRUE));
  1905.         }
  1906.     (void)s_die();
  1907.     return 0;
  1908. }
  1909. #endif
  1910.