added automatic multi-bot rejoin for opless channels
authorpk910 <philipp@zoelle1.de>
Sat, 10 Dec 2011 07:53:21 +0000 (08:53 +0100)
committerpk910 <philipp@zoelle1.de>
Sat, 10 Dec 2011 08:24:54 +0000 (09:24 +0100)
src/ChanNode.c
src/ChanNode.h
src/IRCParser.c
src/bots.c
src/bots.h
src/event_neonserv_join.c
src/event_neonspam_join.c

index bafc3bd055e9ca8263bc5b2529a6b726ccc7eaae..a24de3a1eca8fbcd86f97d5cdd44599556aafb94 100644 (file)
@@ -229,12 +229,12 @@ void freeChanNode(struct ChanNode* chan) {
     free(chan);
 }
 
-void checkChannelVisibility(struct ChanNode* chan) {
+int checkChannelVisibility(struct ChanNode* chan) {
     struct ChanUser *chanuser, *next;
     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
         if(chanuser->user->flags & USERFLAG_ISBOT) {
             chan->chanbot = chanuser->user;
-            return;
+            return 1;
         }
     }
     //free the channel...
@@ -250,4 +250,5 @@ void checkChannelVisibility(struct ChanNode* chan) {
     }
     chan->user = NULL;
     delChannel(chan, 1);
+    return 0;
 }
index 9cb67e3d17f5f7977cf2226a65f524b7e7f7c918..74e50a86fa0e4e64ed67a32d2ede678028e6057c 100644 (file)
@@ -27,6 +27,7 @@ struct NeonSpamSettings;
 #define CHANFLAG_REQUESTED_CHANINFO 0x02
 #define CHANFLAG_CHAN_REGISTERED    0x04
 #define CHANFLAG_HAVE_INVISIBLES    0x08
+#define CHANFLAG_REJOINING          0x10
 
 struct ChanNode {
     char name[CHANNELLEN+1];
@@ -43,6 +44,8 @@ struct ChanNode {
     
     struct NeonSpamSettings *spam_settings;
        
+    void *rejoin_array;
+    
     struct ChanNode *next;
 };
 
@@ -57,6 +60,6 @@ int getChanUserCount();
 int getChanBanCount();
 void delChannel(struct ChanNode* chan, int freeChan);
 void freeChanNode(struct ChanNode* chan);
-void checkChannelVisibility(struct ChanNode* chan);
+int checkChannelVisibility(struct ChanNode* chan);
 
 #endif
\ No newline at end of file
index b757f5dc4d28ca18c9af2f356120ded843736a97..9b91d21552ed8f6dc3f2f463c0ded662ee7d374a 100644 (file)
@@ -213,10 +213,58 @@ static IRC_CMD(raw_join) {
             if(wasRegistering)
                 user->flags &= ~USERFLAG_WAS_REGISTRING;
         }
+        if(!(user->flags & USERFLAG_ISBOT) && (chan->flags & CHANFLAG_REJOINING)) {
+            //ABORT REJOIN (security break)
+            struct ClientSocket **clients = chan->rejoin_array;
+            while(*clients) {
+                putsock(*clients, "JOIN %s", chan->name);
+                clients++;
+            }
+            free(chan->rejoin_array);
+            chan->flags &= ~CHANFLAG_REJOINING;
+        }
+    } else if(chan->usercount == 1 && isUserOnChan(user, chan)) {
+        //first bot rejoined
+        struct ChanUser *chanuser = getChanUser(user, chan);
+        chanuser->flags &= ~CHANUSERFLAG_VOICED;
+        chanuser->flags |= CHANUSERFLAG_OPPED;
     }
     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;
