From 54e1930bcb43a0f5410ecaac28a3f33efda2debb Mon Sep 17 00:00:00 2001 From: pk910 Date: Thu, 11 Aug 2011 23:45:43 +0200 Subject: [PATCH] added raw_topic, raw_privmsg and wrote the small "dead channel garbage collector" --- ChanNode.c | 30 +++++++++++++++++++ ChanUser.c | 47 +++++++++++++++++++---------- ChanUser.h | 2 +- ClientSocket.c | 1 + IRCEvents.c | 4 +++ IRCEvents.h | 1 + IRCParser.c | 80 +++++++++++++++++++++++++++++++++++++++++++------- IRCParser.h | 1 + UserNode.c | 55 ++++++++++++++++++++++++++++++++-- UserNode.h | 9 ++++-- 10 files changed, 197 insertions(+), 33 deletions(-) diff --git a/ChanNode.c b/ChanNode.c index 7707124..9bb9b31 100644 --- a/ChanNode.c +++ b/ChanNode.c @@ -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); +} diff --git a/ChanUser.c b/ChanUser.c index a4cf9de..7366c83 100644 --- a/ChanUser.c +++ b/ChanUser.c @@ -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; } diff --git a/ChanUser.h b/ChanUser.h index e4f19cf..8429a3a 100644 --- a/ChanUser.h +++ b/ChanUser.h @@ -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 diff --git a/ClientSocket.c b/ClientSocket.c index 2f80c71..5a186c6 100644 --- a/ClientSocket.c +++ b/ClientSocket.c @@ -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) { diff --git a/IRCEvents.c b/IRCEvents.c index 6d863f8..acf4ff5 100644 --- a/IRCEvents.c +++ b/IRCEvents.c @@ -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; } diff --git a/IRCEvents.h b/IRCEvents.h index 01e480c..1badf72 100644 --- a/IRCEvents.h +++ b/IRCEvents.h @@ -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); diff --git a/IRCParser.c b/IRCParser.c index 17cafd3..3f8f9bf 100644 --- a/IRCParser.c +++ b/IRCParser.c @@ -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); } diff --git a/IRCParser.h b/IRCParser.h index 5908aff..c4d2801 100644 --- a/IRCParser.h +++ b/IRCParser.h @@ -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 diff --git a/UserNode.c b/UserNode.c index 89f3236..870f11e 100644 --- a/UserNode.c +++ b/UserNode.c @@ -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) diff --git a/UserNode.h b/UserNode.h index 57e52c7..49bb940 100644 --- a/UserNode.h +++ b/UserNode.h @@ -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); -- 2.20.1