]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - src/parse.c
parse(): make reentrant
[irc/rqf/shadowircd.git] / src / parse.c
index 6f24d51bba1ec587c80e030eb7ac5b4693d318f7..a8ce091c77e76a4c83b446c3f0e3a9bb600a40ef 100644 (file)
@@ -1,10 +1,11 @@
 /*
- *  ircd-ratbox: A slightly useful ircd.
+ *  charybdis: an advanced ircd.
  *  parse.c: The message parser.
  *
  *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
  *  Copyright (C) 1996-2002 Hybrid Development Team
  *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2007 William Pitcock
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,7 +22,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
  *  USA
  *
- *  $Id: parse.c 3177 2007-02-01 00:19:14Z jilles $
  */
 
 #include "stdinc.h"
 #include "channel.h"
 #include "common.h"
 #include "hash.h"
-#include "irc_string.h"
-#include "sprintf_irc.h"
+#include "match.h"
 #include "ircd.h"
 #include "numeric.h"
-#include "s_log.h"
+#include "logger.h"
 #include "s_stats.h"
 #include "send.h"
 #include "msg.h"
 #include "s_conf.h"
-#include "memory.h"
 #include "s_serv.h"
 #include "packet.h"
 
-/*
- * NOTE: parse() should not be called recursively by other functions!
- */
-static char *sender;
+static struct Dictionary *cmd_dict = NULL;
+struct Dictionary *alias_dict = NULL;
 
-/* parv[0] == source, and parv[LAST] == NULL */
+/* parv[0] is not used, and parv[LAST] == NULL */
 static char *para[MAXPARA + 2];
 
 static void cancel_clients(struct Client *, struct Client *, char *);
@@ -59,16 +55,8 @@ static void do_alias(struct alias_entry *, struct Client *, char *);
 
 static int handle_command(struct Message *, struct Client *, struct Client *, int, const char**);
 
-static int cmd_hash(const char *p);
-static struct Message *hash_parse(const char *);
-static struct alias_entry *alias_parse(const char *);
-
-struct MessageHash *msg_hash_table[MAX_MSG_HASH];
-
 static char buffer[1024];
 
-dlink_list alias_hash_table[MAX_MSG_HASH];
-
 /* turn a string into a parc/parv pair */
 
 
@@ -110,7 +98,7 @@ string_to_array(char *string, char **parv)
                if(*buf == '\0')
                        return x;
        }
-       /* we can go upto parv[MAXPARA], as parv[0] is taken by source */
+       /* we can go upto parv[MAXPARA], as parv[0] is skipped */
        while (x < MAXPARA);
 
        if(*p == ':')
@@ -123,12 +111,13 @@ string_to_array(char *string, char **parv)
 
 /* parse()
  *
- * given a raw buffer, parses it and generates parv, parc and sender
+ * given a raw buffer, parses it and generates parv and parc
  */
 void
 parse(struct Client *client_p, char *pbuffer, char *bufend)
 {
        struct Client *from = client_p;
+       char *sender;
        char *ch;
        char *s;
        char *end;
@@ -137,7 +126,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
        struct Message *mptr;
 
        s_assert(MyConnect(client_p));
-       s_assert(client_p->localClient->fd >= 0);
+       s_assert(client_p->localClient->F != NULL);
        if(IsAnyDead(client_p))
                return;
 
@@ -167,7 +156,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
                        /* didnt find any matching client, issue a kill */
                        if(from == NULL)
                        {
-                               ServerStats->is_unpf++;
+                               ServerStats.is_unpf++;
                                remove_unknown(client_p, sender, pbuffer);
                                return;
                        }
@@ -177,7 +166,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
                        /* fake direction, hmm. */
                        if(from->from != client_p)
                        {
-                               ServerStats->is_wrdi++;
+                               ServerStats.is_wrdi++;
                                cancel_clients(client_p, from, pbuffer);
                                return;
                        }
@@ -188,7 +177,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
 
        if(*ch == '\0')
        {
-               ServerStats->is_empt++;
+               ServerStats.is_empt++;
                return;
        }
 
@@ -209,7 +198,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
        {
                mptr = NULL;
                numeric = ch;
-               ServerStats->is_num++;
+               ServerStats.is_num++;
                s = ch + 3;     /* I know this is ' ' from above if */
                *s++ = '\0';    /* blow away the ' ', and point s to next part */
        }
@@ -220,7 +209,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
                if((s = strchr(ch, ' ')))
                        *s++ = '\0';
 
-               mptr = hash_parse(ch);
+               mptr = irc_dictionary_retrieve(cmd_dict, ch);
 
                /* no command or its encap only, error */
                if(!mptr || !mptr->cmd)
@@ -240,7 +229,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
                        {
                                if (IsPerson(client_p))
                                {
-                                       struct alias_entry *aptr = alias_parse(ch);
+                                       struct alias_entry *aptr = irc_dictionary_retrieve(alias_dict, ch);
                                        if (aptr != NULL)
                                        {
                                                do_alias(aptr, client_p, s);
@@ -253,7 +242,7 @@ parse(struct Client *client_p, char *pbuffer, char *bufend)
                                                   me.name, from->name, ch);
                                }
                        }
-                       ServerStats->is_unco++;
+                       ServerStats.is_unco++;
                        return;
                }
 
