added session manager and support for an external login system
authorpk910 <philipp@zoelle1.de>
Wed, 9 May 2012 22:04:26 +0000 (00:04 +0200)
committerpk910 <philipp@zoelle1.de>
Thu, 10 May 2012 23:33:52 +0000 (01:33 +0200)
14 files changed:
Makefile.am
login.php [new file with mode: 0644]
src/IOEngine_select.c
src/IOHandler.c
src/IOHandler.h
src/UserClient.c
src/UserClient.h
src/UserSession.c [new file with mode: 0644]
src/UserSession.h [new file with mode: 0644]
src/main.c
src/overall.h
src/tools.c
src/tools.h
transirc.conf [new file with mode: 0644]

index edd0e477affae499f4dc4c26265902938a387d9f..7d04a23042bd48749488d3186f63302685cacb53 100644 (file)
@@ -15,6 +15,7 @@ transirc_SOURCES = src/version.c \
       src/main.c \
       src/ServerSocket.c \
       src/tools.c \
+      src/UserSession.c \
       src/UserClient.c
 
 transirc_LDADD = $(MYSQL_LIBS) $(SYSTEM_LIBS)
diff --git a/login.php b/login.php
new file mode 100644 (file)
index 0000000..c6f95cc
--- /dev/null
+++ b/login.php
@@ -0,0 +1,12 @@
+<?php
+
+$username = $argv[1];
+$password = $argv[2];
+$nick = $argv[3];
+
+if($username == "pk910")
+    echo "ACCEPT\n";
+else
+    echo "REJECT\n";
+
+?>
\ No newline at end of file
index dabe2e6b28ec94f788c19cc592c348b45736ec93..2f32bf04fe9f8eb457bd5c5c5c7dd0f316d04948 100644 (file)
@@ -56,15 +56,16 @@ static void engine_select_loop(struct timeval *timeout) {
             FD_SET(iofd->fd, &read_fds);
             if(iohandler_wants_writes(iofd))
                 FD_SET(iofd->fd, &write_fds);
-        } else if(iofd->type == IOTYPE_TIMER) {
+        }
+        if(iofd->type == IOTYPE_TIMER || iofd->timeout.tv_sec || iofd->timeout.tv_usec) {
             tdiff.tv_sec = iofd->timeout.tv_sec - now.tv_sec;
             tdiff.tv_usec = iofd->timeout.tv_usec - now.tv_usec;
             
             if(tdiff.tv_sec < 0 || (tdiff.tv_sec == 0 && tdiff.tv_usec <= 0)) {
                 //exec timer
-                iofd->state = IO_CLOSED;
-                iohandler_events(iofd, 1, 0);
-                iohandler_close(iofd);
+                iohandler_events(iofd, 0, 0);
+                if(iofd->type == IOTYPE_TIMER)
+                    iohandler_close(iofd);
                 continue;
             } else if(tdiff.tv_usec < 0) {
                 tdiff.tv_sec--;
@@ -87,6 +88,8 @@ static void engine_select_loop(struct timeval *timeout) {
         }
     }
     
+    gettimeofday(&now, NULL);
+    
     //check all descriptors
     for(iofd = first_descriptor; iofd; iofd = tmp_iofd) {
         tmp_iofd = iofd->next;
@@ -94,14 +97,16 @@ static void engine_select_loop(struct timeval *timeout) {
             if(FD_ISSET(iofd->fd, &read_fds) || FD_ISSET(iofd->fd, &write_fds)) {
                 iohandler_events(iofd, FD_ISSET(iofd->fd, &read_fds), FD_ISSET(iofd->fd, &write_fds));
             }
-        } else if(iofd->type == IOTYPE_TIMER) {
+        }
+        if(iofd->type == IOTYPE_TIMER || iofd->timeout.tv_sec || iofd->timeout.tv_usec) {
             tdiff.tv_sec = iofd->timeout.tv_sec - now.tv_sec;
             tdiff.tv_usec = iofd->timeout.tv_usec - now.tv_usec;
             
             if(tdiff.tv_sec < 0 || (tdiff.tv_sec == 0 && tdiff.tv_usec <= 0)) {
                 //exec timer
-                iofd->state = IO_CLOSED;
-                iohandler_events(iofd, 1, 0);
+                iohandler_events(iofd, 0, 0);
+                if(iofd->type == IOTYPE_TIMER)
+                    iohandler_close(iofd);
                 continue;
             }
         }
index b276272ec11a44480468f95e87bc8bae00855598..375bcea86e3a20e8196114a33cbf6f3bbdd47df2 100644 (file)
@@ -71,7 +71,7 @@ struct IODescriptor *iohandler_add(int sockfd, enum IOType type, iohandler_callb
     return descriptor;
 }
 
-static void iohandler_remove(struct IODescriptor *descriptor) {
+static void iohandler_remove(struct IODescriptor *descriptor, int engine_remove) {
     //remove IODescriptor from the list
     if(descriptor->prev)
         descriptor->prev->next = descriptor->next;
@@ -79,7 +79,8 @@ static void iohandler_remove(struct IODescriptor *descriptor) {
         first_descriptor = descriptor->next;
     if(descriptor->next)
         descriptor->next->prev = descriptor->prev;
-    engine->remove(descriptor);
+    if(engine_remove)
+        engine->remove(descriptor);
     if(descriptor->readbuf.buffer)
         free(descriptor->readbuf.buffer);
     if(descriptor->writebuf.buffer)
@@ -296,7 +297,7 @@ void iohandler_write(struct IODescriptor *iofd, const char *line) {
 }
 
 void iohandler_send(struct IODescriptor *iofd, const char *data, size_t datalen) {
-    if(iofd->type == IOTYPE_TIMER) return; //can not write to timer? :D
+    if(iofd->type == IOTYPE_TIMER || iofd->state == IO_CLOSED) return; //can not write to timer? :D
     if(iofd->writebuf.buflen < iofd->writebuf.bufpos + datalen) {
         iohandler_increase_iobuf(&iofd->writebuf, iofd->writebuf.bufpos + datalen);
         if(iofd->writebuf.buflen < iofd->writebuf.bufpos + datalen)
@@ -335,10 +336,24 @@ void iohandler_try_write(struct IODescriptor *iofd) {
 }
 
 void iohandler_close(struct IODescriptor *iofd) {
+    int engine_remove = 1;
+    if(iofd->writebuf.bufpos) {
+        //try to send everything before closing
+#if defined(F_GETFL)
+        flags = fcntl(sockfd, F_GETFL);
+        fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK);
+        flags = fcntl(sockfd, F_GETFD);
+        fcntl(sockfd, F_SETFD, flags|FD_CLOEXEC);
+#else
+        engine_remove = 0;
+        engine->remove(iofd);
+#endif
+        iohandler_try_write(iofd);
+    }
     //close IODescriptor
     if(iofd->type == IOTYPE_SERVER || iofd->type == IOTYPE_CLIENT || iofd->type == IOTYPE_STDIN)
         close(iofd->fd);
-    iohandler_remove(iofd);
+    iohandler_remove(iofd, engine_remove);
 }
 
 void iohandler_update(struct IODescriptor *iofd) {
@@ -360,11 +375,13 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
                 callback_event.type = IOEVENT_TIMEOUT;
             break;
         case IO_LISTENING:
-            callback_event.data.accept_fd = accept(iofd->fd, NULL, 0);
-            if(callback_event.data.accept_fd < 0) {
-                //error: could not accept
-            } else
-                callback_event.type = IOEVENT_ACCEPT;
+            if(readable) {
+                callback_event.data.accept_fd = accept(iofd->fd, NULL, 0);
+                if(callback_event.data.accept_fd < 0) {
+                    //error: could not accept
+                } else
+                    callback_event.type = IOEVENT_ACCEPT;
+            }
             break;
         case IO_CONNECTING:
             if(readable) { //could not connect
@@ -386,6 +403,7 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
                     int bytes = recv(iofd->fd, iofd->readbuf.buffer + iofd->readbuf.bufpos, iofd->readbuf.buflen - iofd->readbuf.bufpos, 0);
                     if(bytes <= 0) {
                         if (errno != EAGAIN) {
+                            iofd->state = IO_CLOSED;
                             callback_event.type = IOEVENT_CLOSED;
                             callback_event.data.errid = errno;
                         }
@@ -429,6 +447,8 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
             }
             break;
     }
+    if(callback_event.type == IOEVENT_IGNORE && !readable && !writeable) 
+        callback_event.type = IOEVENT_TIMEOUT;
     if(callback_event.type != IOEVENT_IGNORE)
         iohandler_trigger_event(&callback_event);
 }
index 7d33ce23f9ee070b37be8129e8e0acd5863290bc..8bc2a37426913a924e1f56f52f4520b6843c88db 100644 (file)
@@ -57,6 +57,7 @@ struct IOBuffer {
 
 struct IODescriptor {
     int fd;
+    FILE *file;
     enum IOType type;
     enum IOStatus state;
     struct timeval timeout;
@@ -80,6 +81,7 @@ struct IOEvent {
 };
 
 struct IODescriptor *iohandler_add(int sockfd, enum IOType type, iohandler_callback *callback);
+struct IODescriptor *iohandler_file(FILE *file, iohandler_callback *callback);
 struct IODescriptor *iohandler_timer(struct timeval timeout, iohandler_callback *callback);
 struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, const char *bind, iohandler_callback *callback);
 struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, iohandler_callback *callback);
index fccf56b1b563bff933b8ecc875a254df53302096..e64b8a0befd995b3e40f40df74629022ff9e83d9 100644 (file)
@@ -17,6 +17,8 @@
 #include "UserClient.h"
 #include "IOHandler.h"
 #include "ServerSocket.h"
+#include "UserSession.h"
+#include "tools.h"
 
 static void userclient_callback(struct IOEvent *event);
 
@@ -29,12 +31,17 @@ void userclient_accepted(struct ServerSocket *server, int sockfd) {
     iofd->state = IO_CONNECTED;
     iofd->read_lines = 1;
     iohandler_update(iofd);
-    client = malloc(sizeof(*client));
+    client = calloc(1, sizeof(*client));
     client->iofd = iofd;
     iofd->data = client;
     client->server = server;
     server->clientcount++;
     
+    struct UserLogin *login = calloc(1, sizeof(*login));
+    client->user = login;
+    login->client = client;
+    
+    
     //add UserClient to the list
     client->prev = NULL;
     client->next = userclients;
@@ -43,10 +50,29 @@ void userclient_accepted(struct ServerSocket *server, int sockfd) {
     userclients = client;
     
     //let's say hello to the client
-    iohandler_printf(iofd, "NOTICE AUTH :*** TransparentIRC " TRANSIRC_VERSION " (use /quote transirc for more information)");
+    iohandler_printf(iofd, "NOTICE AUTH :*** [TransparentIRC] TransparentIRC v" TRANSIRC_VERSION " (use /quote transirc for more information)");
 }
 
 void userclient_close(struct UserClient *client) {
+    if(client->flags & USERCLIENT_LOGGED_IN) {
+        usersession_client_close(client->user);
+    } else {
+        struct UserLogin *login = client->user;
+        if(client->flags & USERCLIENT_LOGIN_PROCESSING) {
+            usersession_login_abort(login);
+        }
+        if(login->username)
+            free(login->username);
+        if(login->password)
+            free(login->password);
+        if(login->nick)
+            free(login->nick);
+        if(login->reject_reason)
+            free(login->reject_reason);
+        if(login->session_class)
+            free(login->session_class);
+        free(login);
+    }
     iohandler_close(client->iofd);
     client->server->clientcount--;
     if(client->prev)
@@ -55,6 +81,7 @@ void userclient_close(struct UserClient *client) {
         userclients = client->next;
     if(client->next)
         client->next->prev = client->prev;
+    
     free(client);
 }
 
@@ -72,7 +99,72 @@ void userclient_close_server(struct ServerSocket *server, int keep_clients) {
 }
 
 static void userclient_recv(struct UserClient *client, char *line) {
-    iohandler_printf(client->iofd, "reply: %s", line);
+    if(!stricmplen(line, "TRANSIRC ", 9)) {
+        /*
+        char *argv[MAXNUMPARAMS];
+        int argc = parse_line(line, argv, 1);
+        */
+        
+    } else if(!(client->flags & USERCLIENT_LOGGED_IN)) {
+        struct UserLogin *login = client->user;
+        char *argv[MAXNUMPARAMS];
+        int argc = parse_line(line, argv, 1);
+        if(argc < 3) return;
+        if(!stricmp(argv[1], "PASS")) {
+            char *delimiter = strchr(argv[2], ':');
+            if(login->password)
+                free(login->password);
+            if(delimiter) {
+                *delimiter = '\0';
+                delimiter++;
+                if(login->username)
+                    free(login->username);
+                login->username = strdup(argv[2]);
+                login->password = strdup(delimiter);
+            } else 
+                login->password = strdup(argv[2]);
+        } else if(!stricmp(argv[1], "USER")) {
+            if(!login->username)
+                login->username = strdup(argv[2]);
+        } else if(!stricmp(argv[1], "NICK")) {
+            if(login->nick)
+                free(login->nick);
+            login->nick = strdup(argv[2]);
+            if(!login->password) {
+                iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] You need to send your LOC data. Try /quote PASS <username>:<password>");
+            }
+        }
+        if(login->username && login->password && login->nick && !(client->flags & USERCLIENT_LOGIN_PROCESSING)) {
+            //try to login
+            iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Checking login...");
+            usersession_login(login);
+        }
+    } else {
+        
+    }
+}
+
+void userclient_login_failed(struct UserLogin *login, char *reason) {
+    iohandler_printf(login->client->iofd, "NOTICE AUTH :*** [TransparentIRC] Login rejected");
+    userclient_close(login->client);
+}
+
+void userclient_login_successful(struct UserLogin *login, struct UserSession *session, int recover) {
+    struct UserClient *client = login->client;
+    iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Login accepted.");
+    if(login->username)
+        free(login->username);
+    if(login->password)
+        free(login->password);
+    if(login->nick)
+        free(login->nick);
+    free(login);
+    client->user = session;
+    if(recover) {
+        iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Recovering previous link (Nick: %s).", session->nick);
+        
+        
+    }
 }
 
 static void userclient_callback(struct IOEvent *event) {
index 6b95ea1f99336ff2d13d0cb9c0d5b70357fe78a5..bde600145e9fd4cc1c5aea87c33d973cafe85813 100644 (file)
 
 struct IODescriptor;
 struct ServerSocket;
-//struct UserSession;
+struct UserSession;
+
+#define USERCLIENT_LOGIN_PROCESSING 0x01
+#define USERCLIENT_LOGGED_IN        0x02
+
+struct UserLogin {
+    struct UserClient *client;
+    char *username;
+    char *password;
+    char *nick;
+    
+    int login_accepted : 1;
+    char *reject_reason;
+    
+    char *session_class;
+    
+    struct IODescriptor *login_iofd;
+};
 
 struct UserClient {
     struct IODescriptor *iofd;
     struct ServerSocket *server;
     
-    //struct UserSession *user;
+    int flags;
+    void *user; /* struct UserSession / struct UserLogin */
+    
+    char *username;
+    char *password;
+    char *nick;
     
     struct UserClient *next, *prev;
 };
@@ -35,5 +57,7 @@ struct UserClient {
 void userclient_accepted(struct ServerSocket *server, int sockfd);
 void userclient_close(struct UserClient *client);
 void userclient_close_server(struct ServerSocket *server, int keep_clients);
+void userclient_login_failed(struct UserLogin *login, char *reason);
+void userclient_login_successful(struct UserLogin *login, struct UserSession *session, int recover);
 
 #endif
diff --git a/src/UserSession.c b/src/UserSession.c
new file mode 100644 (file)
index 0000000..136b767
--- /dev/null
@@ -0,0 +1,221 @@
+/* UserSession.c - TransparentIRC 0.1
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#include "UserSession.h"
+#include "IOHandler.h"
+#include "UserClient.h"
+#include "ConfigParser.h"
+#include "tools.h"
+
+static struct UserSession *usersessions = NULL;
+
+static struct UserSession *usersession_add(char *username, char *password, char *nick) {
+    struct UserSession *session;
+    session = calloc(1, sizeof(*session));
+    session->username = strdup(username);
+    session->password = strdup(password);
+    session->nick = strdup(nick);
+    
+    //add UserSession to the list
+    session->prev = NULL;
+    session->next = usersessions;
+    if(usersessions)
+        usersessions->prev = session;
+    usersessions = session;
+    
+    return session;
+}
+
+/*
+static void usersession_close(struct UserSession *session) {
+    if(session->client)
+        userclient_close(session->client);
+    
+    if(session->prev)
+        session->prev->next = session->next;
+    else
+        usersessions = session->next;
+    if(session->next)
+        session->next->prev = session->prev;
+    free(session->username);
+    free(session->password);
+    free(session->nick);
+    free(session);
+}
+*/
+
+/* ****************** SESSION FUNCTIONS ****************** */
+
+static void usersession_initialize_session(struct UserSession *session) {
+    
+}
+
+/* ****************** EXTERNAL EVENTS ****************** */
+
+void usersession_client_close(struct UserSession *session) {
+    session->client = NULL;
+    session->idle_since = time(0);
+    
+}
+
+void usersession_client_notification(struct UserSession *session, char *notification) {
+    if(session->client) {
+        iohandler_printf(session->client->iofd, ":*TransparentIRC!TransIRC@TransparentIRC.system.notification NOTICE %s :[TransparentIRC] %s", session->nick, notification);
+    }
+}
+
+/* ****************** LOGIN FUNCTIONS ****************** */
+
+static void usersession_login_accept(struct UserLogin *login);
+static void usersession_login_callback(struct IOEvent *event);
+
+void usersession_login(struct UserLogin *login) {
+    if(get_int_field("auth.external.enabled")) {
+        char *execute = get_string_field("auth.external.execute");
+        char *parameters = get_string_field("auth.external.parameters");
+        
+        struct variable_replace_map map[] = {
+            {'U', login->username},
+            {'P', login->password},
+            {'N', login->nick},
+            {0, NULL}
+        };
+        char paramstr[CMDLEN+1];
+        build_var_string(paramstr, parameters, map);
+        char *argv[MAXNUMPARAMS];
+        int argc = parse_line(paramstr, argv+1, 0);
+        argv[0] = execute;
+        argv[argc+1] = NULL;
+        int fp = run_external_process(execute, argv);
+        if(fp < 0) {
+            userclient_login_failed(login, "Login Script error.");
+            return;
+        }
+        struct IODescriptor *iofd = iohandler_add(fp, IOTYPE_CLIENT, usersession_login_callback);
+        if(iofd) {
+            iofd->read_lines = 1;
+            iofd->state = IO_CONNECTED;
+            int timeout = get_int_field("auth.external.timeout");
+            if(timeout) {
+                gettimeofday(&iofd->timeout, NULL);
+                iofd->timeout.tv_sec += timeout;
+            }
+            iofd->data = login;
+            login->login_iofd = iofd;
+            login->client->flags |= USERCLIENT_LOGIN_PROCESSING;
+        } else
+            userclient_login_failed(login, "Internal error.");
+    } else 
+        usersession_login_accept(login);
+}
+
+static void usersession_login_accept(struct UserLogin *login) {
+    //search session for user (or create a new one)
+    struct UserSession *session, *active_session = NULL;
+    int sessioncount = 0;
+    for(session = usersessions; session; session = session->next) {
+        if(!stricmp(login->username, session->username)) {
+            sessioncount++;
+            if(!strcmp(login->password, session->password) && !stricmp(login->nick, session->nick)) {
+                active_session = session;
+            }
+        }
+    }
+    if(active_session) {
+        if(active_session->client) {
+            iohandler_printf(active_session->client->iofd, "ERROR :[TransparentIRC] Another client logged in.");
+            userclient_close(active_session->client);
+        } //active_session->client is now NULL
+        active_session->client = login->client;
+        userclient_login_successful(login, active_session, 1);
+    } else {
+        int sessionlimit = get_int_field("auth.session_limit");
+        if(sessionlimit && sessioncount >= sessionlimit) {
+            userclient_login_failed(login, "Session limit reached.");
+            return;
+        }
+        active_session = usersession_add(login->username, login->password, login->nick);
+        if(!active_session) {
+            userclient_login_failed(login, "Could not create Session.");
+            return;
+        }
+        userclient_login_successful(login, active_session, 0);
+        usersession_initialize_session(active_session);
+    }
+}
+
+void usersession_login_abort(struct UserLogin *login) {
+    struct IODescriptor *iofd = login->login_iofd;
+    iohandler_close(iofd);
+}
+
+static void usersession_login_callback(struct IOEvent *event) {
+    struct UserLogin *login = event->iofd->data;
+    login->client->flags &= ~USERCLIENT_LOGIN_PROCESSING;
+    char *reply;
+    int login_finished = 0;
+    switch(event->type) {
+        case IOEVENT_RECV:
+            reply = event->data.recv_str;
+            if(!stricmplen(reply, "REJECT", 6)) {
+                if((reply = strchr(reply, ' '))) {
+                    char reason[LINELEN];
+                    sprintf(reason, "Access denied: %s", reply + 7);
+                    login->reject_reason = strdup(reason);
+                } else
+                    login->reject_reason = strdup("Access denied.");
+            } else if(!stricmplen(reply, "ACCEPT", 6)) {
+                if((reply = strchr(reply, ' '))) {
+                    char *passwd = strchr(reply, ' ');
+                    if(passwd) {
+                        *passwd = '\0';
+                        passwd++;
+                        free(login->password);
+                        login->password = strdup(passwd);
+                    }
+                    free(login->username);
+                    login->username = strdup(reply);
+                }
+                login->login_accepted = 1;
+            } else {
+                char *argv[MAXNUMPARAMS];
+                int argc = parse_line(reply, argv, 0);
+                if(argc < 2) return;
+                if(!stricmp(argv[0], "CLASS")) {
+                    login->session_class = strdup(argv[1]);
+                }
+                
+            }
+            break;
+        case IOEVENT_TIMEOUT:
+            login->reject_reason = strdup("Login Script timeout.");
+            login_finished = 1;
+            break;
+        case IOEVENT_CLOSED:
+            login->reject_reason = strdup("Login Script error (no reply).");
+            login_finished = 1;
+            break;
+        default:
+            return;
+    }
+    if(login_finished) {
+        iohandler_close(event->iofd);
+        if(login->login_accepted)
+            usersession_login_accept(login);
+        else
+            userclient_login_failed(login, login->reject_reason);
+    }
+}
diff --git a/src/UserSession.h b/src/UserSession.h
new file mode 100644 (file)
index 0000000..deb9f59
--- /dev/null
@@ -0,0 +1,42 @@
+/* UserSession.h - TransparentIRC 0.1
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef _UserSession_h
+#define _UserSession_h
+#include "overall.h"
+
+struct UserClient;
+struct UserLogin;
+
+struct UserSession {
+    char *username;
+    char *password;
+    char *nick;
+    
+    struct UserClient *client;
+    time_t idle_since;
+    time_t connected_since;
+    
+    struct UserSession *next, *prev;
+};
+
+void usersession_client_notification(struct UserSession *session, char *notification);
+void usersession_login(struct UserLogin *login);
+void usersession_login_abort(struct UserLogin *login);
+void usersession_client_close(struct UserSession *session);
+
+#endif
index 19e5307488474bc8ed4727550cd5d1fa3fdc0217..ddf556809236d87a26fcdbf6713f0257fc359685 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "IOHandler.h"
 #include "ServerSocket.h"
+#include "ConfigParser.h"
 
 char *configFile = "transirc.conf";
 
@@ -43,6 +44,7 @@ int main(int argc, char *argv[]) {
     }
     #endif
     parseParameters(argc, argv);
+    loadConfig(configFile);
     
     serversocket_listen("0.0.0.0", 9001);
     
index 7345c79e0789c8cbec527c5ad624cdf14e575a07..edf7157ea6dc1550cb88504e125400db166c8a9a 100644 (file)
@@ -25,6 +25,8 @@
 #define IO_READ_BUFLEN 1024
 #define IO_MAX_TIMEOUT 10
 #define LINELEN 512
+#define CMDLEN 512
+#define MAXNUMPARAMS 200
 
 #include <stdio.h>
 #include <stdlib.h>
index 6478279f7aa2dc0ce5bfa392129c2faed42d3723..5a26b192382c690d35260e723cd31839faf22c25 100644 (file)
@@ -39,4 +39,102 @@ int stricmplen(const char *s1, const char *s2, int len) {
         if(i == len) break;
     }
     return c1 - c2;
-}
\ No newline at end of file
+}
+
+int parse_line(char *line, char **argv, int irc_raw) {
+    int argc = 0;
+    if(irc_raw) {
+        if(line[0] == ':')
+            line++;
+        else
+            argv[argc++] = NULL;
+    }
+    while(*line) {
+        //skip leading spaces
+        while (*line == ' ')
+            *line++ = 0;
+        if (*line == ':' && irc_raw) {
+           //the rest is a single parameter
+           argv[argc++] = line + 1;
+           break;
+        }
+        argv[argc++] = line;
+        if (argc >= MAXNUMPARAMS)
+            break;
+        while (*line != ' ' && *line)
+            line++;
+    }
+    return argc;
+}
+
+void build_var_string(char *buffer, char *format, struct variable_replace_map *map) {
+    int bufferpos = 0;
+    int i, escape = 0;
+    char *p = format;
+    char *tmp;
+    while(*p) {
+        if(escape) {
+            escape = 0;
+            goto build_var_string_addchar;
+        }
+        if(*p == '\\') {
+            escape = 1;
+            p++;
+            continue;
+        }
+        if(*p == '%') {
+            p++;
+            for(i = 0; ; i++) {
+                if(!map[i].character) {
+                    tmp = NULL;
+                    break;
+                }
+                if(map[i].character == *p) {
+                    tmp = map[i].value;
+                    break;
+                }
+            }
+            if(!tmp) {
+                p--;
+                goto build_var_string_addchar;
+            }
+            for(i = 0; tmp[i] && bufferpos < CMDLEN; i++) {
+                buffer[bufferpos++] = tmp[i]; 
+            }
+        } else {
+            build_var_string_addchar:
+            buffer[bufferpos++] = *p;
+            if(bufferpos == CMDLEN)
+                break;
+        }
+        p++;
+    }
+    buffer[bufferpos++] = '\0';
+}
+
+int run_external_process(char *command, char **parameters) { //win32 incompatible
+    int sockets[2], child;
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
+        return -1;
+    if ((child = fork()) == -1) {
+        close(sockets[0]);
+        close(sockets[1]);
+        return -1;
+    }
+    else if (child) { // This is the parent.
+        close(sockets[0]);
+        wait(NULL);
+        return sockets[1];
+    } else { // This is the child.
+        close(sockets[1]);
+        child = fork(); //double fork to prevent zombies
+        if(child < 0) exit(EXIT_FAILURE);
+        if(child != 0) exit(EXIT_SUCCESS);
+        if(dup2(sockets[0], 1) != -1) {
+            execvp(command, parameters);
+        }
+        close(sockets[0]);
+        exit(EXIT_FAILURE);
+    }
+}
+
index 4f4d11e3fd6450de6a0bd4eb2472e926c65a3687..33f4f0233f10387c21c5bfbc107aa1624d97bd7f 100644 (file)
 #define _tools_h
 #include "overall.h"
 
+struct variable_replace_map {
+    char character;
+    char *value;
+};
+
 int stricmp(const char *s1, const char *s2);
 int stricmplen(const char *s1, const char *s2, int len);
+int parse_line(char *line, char **argv, int irc_raw);
+void build_var_string(char *buffer, char *format, struct variable_replace_map *map);
+int run_external_process(char *command, char **parameters);
 
 #endif
diff --git a/transirc.conf b/transirc.conf
new file mode 100644 (file)
index 0000000..9729f84
--- /dev/null
@@ -0,0 +1,14 @@
+
+"auth" {
+    "session_limit" = 2;
+    
+    "external" {
+        "enabled" = 1;
+        "execute" = "./login.php";
+        // %U = Username
+        // %P = Password
+        // %N = Nick
+        "parameters" = "%U %P %N";
+        "timeout" = 5;
+    };
+};
\ No newline at end of file