+        int i = 0;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->user != chan->chanbot && isUserOnChan(bot->user, chan)) {
+                clients[i++] = bot;
+                putsock(bot, "PART %s :rejoining", chan->name);
+            } else if(bot->user == chan->chanbot)
+                chanbot = bot;
+        }
+        chan->flags |= CHANFLAG_REJOINING;
+        chan->rejoin_array = clients;
+        if(botcount == 1) {
+            //we're alone
+            putsock(chanbot, "PART %s :magic hop", chan->name);
+            putsock(chanbot, "JOIN %s", chan->name);
+        }
+    }
+}
+
 static IRC_CMD(raw_part) {
     if(from == NULL || argc < 1) return 0;
     struct UserNode *user = getUserByMask(from);
@@ -224,20 +272,38 @@ static IRC_CMD(raw_part) {
     struct ChanNode *chan = getChanByName(argv[0]);
     if(chan == NULL) return 0;
     if(chan->chanbot != client->user) return 1; //we ignore it - but it's not a parse error
-    if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+    int keep_channel = 1;
+    if(chan->chanbot == user && (chan->flags & CHANFLAG_REJOINING)) {
+        struct ClientSocket **clients = chan->rejoin_array;
+        while(*clients) {
+            putsock(*clients, "JOIN %s", chan->name);
+            clients++;
+        }
+        free(chan->rejoin_array);
+        chan->flags &= ~CHANFLAG_REJOINING;
+        return 0;
+    } else if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
         struct ChanUser *chanuser = getChanUser(user, chan);
         delChanUser(chanuser, 0); //we need to free the chanuser manually!
         event_part(chanuser, (argc > 1 ? argv[1] : NULL));
         freeChanUser(chanuser);
         if(chan->chanbot == user) {
             //check if theres another bot in the channel - otherwise free it
-            checkChannelVisibility(chan);
+            keep_channel = checkChannelVisibility(chan);
         }
     }
     if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
         //remove the user
         delUser(user, 1);
     }
+    if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) {
+        check_full_rejoin(chan);
+    }
+    else if(keep_channel && (chan->flags & CHANFLAG_REJOINING) && chan->usercount == 1) {
+        //bot is alone... rejoin!
+        putsock(client, "PART %s :magic hop", chan->name);
+        putsock(client, "JOIN %s", chan->name);
+    }
     return 1;
 }
 
@@ -246,6 +312,7 @@ static IRC_CMD(raw_quit) {
     struct UserNode *user = getUserByMask(from);
     if(user == NULL) return 0;
     if(!is_firstBotSeeUser(client, user)) return 1; //we ignore it - but it's not a parse error
+    int keep_channel = 1;
     int registering = !stricmp(argv[0], "Registered");
     if((registering && (user->flags & USERFLAG_ISBOT))) return 1; //bot is registering - just ignore it
     delUser(user, 0); //a little bit crazy, but we want to delete the user on the channel's userlists - but not the users channel list
@@ -256,7 +323,7 @@ static IRC_CMD(raw_quit) {
         for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
             next = getUserChannels(user, chanuser);
             if(chanuser->chan->chanbot == user)
-                checkChannelVisibility(chanuser->chan);
+                keep_channel = checkChannelVisibility(chanuser->chan);
         }
         //search the user representing the bot in the world of IRC
         struct ClientSocket *bot;
@@ -266,6 +333,14 @@ static IRC_CMD(raw_quit) {
                 break;
             }
         }
