/* * parse.C: Parsing of IRC messages. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Rights to this code are documented in doc/pod/license.pod. * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) */ static char const rcsid[] = "$Id: parse.C,v 1.7 2007/09/16 18:54:45 pippijn Exp $"; #include "atheme.h" #include "servers.h" #include "uplink.h" #include "pmodule.h" /* by default, we want the 2.8.21 parser */ void (*parse) (char *line) = &irc_parse; /* parses a standard 2.8.21 style IRC stream */ void irc_parse (char *line) { sourceinfo_t si; char *pos; char *origin = NULL; char *command = NULL; char *message = NULL; char *parv[MAXPARC + 1]; static char coreLine[BUFSIZE]; int parc = 0; unsigned int i; pcommand_t const *pcmd; /* clear the parv */ for (i = 0; i <= MAXPARC; i++) parv[i] = NULL; memset (&si, '\0', sizeof si); si.connection = curr_uplink->conn; if (line != NULL) { /* sometimes we'll get a blank line with just a \n on it... * catch those here... they'll core us later on if we don't */ if (*line == '\n') return; if (*line == '\000') return; /* copy the original line so we know what we crashed on */ memset ((char *) &coreLine, '\0', BUFSIZE); strlcpy (coreLine, line, BUFSIZE); slog (LG_RAWDATA, "-> %s", line); /* find the first space */ if ((pos = strchr (line, ' '))) { *pos = '\0'; pos++; /* if it starts with a : we have a prefix/origin * pull the origin off into `origin', and have pos for the * command, message will be the part afterwards */ if (*line == ':') { origin = line + 1; si.s = server_find (origin); si.su = user_find (origin); if ((message = strchr (pos, ' '))) { *message = '\0'; message++; command = pos; } else { command = pos; message = NULL; } } else { if (me.recvsvr) { origin = me.actual; si.s = server_find (origin); } message = pos; command = line; } } else { if (me.recvsvr) { origin = me.actual; si.s = server_find (origin); } command = line; message = NULL; } if (!si.s && !si.su && me.recvsvr) return slog (LG_INFO, "irc_parse(): got message from nonexistant user or server: %s", origin); si.smu = si.su != NULL ? si.su->myuser : NULL; /* okay, the nasty part is over, now we need to make a * parv out of what's left */ if (message) { if (*message == ':') { message++; parv[0] = message; parc = 1; } else parc = tokenize (message, parv); } else parc = 0; /* now we should have origin (or NULL), command, and a parv * with it's accompanying parc... let's make ABSOLUTELY sure */ if (!command) return slog (LG_DEBUG, "irc_parse(): command not found: %s", coreLine); /* take the command through the hash table */ if ((pcmd = pcommand_find (command))) { if (si.su && !(pcmd->sourcetype & MSRC_USER)) return slog (LG_INFO, "irc_parse(): user %s sent disallowed command %s", si.su->nick, pcmd->token); else if (si.s && !(pcmd->sourcetype & MSRC_SERVER)) return slog (LG_INFO, "irc_parse(): server %s sent disallowed command %s", si.s->name, pcmd->token); else if (!me.recvsvr && !(pcmd->sourcetype & MSRC_UNREG)) return slog (LG_INFO, "irc_parse(): unregistered server sent disallowed command %s", pcmd->token); if (parc < pcmd->minparc) return slog (LG_INFO, "irc_parse(): insufficient parameters for command %s", pcmd->token); if (pcmd->handler) pcmd->handler (&si, parc, parv); } } } /* parses a P10 IRC stream */ void p10_parse (char *line) { sourceinfo_t si; char *pos; char *origin = NULL; char *command = NULL; char *message = NULL; char *parv[MAXPARC + 1]; static char coreLine[BUFSIZE]; int parc = 0; unsigned int i; pcommand_t const *pcmd; /* clear the parv */ for (i = 0; i <= MAXPARC; i++) parv[i] = NULL; memset (&si, '\0', sizeof si); si.connection = curr_uplink->conn; if (line != NULL) { /* sometimes we'll get a blank line with just a \n on it... * catch those here... they'll core us later on if we don't */ if (*line == '\n') return; if (*line == '\000') return; /* copy the original line so we know what we crashed on */ memset ((char *) &coreLine, '\0', BUFSIZE); strlcpy (coreLine, line, BUFSIZE); slog (LG_RAWDATA, "-> %s", line); /* find the first spcae */ if ((pos = strchr (line, ' '))) { *pos = '\0'; pos++; /* if it starts with a : we have a prefix/origin * pull the origin off into `origin', and have pos for the * command, message will be the part afterwards */ if (*line == ':' || me.recvsvr == true) { origin = line; if (*origin == ':') { origin++; si.s = server_find (origin); si.su = user_find_named (origin); } else { si.s = server_find (origin); si.su = user_find (origin); } if ((message = strchr (pos, ' '))) { *message = '\0'; message++; command = pos; } else { command = pos; message = NULL; } } else { message = pos; command = line; } } if (!si.s && !si.su && me.recvsvr) return slog (LG_DEBUG, "p10_parse(): got message from nonexistant user or server: %s", origin); si.smu = si.su != NULL ? si.su->myuser : NULL; /* okay, the nasty part is over, now we need to make a * parv out of what's left */ if (message) { if (*message == ':') { message++; parv[0] = message; parc = 1; } else parc = tokenize (message, parv); } else parc = 0; /* now we should have origin (or NULL), command, and a parv * with it's accompanying parc... let's make ABSOLUTELY sure */ if (!command) return slog (LG_DEBUG, "p10_parse(): command not found: %s", coreLine); /* take the command through the hash table */ if ((pcmd = pcommand_find (command))) { if (si.su && !(pcmd->sourcetype & MSRC_USER)) return slog (LG_INFO, "p10_parse(): user %s sent disallowed command %s", si.su->nick, pcmd->token); else if (si.s && !(pcmd->sourcetype & MSRC_SERVER)) return slog (LG_INFO, "p10_parse(): server %s sent disallowed command %s", si.s->name, pcmd->token); else if (!me.recvsvr && !(pcmd->sourcetype & MSRC_UNREG)) return slog (LG_INFO, "p10_parse(): unregistered server sent disallowed command %s", pcmd->token); if (parc < pcmd->minparc) return slog (LG_INFO, "p10_parse(): insufficient parameters for command %s", pcmd->token); if (pcmd->handler) pcmd->handler (&si, parc, parv); } } }