Fix unreg_{notice,privmsg}_func().
[srvx.git] / src / proto-bahamut.c
index d63aef01a2cc7fae8710b62aa0b12336c519dd0f..0e8309feb358939feabbe2859a953a7b5a47d817 100644 (file)
@@ -1,5 +1,5 @@
 /* proto-bahamut.c - IRC protocol output
- * Copyright 2000-2004 srvx Development Team
+ * Copyright 2000-2006 srvx Development Team
  *
  * This file is part of srvx.
  *
@@ -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++) {
@@ -171,10 +175,14 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char *
 }
 
 struct userNode *
-AddService(const char *nick, const char *modes, const char *desc, const char *hostname) {
+AddLocalUser(const char *nick, const char *ident, const char *hostname, const char *desc, const char *modes)
+{
     time_t timestamp = now;
     struct userNode *old_user = GetUserH(nick);
     static const irc_in_addr_t ipaddr;
+
+    if (!modes)
+        modes = "+oikr";
     if (old_user) {
         if (IsLocal(old_user))
             return old_user;
@@ -182,20 +190,7 @@ AddService(const char *nick, const char *modes, const char *desc, const char *ho
     }
     if (!hostname)
         hostname = self->name;
-    return AddUser(self, nick, nick, hostname, modes ? modes : "+oikr", desc, timestamp, ipaddr, 0);
-}
-
-struct userNode *
-AddClone(const char *nick, const char *ident, const char *hostname, const char *desc) {
-    time_t timestamp = now;
-    struct userNode *old_user = GetUserH(nick);
-    static const irc_in_addr_t ipaddr;
-    if (old_user) {
-        if (IsLocal(old_user))
-            return old_user;
-        timestamp = old_user->timestamp - 1;
-    }
-    return AddUser(self, nick, ident, hostname, "+ir", desc, timestamp, ipaddr, 0);
+    return AddUser(self, nick, ident, hostname, modes, desc, timestamp, ipaddr, 0);
 }
 
 void
@@ -210,7 +205,7 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char
     unsigned int nn;
 
     for (nn=user->channels.used; nn>0;) {
-        DelChannelUser(user, user->channels.list[--nn]->channel, false, 0);
+        DelChannelUser(user, user->channels.list[--nn]->channel, NULL, false);
     }
     for (nn=duf_used; nn>0; ) duf_list[--nn](user, killer, why);
     user->uplink->clients--;
@@ -225,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) {
@@ -247,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';
@@ -362,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
@@ -892,12 +918,6 @@ static CMD_FUNC(cmd_topic) {
     return 1;
 }
 
-static CMD_FUNC(cmd_part) {
-    if (argc < 2) return 0;
-    parse_foreach(argv[1], part_helper, NULL, NULL, NULL, GetUserH(origin));
-    return 1;
-}
-
 static CMD_FUNC(cmd_away) {
     struct userNode *un;
 
@@ -1153,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);
@@ -1163,6 +1195,18 @@ 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)
 {
@@ -1208,17 +1252,14 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
                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;
        }
 #undef do_user_mode
     }