Merge remote branch 'upstream/master'
[srvx.git] / src / proto-bahamut.c
index d2edc2a3b48629db744d980300835d897631729c..a0c1d98ef102d5f80004c0a05aa3cb8dc21a2f79 100644 (file)
@@ -38,10 +38,13 @@ static dict_t service_msginfo_dict; /* holds service_message_info structs */
 static int uplink_capab;
 static void privmsg_user_helper(struct userNode *un, void *data);
 
+/* These correspond to 1 << X:      012345678901234567 */
+const char irc_user_mode_chars[] = "o iw dkg      r   ";
+
 void irc_svsmode(struct userNode *target, char *modes, unsigned long stamp);
 
 struct server *
-AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t link, UNUSED_ARG(const char *numeric), const char *description) {
+AddServer(struct server *uplink, const char *name, int hops, unsigned long boot, unsigned long link_time, UNUSED_ARG(const char *numeric), const char *description) {
     struct server* sNode;
 
     sNode = calloc(1, sizeof(*sNode));
@@ -49,7 +52,7 @@ AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t
     safestrncpy(sNode->name, name, sizeof(sNode->name));
     sNode->hops = hops;
     sNode->boot = boot;
-    sNode->link = link;
+    sNode->link_time = link_time;
     sNode->users = dict_new();
     safestrncpy(sNode->description, description, sizeof(sNode->description));
     serverList_init(&sNode->children);
@@ -112,7 +115,7 @@ is_valid_nick(const char *nick) {
 }
 
 struct userNode *
-AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *userinfo, time_t timestamp, irc_in_addr_t realip, const char *stamp) {
+AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *userinfo, unsigned long timestamp, irc_in_addr_t realip, unsigned long stamp) {
     struct userNode *uNode, *oldUser;
     unsigned int nn, dummy;
 
@@ -166,18 +169,17 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char *
 
     mod_usermode(uNode, modes);
     if (dummy) uNode->modes |= FLAGS_DUMMY;
-    if (stamp) call_account_func(uNode, stamp);
+    if (stamp) call_account_func(uNode, NULL, 0, stamp);
     if (IsLocal(uNode)) irc_user(uNode);
-    for (nn=0; nn<nuf_used; nn++) {
-        if (nuf_list[nn](uNode)) break;
-    }
+    for (nn=0; (nn<nuf_used) && !uNode->dead; nn++)
+        nuf_list[nn](uNode);
     return uNode;
 }
 
 struct userNode *
 AddLocalUser(const char *nick, const char *ident, const char *hostname, const char *desc, const char *modes)
 {
-    time_t timestamp = now;
+    unsigned long timestamp = now;
     struct userNode *old_user = GetUserH(nick);
     static const irc_in_addr_t ipaddr;
 
@@ -242,33 +244,26 @@ irc_server(struct server *srv) {
 void
 irc_user(struct userNode *user) {
     char modes[32];
-    int modelen = 0;
     if (!user || user->nick[0] != ' ') return;
-    if (IsOper(user)) modes[modelen++] = 'o';
-    if (IsInvisible(user)) modes[modelen++] = 'i';
-    if (IsWallOp(user)) modes[modelen++] = 'w';
-    if (IsService(user)) modes[modelen++] = 'k';
-    if (IsDeaf(user)) modes[modelen++] = 'd';
-    if (IsReggedNick(user)) modes[modelen++] = 'r';
-    if (IsGlobal(user)) modes[modelen++] = 'g';
-    modes[modelen] = 0;
-    putsock("NICK %s %d "FMT_TIME_T" +%s %s %s %s %d %u :%s",
-            user->nick, user->uplink->hops+2, user->timestamp, modes,
-            user->ident, user->hostname, user->uplink->name, 0, ntohl(user->ip.in6_32[3]), user->info);
+    irc_user_modes(user, modes, sizeof(modes));
+    putsock("NICK %s %d %lu +%s %s %s %s %d %u :%s",
+            user->nick, user->uplink->hops+2, (unsigned long)user->timestamp,
+            modes, user->ident, user->hostname, user->uplink->name, 0,
+            ntohl(user->ip.in6_32[3]), user->info);
 }
 
 void
-irc_account(struct userNode *user, const char *stamp)
+irc_account(struct userNode *user, UNUSED_ARG(const char *stamp), UNUSED_ARG(unsigned long timestamp), unsigned long serial)
 {
     if (IsReggedNick(user)) {
-        irc_svsmode(user, "+rd", base64toint(stamp, IDLEN));
+        irc_svsmode(user, "+rd", serial);
     } else {
-        irc_svsmode(user, "+d", base64toint(stamp, IDLEN));
+        irc_svsmode(user, "+d", serial);
     }
 }
 
 void
-irc_fakehost(UNUSED_ARG(struct userNode *user), UNUSED_ARG(const char *host))
+irc_fakehost(UNUSED_ARG(struct userNode *user), UNUSED_ARG(const char *host), UNUSED_ARG(const char *ident), UNUSED_ARG(int force))
 {
     /* not supported in bahamut */
 }
@@ -293,7 +288,7 @@ irc_nick(struct userNode *user, const char *old_nick) {
             dict_insert(service_msginfo_dict, user->nick, smi);
         }
     }
-    putsock(":%s NICK %s :"FMT_TIME_T, old_nick, user->nick, user->timestamp);
+    putsock(":%s NICK %s :%lu", old_nick, user->nick, (unsigned long)user->timestamp);
 }
 
 void
@@ -308,12 +303,12 @@ irc_capab() {
 
 void
 irc_svinfo() {
-    putsock("SVINFO 3 3 0 :"FMT_TIME_T, now);
+    putsock("SVINFO 3 3 0 :%lu", (unsigned long)now);
 }
 
 void
 irc_introduce(const char *passwd) {
-    extern time_t burst_begin;
+    extern unsigned long burst_begin;
 
     irc_pass(passwd);
     irc_capab();
@@ -410,9 +405,9 @@ irc_wallchops(UNUSED_ARG(struct userNode *from), UNUSED_ARG(const char *to), UNU
 void
 irc_join(struct userNode *who, struct chanNode *what) {
     if (what->members.used == 1) {
-        putsock(":%s SJOIN "FMT_TIME_T" %s + :@%s", self->name, what->timestamp, what->name, who->nick);
+        putsock(":%s SJOIN %lu %s + :@%s", self->name, (unsigned long)what->timestamp, what->name, who->nick);
     } else {
-        putsock(":%s SJOIN "FMT_TIME_T" %s", who->nick, what->timestamp, what->name);
+        putsock(":%s SJOIN %lu %s", who->nick, (unsigned long)what->timestamp, what->name);
     }
 }
 
@@ -423,16 +418,16 @@ irc_invite(struct userNode *from, struct userNode *who, struct chanNode *to) {
 
 void
 irc_mode(struct userNode *who, struct chanNode *target, const char *modes) {
-    putsock(":%s MODE %s "FMT_TIME_T" %s", who->nick, target->name, target->timestamp, modes);
+    putsock(":%s MODE %s %lu %s", who->nick, target->name, (unsigned long)target->timestamp, modes);
 }
 
 void
 irc_svsmode(struct userNode *target, char *modes, unsigned long stamp) {
     extern struct userNode *nickserv;
     if (stamp) {
-       putsock(":%s SVSMODE %s "FMT_TIME_T" %s %lu", nickserv->nick, target->nick, target->timestamp, modes, stamp);
+        putsock(":%s SVSMODE %s %lu %s %lu", nickserv->nick, target->nick, (unsigned long)target->timestamp, modes, stamp);
     } else {
-       putsock(":%s SVSMODE %s "FMT_TIME_T" %s", nickserv->nick, target->nick, target->timestamp, modes);
+        putsock(":%s SVSMODE %s %lu %s", nickserv->nick, target->nick, (unsigned long)target->timestamp, modes);
     }
 }
 
@@ -478,11 +473,11 @@ irc_gline(struct server *srv, struct gline *gline) {
     if (len > ArrayLength(ident)) len = ArrayLength(ident);
     safestrncpy(ident, gline->target, len);
     safestrncpy(host, sep+1, ArrayLength(host));
-    putsock(":%s AKILL %s %s "FMT_TIME_T" %s "FMT_TIME_T" :%s", self->name, host, ident, gline->expires-gline->issued, gline->issuer, gline->issued, gline->reason);
+    putsock(":%s AKILL %s %s %lu %s %lu :%s", self->name, host, ident, (unsigned long)(gline->expires-gline->issued), gline->issuer, (unsigned long)gline->issued, gline->reason);
 }
 
 void
-irc_settime(UNUSED_ARG(const char *srv_name_mask), UNUSED_ARG(time_t new_time))
+irc_settime(UNUSED_ARG(const char *srv_name_mask), UNUSED_ARG(unsigned long new_time))
 {
     /* Bahamut has nothing like this, so ignore it. */
 }
@@ -533,7 +528,7 @@ irc_stats(struct userNode *from, struct server *target, char type) {
 void
 irc_svsnick(struct userNode *from, struct userNode *target, const char *newnick)
 {
-    putsock(":%s SVSNICK %s %s :"FMT_TIME_T, from->nick, target->nick, newnick, now);
+    putsock(":%s SVSNICK %s %s :%lu", from->nick, target->nick, newnick, (unsigned long)now);
 }
 
 void
@@ -550,47 +545,47 @@ static void
 parse_foreach(char *target_list, foreach_chanfunc cf, foreach_nonchan nc, foreach_userfunc uf, foreach_nonuser nu, void *data) {
     char *j, old;
     do {
-       j = target_list;
-       while (*j != 0 && *j != ',') j++;
-       old = *j;
+        j = target_list;
+        while (*j != 0 && *j != ',') j++;
+        old = *j;
         *j = 0;
-       if (IsChannelName(target_list)) {
-           struct chanNode *chan = GetChannel(target_list);
+        if (IsChannelName(target_list)) {
+            struct chanNode *chan = GetChannel(target_list);
             if (chan) {
                 if (cf) cf(chan, data);
             } else {
                 if (nc) nc(target_list, data);
             }
-       } else {
-           struct userNode *user;
+        } else {
+            struct userNode *user;
             struct privmsg_desc *pd = data;
 
             pd->is_qualified = 0;
             if (*target_list == '@') {
                 user = NULL;
             } else if (strchr(target_list, '@')) {
-               struct server *server;
+                struct server *server;
 
                 pd->is_qualified = 1;
-               user = GetUserH(strtok(target_list, "@"));
-               server = GetServerH(strtok(NULL, "@"));
-
-               if (user && (user->uplink != server)) {
-                   /* Don't attempt to index into any arrays
-                      using a user's numeric on another server. */
-                   user = NULL;
-               }
-           } else {
-               user = GetUserH(target_list);
-           }
+                user = GetUserH(strtok(target_list, "@"));
+                server = GetServerH(strtok(NULL, "@"));
+
+                if (user && (user->uplink != server)) {
+                    /* Don't attempt to index into any arrays
+                       using a user's numeric on another server. */
+                    user = NULL;
+                }
+            } else {
+                user = GetUserH(target_list);
+            }
 
             if (user) {
                 if (uf) uf(user, data);
             } else {
                 if (nu) nu(target_list, data);
             }
-       }
-       target_list = j+1;
+        }
+        target_list = j+1;
     } while (old == ',');
 }
 
@@ -685,7 +680,7 @@ static void burst_channel(struct chanNode *chan) {
 
     if (!chan->members.used) return;
     /* send list of users in the channel.. */
-    base_len = sprintf(line, ":%s SJOIN "FMT_TIME_T" %s ", self->name, chan->timestamp, chan->name);
+    base_len = sprintf(line, ":%s SJOIN %lu %s ", self->name, (unsigned long)chan->timestamp, chan->name);
     len = irc_make_chanmode(chan, line+base_len);
     pos = base_len + len;
     line[pos++] = ' ';
@@ -711,7 +706,7 @@ static void burst_channel(struct chanNode *chan) {
     line[pos] = 0;
     putsock("%s", line);
     /* now send the bans.. */
-    base_len = sprintf(line, ":%s MODE "FMT_TIME_T" %s +", self->name, chan->timestamp, chan->name);
+    base_len = sprintf(line, ":%s MODE %lu %s +", self->name, (unsigned long)chan->timestamp, chan->name);
     pos = sizeof(line)-1;
     line[pos] = 0;
     for (nn=queued=0; nn<chan->banlist.used; nn++) {
@@ -804,16 +799,14 @@ static CMD_FUNC(cmd_nick) {
         NickChange(un, argv[1], 1);
     } else {
         /* new nick from a server */
-        char id[8];
         unsigned long stamp;
         irc_in_addr_t ip;
 
         if (argc < 10) return 0;
         stamp = strtoul(argv[8], NULL, 0);
-        if (stamp) inttobase64(id, stamp, IDLEN);
         if (argc > 10)
             ip.in6_32[3] = htonl(atoi(argv[9]));
-        un = AddUser(GetServerH(argv[7]), argv[1], argv[5], argv[6], argv[4], argv[argc-1], atoi(argv[3]), ip, (stamp ? id : 0));
+        un = AddUser(GetServerH(argv[7]), argv[1], argv[5], argv[6], argv[4], argv[argc-1], atoi(argv[3]), ip, stamp);
     }
     return 1;
 }
@@ -958,10 +951,10 @@ static CMD_FUNC(cmd_pong)
 {
     if (argc < 3) return 0;
     if (!strcmp(argv[2], self->name)) {
-       timeq_del(0, timed_send_ping, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
-       timeq_del(0, timed_ping_timeout, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
-       timeq_add(now + ping_freq, timed_send_ping, 0);
-       received_ping();
+        timeq_del(0, timed_send_ping, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
+        timeq_del(0, timed_ping_timeout, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
+        timeq_add(now + ping_freq, timed_send_ping, 0);
+        received_ping();
     }
     return 1;
 }
@@ -1044,12 +1037,9 @@ static CMD_FUNC(cmd_svsnick)
     return 1;
 }
 
-static oper_func_t *of_list;
-static unsigned int of_size = 0, of_used = 0;
-
 void parse_cleanup(void) {
     unsigned int nn;
-    if (of_list) free(of_list);
+    free(of_list);
     dict_delete(irc_func_dict);
     dict_delete(service_msginfo_dict);
     free(mcf_list);
@@ -1115,6 +1105,7 @@ void init_parse(void) {
 
     userList_init(&dead_users);
     reg_exit_func(parse_cleanup);
+    (void)call_xquery_funcs;
 }
 
 int parse_line(char *line, int recursive) {
@@ -1138,7 +1129,7 @@ int parse_line(char *line, int recursive) {
         res = 0;
     }
     if (!res) {
-       log_module(MAIN_LOG, LOG_ERROR, "PARSE ERROR on line: %s", unsplit_string(argv, argc, NULL));
+        log_module(MAIN_LOG, LOG_ERROR, "PARSE ERROR on line: %s", unsplit_string(argv, argc, NULL));
     } else if (!recursive) {
         unsigned int i;
         for (i=0; i<dead_users.used; i++) {
@@ -1173,6 +1164,18 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler) {
     info->on_privmsg = handler;
 }
 
+void
+unreg_privmsg_func(struct userNode *user) {
+    struct service_message_info *info;
+    info = dict_find(service_msginfo_dict, user->nick, NULL);
+    if (info) {
+        info->on_privmsg = NULL;
+        if (info->on_notice == NULL) {
+            dict_remove(service_msginfo_dict, user->nick);
+        }
+    }
+}
+
 void
 reg_notice_func(struct userNode *user, privmsg_func_t handler) {
     struct service_message_info *info = dict_find(service_msginfo_dict, user->nick, NULL);
@@ -1184,28 +1187,14 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) {
 }
 
 void
-reg_oper_func(oper_func_t handler)
-{
-    if (of_used == of_size) {
-       if (of_size) {
-           of_size <<= 1;
-           of_list = realloc(of_list, of_size*sizeof(oper_func_t));
-       } else {
-           of_size = 8;
-           of_list = malloc(of_size*sizeof(oper_func_t));
-       }
-    }
-    of_list[of_used++] = handler;
-}
-
-static void
-call_oper_funcs(struct userNode *user)
-{
-    unsigned int n;
-    if (IsLocal(user)) return;
-    for (n=0; n<of_used; n++)
-    {
-       of_list[n](user);
+unreg_notice_func(struct userNode *user) {
+    struct service_message_info *info;
+    info = dict_find(service_msginfo_dict, user->nick, NULL);
+    if (info) {
+        info->on_notice = NULL;
+        if (info->on_privmsg == NULL) {
+            dict_remove(service_msginfo_dict, user->nick);
+        }
     }
 }
 
@@ -1215,34 +1204,34 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
     if (!user || !mode_change) return;
     while (1) {
 #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
-       switch (*mode_change++) {
-       case 0: return;
-       case '+': add = 1; break;
-       case '-': add = 0; break;
-       case 'o':
-           do_user_mode(FLAGS_OPER);
-           if (add) {
-               userList_append(&curr_opers, user);
-               call_oper_funcs(user);
-           } else {
-               userList_remove(&curr_opers, user);
-           }
-           break;
-       case 'i': do_user_mode(FLAGS_INVISIBLE);
-           if (add) invis_clients++; else invis_clients--;
-           break;
-       case 'w': do_user_mode(FLAGS_WALLOP); break;
-       case 'd': do_user_mode(FLAGS_DEAF); break;
-       case 'r': do_user_mode(FLAGS_REGNICK); break;
-       case 'k': do_user_mode(FLAGS_SERVICE); break;
-       case 'g': do_user_mode(FLAGS_GLOBAL); break;
-       }
+        switch (*mode_change++) {
+        case 0: return;
+        case '+': add = 1; break;
+        case '-': add = 0; break;
+        case 'o':
+            do_user_mode(FLAGS_OPER);
+            if (add) {
+                userList_append(&curr_opers, user);
+                call_oper_funcs(user);
+            } else {
+                userList_remove(&curr_opers, user);
+            }
+            break;
+        case 'i': do_user_mode(FLAGS_INVISIBLE);
+            if (add) invis_clients++; else invis_clients--;
+            break;
+        case 'w': do_user_mode(FLAGS_WALLOP); break;
+        case 'd': do_user_mode(FLAGS_DEAF); break;
+        case 'r': do_user_mode(FLAGS_REGNICK); break;
+        case 'k': do_user_mode(FLAGS_SERVICE); break;
+        case 'g': do_user_mode(FLAGS_GLOBAL); break;
+        }
 #undef do_user_mode
     }
 }
 
 struct mod_chanmode *
-mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags, short base_oplevel)
+mod_chanmode_parse(struct chanNode *channel, struct userNode *user, char **modes, unsigned int argc, unsigned int flags, short base_oplevel)
 {
     struct mod_chanmode *change;
     unsigned int ii, in_arg, ch_arg, add;
@@ -1272,14 +1261,14 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
         case 'p': do_chan_mode(MODE_PRIVATE); break;
         case 's': do_chan_mode(MODE_SECRET); break;
         case 't': do_chan_mode(MODE_TOPICLIMIT); break;
-       case 'r':
-           if (!(flags & MCP_REGISTERED)) {
-            do_chan_mode(MODE_REGISTERED);
-           } else {
-            mod_chanmode_free(change);
-            return NULL;
-           }
-           break;
+        case 'r':
+            if (!(flags & MCP_REGISTERED)) {
+             do_chan_mode(MODE_REGISTERED);
+            } else {
+             mod_chanmode_free(change);
+             return NULL;
+            }
+            break;
 #undef do_chan_mode
         case 'l':
             if (add) {
@@ -1485,6 +1474,9 @@ char *
 mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
 {
     unsigned int used = 0;
+    unsigned int args_used = 0;
+    char args[MAXLEN];
+
     assert(change->argc <= change->alloc_argc);
     if (change->modes_clear) {
         outbuff[used++] = '-';
@@ -1516,19 +1508,11 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
         DO_MODE_CHAR(REGONLY, 'R');
         DO_MODE_CHAR(NOCOLORS, 'c');
         DO_MODE_CHAR(REGISTERED, 'r');
+        DO_MODE_CHAR(LIMIT, 'l'), args_used += sprintf(args + args_used, " %d", change->new_limit);
+        DO_MODE_CHAR(KEY, 'k'), args_used += sprintf(args + args_used, " %s", change->new_key);
 #undef DO_MODE_CHAR
-        switch (change->modes_set & (MODE_KEY|MODE_LIMIT)) {
-        case MODE_KEY|MODE_LIMIT:
-            used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
-            break;
-        case MODE_KEY:
-            used += sprintf(outbuff+used, "k %s", change->new_key);
-            break;
-        case MODE_LIMIT:
-            used += sprintf(outbuff+used, "l %d", change->new_limit);
-            break;
-        }
     }
-    outbuff[used] = 0;
+    args[args_used] = '\0';
+    strcpy(outbuff + used, args);
     return outbuff;
 }