@@ -370,7 +359,7 @@ handle_command(struct Message *mptr, struct Client *client_p,
                ilog(L_SERVER,
                     "Insufficient parameters (%d < %d) for command '%s' from %s.",
                     i, ehandler.min_para, mptr->cmd, client_p->name);
-               snprintf(squitreason, sizeof squitreason,
+               rb_snprintf(squitreason, sizeof squitreason,
                                "Insufficient parameters (%d < %d) for command '%s'",
                                i, ehandler.min_para, mptr->cmd);
                exit_client(client_p, client_p, client_p, squitreason);
@@ -391,7 +380,7 @@ handle_encap(struct Client *client_p, struct Client *source_p,
 
        parv[0] = source_p->name;
 
-       mptr = hash_parse(command);
+       mptr = irc_dictionary_retrieve(cmd_dict, command);
 
        if(mptr == NULL || mptr->cmd == NULL)
                return;
@@ -418,7 +407,7 @@ handle_encap(struct Client *client_p, struct Client *source_p,
 void
 clear_hash_parse()
 {
-       memset(msg_hash_table, 0, sizeof(msg_hash_table));
+       cmd_dict = irc_dictionary_create(strcasecmp);
 }
 
 /* mod_add_cmd
@@ -433,38 +422,18 @@ clear_hash_parse()
 void
 mod_add_cmd(struct Message *msg)
 {
-       struct MessageHash *ptr;
-       struct MessageHash *last_ptr = NULL;
-       struct MessageHash *new_ptr;
-       int msgindex;
-
        s_assert(msg != NULL);
        if(msg == NULL)
                return;
 
-       msgindex = cmd_hash(msg->cmd);
-
-       for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next)
-       {
-               if(strcasecmp(msg->cmd, ptr->cmd) == 0)
-                       return; /* Its already added */
-               last_ptr = ptr;
-       }
-
-       new_ptr = (struct MessageHash *) MyMalloc(sizeof(struct MessageHash));
-
-       new_ptr->next = NULL;
-       DupString(new_ptr->cmd, msg->cmd);
-       new_ptr->msg = msg;
+       if (irc_dictionary_find(cmd_dict, msg->cmd) != NULL)
+               return;
 
        msg->count = 0;
        msg->rcount = 0;
        msg->bytes = 0;
 
-       if(last_ptr == NULL)
-               msg_hash_table[msgindex] = new_ptr;
-       else
-               last_ptr->next = new_ptr;
+       irc_dictionary_add(cmd_dict, msg->cmd, msg);
 }
 
 /* mod_del_cmd
@@ -476,101 +445,11 @@ mod_add_cmd(struct Message *msg)
 void
 mod_del_cmd(struct Message *msg)
 {
-       struct MessageHash *ptr;
-       struct MessageHash *last_ptr = NULL;
-       int msgindex;
-
        s_assert(msg != NULL);
        if(msg == NULL)
                return;
 
-       msgindex = cmd_hash(msg->cmd);
-
-       for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next)
-       {
-               if(strcasecmp(msg->cmd, ptr->cmd) == 0)
-               {
-                       MyFree(ptr->cmd);
-                       if(last_ptr != NULL)
-                               last_ptr->next = ptr->next;
-                       else
-                               msg_hash_table[msgindex] = ptr->next;
-                       MyFree(ptr);
-                       return;
-               }
-               last_ptr = ptr;
-       }
-}
-
-/* hash_parse
- *
- * inputs      - command name
- * output      - pointer to struct Message
- * side effects - 
- */
-static struct Message *
-hash_parse(const char *cmd)
-{
-       struct MessageHash *ptr;
-       int msgindex;
-
-       msgindex = cmd_hash(cmd);
-
-       for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next)
-       {
-               if(strcasecmp(cmd, ptr->cmd) == 0)
-                       return (ptr->msg);
-       }
-
-       return NULL;
-}
-
-/* alias_parse
- *
- * inputs      - command name
- * output      - pointer to struct Message
- * side effects - 
- */
-static struct alias_entry *
-alias_parse(const char *cmd)
-{
-       dlink_node *ptr;
-       int msgindex;
-
-       msgindex = cmd_hash(cmd);
-
-       DLINK_FOREACH(ptr, alias_hash_table[msgindex].head)
-       {
-               struct alias_entry *ent = (struct alias_entry *) ptr->data;
-
-               if(strcasecmp(cmd, ent->name) == 0)
-                       return ent;
-       }
-
-       return NULL;
-}
-
-/*
- * hash
- *
- * inputs      - char string
- * output      - hash index
- * side effects - NONE
- *
- * BUGS                - This a HORRIBLE hash function
- */
-static int
-cmd_hash(const char *p)
-{
-       int hash_val = 0;
-
-       while (*p)
-       {
-               hash_val += ((int) (*p) & 0xDF);
-               p++;
-       }
-
-       return (hash_val % MAX_MSG_HASH);
+       irc_dictionary_delete(cmd_dict, msg->cmd);
 }
 
 /*
@@ -583,33 +462,25 @@ cmd_hash(const char *p)
 void
 report_messages(struct Client *source_p)
 {
-       int i;
-       struct MessageHash *ptr;
-       dlink_node *pptr;
+       struct DictionaryIter iter;
+       struct Message *msg;
+       struct alias_entry *amsg;
 
-       for (i = 0; i < MAX_MSG_HASH; i++)
+       DICTIONARY_FOREACH(msg, &iter, cmd_dict)
        {
-               for (ptr = msg_hash_table[i]; ptr; ptr = ptr->next)
-               {
-                       s_assert(ptr->msg != NULL);
-                       s_assert(ptr->cmd != NULL);
-
-                       sendto_one_numeric(source_p, RPL_STATSCOMMANDS, 
-                                          form_str(RPL_STATSCOMMANDS),
-                                          ptr->cmd, ptr->msg->count, 
-                                          ptr->msg->bytes, ptr->msg->rcount);
-               }
-
-               DLINK_FOREACH(pptr, alias_hash_table[i].head)
-               {
-                       struct alias_entry *aptr = (struct alias_entry *) pptr->data;
-
-                       s_assert(aptr->name != NULL);
+               s_assert(msg->cmd != NULL);
+               sendto_one_numeric(source_p, RPL_STATSCOMMANDS, 
+                                  form_str(RPL_STATSCOMMANDS),
+                                  msg->cmd, msg->count, 
+                                  msg->bytes, msg->rcount);
+       }
 
-                       sendto_one_numeric(source_p, RPL_STATSCOMMANDS,
-                                          form_str(RPL_STATSCOMMANDS),
-                                          aptr->name, aptr->hits, 0, 0);
-               }
+       DICTIONARY_FOREACH(amsg, &iter, alias_dict)
+       {
+               s_assert(amsg->name != NULL);
+               sendto_one_numeric(source_p, RPL_STATSCOMMANDS,
+                                  form_str(RPL_STATSCOMMANDS),
+                                  amsg->name, amsg->hits, 0, 0);
        }
 }
 
@@ -632,7 +503,7 @@ cancel_clients(struct Client *client_p, struct Client *source_p, char *cmd)
                sendto_realops_snomask(SNO_DEBUG, L_ALL,
                                     "Message for %s[%s] from %s",
                                     source_p->name, source_p->from->name,
-                                    get_server_name(client_p, SHOW_IP));
+                                    client_p->name);
        }
        else
        {
@@ -642,7 +513,7 @@ cancel_clients(struct Client *client_p, struct Client *source_p, char *cmd)
                                     source_p->username,
                                     source_p->host,
                                     source_p->from->name,
-                                    get_server_name(client_p, SHOW_IP));
+                                    client_p->name);
        }
 }
 
@@ -656,8 +527,10 @@ static void
 remove_unknown(struct Client *client_p, char *lsender, char *lbuffer)
 {
        int slen = strlen(lsender);
+       char sid[4];
+       struct Client *server;
 
-       /* meepfoo      is a nickname (KILL)
+       /* meepfoo      is a nickname (ignore)
         * #XXXXXXXX    is a UID (KILL)
         * #XX          is a SID (SQUIT)
         * meep.foo     is a server (SQUIT)
@@ -667,16 +540,28 @@ remove_unknown(struct Client *client_p, char *lsender, char *lbuffer)
        {
                sendto_realops_snomask(SNO_DEBUG, L_ALL,
                                     "Unknown prefix (%s) from %s, Squitting %s",
-                                    lbuffer, get_server_name(client_p, SHOW_IP), lsender);
+                                    lbuffer, client_p->name, lsender);
 
                sendto_one(client_p,
                           ":%s SQUIT %s :(Unknown prefix (%s) from %s)",
                           get_id(&me, client_p), lsender, 
                           lbuffer, client_p->name);
        }
+       else if(!IsDigit(lsender[0]))
+               ;
+       else if(slen != 9)
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Invalid prefix (%s) from %s",
+                                    lbuffer, client_p->name);
        else
-               sendto_one(client_p, ":%s KILL %s :%s (Unknown Client)", 
-                          get_id(&me, client_p), lsender, me.name);
+       {
+               memcpy(sid, lsender, 3);
+               sid[3] = '\0';
+               server = find_server(NULL, sid);
+               if (server != NULL && server->from == client_p)
+                       sendto_one(client_p, ":%s KILL %s :%s (Unknown Client)", 
+                                       get_id(&me, client_p), lsender, me.name);
+       }
 }
 
 
@@ -684,7 +569,6 @@ remove_unknown(struct Client *client_p, char *lsender, char *lbuffer)
 /*
  *
  *      parc    number of arguments ('sender' counted as one!)
- *      parv[0] pointer to 'sender' (may point to empty string) (not used)
  *      parv[1]..parv[parc-1]
  *              pointers to additional parameters, this is a NULL
  *              terminated list (parv[parc] == NULL).
@@ -722,10 +606,10 @@ do_numeric(char numeric[], struct Client *client_p, struct Client *source_p, int
                int tl;         /* current length of presently being built string in t */
                for (i = 2; i < (parc - 1); i++)
                {
-                       tl = ircsprintf(t, " %s", parv[i]);
+                       tl = rb_sprintf(t, " %s", parv[i]);
                        t += tl;
                }
-               ircsprintf(t, " :%s", parv[parc - 1]);
+               rb_sprintf(t, " :%s", parv[parc - 1]);
        }
 
        if((target_p = find_client(parv[1])) != NULL)
@@ -780,9 +664,9 @@ do_numeric(char numeric[], struct Client *client_p, struct Client *source_p, int
                return;
        }
        else if((chptr = find_channel(parv[1])) != NULL)
-               sendto_channel_local(ALL_MEMBERS, chptr,
-                                    ":%s %s %s %s",
-                                    source_p->name, numeric, chptr->chname, buffer);
+               sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
+                                    "%s %s%s",
+                                    numeric, chptr->chname, buffer);
 }
 
 static void do_alias(struct alias_entry *aptr, struct Client *source_p, char *text)