added raw_topic, raw_privmsg and wrote the small "dead channel garbage collector"
authorpk910 <philipp@zoelle1.de>
Thu, 11 Aug 2011 21:45:43 +0000 (23:45 +0200)
committerpk910 <philipp@zoelle1.de>
Thu, 11 Aug 2011 21:45:43 +0000 (23:45 +0200)
ChanNode.c
ChanUser.c
ChanUser.h
ClientSocket.c
IRCEvents.c
IRCEvents.h
IRCParser.c
IRCParser.h
UserNode.c
UserNode.h

index 77071243119f886af200ca12f2579d538cdd65be..9bb9b313e465cde9cb708d401e2c26a6bfd42445 100644 (file)
@@ -1,4 +1,6 @@
 #include "ChanNode.h"
+#include "ChanUser.h"
+#include "UserNode.h"
 
 static struct ChanNode **chanList;
 
@@ -97,8 +99,36 @@ void delChannel(struct ChanNode* chan, int freeChan) {
         } else
             last_chan = cchan;
     }
+    if(chan->user) {
+        //free all chanusers
+        struct ChanUser *chanuser, *next;
+        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
+            next = getChannelUsers(chan, chanuser);
+            removeChanUserFromLists(chanUser, 0, 1, 1);
+        }
+    }
     if(freeChan)
         free(chan);
     else
         chan->next = NULL;
 }
+
+void checkChannelVisibility(struct ChanNode* chan) {
+    struct ChanUser *chanuser, *cchanuser, *next, *last = NULL;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(chanuser->user->flags & USERFLAG_ISBOT) return;
+    }
+    //free the channel...
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
+        next = getChannelUsers(chan, chanuser);
+        //remove the channel from the user's channel-list
+        removeChanUserFromLists(chanUser, 0, 1, 0);
+        if(!chanuser->user->channel) {
+            //free the user (no more channels)
+            delUser(chanuser->user, 1);
+        }
+        free(chanuser);
+    }
+    chan->user = NULL;
+    delChannel(chan, 1);
+}
index a4cf9de629daab860c5d3eef50eac04f92c05fe2..7366c83be0b7e83ce8f4ce5e64b07f90aa0ca3f1 100644 (file)
@@ -90,23 +90,40 @@ void delChanUser(struct ChanUser *chanuser, int freeChanUser) {
     }
 }
 
-void quitChanUser(struct ChanUser *chanuser, int freeChanUser) {
-    struct ChanUser *cchanuser, *last = NULL;
-    last = NULL;
-    for(cchanuser = chanuser->chan->user; cchanuser; cchanuser = cchanuser->next_user) {
-        if(cchanuser == chanuser) {
-            if(last) 
-                last->next_user = chanuser->next_user;
-            else
-                chanuser->chan->user = chanuser->next_user;
-            break;
-        } else
-            last = cchanuser;
+void removeChanUserFromLists(struct ChanUser *chanuser, int remove_from_userlist, int remove_from_channellist int freeChanUser) {
+    struct ChanUser *cchanuser, *last;
+    if(remove_from_userlist) {
+        //remove it from the channel's user-list
+        last = NULL;
+        for(cchanuser = chanuser->chan->user; cchanuser; cchanuser = cchanuser->next_user) {
+            if(cchanuser == chanuser) {
+                if(last) 
+                    last->next_user = chanuser->next_user;
+                else
+                    chanuser->chan->user = chanuser->next_user;
+                break;
+            } else
+                last = cchanuser;
+        }
+        chanuser->next_user = NULL;
     }
-
+    if(remove_from_channellist) {
+        //remove it from the user's channel-list
+        last = NULL;
+        for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
+            if(cchanuser == chanuser) {
+                if(last) 
+                    last->next_chan = chanuser->next_chan;
+                else
+                    chanuser->user->channel = chanuser->next_chan;
+                break;
+            } else
+                last = cchanuser;
+        }
+        chanuser->next_chan = NULL;
+    }
+    
     if(freeChanUser)
         free(chanuser);
-    else
-        chanuser->next_user = NULL;
 }
 
index e4f19cfdbacea6980275bbae312cbd474290287f..8429a3a74cf51e5ee3e2026d05999ccd5c9a2992 100644 (file)
@@ -25,6 +25,6 @@ struct ChanUser* getChanUser(struct UserNode *user, struct ChanNode *chan);
 struct ChanUser* getChannelUsers(struct ChanNode *chan, struct ChanUser *last);
 struct ChanUser* getUserChannels(struct UserNode *user, struct ChanUser *last);
 void delChanUser(struct ChanUser *chanuser, int freeChanUser);
-void quitChanUser(struct ChanUser *chanuser, int freeChanUser);
+void removeChanUserFromLists(struct ChanUser *chanuser, int remove_from_userlist, int remove_from_channellist int freeChanUser);
 
 #endif
\ No newline at end of file
index 2f80c71bbeee31e9bff8f7dfdd7672a26cf319ae..5a186c6fe542f26645b74a3e1f9ae8e82a3c695f 100644 (file)
@@ -156,6 +156,7 @@ void socket_loop(int timeout_seconds) {
             if(bytes <= 0) {
                 //error
                 sock->flags &= ~(SOCKET_FLAG_CONNECTED | SOCKET_FLAG_READY);
+                bot_disconnect(sock);
             } else {
                 int used = parse_lines(sock, sock->buffer, sock->bufferpos);
                 if(used == sock->bufferpos + 1) {
index 6d863f84059628f8b96598966f64f2eb23589ced..acf4ff5cb163c66d7cbec54f3df034c16fc81faa 100644 (file)
@@ -17,6 +17,10 @@ int event_kick(struct UserNode *user, struct ChanUser *target, char *reason) {
     return 1;
 }
 
+int event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
+    return 1;
+}
+
 int event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
     return 1;
 }
index 01e480c9f2607436cebe842a1803f3d64ea0fc5c..1badf72da9ffd21b71db44308628a73b9d68f782 100644 (file)
@@ -10,6 +10,7 @@ int event_join(struct ChanUser *chanuser);
 int event_part(struct ChanUser *chanuser, char *reason);
 int event_quit(struct UserNode *user, char *reason);
 int event_kick(struct UserNode *user, struct ChanUser *target, char *reason);
+int event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic);
 int event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message);
 int event_privmsg(struct UserNode *user, struct UserNode *target, char *message);
 
index 17cafd3f9004a178162b2d4a816d1ebf98c88b71..3f8f9bf252783f826622a18b74d6d2da09e4fe71 100644 (file)
@@ -84,8 +84,9 @@ static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char *
 }
 
 static USERLIST_CALLBACK(got_channel_userlist) {
+    struct ChanUser *chanuser = data;
+    event_join(chanuser);
     putsock(client, "PRIVMSG %s :[BOT JOIN] Users on this Channel:", chan->name);
-    struct ChanUser *chanuser;
     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
         putsock(client, "PRIVMSG %s :  %s!%s@%s [%s]  rights: %d", chan->name, chanuser->user->nick, chanuser->user->ident, chanuser->user->host, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "*"), chanuser->flags);
     }
@@ -107,8 +108,8 @@ static IRC_CMD(raw_join) {
     if(chan == NULL) {
         chan = addChannel(argv[0]);
         //request member list
-        addChanUser(chan, user); //it must be a bot
-        get_userlist(chan, got_channel_userlist, NULL);
+        struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
+        get_userlist(chan, got_channel_userlist, chanuser);
     } else if(!isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
         struct ChanUser *chanuser = addChanUser(chan, user);
         event_join(chanuser);
@@ -129,14 +130,13 @@ static IRC_CMD(raw_part) {
         free(chanuser);
         if(user->flags & USERFLAG_ISBOT) {
             //check if theres another bot in the channel - otherwise free it
-            
+            checkChannelVisibility(chan);
         }
     }
     if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
         //remove the user
         delUser(user, 1);
     }
-    
     return 1;
 }
 
@@ -148,27 +148,50 @@ static IRC_CMD(raw_quit) {
     event_quit(user, argv[1]);
     if(user->flags & USERFLAG_ISBOT) {
         //check if there are other bots in the users channel - otherwise free them
-        
+        struct ChanUser *chanuser, *next;
+        for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
+            next = getUserChannels(user, chanuser);
+            checkChannelVisibility(chanuser->chan);
+        }
     }
     delUser(user, 1); //now we fully free the user
     return 1;
 }
 
+void bot_disconnect(struct ClientSocket *client) {
+    struct UserNode *user = client->user;
+    struct ChanUser *chanuser, *next;
+    delUser(user, 0);
+    event_quit(user, "disconnected");
+    for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
+        next = getUserChannels(user, chanuser);
+        checkChannelVisibility(chanuser->chan);
+        free(chanuser);
+    }
+    user->channel = NULL;
+}
+
 static IRC_CMD(raw_kick) {
     if(from == NULL || argc < 3) return 0;
     struct UserNode *user = getUserByMask(from);
     struct UserNode *target = getUserByNick(argv[1]);
-    if(user == NULL || target == NULL) return 0;
     struct ChanNode *chan = getChanByName(argv[0]);
-    if(chan == NULL) return 0;
+    if(chan == NULL || target == NULL) return 0;
     if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+        if(user == NULL) {
+            user = createTempUser(from);
+            user->flags |= USERFLAG_ISTMPUSER;
+        }
         struct ChanUser *chanuser = getChanUser(target, chan);
         delChanUser(chanuser, 0); //we need to free the chanuser manually!
         event_kick(user, chanuser, argv[1]);
         free(chanuser);
+        if(user->flags & USERFLAG_ISTMPUSER) {
+            free(user);
+        }
         if(target->flags & USERFLAG_ISBOT) {
             //check if theres another bot in the channel - otherwise free it
-            
+            checkChannelVisibility(chan);
         }
     }
     if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
@@ -178,6 +201,39 @@ static IRC_CMD(raw_kick) {
     return 1;
 }
 
+static IRC_CMD(raw_topic) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(chan == NULL) return 0;
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    event_topic(user, chan, argv[1]);
+    strcpy(chan->topic, argv[1])
+    if(user->flags & USERFLAG_ISTMPUSER) {
+        free(user);
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_privmsg) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(chan == NULL) return 0;
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    //event_topic(user, chan, argv[1]);
+    if(user->flags & USERFLAG_ISTMPUSER) {
+        free(user);
+    }
+    return 1;
+}
+
 static IRC_CMD(raw_ping) {
     if(argc == 0) return 0;
     putsock(client, "PONG :%s", argv[0]);
@@ -197,11 +253,13 @@ static IRC_CMD(raw_315) {
 void parser_init() {
     //all the raws we receive...
     register_irc_function("001", raw_001);
-    register_irc_function("354", raw_354);
-    register_irc_function("315", raw_315);
+    register_irc_function("TOPIC", raw_topic);
     register_irc_function("KICK", raw_kick);
     register_irc_function("JOIN", raw_join);
     register_irc_function("PART", raw_part);
     register_irc_function("QUIT", raw_quit);
+    register_irc_function("354", raw_354);
+    register_irc_function("315", raw_315);
     register_irc_function("PING", raw_ping);
+    register_irc_function("PRIVMSG", raw_privmsg);
 }
index 5908aff594e70615603aa996f11cb2b90c77a19d..c4d2801e02a741149d368b012ff77f47e6cf96f1 100644 (file)
@@ -16,6 +16,7 @@ struct irc_cmd {
 };
 
 int parse_lines(struct ClientSocket *client, char *lines, int len);
+void bot_disconnect(struct ClientSocket *client);
 void parser_init();
 
 #endif
\ No newline at end of file
index 89f32360da719bf66e75541a597a6d715157ffee..870f11e3ce33939472c98bd687a3e5b992ea282e 100644 (file)
@@ -109,7 +109,6 @@ struct UserNode* addUser(const char *nick) {
     return user;
 }
 
-
 struct UserNode* addUserMask(const char *mask) {
     char cmask[strlen(mask)+1];
     strcpy(cmask, mask);
@@ -118,7 +117,7 @@ struct UserNode* addUserMask(const char *mask) {
     for(i = 0; i < strlen(mask)+1; i++) {
         if(cmask[i] == '!') {
             cmask[i] = 0;
-            user = addUser(&cmask[0]);
+            user = addUser(cmask);
             if(user == NULL) return NULL;
             ii = i+1;
         } else if(cmask[i] == '.' && !user) {
@@ -137,6 +136,56 @@ struct UserNode* addUserMask(const char *mask) {
     return user;
 }
 
+struct UserNode* createTempUser(const char *mask) {
+    //note: it could also be a server we have to create a temponary user for...
+    char cmask[strlen(mask)+1];
+    strcpy(cmask, mask);
+    int i, ii = 0;
+    struct UserNode *user = NULL;
+    for(i = 0; i < strlen(mask)+1; i++) {
+        if(cmask[i] == '!') {
+            cmask[i] = 0;
+            struct UserNode *user = malloc(sizeof(*user));
+            if (!user)
+            {
+                perror("malloc() failed");
+                return NULL;
+            }
+            strcpy(user->nick, nick);
+            user->ident[0] = 0;
+            user->host[0] = 0;
+            user->realname[0] = 0;
+            user->flags = 0;
+            user->channel = NULL;
+            ii = i+1;
+        } else if(cmask[i] == '.' && !user) {
+            //it's a server
+            struct UserNode *user = malloc(sizeof(*user));
+            if (!user)
+            {
+                perror("malloc() failed");
+                return NULL;
+            }
+            strcpy(user->host, cmask);
+            user->ident[0] = 0;
+            user->host[0] = 0;
+            user->realname[0] = 0;
+            user->flags = USERFLAG_ISSERVER;
+            user->channel = NULL;
+            return user;
+        } else if(cmask[i] == '@') {
+            if(user == NULL) return NULL;
+            cmask[i] = 0;
+            strcpy(user->ident, &cmask[ii]);
+            ii = i+1;
+        } else if(cmask[i] == '\0') {
+            if(user == NULL) return NULL;
+            strcpy(user->host, &cmask[ii]);
+        }
+    }
+    return user;
+}
+
 int renameUser(struct UserNode* user, const char *new_nick) {
     if(!is_valid_nick(new_nick))
         return 0;
@@ -170,7 +219,7 @@ void delUser(struct UserNode* user, int freeUser) {
         struct ChanUser *chanUser, *next;
         for(chanUser = user->channel; chanUser; chanUser = next) {
             next = chanUser->next_chan;
-            quitChanUser(chanUser, freeUser);
+            removeChanUserFromLists(chanUser, 1, 0, freeUser);
         }
     }
     if(freeUser)
index 57e52c74c9c63dfc69efc260f3d80b1c75dc3181..49bb94067a446cfc3629fb848f5e2a4fc1201a21 100644 (file)
@@ -2,9 +2,11 @@
 #define _UserNode_h
 #include "main.h"
 
-#define USERFLAG_ISBOT    0x01
-#define USERFLAG_ISAUTHED 0x02
-#define USERFLAG_ISIRCOP  0x04
+#define USERFLAG_ISBOT     0x01
+#define USERFLAG_ISAUTHED  0x02
+#define USERFLAG_ISIRCOP   0x04
+#define USERFLAG_ISTMPUSER 0x08
+#define USERFLAG_ISSERVER  0x10
 struct ChanUser;
 
 struct UserNode {
@@ -26,6 +28,7 @@ struct UserNode* getUserByMask(const char *mask);
 struct UserNode* searchUserByNick(const char *nick);
 struct UserNode* addUser(const char *nick);
 struct UserNode* addUserMask(const char *mask);
+struct UserNode* createTempUser(const char *mask);
 int renameUser(struct UserNode* user, const char *new_nick);
 void delUser(struct UserNode* user, int freeUser);