Fix service triggers; allow service hostname configuration; fix glitches
[srvx.git] / src / proto-p10.c
index b711c101f709b5e63ef5537296dcd57c04f522b6..ac7ad8be62c338505607fa7db687e499f4eb0a8f 100644 (file)
@@ -1,11 +1,12 @@
 /* proto-p10.c - IRC protocol output
  * Copyright 2000-2004 srvx Development Team
  *
- * This program is free software; you can redistribute it and/or modify
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.  Important limitations are
- * listed in the COPYING file that accompanies this software.
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,7 +14,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, email srvx-maintainers@srvx.net.
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
 
 #include "proto-common.c"
@@ -472,6 +474,12 @@ irc_notice(struct userNode *from, const char *to, const char *message)
     putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message);
 }
 
+void
+irc_notice_user(struct userNode *from, struct userNode *to, const char *message)
+{
+    putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message);
+}
+
 void
 irc_privmsg(struct userNode *from, const char *to, const char *message)
 {
@@ -875,20 +883,14 @@ static void
 create_helper(char *name, void *data)
 {
     struct create_desc *cd = data;
-    /* We can't assume the channel create was allowed because of the
-     * bad-word channel checking.
-     */
-    struct chanNode *cn;
-    struct modeNode *mn;
+
     if (!strcmp(name, "0")) {
         while (cd->user->channels.used > 0)
             DelChannelUser(cd->user, cd->user->channels.list[0]->channel, 0, 0);
         return;
     }
-    cn = AddChannel(name, cd->when, NULL, NULL);
-    mn = AddChannelUser(cd->user, cn);
-    if (mn && (cn->members.used == 1))
-        mn->modes = MODE_CHANOP;
+
+    AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL));
 }
 
 static CMD_FUNC(cmd_create)
@@ -1124,7 +1126,8 @@ static CMD_FUNC(cmd_clearmode)
 
 static CMD_FUNC(cmd_topic)
 {
-    static struct chanNode *cn;
+    struct chanNode *cn;
+    time_t chan_ts, topic_ts;
 
     if (argc < 3)
         return 0;
@@ -1132,7 +1135,16 @@ static CMD_FUNC(cmd_topic)
         log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose topic is being set", argv[1]);
         return 0;
     }
-    SetChannelTopic(cn, GetUserH(origin), argv[2], 0);
+    if (argc >= 5) {
+        /* Looks like an Asuka style topic burst. */
+        chan_ts = atoi(argv[2]);
+        topic_ts = atoi(argv[3]);
+    } else {
+        chan_ts = cn->timestamp;
+        topic_ts = now;
+    }
+    SetChannelTopic(cn, GetUserH(origin), argv[argc-1], 0);
+    cn->topic_time = topic_ts;
     return 1;
 }
 
@@ -1506,6 +1518,7 @@ init_parse(void)
     dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
     dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
     dict_insert(irc_func_dict, "461", cmd_dummy); /* Not enough parameters (after TOPIC w/ 0 args) */
+    dict_insert(irc_func_dict, "467", cmd_dummy); /* Channel key already set */
 
     num_privmsg_funcs = 16;
     privmsg_funcs = malloc(sizeof(privmsg_func_t)*num_privmsg_funcs);
@@ -1724,7 +1737,7 @@ void DelServer(struct server* serv, int announce, const char *message)
 }
 
 struct userNode *
-AddService(const char *nick, const char *desc)
+AddService(const char *nick, const char *desc, const char *hostname)
 {
     char numeric[COMBO_NUMERIC_LEN+1];
     int local_num = get_local_numeric();
@@ -1740,8 +1753,10 @@ AddService(const char *nick, const char *desc)
         log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for service %s", nick);
         return 0;
     }
+    if (!hostname)
+        hostname = self->name;
     make_numeric(self, local_num, numeric);
-    return AddUser(self, nick, nick, self->name, "+oik", numeric, desc, now, "AAAAAA");
+    return AddUser(self, nick, nick, hostname, "+oik", numeric, desc, now, "AAAAAA");
 }
 
 struct userNode *
@@ -2041,10 +2056,16 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
                 victim = GetUserN(modes[in_arg++]);
             else
                 victim = GetUserH(modes[in_arg++]);
+            if (!victim)
+                continue;
             if ((change->args[ch_arg].member = GetUserMode(channel, victim)))
                 ch_arg++;
             break;
         }
+        default:
+            if (!(flags & MCP_FROM_SERVER))
+                goto error;
+            break;
         }
     }
     change->argc = ch_arg; /* in case any turned out to be ignored */
@@ -2077,7 +2098,8 @@ static void
 mod_chanmode_append(struct chanmode_buffer *buf, char ch, const char *arg)
 {
     size_t arg_len = strlen(arg);
-    if (buf->modes_used + buf->args_used + buf->chname_len + arg_len > 450) {
+    if (buf->modes_used > (MAXMODEPARAMS) ||
+        buf->modes_used + buf->args_used + buf->chname_len + arg_len > 450) {
         memcpy(buf->modes + buf->modes_used, buf->args, buf->args_used);
         buf->modes[buf->modes_used + buf->args_used] = '\0';
         irc_mode((buf->is_chanop ? buf->actor : NULL), buf->channel, buf->modes);
@@ -2099,6 +2121,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
     struct modeNode *mn;
     char int_buff[32], mode = '\0';
 
+    assert(change->argc <= change->alloc_argc);
     memset(&chbuf, 0, sizeof(chbuf));
     chbuf.channel = channel;
     chbuf.actor = who;
@@ -2200,6 +2223,7 @@ char *
 mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
 {
     unsigned int used = 0;
+    assert(change->argc <= change->alloc_argc);
     if (change->modes_clear) {
         outbuff[used++] = '-';
 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR