/* RFC1459+TS8 protocol module for IRC Services. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file COPYING for * details. */ #include "services.h" #include "modules.h" #include "conffile.h" #include "messages.h" /*************************************************************************/ static Module *module; static char *NetworkDomain = NULL; /*************************************************************************/ /************************** User/channel modes ***************************/ /*************************************************************************/ struct modedata_init { uint8 mode; ModeData data; }; static const struct modedata_init new_usermodes[] = { }; static const struct modedata_init new_chanmodes[] = { }; static const struct modedata_init new_chanusermodes[] = { }; static void init_modes(void) { int i; for (i = 0; i < lenof(new_usermodes); i++) usermodes[new_usermodes[i].mode] = new_usermodes[i].data; for (i = 0; i < lenof(new_chanmodes); i++) chanmodes[new_chanmodes[i].mode] = new_chanmodes[i].data; for (i = 0; i < lenof(new_chanusermodes); i++) chanusermodes[new_chanusermodes[i].mode] = new_chanusermodes[i].data; mode_setup(); }; /*************************************************************************/ /************************* IRC message receiving *************************/ /*************************************************************************/ static void m_nick(char *source, int ac, char **av) { if (*source) { /* Old user changing nicks. */ if (ac != 2) { if (debug) module_log("debug: NICK message: wrong number of parameters" " (%d) for source `%s'", ac, source); } else { do_nick(source, ac, av); } return; } /* New user. We get the information we want from the USER command, so * we don't do anything else here. */ } /*************************************************************************/ static void m_user(char *source, int ac, char **av) { char *new_av[7]; if (ac != 5) return; new_av[0] = source; /* Nickname */ new_av[1] = (char *)"0"; /* # of hops (was in NICK command... we lose) */ new_av[2] = av[0]; /* Timestamp */ new_av[3] = av[1]; /* Username */ new_av[4] = av[2]; /* Hostname */ new_av[5] = av[3]; /* Server */ new_av[6] = av[4]; /* Real name */ do_nick("", 7, new_av); } /*************************************************************************/ static Message ts8_messages[] = { { "NICK", m_nick }, { "USER", m_user }, { NULL } }; /*************************************************************************/ /************************** IRC message sending **************************/ /*************************************************************************/ /* Send a NICK command for a new user. */ static void do_send_nick(const char *nick, const char *user, const char *host, const char *server, const char *name, const char *modes) { send_cmd(NULL, "NICK %s :1", nick); send_cmd(nick, "USER %ld %s %s %s :%s", (long)time(NULL), user, host, server, name); if (modes) send_cmd(nick, "MODE %s +%s", nick, modes); } /*************************************************************************/ /* Send a NICK command to change an existing user's nick. */ static void do_send_nickchange(const char *nick, const char *newnick) { send_cmd(nick, "NICK %s %ld", newnick, (long)time(NULL)); } /*************************************************************************/ /* Send a command to change a user's "real name". */ static void do_send_namechange(const char *nick, const char *newname) { /* Not supported by this protocol. */ } /*************************************************************************/ /* Send a SERVER command, and anything else needed at the beginning of the * connection. */ static void do_send_server(void) { send_cmd(NULL, "PASS :%s", RemotePassword); send_cmd(NULL, "SERVER %s 1 :%s", ServerName, ServerDesc); } /*************************************************************************/ /* Send a SERVER command for a remote (juped) server. */ static void do_send_server_remote(const char *server, const char *reason) { send_cmd(NULL, "SERVER %s 2 :%s", server, reason); } /*************************************************************************/ /* Send a WALLOPS. */ static void do_wallops(const char *source, const char *fmt, ...) { va_list args; char buf[BUFSIZE]; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); send_cmd(source ? source : ServerName, "WALLOPS :%s", buf); } /*************************************************************************/ /* Send a NOTICE to all users on the network. */ static void do_notice_all(const char *source, const char *fmt, ...) { va_list args; char msgbuf[BUFSIZE]; va_start(args, fmt); vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); va_end(args); if (NetworkDomain) { send_cmd(source, "NOTICE $*.%s :%s", NetworkDomain, msgbuf); } else { /* Go through all common top-level domains. If you have others, * add them here. */ send_cmd(source, "NOTICE $*.com :%s", msgbuf); send_cmd(source, "NOTICE $*.net :%s", msgbuf); send_cmd(source, "NOTICE $*.org :%s", msgbuf); send_cmd(source, "NOTICE $*.edu :%s", msgbuf); } } /*************************************************************************/ /* Send a command which modifies channel status. */ static void do_send_channel_cmd(const char *source, const char *fmt, ...) { va_list args; va_start(args, fmt); vsend_cmd(source, fmt, args); va_end(args); } /*************************************************************************/ /******************************* Callbacks *******************************/ /*************************************************************************/ static int do_set_topic(const char *source, Channel *c, const char *topic, const char *setter, time_t t) { if (c->topic_time && t >= c->topic_time) t = c->topic_time - 1; /* Force topic change */ if (setter) return 0; c->topic_time = t; send_cmd(source, "TOPIC %s %s %ld :%s", c->name, c->topic_setter, (long)c->topic_time, c->topic ? c->topic : ""); return 1; } /*************************************************************************/ /***************************** Module stuff ******************************/ /*************************************************************************/ const int32 module_version = MODULE_VERSION_CODE; ConfigDirective module_config[] = { { "NetworkDomain", { { CD_STRING, 0, &NetworkDomain } } }, { NULL } }; /*************************************************************************/ int init_module(Module *module_) { module = module_; protocol_name = "RFC1459+TS8"; protocol_version = "ircd2.8.x"; protocol_features = 0; protocol_nickmax = 9; if (!register_messages(ts8_messages)) { module_log("Unable to register messages"); exit_module(1); return 0; } if (!add_callback(NULL, "set topic", do_set_topic)) { module_log("Unable to add callbacks"); exit_module(1); return 0; } init_modes(); send_nick = do_send_nick; send_nickchange = do_send_nickchange; send_namechange = do_send_namechange; send_server = do_send_server; send_server_remote = do_send_server_remote; wallops = do_wallops; notice_all = do_notice_all; send_channel_cmd = do_send_channel_cmd; pseudoclient_modes = ""; enforcer_modes = ""; return 1; } /*************************************************************************/ int exit_module(int shutdown) { if (!shutdown) { /* Do not allow removal */ return 0; } remove_callback(NULL, "set topic", do_set_topic); unregister_messages(ts8_messages); return 1; } /*************************************************************************/