added UserBot rejoin system
authorpk910 <philipp@zoelle1.de>
Wed, 5 Sep 2012 02:17:16 +0000 (04:17 +0200)
committerpk910 <philipp@zoelle1.de>
Wed, 5 Sep 2012 02:23:24 +0000 (04:23 +0200)
neonserv.example.conf
src/ChanNode.h
src/IRCParser.c
src/bots.c

index d93cd4242ba5b83460d2f481e9ccd6eee99099fc..afa81c01de00b796ca245b5fcb01319709f51833 100644 (file)
         //180 miutes, every 2 seconds: 5400 auth checks
         "alertchan" = "#krypton.intern";
     };
+    "UserBots" {
+        "OtherServ" {
+            "enabled" = 1;
+            "nick" = "OtherServ,OtherServ2"; //optional check (mask)
+            "sourcebot" = "NeonServ"; //send messages through a bot of this botclass
+            "opless_part" = "PRIVMSG %s :part %s"; //args: botnick, channel
+            "opless_join" = "PRIVMSG %s :join %s"; //args: botnick, channel
+        };
+    };
 };
 "QServer" {
     "enabled" = 0;
index 6c71330298ee8408bb157ebfaa1d9b1e9250c6ec..f17792f3c2901be4180bd6bd4a3106151f5c5f7a 100644 (file)
@@ -22,6 +22,7 @@ struct ChanUser;
 struct trigger_cache;
 struct ModeNode;
 struct NeonSpamSettings;
+struct timeq_entry;
 
 #define CHANFLAG_RECEIVED_USERLIST  0x01
 #define CHANFLAG_REQUESTED_CHANINFO 0x02
@@ -45,7 +46,8 @@ struct ChanNode {
     
     struct NeonSpamSettings *spam_settings;
        
-    void *rejoin_array;
+    void *rejoin_bots;
+    struct timeq_entry *rejoin_timeout;
     
     struct ChanNode *next;
 };
index 1d53ec2aa1ba6c4e82e0d1a53a527ded07a56747..bd505f23ab514ff92106d39602d6a8ed53b3e2e6 100644 (file)
@@ -28,6 +28,8 @@
 #include "ModeNode.h"
 #include "tools.h"
 #include "bots.h"
+#include "timeq.h"
+#include "ConfigParser.h"
 
 struct irc_cmd *irc_commands = NULL;
 //static struct UserNode *registering_users = NULL;
@@ -38,6 +40,20 @@ int statistics_network_channels = 0;
 static void register_irc_function(char *command, irc_cmd_t *func);
 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
 
+struct OplessRejoinUserbot {
+    char *nick;
+    char *auth;
+};
+
+struct OplessRejoinBot {
+    unsigned char is_client;
+    union {
+        struct ClientSocket *client;
+        struct OplessRejoinUserbot *userbot;
+    } bot;
+    struct OplessRejoinBot *next;
+};
+
 void parse_line(struct ClientSocket *client, char *line) {
     int argc = 0;
     char *argv[MAXNUMPARAMS];
@@ -141,6 +157,153 @@ static IRC_CMD(raw_002) { //fixed: ZNC fakes a 001 raw even if we're not connect
     return 1;
 }
 
+static int check_userbot_rejoin(struct UserNode *user) {
+    if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
+    char tmp[MAXLEN];
+    sprintf(tmp, "General.UserBots.%s.enabled", user->auth);
+    if(!get_int_field(tmp))
+        return 0;
+    sprintf(tmp, "General.UserBots.%s.nicks", user->auth);
+    char *nicks = get_string_field(tmp);
+    if(nicks) {
+        char *cnick = nicks;
+        int matching_nick = 0;
+        do {
+            nicks = strchr(cnick, ',');
+            if(nicks) 
+                *nicks = '\0';
+            if(!match(cnick, user->nick))
+                matching_nick = 1;
+            if(nicks) {
+                *nicks = ',';
+                nicks++;
+            }
+        } while((cnick = nicks) && !matching_nick);
+        if(!matching_nick)
+            return 0;
+    }
+    sprintf(tmp, "General.UserBots.%s.opless_part", user->auth);
+    if(!get_string_field(tmp))
+        return 0;
+    return 1;
+}
+
+static void free_rejoin_clients(struct ChanNode *chan, int rejoin) {
+    struct OplessRejoinBot *rejoin_bot, *next_rejoin_bot;
+    char tmp[MAXLEN];
+    int sourceid;
+    struct ClientSocket *bot;
+    for(rejoin_bot = chan->rejoin_bots; rejoin_bot; rejoin_bot = next_rejoin_bot) {
+        next_rejoin_bot = rejoin_bot->next;
+        if(rejoin) {
+            if(rejoin_bot->is_client) {
+                putsock(rejoin_bot->bot.client, "JOIN %s", chan->name);
+            } else {
+                sprintf(tmp, "General.UserBots.%s.sourcebot", rejoin_bot->bot.userbot->auth);
+                if(get_string_field(tmp)) {
+                    sourceid = resolve_botalias(get_string_field(tmp));
+                    if(sourceid == -1)
+                        sourceid = 0;
+                } else 
+                    sourceid = 0;
+                bot = getChannelBot(NULL, sourceid);
+                if(!bot)
+                    bot = getChannelBot(NULL, 0);
+                sprintf(tmp, "General.UserBots.%s.opless_join", rejoin_bot->bot.userbot->auth);
+                if(get_string_field(tmp))
+                    putsock(bot, get_string_field(tmp), rejoin_bot->bot.userbot->nick, chan->name);
+            }
+        }
+        if(!rejoin_bot->is_client) {
+            free(rejoin_bot->bot.userbot->nick);
+            free(rejoin_bot->bot.userbot->auth);
+            free(rejoin_bot->bot.userbot);
+        }
+        free(rejoin_bot);
+    }
+    if(chan->rejoin_timeout)
+        timeq_del(chan->rejoin_timeout);
+}
+
+static TIMEQ_CALLBACK(full_rejoin_timeout) {
+    struct ChanNode *chan = data;
+    chan->rejoin_timeout = NULL;
+    free_rejoin_clients(chan, 1);
+    chan->flags &= ~CHANFLAG_REJOINING;
+}
+
+static void check_full_rejoin(struct ChanNode *chan) {
+    struct ChanUser *chanuser;
+    char do_rejoin = 1;
+    int botcount = 0;
+    int userbots = 0;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if((chanuser->flags & CHANUSERFLAG_OPPED) || !(isBot(chanuser->user) || check_userbot_rejoin(chanuser->user))) {
+            do_rejoin = 0;
+            break;
+        }
+        botcount++;
+        if(!isBot(chanuser->user))
+            userbots++;
+    }
+    if(do_rejoin) {
+        struct OplessRejoinBot *rejoin_bot;
+        struct ClientSocket *bot, *chanbot = NULL;
+        chan->rejoin_bots = NULL;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(!isUserOnChan(bot->user, chan))
+                continue;
+            if(!chanbot && ((bot->flags & SOCKET_FLAG_PREFERRED) || !getBots(SOCKET_FLAG_READY, bot)))
+                chanbot = bot;
+            else {
+                rejoin_bot = malloc(sizeof(*rejoin_bot));
+                rejoin_bot->is_client = 1;
+                rejoin_bot->bot.client = bot;
+                rejoin_bot->next = chan->rejoin_bots;
+                chan->rejoin_bots = rejoin_bot;
+                putsock(bot, "PART %s :rejoining", chan->name);
+            }
+        }
+        if(userbots) {
+            char tmp[MAXLEN];
+            int sourceid;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if(check_userbot_rejoin(chanuser->user)) {
+                    rejoin_bot = malloc(sizeof(*rejoin_bot));
+                    rejoin_bot->is_client = 0;
+                    rejoin_bot->bot.userbot = malloc(sizeof(struct OplessRejoinUserbot));
+                    rejoin_bot->bot.userbot->nick = strdup(chanuser->user->nick);
+                    rejoin_bot->bot.userbot->auth = strdup(chanuser->user->auth);
+                    rejoin_bot->next = chan->rejoin_bots;
+                    chan->rejoin_bots = rejoin_bot;
+                    sprintf(tmp, "General.UserBots.%s.sourcebot", chanuser->user->auth);
+                    if(get_string_field(tmp)) {
+                        sourceid = resolve_botalias(get_string_field(tmp));
+                        if(sourceid == -1)
+                            sourceid = 0;
+                    } else 
+                        sourceid = 0;
+                    bot = getChannelBot(NULL, sourceid);
+                    if(!bot)
+                        bot = getChannelBot(NULL, 0);
+                    sprintf(tmp, "General.UserBots.%s.opless_part", chanuser->user->auth);
+                    putsock(bot, get_string_field(tmp), chanuser->user->nick, chan->name);
+                }
+            }
+        }
+        
+        if(botcount == 1) {
+            //we're alone
+            free(chan->rejoin_bots);
+            putsock(chanbot, "PART %s :magic hop", chan->name);
+            putsock(chanbot, "JOIN %s", chan->name);
+        } else {
+            chan->flags |= CHANFLAG_REJOINING;
+            chan->rejoin_timeout = timeq_add(10, 0, full_rejoin_timeout, chan);
+        }
+    }
+}
+
 static IRC_CMD(raw_join) {
     if(from == NULL || argc < 1) return 0;
     SYNCHRONIZE(cache_sync);
@@ -197,12 +360,7 @@ static IRC_CMD(raw_join) {
         
         if(!(user->flags & USERFLAG_ISBOT) && (chan->flags & CHANFLAG_REJOINING)) {
             //ABORT AUTOMATIC REJOIN (security break)
-            struct ClientSocket **clients = chan->rejoin_array;
-            while(*clients) {
-                putsock(*clients, "JOIN %s", chan->name);
-                clients++;
-            }
-            free(chan->rejoin_array);
+            free_rejoin_clients(chan, 1);
             chan->flags &= ~CHANFLAG_REJOINING;
         }
     } else { 
@@ -220,44 +378,6 @@ static IRC_CMD(raw_join) {
     return 1;
 }
 
-static void check_full_rejoin(struct ChanNode *chan) {
-    struct ChanUser *chanuser;
-    char do_rejoin = 1;
-    int botcount = 0;
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if((chanuser->flags & CHANUSERFLAG_OPPED) || !(chanuser->user->flags & USERFLAG_ISBOT)) {
-            do_rejoin = 0;
-            break;
-        }
-        if((chanuser->user->flags & USERFLAG_ISBOT))
-            botcount++;
-    }
-    if(do_rejoin) {
-        struct ClientSocket **clients = calloc(botcount, sizeof(*clients));
-        struct ClientSocket *bot, *chanbot = NULL;
-        int i = 0;
-        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-            if(!isUserOnChan(bot->user, chan))
-                continue;
-            if(!chanbot && ((bot->flags & SOCKET_FLAG_PREFERRED) || !getBots(SOCKET_FLAG_READY, bot)))
-                chanbot = bot;
-            else {
-                clients[i++] = bot;
-                putsock(bot, "PART %s :rejoining", chan->name);
-            }
-        }
-        if(botcount == 1) {
-            //we're alone
-            free(clients);
-            putsock(chanbot, "PART %s :magic hop", chan->name);
-            putsock(chanbot, "JOIN %s", chan->name);
-        } else {
-            chan->flags |= CHANFLAG_REJOINING;
-            chan->rejoin_array = clients;
-        }
-    }
-}
-
 static IRC_CMD(raw_part) {
     if(from == NULL || argc < 1) return 0;
     SYNCHRONIZE(cache_sync);
@@ -281,12 +401,7 @@ static IRC_CMD(raw_part) {
     int keep_channel = 1;
     if(chan->usercount == 0) {
         if((chan->flags & CHANFLAG_REJOINING)) {
-            struct ClientSocket **clients = chan->rejoin_array;
-            while(*clients) {
-                putsock(*clients, "JOIN %s", chan->name);
-                clients++;
-            }
-            free(chan->rejoin_array);
+            free_rejoin_clients(chan, 1);
             chan->flags &= ~CHANFLAG_REJOINING;
         }
         delChannel(chan, 1);
@@ -339,12 +454,7 @@ static IRC_CMD(raw_kick) {
     int keep_channel = 1;
     if(chan->usercount == 0) {
         if((chan->flags & CHANFLAG_REJOINING)) {
-            struct ClientSocket **clients = chan->rejoin_array;
-            while(*clients) {
-                putsock(*clients, "JOIN %s", chan->name);
-                clients++;
-            }
-            free(chan->rejoin_array);
+            free_rejoin_clients(chan, 1);
             chan->flags &= ~CHANFLAG_REJOINING;
         }
         delChannel(chan, 1);
index 4875b5a5c987e97036c6084b704c2ddb58a58362..aaddcb705b1e34b89c1bb2dc975d98005e0b3d04 100644 (file)
@@ -151,8 +151,8 @@ struct ClientSocket *getChannelBot(struct ChanNode *chan, int botid) {
     struct ChanUser *chanuser;
     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
         if(botid && bot->botid != botid) continue;
-        if((chanuser = getChanUser(bot->user, chan)) != NULL) {
-            if((chanuser->flags & CHANUSERFLAG_OPPED)) {
+        if(!chan || (chanuser = getChanUser(bot->user, chan)) != NULL) {
+            if(chan && (chanuser->flags & CHANUSERFLAG_OPPED)) {
                 use_bot = bot;
                 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
             } else if(bot->flags & SOCKET_FLAG_PREFERRED)