home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / common / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  12.9 KB  |  547 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 a user@host (server or user).
  100. **
  101. **  *Note*
  102. **    Semantics of this function has been changed from
  103. **    the old. 'name' is now assumed to be a null terminated
  104. **    string and the search is the for server and user.
  105. */
  106. aClient *find_userhost(user, host, cptr, count)
  107. char    *user, *host;
  108. aClient *cptr;
  109. int    *count;
  110.     {
  111.     Reg1    aClient    *c2ptr;
  112.     Reg2    aClient    *res = cptr;
  113.  
  114.     *count = 0;
  115.     if (collapse(user))
  116.         for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) 
  117.             {
  118.             if (!MyClient(c2ptr)) /* implies mine and a user */
  119.                 continue;
  120.             if ((!host || !match(host, c2ptr->user->host)) &&
  121.                  mycmp(user, c2ptr->user->username) == 0)
  122.                 {
  123.                 (*count)++;
  124.                 res = c2ptr;
  125.                 }
  126.             }
  127.     return res;
  128.     }
  129.  
  130. /*
  131. **  Find server by name.
  132. **
  133. **    This implementation assumes that server and user names
  134. **    are unique, no user can have a server name and vice versa.
  135. **    One should maintain separate lists for users and servers,
  136. **    if this restriction is removed.
  137. **
  138. **  *Note*
  139. **    Semantics of this function has been changed from
  140. **    the old. 'name' is now assumed to be a null terminated
  141. **    string.
  142. */
  143. #ifndef CLIENT_COMPILE
  144. aClient *find_server(name, cptr)
  145. char    *name;
  146. Reg1    aClient *cptr;
  147. {
  148.     if (name)
  149.         cptr = hash_find_server(name, cptr);
  150.     return cptr;
  151. }
  152.  
  153. aClient *find_name(name, cptr)
  154. char    *name;
  155. aClient *cptr;
  156. {
  157.     Reg1 aClient *c2ptr = cptr;
  158.  
  159.     if (!collapse(name))
  160.         return c2ptr;
  161.  
  162.     if ((c2ptr = hash_find_server(name, cptr)))
  163.         return (c2ptr);
  164.     if (!index(name, '*'))
  165.         return c2ptr;
  166.     for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
  167.         {
  168.         if (!IsServer(c2ptr) && !IsMe(c2ptr))
  169.             continue;
  170.         if (match(name, c2ptr->name) == 0)
  171.             break;
  172.         if (index(c2ptr->name, '*'))
  173.             if (match(c2ptr->name, name) == 0)
  174.                     break;
  175.         }
  176.     return (c2ptr ? c2ptr : cptr);
  177. }
  178. #else
  179. aClient    *find_server(name, cptr)
  180. char    *name;
  181. aClient    *cptr;
  182. {
  183.     Reg1    aClient *c2ptr = cptr;
  184.  
  185.     if (!collapse(name))
  186.         return c2ptr;
  187.  
  188.     for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
  189.         {
  190.         if (!IsServer(c2ptr) && !IsMe(c2ptr))
  191.             continue;
  192.         if (match(c2ptr->name, name) == 0 ||
  193.             match(name, c2ptr->name) == 0)
  194.             break;
  195.         }
  196.     return (c2ptr ? c2ptr : cptr);
  197. }
  198. #endif
  199.  
  200. /*
  201. **  Find person by (nick)name.
  202. */
  203. aClient *find_person(name, cptr)
  204. char    *name;
  205. aClient *cptr;
  206.     {
  207.     Reg1    aClient    *c2ptr = cptr;
  208.  
  209.     c2ptr = find_client(name, c2ptr);
  210.  
  211.     if (c2ptr && IsClient(c2ptr) && c2ptr->user)
  212.         return c2ptr;
  213.     else
  214.         return cptr;
  215.     }
  216.  
  217. /*
  218.  * parse a buffer.
  219.  *
  220.  * NOTE: parse() should not be called recusively by any other fucntions!
  221.  */
  222. int    parse(cptr, buffer, bufend, mptr)
  223. aClient *cptr;
  224. char    *buffer, *bufend;
  225. struct    Message *mptr;
  226.     {
  227.     Reg1    aClient *from = cptr;
  228.     Reg2    char *ch, *s;
  229.     Reg3    int    len, i, numeric, paramcount;
  230.  
  231.     Debug((DEBUG_DEBUG,"Parsing: %s", buffer));
  232. #ifndef    CLIENT_COMPILE
  233.     if (IsDead(cptr))
  234.         return 0;
  235. #endif
  236.  
  237.     s = sender;
  238.     *s = '\0';
  239.     for (ch = buffer; *ch == ' '; ch++)
  240.         ;
  241.     para[0] = from->name;
  242.     if (*ch == ':')
  243.         {
  244.         /*
  245.         ** Copy the prefix to 'sender' assuming it terminates
  246.         ** with SPACE (or NULL, which is an error, though).
  247.         */
  248.         for (++ch, i = 0; *ch && *ch != ' '; ++ch )
  249.             if (s < (sender + sizeof(sender)-1))
  250.                 *s++ = *ch; /* leave room for NULL */
  251.         *s = '\0';
  252. #ifdef CLIENT_COMPILE
  253.         if ((s = index(sender, '!')))
  254.             {
  255.             *s++ = '\0';
  256.             strncpyzt(userhost, s, sizeof(userhost));
  257.             }
  258.         else if ((s = index(sender, '@')))
  259.             {
  260.             *s++ = '\0';
  261.             strncpyzt(userhost, s, sizeof(userhost));
  262.             }
  263. #endif
  264.         /*
  265.         ** Actually, only messages coming from servers can have
  266.         ** the prefix--prefix silently ignored, if coming from
  267.         ** a user client...
  268.         **
  269.         ** ...sigh, the current release "v2.2PL1" generates also
  270.         ** null prefixes, at least to NOTIFY messages (e.g. it
  271.         ** puts "sptr->nickname" as prefix from server structures
  272.         ** where it's null--the following will handle this case
  273.         ** as "no prefix" at all --msa  (": NOTICE nick ...")
  274.         */
  275.         if (*sender && IsServer(cptr))
  276.             {
  277.              from = find_client(sender, (aClient *) NULL);
  278.             if (!from || matches(from->name, sender))
  279.                 from = find_server(sender, (aClient *)NULL);
  280. #ifndef    CLIENT_COMPILE
  281.             else if (!from && index(sender, '@'))
  282.                 from = find_nickserv(sender, (aClient *)NULL);
  283. #endif
  284.  
  285.             para[0] = sender;
  286.  
  287.             /* Hmm! If the client corresponding to the
  288.              * prefix is not found--what is the correct
  289.              * action??? Now, I will ignore the message
  290.              * (old IRC just let it through as if the
  291.              * prefix just wasn't there...) --msa
  292.              */
  293.             if (!from)
  294.                 {
  295.                 Debug((DEBUG_ERROR,
  296.                     "Unknown prefix (%s)(%s) from (%s)",
  297.                     sender, buffer, cptr->name));
  298.                 ircstp->is_unpf++;
  299. #ifndef    CLIENT_COMPILE
  300.                 remove_unknown(cptr, sender);
  301. #endif
  302.                 return -1;
  303.                 }
  304.             if (from->from != cptr)
  305.                 {
  306.                 ircstp->is_wrdi++;
  307.                 Debug((DEBUG_ERROR,
  308.                     "Message (%s) coming from (%s)",
  309.                     buffer, cptr->name));
  310. #ifndef    CLIENT_COMPILE
  311.                 return cancel_clients(cptr, from, buffer);
  312. #else
  313.                 return -1;
  314. #endif
  315.                 }
  316.             }
  317.         while (*ch == ' ')
  318.             ch++;
  319.         }
  320.     if (*ch == '\0')
  321.         {
  322.         ircstp->is_empt++;
  323.         Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
  324.               cptr->name, from->name));
  325.         return(-1);
  326.         }
  327.     /*
  328.     ** Extract the command code from the packet.  Point s to the end
  329.     ** of the command code and calculate the length using pointer
  330.     ** arithmetic.  Note: only need length for numerics and *all*
  331.     ** numerics must have paramters and thus a space after the command
  332.     ** code. -avalon
  333.     */
  334.     s = (char *)index(ch, ' '); /* s -> End of the command code */
  335.     len = (s) ? (s - ch) : 0;
  336.     if (len == 3 &&
  337.         isdigit(*ch) && isdigit(*(ch + 1)) && isdigit(*(ch + 2)))
  338.         {
  339.         mptr = NULL;
  340.         numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10
  341.             + (*(ch + 2) - '0');
  342.         paramcount = MAXPARA;
  343.         ircstp->is_num++;
  344.         }
  345.     else
  346.         {
  347.         if (s)
  348.             *s++ = '\0';
  349.         for (; mptr->cmd; mptr++) 
  350.             if (mycmp(mptr->cmd, ch) == 0)
  351.                 break;
  352.  
  353.         if (!mptr->cmd)
  354.             {
  355.             /*
  356.             ** Note: Give error message *only* to recognized
  357.             ** persons. It's a nightmare situation to have
  358.             ** two programs sending "Unknown command"'s or
  359.             ** equivalent to each other at full blast....
  360.             ** If it has got to person state, it at least
  361.             ** seems to be well behaving. Perhaps this message
  362.             ** should never be generated, though...  --msa
  363.             ** Hm, when is the buffer empty -- if a command
  364.             ** code has been found ?? -Armin
  365.             */
  366.             if (buffer[0] != '\0')
  367.                 {
  368.                 if (IsPerson(from))
  369.                     sendto_one(from,
  370.                         ":%s %d %s %s :Unknown command",
  371.                         me.name, ERR_UNKNOWNCOMMAND,
  372.                         from->name, ch);
  373. #ifdef    CLIENT_COMPILE
  374.                 Debug((DEBUG_ERROR,"Unknown (%s) from %s[%s]",
  375.                     ch, cptr->name, cptr->sockhost));
  376. #else
  377.                 Debug((DEBUG_ERROR,"Unknown (%s) from %s",
  378.                     ch, get_client_name(cptr, TRUE)));
  379. #endif
  380.                 }
  381.             ircstp->is_unco++;
  382.             return(-1);
  383.             }
  384.         paramcount = mptr->parameters;
  385.         i = bufend - ((s) ? s : ch);
  386.         mptr->bytes += i;
  387.         if ((mptr->flags & 1) && !(IsServer(cptr) || IsService(cptr)))
  388.             cptr->since += (2 + i / 120);
  389.                     /* Allow only 1 msg per 2 seconds
  390.                      * (on average) to prevent dumping.
  391.                      * to keep the response rate up,
  392.                      * bursts of up to 5 msgs are allowed
  393.                      * -SRB
  394.                      */
  395.         }
  396.     /*
  397.     ** Must the following loop really be so devious? On
  398.     ** surface it splits the message to parameters from
  399.     ** blank spaces. But, if paramcount has been reached,
  400.     ** the rest of the message goes into this last parameter
  401.     ** (about same effect as ":" has...) --msa
  402.     */
  403.  
  404.     /* Note initially true: s==NULL || *(s-1) == '\0' !! */
  405.  
  406. #ifdef    CLIENT_COMPILE
  407.     if (me.user)
  408.         para[0] = sender;
  409. #endif
  410.     i = 0;
  411.     if (s)
  412.         {
  413.         if (paramcount > MAXPARA)
  414.             paramcount = MAXPARA;
  415.         for (;;)
  416.             {
  417.             /*
  418.             ** Never "FRANCE " again!! ;-) Clean
  419.             ** out *all* blanks.. --msa
  420.             */
  421.             while (*s == ' ')
  422.                 *s++ = '\0';
  423.  
  424.             if (*s == '\0')
  425.                 break;
  426.             if (*s == ':')
  427.                 {
  428.                 /*
  429.                 ** The rest is single parameter--can
  430.                 ** include blanks also.
  431.                 */
  432.                 para[++i] = s + 1;
  433.                 break;
  434.                 }
  435.             para[++i] = s;
  436.             if (i >= paramcount)
  437.                 break;
  438.             for (; *s != ' ' && *s; s++)
  439.                 ;
  440.             }
  441.         }
  442.     para[++i] = NULL;
  443.     if (mptr == NULL)
  444.         return (do_numeric(numeric, cptr, from, i, para));
  445.     mptr->count++;
  446.     if (IsRegisteredUser(cptr) &&
  447. #ifdef    IDLE_FROM_MSG
  448.         mptr->func == m_private)
  449. #else
  450.         mptr->func != m_ping && mptr->func != m_pong)
  451. #endif
  452.         from->user->last = time(NULL);
  453.     return (*mptr->func)(cptr, from, i, para);
  454.     }
  455.  
  456. /*
  457.  * field breakup for ircd.conf file.
  458.  */
  459. char    *getfield(newline)
  460. char    *newline;
  461. {
  462.     static    char *line = NULL;
  463.     char    *end, *field;
  464.     
  465.     if (newline)
  466.         line = newline;
  467.     if (line == NULL)
  468.         return(NULL);
  469.  
  470.     field = line;
  471.     if ((end = (char *)index(line,':')) == NULL)
  472.         {
  473.         line = NULL;
  474.         if ((end = (char *)index(field,'\n')) == NULL)
  475.             end = field + strlen(field);
  476.         }
  477.     else
  478.         line = end + 1;
  479.     *end = '\0';
  480.     return(field);
  481. }
  482.  
  483. #ifndef    CLIENT_COMPILE
  484. static    int    cancel_clients(cptr, sptr, cmd)
  485. aClient    *cptr, *sptr;
  486. char    *cmd;
  487. {
  488.     /*
  489.      * kill all possible points that are causing confusion here,
  490.      * I'm not sure I've got this all right...
  491.      * - avalon
  492.      */
  493.     sendto_ops("Message (%s) for %s[%s!%s@%s] from %s", cmd,
  494.            sptr->name, sptr->from->name, sptr->from->username,
  495.            sptr->from->sockhost, get_client_name(cptr, TRUE));
  496.     /*
  497.      * Incorrect prefix for a server from some connection.  If it is a
  498.      * client trying to be annoying, just QUIT them, if it is a server
  499.      * then the same deal.
  500.      */
  501.     if (IsServer(sptr) || IsMe(sptr))
  502.         {
  503.         sendto_ops("Dropping server %s", cptr->name);
  504.         return exit_client(cptr, cptr, &me, "Fake Direction");
  505.         }
  506.     /*
  507.      * Ok, someone is trying to impose as a client and things are
  508.      * confused.  If we got the wrong prefix from a server, send out a
  509.      * kill, else just exit the lame client.
  510.      */
  511.     if (IsServer(cptr))
  512.         {
  513.         sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)",
  514.                    me.name, sptr->name, me.name,
  515.                    sptr->name, sptr->from->name,
  516.                    get_client_name(cptr, TRUE));
  517.         sptr->flags |= FLAGS_KILLED;
  518.         return exit_client(cptr, sptr, &me, "Fake Prefix");
  519.         }
  520.     return exit_client(cptr, cptr, &me, "Fake prefix");
  521. }
  522.  
  523. static    void    remove_unknown(cptr, sender)
  524. aClient    *cptr;
  525. char    *sender;
  526. {
  527.     if (!IsRegistered(cptr) || IsClient(cptr))
  528.         return;
  529.     /*
  530.      * Not from a server so don't need to worry about it.
  531.      */
  532.     if (!IsServer(cptr))
  533.         return;
  534.     /*
  535.      * Do kill if it came from a server because it means there is a ghost
  536.      * user on the other server which needs to be removed. -avalon
  537.      */
  538.     if (!index(sender, '.'))
  539.         sendto_one(cptr, ":%s KILL %s :%s (%s(?) <- %s)",
  540.                me.name, sender, me.name, sender,
  541.                get_client_name(cptr, FALSE));
  542.     else
  543.         sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)",
  544.                me.name, sender, get_client_name(cptr, FALSE));
  545. }
  546. #endif
  547.