+    } else if(!registering) {
+        struct ChanUser *chanuser;
+        struct ChanNode *chan;
+        for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) {
+            chan = chanuser->chan;
+            if((chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING))
+                check_full_rejoin(chan);
+        }
     }
     if(registering && !(user->flags & USERFLAG_ISBOT)) {
         user->next = registering_users;
@@ -312,6 +387,7 @@ static IRC_CMD(raw_kick) {
     struct ChanNode *chan = getChanByName(argv[0]);
     if(chan == NULL || target == NULL) return 0;
     if(chan->chanbot != client->user) return 1; //we ignore it - but it's not a parse error
+    int keep_channel = 1;
     if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
         if(user == NULL) {
             user = createTempUser(from);
@@ -322,7 +398,7 @@ static IRC_CMD(raw_kick) {
         event_kick(user, chanuser, argv[1]);
         if(chanuser->chan->chanbot == user) {
             //check if theres another bot in the channel - otherwise free it
-            checkChannelVisibility(chan);
+            keep_channel = checkChannelVisibility(chan);
         }
         freeChanUser(chanuser);
     }
@@ -330,6 +406,9 @@ static IRC_CMD(raw_kick) {
         //remove the user
         delUser(target, 1);
     }
+    if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) {
+        check_full_rejoin(chan);
+    }
     return 1;
 }
 
index b30b5332767396b863d980d973cb302fa5b8b1a6..aece825925436b39f296e18c6ecf9f539c9601b8 100644 (file)
@@ -94,6 +94,24 @@ struct ClientSocket *getChannelBot(struct ChanNode *chan, int botid) {
     return use_bot;
 }
 
+void requestOp(struct UserNode *user, struct ChanNode *chan) {
+    struct ClientSocket *bot;
+    struct ChanUser *chanuser = getChanUser(user, chan);
+    char opped = 0;
+    if(!chanuser) return;
+    if((chanuser->flags & CHANUSERFLAG_OPPED)) return;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if((chanuser = getChanUser(bot->user, chan)) != NULL && (chanuser->flags & CHANUSERFLAG_OPPED)) {
+            opped = 1;
+            putsock(bot, "MODE %s +o %s", chan->name, user->nick);
+            break;
+        }
+    }
+    if(!opped) {
+        //self op?
+    }
+}
+
 TIMEQ_CALLBACK(channel_ban_timeout) {
     char *str_banid = data;
     MYSQL_RES *res;
index 0fead874c7c78dfaaa0504983c9d57f79025a306..35f09dbfa5966d539527481c1220f228810a0de5 100644 (file)
@@ -29,6 +29,7 @@ void loop_bots();
 void free_bots();
 
 struct ClientSocket *getChannelBot(struct ChanNode *chan, int botid);
+void requestOp(struct UserNode *user, struct ChanNode *chan);
 TIMEQ_CALLBACK(channel_ban_timeout);
 void general_event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text);
 void set_bot_alias(int botid, char *alias);
index f3e94ae2a993f5c1a58e4c45cba2a46e2d15bc9c..98bea3bcc556fdffc4d612e972cb1ea396d61a3c 100644 (file)
@@ -29,10 +29,11 @@ static void neonserv_event_join(struct ChanUser *chanuser) {
     struct UserNode *user = chanuser->user;
     struct ClientSocket *client = getBotForChannel(chanuser->chan);
     if(!client) return; //we can't "see" this event
-    if(user->flags & USERFLAG_ISBOT) {
-        putsock(client, "MODE %s +o %s", chanuser->chan->name, chanuser->user->nick);
+    if(chanuser->user == client->user) {
+        requestOp(client->user, chanuser->chan);
         return;
     }
+    if(chanuser->user->flags & USERFLAG_ISBOT) return;
     loadChannelSettings(chanuser->chan);
     if(!(chanuser->chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
     char *ban;
index a192d792c284154c3a74be5d51c971c2f8fd1a70..fc501e75f5aeb426060d6d5eb7d9df72eaacf5f6 100644 (file)
@@ -30,6 +30,11 @@ static void neonspam_event_join(struct ChanUser *chanuser) {
     if(chanuser->user->flags & USERFLAG_WAS_REGISTRING) return;
     struct ClientSocket *client = getChannelBot(chanuser->chan, BOTID);
     if(!client) return; //we can't "see" this event
+    if(chanuser->user == client->user) {
+        requestOp(client->user, chanuser->chan);
+        return;
+    }
+    if(chanuser->user->flags & USERFLAG_ISBOT) return;
     loadNeonSpamSettings(chanuser->chan);
     struct NeonSpamSettings *settings = chanuser->chan->spam_settings;
     if(!settings || !(settings->flags & SPAMSETTINGS_JOINSCAN)) return;