fixed viscount update when another bot joins a channel
[NeonServV5.git] / src / IRCParser.c
index efbdbfd525e47ffbca041585976edcc945858668..1d53ec2aa1ba6c4e82e0d1a53a527ded07a56747 100644 (file)
@@ -35,27 +35,10 @@ int statistics_privmsg = 0;
 int statistics_network_users = 0;
 int statistics_network_channels = 0;
 
-static void parse_line(struct ClientSocket *client, char *line);
 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);
 
-int parse_lines(struct ClientSocket *client, char *lines, int len) {
-    int i, used = 0;
-    char *line = lines;
-    for(i = 0; i < len; i++) {
-        if(lines[i] == '\r') //just zero it out :D
-            lines[i] = 0;
-        if(lines[i] == '\n') {
-            lines[i] = 0;
-            parse_line(client, line);
-            line = lines+(i+1);
-            used = i+1;
-        }
-    }
-    return used;
-}
-
-static void parse_line(struct ClientSocket *client, char *line) {
+void parse_line(struct ClientSocket *client, char *line) {
     int argc = 0;
     char *argv[MAXNUMPARAMS];
     #ifdef HAVE_THREADS
@@ -116,8 +99,34 @@ static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char *
     }
 }
 
+static void increase_viscount_butone(struct ChanNode *chan, struct ChanUser *ignore) {
+    struct ChanUser *chanuser;
+    
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(chanuser == ignore)
+            continue;
+        chanuser->visCount++;
+    }
+}
+
+static void decrease_viscount_butone(struct ChanNode *chan, struct ChanUser *ignore) {
+    struct ChanUser *chanuser, *next_chanuser;
+    
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next_chanuser) {
+        next_chanuser = getChannelUsers(chan, chanuser);
+        if(chanuser == ignore)
+            continue;
+        chanuser->visCount--;
+        if(chanuser->visCount <= 0)
+            delChanUser(chanuser, 1);
+    }
+}
+
 static USERLIST_CALLBACK(got_channel_userlist) {
     struct ChanUser *chanuser = data;
+    
+    increase_viscount_butone(chanuser->chan, chanuser);
+    
     event_join(chanuser);
 }
 
@@ -161,12 +170,28 @@ static IRC_CMD(raw_join) {
         
         event_registered(user, from);
         user->flags &= ~USERFLAG_WAS_REGISTERING;
+    } else if(!(chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+        if(client->user != user) { //bots are allowed to add themselves
+            DESYNCHRONIZE(cache_sync);
+            return 1; //ignore join
+        }
+        
+        chanuser = addChanUser(chan, user);
+        chanuser->visCount = 1;
+        
+        if(isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible
+            chanuser->flags |= CHANUSERFLAG_INVISIBLE;
+        
+        get_userlist_with_invisible(chan, 0, got_channel_userlist, chanuser);
     } else if(!isUserOnChan(user, chan)) {
         //join user to an existing channel
         chanuser = addChanUser(chan, user);
         chanuser->visCount = 1;
-        if(isBot(user) && isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible
-            chanuser->flags |= CHANUSERFLAG_INVISIBLE;
+        if(isBot(user) && client->user == user) {
+            if(isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible
+                chanuser->flags |= CHANUSERFLAG_INVISIBLE;
+            increase_viscount_butone(chan, chanuser);
+        }
         
         event_join(chanuser);
         
@@ -184,6 +209,10 @@ static IRC_CMD(raw_join) {
         //user is already in the channel
         chanuser = getChanUser(user, chan);
         chanuser->visCount++;
+        
+        if(isBot(user) && client->user == user)
+            increase_viscount_butone(chan, chanuser);
+        
         //if multiple bots see the user, it can't be invisible
         chanuser->flags &= ~CHANUSERFLAG_INVISIBLE;
     }
@@ -239,6 +268,8 @@ static IRC_CMD(raw_part) {
         DESYNCHRONIZE(cache_sync);
         return 0;
     }
+    if(isBot(user) && user == client->user) 
+        decrease_viscount_butone(chan, chanuser);
     chanuser->visCount--;
     if(chanuser->visCount == 0) {
         delChanUser(chanuser, 0); //not free, yet!
@@ -295,6 +326,8 @@ static IRC_CMD(raw_kick) {
         DESYNCHRONIZE(cache_sync);
         return 0;
     }
+    if(isBot(target) && target == client->user) 
+        decrease_viscount_butone(chan, chanuser);
     chanuser->visCount--;
     if(chanuser->visCount == 0) {
         delChanUser(chanuser, 0); //not free, yet!
@@ -362,13 +395,16 @@ static IRC_CMD(raw_quit) {
     struct ChanUser *chanuser, *next_chanuser;
     for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next_chanuser) {
         next_chanuser = getUserChannels(user, chanuser);
-        chanuser->visCount--;
-        if(chanuser->visCount == 0) {
-            delChanUser(chanuser, 0); //not free, yet!
-            event_part(chanuser, 1, argv[0]);
-            if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING))
-                check_full_rejoin(chanuser->chan);
-            freeChanUser(chanuser);
+        //decrease visCount counter only if client is in the channel
+        if(isUserOnChan(client->user, chanuser->chan)) {
+            chanuser->visCount--;
+            if(chanuser->visCount <= 0 && !(user->flags & USERFLAG_WAS_REGISTERING)) {
+                delChanUser(chanuser, 0); //not free, yet!
+                event_part(chanuser, 1, argv[0]);
+                if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING))
+                    check_full_rejoin(chanuser->chan);
+                freeChanUser(chanuser);
+            }
         }
     }
     
@@ -399,12 +435,13 @@ void bot_disconnect(struct ClientSocket *client) {
         struct ChanUser *chanuser, *next_chanuser;
         for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next_chanuser) {
             next_chanuser = getUserChannels(user, chanuser);
+            decrease_viscount_butone(chanuser->chan, chanuser);
             chanuser->visCount--;
-            if(chanuser->visCount == 0) {
+            if(chanuser->visCount <= 0) {
                 delChanUser(chanuser, 0); //not free, yet!
                 event_part(chanuser, 1, "QUIT");
-                if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING))
-                    check_full_rejoin(chanuser->chan);
+                if(chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST)
+                    checkChannelVisibility(chanuser->chan);
                 freeChanUser(chanuser);
             }
         }