Do not eat first word in ?part reason.
[srvx.git] / src / proto-bahamut.c
index faa89fe9a1301478d3def034187a2219897ad942..6483ba34285f707f2a0444a46c98219e160be7da 100644 (file)
@@ -114,14 +114,17 @@ 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) {
     struct userNode *uNode, *oldUser;
-    unsigned int nn;
+    unsigned int nn, dummy;
 
     if (!uplink) {
         log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server does not exist!", uplink, nick);
         return NULL;
     }
 
-    if (!is_valid_nick(nick)) {
+    dummy = modes && modes[0] == '*';
+    if (dummy) {
+        ++modes;
+    } else if (!is_valid_nick(nick)) {
         log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, nick);
         return NULL;
     }
@@ -162,6 +165,7 @@ 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 (IsLocal(uNode)) irc_user(uNode);
     for (nn=0; nn<nuf_used; nn++) {
@@ -216,6 +220,7 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char
             irc_kill(killer, user, why);
         }
     }
+    dict_remove(service_msginfo_dict, user->nick);
     modeList_clean(&user->channels);
     user->dead = 1;
     if (dead_users.size) {
@@ -238,11 +243,11 @@ 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 (IsServNotice(user)) modes[modelen++] = 's';
     if (IsDeaf(user)) modes[modelen++] = 'd';
     if (IsReggedNick(user)) modes[modelen++] = 'r';
     if (IsGlobal(user)) modes[modelen++] = 'g';
@@ -353,19 +358,49 @@ irc_squit(struct server *srv, const char *message, const char *service_message)
     }
 }
 
+static int
+deliver_to_dummy(struct userNode *source, struct userNode *dest, const char *message, int type)
+{
+    struct service_message_info *smi;
+
+    if (!dest || !IsDummy(dest) || !IsLocal(dest))
+        return 0;
+    smi = dict_find(service_msginfo_dict, dest->nick, NULL);
+    switch (type) {
+    default:
+        if (smi && smi->on_privmsg)
+        {
+            smi->on_privmsg(source, dest, message, 0);
+            return 1;
+        }
+        break;
+    case 1:
+        if (smi && smi->on_notice)
+        {
+            smi->on_notice(source, dest, message, 0);
+            return 1;
+        }
+        break;
+    }
+    return 0;
+}
+
 void
 irc_privmsg(struct userNode *from, const char *to, const char *message) {
-    putsock(":%s PRIVMSG %s :%s", from->nick, to, message);
+    if (!deliver_to_dummy(from, GetUserH(to), message, 1))
+        putsock(":%s PRIVMSG %s :%s", from->nick, to, message);
 }
 
 void
 irc_notice(struct userNode *from, const char *to, const char *message) {
-    putsock(":%s NOTICE %s :%s", from->nick, to, message);
+    if (!deliver_to_dummy(from, GetUserH(to), message, 0))
+        putsock(":%s NOTICE %s :%s", from->nick, to, message);
 }
 
 void
 irc_notice_user(struct userNode *from, struct userNode *to, const char *message) {
-    putsock(":%s NOTICE %s :%s", from->nick, to->nick, message);
+    if (!deliver_to_dummy(from, to, message, 0))
+        putsock(":%s NOTICE %s :%s", from->nick, to->nick, message);
 }
 
 void
@@ -395,9 +430,9 @@ 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 "FMT_TIME_T" %s %lu", nickserv->nick, target->nick, target->timestamp, modes, stamp);
     } else {
-       putsock(":%s SVSMODE %s "FMT_TIME_T" %s", nickserv->nick, target->nick, target->timestamp, modes);
+        putsock(":%s SVSMODE %s "FMT_TIME_T" %s", nickserv->nick, target->nick, target->timestamp, modes);
     }
 }
 
@@ -515,47 +550,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 == ',');
 }
 
@@ -923,10 +958,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;
 }
@@ -1103,7 +1138,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++) {
@@ -1138,6 +1173,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);
@@ -1148,17 +1195,29 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) {
     info->on_notice = handler;
 }
 
+void
+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);
+        }
+    }
+}
+
 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));
-       }
+        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;
 }
@@ -1170,7 +1229,7 @@ call_oper_funcs(struct userNode *user)
     if (IsLocal(user)) return;
     for (n=0; n<of_used; n++)
     {
-       of_list[n](user);
+        of_list[n](user);
     }
 }
 
@@ -1180,31 +1239,28 @@ 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 'O': do_user_mode(FLAGS_LOCOP); 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 's': do_user_mode(FLAGS_SERVNOTICE); 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;
-       case 'h': do_user_mode(FLAGS_HELPER); 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
     }
 }
@@ -1240,14 +1296,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) {