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

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, common/parse.c
  3.  *   Copyright (C) 1990 Jarkko Oikarinen and
  4.  *                      University of Oulu, Computing Center
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 1, or (at your option)
  9.  *   any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* -- Jto -- 03 Jun 1990
  22.  * Changed the order of defines...
  23.  */
  24.  
  25. #ifndef lint
  26. static  char sccsid[] = "@(#)parse.c    2.33 1/30/94 (C) 1988 University of Oulu, \
  27. Computing Center and Jarkko Oikarinen";
  28. #endif
  29. #include "struct.h"
  30. #include "common.h"
  31. #define MSGTAB
  32. #include "msg.h"
  33. #undef MSGTAB
  34. #include "sys.h"
  35. #include "numeric.h"
  36. #include "h.h"
  37.  
  38. /*
  39.  * NOTE: parse() should not be called recursively by other functions!
  40.  */
  41. static    char    *para[MAXPARA+1];
  42.  
  43. #ifdef    CLIENT_COMPILE
  44. static    char    sender[NICKLEN+USERLEN+HOSTLEN+3];
  45. char    userhost[USERLEN+HOSTLEN+2];
  46. #else
  47. static    char    sender[HOSTLEN+1];
  48. static    int    cancel_clients PROTO((aClient *, aClient *, char *));
  49. static    void    remove_unknown PROTO((aClient *, char *));
  50. #endif
  51.  
  52. /*
  53. **  Find a client (server or user) by name.
  54. **
  55. **  *Note*
  56. **    Semantics of this function has been changed from
  57. **    the old. 'name' is now assumed to be a null terminated
  58. **    string and the search is the for server and user.
  59. */
  60. #ifndef CLIENT_COMPILE
  61. aClient *find_client(name, cptr)
  62. char    *name;
  63. Reg1    aClient *cptr;
  64.     {
  65.     if (name)
  66.         cptr = hash_find_client(name, cptr);
  67.  
  68.     return cptr;
  69.     }
  70.  
  71. aClient    *find_nickserv(name, cptr)
  72. char    *name;
  73. Reg1    aClient *cptr;
  74.     {
  75.     if (name)
  76.         cptr = hash_find_nickserver(name, cptr);
  77.  
  78.     return cptr;
  79.     }
  80.  
  81. #else
  82. aClient *find_client(name, cptr)
  83. char *name;
  84. aClient *cptr;
  85.     {
  86.     Reg1 aClient *c2ptr = cptr;
  87.  
  88.     if (!name)
  89.         return c2ptr;
  90.  
  91.     for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) 
  92.         if (mycmp(name, c2ptr->name) == 0)
  93.             return c2ptr;
  94.     return cptr;
  95.     }
  96. #endif
  97.  
  98. /*
  99. **  Find server by name.
  100. **
  101. **    This implementation assumes that server and user names
  102. **    are unique, no user can have a server name and vice versa.
  103. **    One should maintain separate lists for users and servers,
  104. **    if this restriction is removed.
  105. **
  106. **  *Note*
  107. **    Semantics of this function has been changed from
  108. **    the old. 'name' is now assumed to be a null terminated
  109. **    string.
  110. */
  111. #ifndef CLIENT_COMPILE
  112. aClient *find_server(name, cptr)
  113. char    *name;
  114. Reg1    aClient *cptr;
  115. {
  116.     if (name)
  117.         cptr = hash_find_server(name, cptr);
  118.     return cptr;
  119. }
  120.  
  121. aClient *find_name(name, cptr)
  122. char    *name;
  123. aClient *cptr;
  124. {
  125.     Reg1 aClient *c2ptr = cptr;
  126.  
  127.     if (!collapse(name))
  128.         return c2ptr;
  129.  
  130.     if ((c2ptr = hash_find_server(name, cptr)))
  131.         return (c2ptr);
  132.     if (!index(name, '*'))
  133.         return c2ptr;
  134.     for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
  135.         {
  136.         if (!IsServer(c2ptr) && !IsMe(c2ptr))
  137.             continue;
  138.         if (match(name, c2ptr->name) == 0)
  139.             break;
  140.         if (index(c2ptr->name, '*'))
  141.             if (match(c2ptr->name, name) == 0)
  142.                     break;
  143.         }
  144.     return (c2ptr ? c2ptr : cptr);
  145. }
  146. #else
  147. aClient    *find_server(name, cptr)
  148. char    *name;
  149. aClient    *cptr;
  150. {
  151.     Reg1    aClient *c2ptr = cptr;
  152.  
  153.     if (!collapse(name))
  154.         return c2ptr;
  155.  
  156.     for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
  157.         {
  158.         if (!IsServer(c2ptr) && !IsMe(c2ptr))
  159.             continue;
  160.         if (match(c2ptr->name, name) == 0 ||
  161.             match(name, c2ptr->name) == 0)
  162.             break;
  163.         }
  164.     return (c2ptr ? c2ptr : cptr);
  165. }
  166. #endif
  167.  
  168. /*
  169. **  Find person by (nick)name.
  170. */
  171. aClient *find_person(name, cptr)
  172. char    *name;
  173. aClient *cptr;
  174.     {
  175.     Reg1    aClient    *c2ptr = cptr;
  176.  
  177.     c2ptr = find_client(name, c2ptr);
  178.  
  179.     if (c2ptr && IsClient(c2ptr) && c2ptr->user)
  180.         return c2ptr;
  181.     else
  182.         return cptr;
  183.     }
  184.  
  185. /*
  186.  * parse a buffer.
  187.  *
  188.  * NOTE: parse() should not be called recusively by any other fucntions!
  189.  */
  190. int    parse(cptr, buffer, bufend, mptr)
  191. aClient *cptr;
  192. char    *buffer, *bufend;
  193. struct    Message *mptr;
  194.     {
  195.     Reg1    aClient *from = cptr;
  196.     Reg2    char *ch, *s;
  197.     Reg3    int    len, i, numeric, paramcount, noprefix = 0;
  198. #ifdef DEBUGMODE
  199.     time_t    then, ticks;
  200.     int    retval;
  201. #endif
  202.  
  203.     Debug((DEBUG_DEBUG,"Parsing: %s", buffer));
  204. #ifndef    CLIENT_COMPILE
  205.     if (IsDead(cptr))
  206.         return 0;
  207. #endif
  208.  
  209.     s = sender;
  210.     *s = '\0';
  211.     for (ch = buffer; *ch == ' '; ch++)
  212.         ;
  213.     para[0] = from->name;
  214.     if (*ch == ':')
  215.         {
  216.         /*
  217.         ** Copy the prefix to 'sender' assuming it terminates
  218.         ** with SPACE (or NULL, which is an error, though).
  219.         */
  220.         for (++ch, i = 0; *ch && *ch != ' '; ++ch )
  221.             if (s < (sender + sizeof(sender)-1))
  222.                 *s++ = *ch; /* leave room for NULL */
  223.         *s = '\0';
  224. #ifdef CLIENT_COMPILE
  225.         if ((s = index(sender, '!')))
  226.             {
  227.             *s++ = '\0';
  228.             strncpyzt(userhost, s, sizeof(userhost));
  229.             }
  230.         else if ((s = index(sender, '@')))
  231.             {
  232.             *s++ = '\0';
  233.             strncpyzt(userhost, s, sizeof(userhost));
  234.             }
  235. #endif
  236.         /*
  237.         ** Actually, only messages coming from servers can have
  238.         ** the prefix--prefix silently ignored, if coming from
  239.         ** a user client...
  240.         **
  241.         ** ...sigh, the current release "v2.2PL1" generates also
  242.         ** null prefixes, at least to NOTIFY messages (e.g. it
  243.         ** puts "sptr->nickname" as prefix from server structures
  244.         ** where it's null--the following will handle this case
  245.         ** as "no prefix" at all --msa  (": NOTICE nick ...")
  246.         */
  247.         if (*sender && IsServer(cptr))
  248.             {
  249.              from = find_client(sender, (aClient *) NULL);
  250.             if (!from || match(from->name, sender))
  251.                 from = find_server(sender, (aClient *)NULL);
  252. #ifndef    CLIENT_COMPILE
  253.             else if (!from && index(sender, '@'))
  254.                 from = find_nickserv(sender, (aClient *)NULL);
  255. #endif
  256.  
  257.             para[0] = sender;
  258.  
  259.             /* Hmm! If the client corresponding to the
  260.              * prefix is not found--what is the correct
  261.              * action??? Now, I will ignore the message
  262.              * (old IRC just let it through as if the
  263.              * prefix just wasn't there...) --msa
  264.              */
  265.             if (!from)
  266.                 {
  267.                 Debug((DEBUG_ERROR,
  268.                     "Unknown prefix (%s)(%s) from (%s)",
  269.                     sender, buffer, cptr->name));
  270.                 ircstp->is_unpf++;
  271. #ifndef    CLIENT_COMPILE
  272.                 remove_unknown(cptr, sender);
  273. #endif
  274.                 return -1;
  275.                 }
  276.             if (from->from != cptr)
  277.                 {
  278.                 ircstp->is_wrdi++;
  279.                 Debug((DEBUG_ERROR,
  280.                     "Message (%s) coming from (%s)",
  281.                     buffer, cptr->name));
  282. #ifndef    CLIENT_COMPILE
  283.                 return cancel_clients(cptr, from, ch);
  284. #else
  285.                 return -1;
  286. #endif
  287.                 }
  288.             }
  289.         while (*ch == ' ')
  290.             ch++;
  291.         }
  292.     else
  293.       noprefix = 1;
  294.     if (*ch == '\0')
  295.         {
  296.         ircstp->is_empt++;
  297.         Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
  298.               cptr->name, from->name));
  299.         return(-1);
  300.         }
  301.     /*
  302.     ** Extract the command code from the packet.  Point s to the end
  303.     ** of the command code and calculate the length using pointer
  304.     ** arithmetic.  Note: only need length for numerics and *all*
  305.     ** numerics must have paramters and thus a space after the command
  306.     ** code. -avalon
  307.     */
  308.     s = (char *)index(ch, ' '); /* s -> End of the command code */
  309.     len = (s) ? (s - ch) : 0;
  310.     if (len == 3 &&
  311.         isdigit(*ch) && isdigit(*(ch + 1)) && isdigit(*(ch + 2)))
  312.         {
  313.         mptr = NULL;
  314.         numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10
  315.             + (*(ch + 2) - '0');
  316.         paramcount = MAXPARA;
  317.         ircstp->is_num++;
  318.         }
  319.     else
  320.         {
  321.         if (s)
  322.             *s++ = '\0';
  323.         if (ch[1] == '\0' && IsToken(cptr))
  324.             mptr = msgmap[(u_char)*ch];
  325.         else
  326.             for (; mptr->cmd; mptr++) 
  327.                 if (mycmp(mptr->cmd, ch) == 0)
  328.                     break;
  329.  
  330.         if (!mptr->cmd)
  331.             {
  332.             /*
  333.             ** Note: Give error message *only* to recognized
  334.             ** persons. It's a nightmare situation to have
  335.             ** two programs sending "Unknown command"'s or
  336.             ** equivalent to each other at full blast....
  337.             ** If it has got to person state, it at least
  338.             ** seems to be well behaving. Perhaps this message
  339.             ** should never be generated, though...  --msa
  340.             ** Hm, when is the buffer empty -- if a command
  341.             ** code has been found ?? -Armin
  342.             */
  343.             if (buffer[0] != '\0')
  344.                 {
  345.                 if (IsPerson(from))
  346.                     sendto_one(from,
  347.                         ":%s %d %s %s :Unknown command",
  348.                         me.name, ERR_UNKNOWNCOMMAND,
  349.                         from->name, ch);
  350. #ifdef    CLIENT_COMPILE
  351.                 Debug((DEBUG_ERROR,"Unknown (%s) from %s[%s]",
  352.                     ch, cptr->name, cptr->sockhost));
  353. #else
  354.                 Debug((DEBUG_ERROR,"Unknown (%s) from %s",
  355.                     ch, get_client_name(cptr, TRUE)));
  356. #endif
  357.                 }
  358.             ircstp->is_unco++;
  359.             return(-1);
  360.             }
  361.         paramcount = mptr->parameters;
  362.         i = bufend - ch; /* Is this right? -Donwulff */
  363.         mptr->bytes += i;
  364.         if ((mptr->flags & 1) && !(IsServer(cptr) || IsService(cptr)))
  365.             cptr->since += (2 + i / 120);
  366.                     /* Allow only 1 msg per 2 seconds
  367.                      * (on average) to prevent dumping.
  368.                      * to keep the response rate up,
  369.                      * bursts of up to 5 msgs are allowed
  370.                      * -SRB
  371.                      */
  372.         }
  373.     /*
  374.     ** Must the following loop really be so devious? On
  375.     ** surface it splits the message to parameters from
  376.     ** blank spaces. But, if paramcount has been reached,
  377.     ** the rest of the message goes into this last parameter
  378.     ** (about same effect as ":" has...) --msa
  379.     */
  380.  
  381.     /* Note initially true: s==NULL || *(s-1) == '\0' !! */
  382.  
  383. #ifdef    CLIENT_COMPILE
  384.     if (me.user)
  385.         para[0] = sender;
  386. #endif
  387.     i = 0;
  388.     if (s)
  389.         {
  390.         if (paramcount > MAXPARA)
  391.             paramcount = MAXPARA;
  392.         for (;;)
  393.             {
  394.             /*
  395.             ** Never "FRANCE " again!! ;-) Clean
  396.             ** out *all* blanks.. --msa
  397.             */
  398.             while (*s == ' ')
  399.                 *s++ = '\0';
  400.  
  401.             if (*s == '\0')
  402.                 break;
  403.             if (*s == ':')
  404.                 {
  405.                 /*
  406.                 ** The rest is single parameter--can
  407.                 ** include blanks also.
  408.                 */
  409.                 para[++i] = s + 1;
  410.                 break;
  411.                 }
  412.             para[++i] = s;
  413.             if (i >= paramcount)
  414.                 break;
  415.             for (; *s != ' ' && *s; s++)
  416.                 ;
  417.             }
  418.         }
  419.     para[++i] = NULL;
  420.     if (mptr == NULL)
  421.         return (do_numeric(numeric, cptr, from, i, para));
  422.     mptr->count++;
  423.     if (IsRegisteredUser(cptr) &&
  424. #ifdef    IDLE_FROM_MSG
  425.         mptr->func == m_private)
  426. #else
  427.         mptr->func != m_ping && mptr->func != m_pong)
  428. #endif
  429.         from->user->last = time(NULL);
  430.  
  431.     /* Lame protocol 4 stuff... this if can be removed when all are 2.9 */
  432.     if (noprefix && IsServer(cptr) && i >= 2 && mptr->func == m_squit &&
  433.         (!(from = find_server(para[1], (aClient *)NULL)) ||
  434.         from->from != cptr))
  435.     {
  436.       Debug((DEBUG_DEBUG,"Ignoring protocol 4 \"%s %s %s ...\"",
  437.           para[0], para[1], para[2]));
  438.       return 0;
  439.         }
  440.  
  441. #ifndef DEBUGMODE
  442.     return (*mptr->func)(cptr, from, i, para);
  443. #else
  444.     then = clock();
  445.     retval = (*mptr->func)(cptr, from, i, para);
  446.     if (retval != FLUSH_BUFFER) {
  447.         ticks = (clock()-then);
  448.         if (IsServer(cptr))
  449.             mptr->rticks += ticks;
  450.         else
  451.             mptr->lticks += ticks;
  452.         cptr->cputime += ticks;
  453.     }
  454.  
  455.     return retval;
  456. #endif
  457.     }
  458.  
  459. /*
  460.  * field breakup for ircd.conf file.
  461.  */
  462. char    *getfield(newline)
  463. char    *newline;
  464. {
  465.     static    char *line = NULL;
  466.     char    *end, *field;
  467.     
  468.     if (newline)
  469.         line = newline;
  470.     if (line == NULL)
  471.         return(NULL);
  472.  
  473.     field = line;
  474.     if ((end = (char *)index(line,':')) == NULL)
  475.         {
  476.         line = NULL;
  477.         if ((end = (char *)index(field,'\n')) == NULL)
  478.             end = field + strlen(field);
  479.         }
  480.     else
  481.         line = end + 1;
  482.     *end = '\0';
  483.     return(field);
  484. }
  485.  
  486. #ifndef    CLIENT_COMPILE
  487. static    int    cancel_clients(cptr, sptr, cmd)
  488. aClient    *cptr, *sptr;
  489. char    *cmd;
  490. {
  491.     char *cmdpriv;    
  492.     /*
  493.      * kill all possible points that are causing confusion here,
  494.      * I'm not sure I've got this all right...
  495.      * - avalon
  496.      * No you didn't...
  497.      * - Run
  498.      */
  499.     /* This little bit of code allowed paswords to nickserv to be 
  500.      * seen.  A definite no-no.  --Russell
  501.     sendto_ops("Message (%s) for %s[%s!%s@%s] from %s", cmd,
  502.            sptr->name, sptr->from->name, sptr->from->username,
  503.            sptr->from->sockhost, get_client_name(cptr, TRUE));*/
  504.     /*
  505.      * Incorrect prefix for a server from some connection.  If it is a
  506.      * client trying to be annoying, just QUIT them, if it is a server
  507.      * then the same deal.
  508.      */
  509.     if (IsServer(sptr) || IsMe(sptr))
  510.         {
  511.         /*
  512.          * First go at tracking down what really causes the
  513.          * dreaded Fake Direction error.  It should not be possible
  514.          * ever to happen.  Assume nothing here since this is an
  515.          * impossibility.
  516.          *
  517.          * Check for valid fields, then send out globops with
  518.          * the msg command recieved, who apperently sent it,
  519.          * where it came from, and where it was suppose to come
  520.          * from.  We send the msg command to find out if its some
  521.          * bug somebody found with an old command, maybe some
  522.          * weird thing like, /ping serverto.* serverfrom.* and on
  523.          * the way back, fake direction?  Don't know, maybe this
  524.          * will tell us.  -Cabal95
  525.          *
  526.          * Take #2 on Fake Direction.  Most of them seem to be
  527.          * numerics.  But sometimes its getting fake direction on
  528.          * SERVER msgs.. HOW??  Display the full message now to
  529.          * figure it out... -Cabal95
  530.          *
  531.          * Okay I give up.  Can't find it.  Seems like it will
  532.          * exist untill ircd is completely rewritten. :/ For now
  533.          * just completely ignore them.  Needs to be modified to
  534.          * send these messages to a special oper channel. -Cabal95
  535.          *
  536.         aClient *from;
  537.         char    *fromname=NULL, *sptrname=NULL, *cptrname=NULL, *s;
  538.  
  539.         while (*cmd == ' ')
  540.             cmd++;
  541.         if (s = index(cmd, ' '))
  542.             *s++ = '\0';
  543.         if (!strcasecmp(cmd, "PRIVMSG") ||
  544.             !strcasecmp(cmd, "NOTICE") ||
  545.             !strcasecmp(cmd, "PASS"))
  546.             s = NULL;
  547.         if (sptr && sptr->name)
  548.             sptrname = sptr->name;
  549.         if (cptr && cptr->name)
  550.             cptrname = cptr->name;
  551.         if (sptr && sptr->from && sptr->from->name)
  552.             fromname = sptr->from->name;
  553.  
  554.         sendto_serv_butone(NULL, ":%s GLOBOPS :"
  555.             "Fake Direction: Message[%s %s] from %s via %s "
  556.             "instead of %s (Tell Cabal95)", me.name, cmd,
  557.             (s ? s : ""),
  558.             (sptr->name!=NULL)?sptr->name:"<unknown>",
  559.             (cptr->name!=NULL)?cptr->name:"<unknown>",
  560.             (fromname!=NULL)?fromname:"<unknown>");
  561.         sendto_ops(
  562.             "Fake Direction: Message[%s %s] from %s via %s "
  563.             "instead of %s (Tell Cabal95)", cmd,
  564.             (s ? s : ""),
  565.             (sptr->name!=NULL)?sptr->name:"<unknown>",
  566.             (cptr->name!=NULL)?cptr->name:"<unknown>",
  567.             (fromname!=NULL)?fromname:"<unknown>");
  568.  
  569.         /*
  570.          * We don't drop the server anymore.  Just ignore
  571.          * the message and go about your business.  And hope
  572.          * we don't get flooded. :-)  -Cabal95
  573.         sendto_ops("Dropping server %s", cptr->name);
  574.         return exit_client(cptr, cptr, &me, "Fake Direction");
  575.          */
  576.         return 0;
  577.         }
  578.     /*
  579.      * Ok, someone is trying to impose as a client and things are
  580.      * confused.  If we got the wrong prefix from a server, send out a
  581.      * kill, else just exit the lame client.
  582.      */
  583.     if (IsServer(cptr))
  584.         {
  585.         /*
  586.         ** It is NOT necessary to send a KILL here...
  587.         ** We come here when a previous 'NICK new'
  588.         ** nick collided with an older nick, and was
  589.         ** ignored, and other messages still were on
  590.         ** the way (like the following USER).
  591.         ** We simply ignore it all, a purge will be done
  592.         ** automatically by the server 'cptr' as a reaction
  593.         ** on our 'NICK older'. --Run
  594.         */
  595.         return 0; /* On our side, nothing changed */
  596.         }
  597.     return exit_client(cptr, cptr, &me, "Fake prefix");
  598. }
  599.  
  600. static    void    remove_unknown(cptr, sender)
  601. aClient    *cptr;
  602. char    *sender;
  603. {
  604.     if (!IsRegistered(cptr) || IsClient(cptr))
  605.         return;
  606.     /*
  607.      * Not from a server so don't need to worry about it.
  608.      */
  609.     if (!IsServer(cptr))
  610.         return;
  611.     /*
  612.      * Do kill if it came from a server because it means there is a ghost
  613.      * user on the other server which needs to be removed. -avalon
  614.      */
  615.     if (!index(sender, '.'))
  616.         sendto_one(cptr, ":%s KILL %s :%s (%s(?) <- %s)",
  617.                me.name, sender, me.name, sender,
  618.                get_client_name(cptr, FALSE));
  619.     else
  620.         sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)",
  621.                me.name, sender, get_client_name(cptr, FALSE));
  622. }
  623. #endif
  624.