added channel rejoin faker (session recover)
[TransparentIRC.git] / src / IRCClient.c
index 46e030ea45ff47600042dbf9d21dc9a76ed2ae7a..eee86b1f8162d78e6f4fc81cc0416dfed58b17ef 100644 (file)
@@ -53,6 +53,12 @@ void ircclient_close(struct IRCClient *client) {
     client->session->irc = NULL;
     iohandler_printf(client->iofd, "QUIT :[TransparentIRC] Quit");
     iohandler_close(client->iofd);
+    struct IRCLine *recover_line, *next_line;
+    for(recover_line = client->recover_header; recover_line; recover_line = next_line) {
+        next_line = recover_line->next;
+        free(recover_line->line);
+        free(recover_line);
+    }
     free(client);
 }
 
@@ -66,6 +72,35 @@ static void ircclient_handshake(struct IRCClient *client) {
     session->realname = NULL;
 }
 
+static struct IRCUser ircclient_parse_user(char *from) {
+    struct IRCUser user;
+    char *a = from, *b = from;
+    while(*b != '!') {
+        b++;
+    }
+    user.nick = a;
+    if(!*b) {
+        user.ident = "";
+        user.host = "";
+        return user;
+    }
+    *b = '\0';
+    b++;
+    a = b;
+    while(*b && *b != '@') {
+        b++;
+    }
+    user.ident = a;
+    if(!*b) {
+        user.host = "";
+        return user;
+    }
+    *b = '\0';
+    b++;
+    user.host = b;
+    return user;
+}
+
 static void ircclient_recv(struct IRCClient *client, char *line) {
     struct UserSession *session = client->session;
     char *argv[MAXNUMPARAMS];
@@ -85,7 +120,89 @@ static void ircclient_recv(struct IRCClient *client, char *line) {
             pass_to_client = 0;
         }
     } else {
-        
+        if(!stricmp(argv[1], "001")) {
+            free(session->nick);
+            session->nick = strdup(argv[2]);
+            client->fully_connected = 1;
+        }
+        if(!stricmp(argv[1], "001") ||
+            !stricmp(argv[1], "002") ||
+            !stricmp(argv[1], "003") ||
+            !stricmp(argv[1], "004") ||
+            !stricmp(argv[1], "005") ||
+            !stricmp(argv[1], "375") ||
+            !stricmp(argv[1], "372") ||
+            !stricmp(argv[1], "376")
+          ) {
+            //save these raw's for recovering the connection later
+            struct IRCLine *recover_line = NULL, *new_line;
+            if(client->recover_header)
+                for(recover_line = client->recover_header; recover_line->next; recover_line = recover_line->next) {};
+            new_line = malloc(sizeof(*new_line));
+            if(new_line) {
+                new_line->line = strdup(line);
+                new_line->next = NULL;
+                if(recover_line)
+                    recover_line->next = new_line;
+                else
+                    client->recover_header = new_line;
+            }
+        } else if(!stricmp(argv[1], "JOIN")) {
+            struct IRCUser from = ircclient_parse_user(argv[0]);
+            if(!stricmp(from.nick, session->nick)) {
+                struct IRCChannel *lchannel = NULL, *channel = malloc(sizeof(*channel));
+                if(client->channel)
+                    for(lchannel = client->channel; lchannel->next; lchannel = lchannel->next) {}
+                channel->name = strdup(argv[2]);
+                channel->next = NULL;
+                channel->prev = lchannel;
+                if(lchannel)
+                    lchannel->next = channel;
+                else
+                    client->channel = channel;
+            }
+        } else if(!stricmp(argv[1], "PART")) {
+            struct IRCUser from = ircclient_parse_user(argv[0]);
+            if(!stricmp(from.nick, session->nick)) {
+                struct IRCChannel *channel;
+                for(channel = client->channel; channel; channel = channel->next) {
+                    if(!stricmp(channel->name, argv[2])) {
+                        if(channel->prev)
+                            channel->prev->next = channel->next;
+                        else
+                            client->channel = channel->next;
+                        if(channel->next)
+                            channel->next->prev = channel->prev;
+                        free(channel->name);
+                        free(channel);
+                        break;
+                    }
+                }
+            }
+        } else if(!stricmp(argv[1], "KICK")) {
+            if(!stricmp(argv[3], session->nick)) {
+                struct IRCChannel *channel;
+                for(channel = client->channel; channel; channel = channel->next) {
+                    if(!stricmp(channel->name, argv[2])) {
+                        if(channel->prev)
+                            channel->prev->next = channel->next;
+                        else
+                            client->channel = channel->next;
+                        if(channel->next)
+                            channel->next->prev = channel->prev;
+                        free(channel->name);
+                        free(channel);
+                        break;
+                    }
+                }
+            }
+        } else if(!stricmp(argv[1], "NICK")) {
+            struct IRCUser from = ircclient_parse_user(argv[0]);
+            if(!stricmp(from.nick, session->nick)) {
+                free(session->nick);
+                session->nick = strdup(argv[2]);
+            }
+        }
     }
     if(pass_to_client)
         usersession_client_raw(session, line);
@@ -114,3 +231,21 @@ static void ircclient_callback(struct IOEvent *event) {
 void ircclient_send(struct IRCClient *client, char *line) {
     iohandler_printf(client->iofd, "%s", line);
 }
+
+void ircclient_recover_session(struct UserSession *session) {
+    struct IRCClient *client = session->irc;
+    //replay header
+    struct IRCLine *recover_line;
+    for(recover_line = client->recover_header; recover_line; recover_line = recover_line->next) {
+        usersession_client_raw(session, recover_line->line);
+    }
+    struct IRCChannel *channel;
+    char raw[LINELEN];
+    for(channel = client->channel; channel; channel = channel->next) {
+        sprintf(raw, ":%s!%s@TransparentIRC.session.recover JOIN %s", client->session->nick, client->session->username, channel->name);
+        usersession_client_raw(session, raw);
+        
+        sprintf(raw, "NAMES %s", channel->name);
+        ircclient_send(client, raw);
+    }
+}