added QServer for external cache access
authorpk910 <philipp@zoelle1.de>
Sun, 15 Jan 2012 12:34:53 +0000 (13:34 +0100)
committerpk910 <philipp@zoelle1.de>
Sun, 15 Jan 2012 14:26:13 +0000 (15:26 +0100)
Makefile.am
QServer/NeonServ_QServer.class.php [new file with mode: 0644]
neonserv.example.conf
src/QServer.c [new file with mode: 0644]
src/QServer.h [new file with mode: 0644]
src/main.c

index ea2f28645c226ba7fd6d025ec8f777aa5e01daf0..3789db908cad16585f98843bc09a8d67d30ceb61 100644 (file)
@@ -134,7 +134,8 @@ neonserv_SOURCES = src/version.c \
       src/cmd_neonserv_halfopall.c \
       src/cmd_neonserv_dehalfopall.c \
       src/cmd_funcmds.c \
-      src/ConfigParser.c
+      src/ConfigParser.c \
+      src/QServer.c
 
 neonserv_LDADD = $(MYSQL_LIBS) $(WINSOCK_LIBS)
 
diff --git a/QServer/NeonServ_QServer.class.php b/QServer/NeonServ_QServer.class.php
new file mode 100644 (file)
index 0000000..e3fb4b0
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/* NeonServ_QServer.class.php - NeonServ v5
+ * 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/>. 
+ */
+
+class NeonServ_QServer {
+    private $admin, $socket, $numeric;
+    
+    function NeonServ_QServer() {
+        $this->admin['pass']='*'; // QServer Passwort
+        $this->admin['host']='127.0.0.1';
+        $this->admin['port']=7499;
+    }
+    
+    public function disconnect() {
+        fclose($this->socket);
+        $this->socket=false;
+    }
+    
+    public function connect() {
+        if($this->socket) {
+            $this->disconnect();
+        }
+        $this->socket=@fsockopen($this->admin['host'], $this->admin['port'], $errno, $errstr, 3);
+        if ($this->socket) {
+            stream_set_timeout($this->socket, 2);
+            fputs($this->socket, "A ".$this->admin['pass']."\n");
+            $data = $this->parseLine(@fgets($this->socket));
+            if($data[0] == "A")
+                return true;
+            $this->disconnect(); //not logged in...
+            return false;
+        }
+    }
+    
+    public function connected() {
+        if($this->socket) return true;
+        return false;
+    }
+    
+    private function parseLine($line) {
+        $line = str_replace(array("\r", "\n"), array("", ""), $line);
+        $highExplode = explode(" :", $line, 2);
+        $tokens = explode(" ", $highExplode[0]);
+        if(count($highExplode) > 1)
+            $tokens[] = $highExplode[1];
+        return $tokens;
+    }
+    
+    /* Get IRC User Information
+    * returns array: nick, ident, host, auth, realname
+    */
+    public function getUser($nick) {
+        fputs($this->socket, "U ".$nick."\n");
+        $data = $this->parseLine(@fgets($this->socket));
+        if($data[0] != "U") return NULL;
+        if($data[1] == "0") return NULL; //User not found
+        $user = array();
+        $user['nick'] = $data[2];
+        $user['ident'] = $data[3];
+        $user['host'] = $data[4];
+        $user['auth'] = ($data[5] == "0" ? NULL : $data[5]);
+        $user['realname'] = $data[6];
+        return $user;
+    }
+    
+    /* Get IRC Channel Information
+    * returns array: name, usercount, modes, topic
+    */
+    public function getChannel($name) {
+        fputs($this->socket, "C ".$name."\n");
+        $data = $this->parseLine(@fgets($this->socket));
+        if($data[0] != "C") return NULL;
+        if($data[1] == "0") return NULL; //Channel not found
+        $chan = array();
+        $chan['name'] = $data[2];
+        $chan['usercount'] = $data[3];
+        $chan['modes'] = implode(" ", array_slice($data, 4, (count($data) - 5)));
+        $chan['topic'] = $data[count($data)-1];
+        return $chan;
+    }
+    
+    /* Get All IRC Channels
+    * returns array with subarrays: name, usercount, modes, topic
+    */
+    public function getChannels() {
+        fputs($this->socket, "AC\n");
+        $channels = array();
+        while(true) {
+            $data = $this->parseLine(@fgets($this->socket));
+            if($data[0] == "E") return NULL;
+            if($data[0] == "ACE") break;
+            if($data[0] == "AC") {
+                $chan = array();
+                $chan['name'] = $data[1];
+                $chan['usercount'] = $data[2];
+                $chan['modes'] = implode(" ", array_slice($data, 3, (count($data) - 4)));
+                $chan['topic'] = $data[count($data)-1];
+                $channels[] = $chan;
+            }
+        }
+        return $channels;
+    }
+    
+    /* Get IRC Channel Users
+    * returns array with subarrays: nick, auth, flags
+    */
+    public function getChannelUsers($name, $invisibles = false) {
+        fputs($this->socket, "ACU ".$name." ".($invisibles ? "1" : "0")."\n");
+        $chanusers = array();
+        while(true) {
+            $data = $this->parseLine(@fgets($this->socket));
+            if($data[0] == "E") return NULL;
+            if($data[0] == "ACUE") break;
+            if($data[0] == "ACU") {
+                $chanuser = array();
+                $chanuser['nick'] = $data[1];
+                $chanuser['auth'] = ($data[2] == "0" ? NULL : $data[2]);
+                $chanuser['flags'] = $data[3];
+                $chanusers[] = $chanuser;
+            }
+        }
+        return $chanusers;
+    }
+    
+    /* send IRC RAW
+    * returns true / false
+    */
+    public function sendRAW($class, $raw, $classIsNick = false) {
+        fputs($this->socket, "R ".($classIsNick ? "1" : "0")." ".$class." :".$raw."\n");
+        $data = $this->parseLine(@fgets($this->socket));
+        if($data[0] == "R" && $data[1] == "1") return true;
+        return false;
+    }
+}
+
+?>
index abb149d5338bcf56cd356d69a40233273fa74369..b0321641012c8b992ecf5a1f001d5caf921c4e0b 100644 (file)
@@ -12,4 +12,9 @@
 "General" {
     "alertchan" = "";
     "have_halfop" = 0;
+};
+"QServer" {
+    "enabled" = 1;
+    "port" = 7499;
+    "pass" = "blaa";
 };
\ No newline at end of file
diff --git a/src/QServer.c b/src/QServer.c
new file mode 100644 (file)
index 0000000..fd10beb
--- /dev/null
@@ -0,0 +1,421 @@
+/* QServer.c - NeonServ v5.3
+ * 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 "QServer.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ModeNode.h"
+#include "ChanUser.h"
+#include "ClientSocket.h"
+#include "WHOHandler.h"
+#include "ConfigParser.h"
+#include "bots.h"
+
+#define QSERVER_TIMEOUT 30
+#define QSERVER_MAXCLIENTS 100
+
+#define QSERVER_FLAG_DISCONNECT 0x01
+#define QSERVER_FLAG_AUTHED     0x02
+#define QSERVER_FLAG_IN_USE     0x04
+
+struct QServerClient {
+    int sock;
+    unsigned int flags;
+    time_t lastmsg;
+    char buffer[MAXLEN];
+    int bufferpos;
+    int references;
+    struct QServerClient *next;
+};
+
+static int server_sockfd = 0;
+struct QServerClient *qserver_clients = NULL;
+static int qserver_clientcount = 0;
+
+void qserver_init() {
+    if(get_int_field("QServer.enabled")) {
+        server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
+        if (server_sockfd < 0) 
+            return;
+        struct sockaddr_in serv_addr;
+        bzero((char *) &serv_addr, sizeof(serv_addr));
+        int portno = get_int_field("QServer.port");
+        if(!portno)
+            portno = 7499;
+        serv_addr.sin_family = AF_INET;
+        serv_addr.sin_addr.s_addr = INADDR_ANY;
+        serv_addr.sin_port = htons(portno);
+        if (bind(server_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
+            return;
+        listen(server_sockfd,5);
+    }
+}
+
+static int qserver_write(struct QServerClient *client, char* msg, int len) {
+    if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return 0;
+    if(!len)
+        len = strlen(msg);
+    #ifdef WIN32
+    send(client->sock, msg, len, 0);
+    #else
+    write(client->sock, msg, len);
+    #endif
+    return 1;
+}
+
+static void qserver_put(struct QServerClient *client, const char *text, ...) {
+    va_list arg_list;
+    char sendBuf[MAXLEN];
+    int pos;
+    if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
+    sendBuf[0] = '\0';
+    va_start(arg_list, text);
+    pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
+    va_end(arg_list);
+    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
+    sendBuf[pos] = '\n';
+    sendBuf[pos+1] = '\0';
+    qserver_write(client, sendBuf, pos+1);
+}
+
+static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
+    if(client->flags & QSERVER_FLAG_AUTHED) {
+        qserver_put(client, "E :Already Authed");
+        return;
+    }
+    if(!argv) {
+        qserver_put(client, "E :Missing Parameter");
+        return;
+    }
+    if(strcmp(argv[0], get_string_field("QServer.pass"))) {
+        qserver_put(client, "E :Wrong Password");
+        return;
+    }
+    client->flags |= QSERVER_FLAG_AUTHED;
+    client->lastmsg = time(0);
+    qserver_put(client, "A :Logged in");
+}
+
+#define QSERVER_COMMAND_HEADER {\
+    if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
+        qserver_put(client, "E :Not Authed");\
+        return;\
+    }\
+    client->lastmsg = time(0);\
+}
+
+static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
+static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
+static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
+static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
+static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
+
+static void qserver_parse(struct QServerClient *client, char *line, int len) {
+    int argc = 0;
+    char *argv[MAXNUMPARAMS];
+    while(*line) {
+        //skip leading spaces
+        while (*line == ' ')
+            *line++ = 0;
+        if (*line == ':') {
+           //the rest is a single parameter
+           argv[argc++] = line + 1;
+           break;
+        }
+        argv[argc++] = line;
+        if (argc >= MAXNUMPARAMS)
+            break;
+        while (*line != ' ' && *line)
+            line++;
+    }
+    if(!stricmp(argv[0], "A")) //AUTH
+        qserver_parse_A(client, argv+1, argc-1);
+    else if(!stricmp(argv[0], "U")) //get User
+        qserver_parse_U(client, argv+1, argc-1);
+    else if(!stricmp(argv[0], "C")) //get Channel
+        qserver_parse_C(client, argv+1, argc-1);
+    else if(!stricmp(argv[0], "AC")) //get All Channels
+        qserver_parse_AC(client, argv+1, argc-1);
+    else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
+        qserver_parse_ACU(client, argv+1, argc-1);
+    else if(!stricmp(argv[0], "R")) //RAW
+        qserver_parse_R(client, argv+1, argc-1);
+    else
+        qserver_put(client, "E :Unknown Command");
+}
+
+void qserver_loop() {
+    struct timeval tv;
+    struct QServerClient *client, *next, *prev = NULL;
+    int ret;
+    time_t now = time(0);
+    fd_set fds;
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    FD_ZERO(&fds);
+    ret = server_sockfd;
+    FD_SET(server_sockfd, &fds);
+    for (client = qserver_clients; client; client = next) {
+        next = client->next;
+        if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
+            close(client->sock);
+            if(prev) 
+                prev->next = client->next;
+            else
+                qserver_clients = client->next;
+            qserver_clientcount--;
+            free(client);
+            continue;
+        }
+        prev = client;
+        if(client->flags & QSERVER_FLAG_DISCONNECT) continue;
+        if(now - client->lastmsg > QSERVER_TIMEOUT) {
+            qserver_put(client, "E :Timeout");
+            client->flags |= QSERVER_FLAG_DISCONNECT;
+            continue;
+        }
+        FD_SET(client->sock, &fds);
+        if(client->sock > ret)
+            ret = client->sock;
+    }
+    ret = select(ret + 1, &fds, NULL, NULL, &tv);
+    if(ret == 0) {
+        return;
+    }
+    if(FD_ISSET(server_sockfd, &fds)) {
+        //new connection
+        struct sockaddr_in cli_addr;
+        socklen_t clilen;
+        if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
+            qserver_put(client, "E :Maximum QServer Connections reached");
+            close(client->sock);
+        } else {
+            client = malloc(sizeof(*client));
+            clilen = sizeof(cli_addr);
+            client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
+            client->flags = 0;
+            client->lastmsg = now;
+            client->bufferpos = 0;
+            client->references = 0;
+            client->next = qserver_clients;
+            qserver_clients = client;
+            qserver_clientcount++;
+        }
+    }
+    int bytes, i;
+    char buffer[MAXLEN];
+    for (client = qserver_clients; client; client = next) {
+        next = client->next;
+        if(FD_ISSET(client->sock, &fds)) {
+            #ifdef WIN32
+            bytes = recv(client->sock, buffer, sizeof(buffer), 0);
+            #else
+            bytes = read(client->sock, buffer, sizeof(buffer));
+            #endif
+            if(bytes <= 0) {
+                client->flags |= QSERVER_FLAG_DISCONNECT;
+                continue;
+            }
+            for(i = 0; i < bytes; i++) {
+                if(client->bufferpos == MAXLEN-1) {
+                    //buffer overflow
+                    qserver_put(client, "E :Buffer Overflow");
+                    client->flags |= QSERVER_FLAG_DISCONNECT;
+                    break;
+                }
+                if(buffer[i] == '\r') continue;
+                else if(buffer[i] == '\n') {
+                    client->buffer[client->bufferpos] = '\0';
+                    qserver_parse(client, client->buffer, client->bufferpos);
+                    client->bufferpos = 0;
+                } else {
+                    client->buffer[client->bufferpos++] = buffer[i];
+                }
+            }
+        }
+    }
+}
+
+void qserver_free() {
+    struct QServerClient *client, *next;
+    for (client = qserver_clients; client; client = next) {
+        next = client->next;
+        close(client->sock);
+        free(client);
+    }
+    qserver_clients = NULL;
+    qserver_clientcount = 0;
+    close(server_sockfd);
+}
+
+/* 
+* Command functions
+*/
+
+static USERAUTH_CALLBACK(qserver_parse_U_async);
+static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
+    QSERVER_COMMAND_HEADER;
+    if(!argv) {
+        qserver_put(client, "E :Missing Parameter");
+        return;
+    }
+    struct UserNode *cuser = getUserByNick(argv[0]);
+    if(!cuser) {
+        cuser = createTempUser(argv[0]);
+        if(!cuser) {
+            qserver_put(client, "U 0 :Unknown User");
+            return;
+        }
+        cuser->flags |= USERFLAG_ISTMPUSER;
+    }
+    client->references++;
+    client->flags |= QSERVER_FLAG_IN_USE;
+    get_userauth(cuser, qserver_parse_U_async, client);
+}
+
+static USERAUTH_CALLBACK(qserver_parse_U_async) {
+    struct QServerClient *qclient = data;
+    qclient->references--;
+    if(!qclient->references)
+        qclient->flags &= ~QSERVER_FLAG_IN_USE;
+    if(!user) {
+        qserver_put(qclient, "U 0 :Unknown User");
+        return;
+    }
+    qserver_put(qclient, "U 1 %s %s %s %s :%s", user->nick, user->ident, user->host, ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "0"), user->realname);
+}
+
+static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
+    QSERVER_COMMAND_HEADER;
+    if(!argv) {
+        qserver_put(client, "E :Missing Parameter");
+        return;
+    }
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(!chan) {
+        qserver_put(client, "C 0 :Unknown Channel");
+        return;
+    }
+    char tmpStr[MAXLEN];
+    getModeString(chan->modes, tmpStr);
+    qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
+}
+
+static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
+    QSERVER_COMMAND_HEADER;
+    struct ChanNode *chan;
+    char tmpStr[MAXLEN];
+    for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
+        getModeString(chan->modes, tmpStr);
+        qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
+    }
+    qserver_put(client, "ACE"); //AllChannelsEnd
+}
+
+static USERLIST_CALLBACK(qserver_parse_ACU_async);
+static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
+    QSERVER_COMMAND_HEADER;
+    if(!argv) {
+        qserver_put(client, "E :Missing Parameter");
+        return;
+    }
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(!chan) {
+        qserver_put(client, "ACUE 0 :Unknown Channel");
+        return;
+    }
+    if(argc > 1 && !stricmp(argv[1], "1")) {
+        client->references++;
+        client->flags |= QSERVER_FLAG_IN_USE;
+        get_userlist_if_invisible(chan, qserver_parse_ACU_async, client);
+        return;
+    }
+    char tmpStr[6];
+    int tmpStrPos;
+    struct ChanUser *chanuser;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        tmpStrPos = 0;
+        if(chanuser->flags & CHANUSERFLAG_OPPED)
+            tmpStr[tmpStrPos++] = '@';
+        if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
+            tmpStr[tmpStrPos++] = '%';
+        if(chanuser->flags & CHANUSERFLAG_VOICED)
+            tmpStr[tmpStrPos++] = '+';
+        if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
+            tmpStr[tmpStrPos++] = '<';
+        tmpStr[tmpStrPos] = '\0';
+        qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
+    }
+    qserver_put(client, "ACUE 1");
+}
+
+static USERLIST_CALLBACK(qserver_parse_ACU_async) {
+    struct QServerClient *qclient = data;
+    qclient->references--;
+    if(!qclient->references)
+        qclient->flags &= ~QSERVER_FLAG_IN_USE;
+    char tmpStr[6];
+    int tmpStrPos;
+    struct ChanUser *chanuser;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        tmpStrPos = 0;
+        if(chanuser->flags & CHANUSERFLAG_OPPED)
+            tmpStr[tmpStrPos++] = '@';
+        if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
+            tmpStr[tmpStrPos++] = '%';
+        if(chanuser->flags & CHANUSERFLAG_VOICED)
+            tmpStr[tmpStrPos++] = '+';
+        if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
+            tmpStr[tmpStrPos++] = '<';
+        tmpStr[tmpStrPos] = '\0';
+        qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
+    }
+    qserver_put(qclient, "ACUE 1");
+}
+
+static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
+    QSERVER_COMMAND_HEADER;
+    if(argc < 3) {
+        qserver_put(client, "E :Missing Parameter");
+        return;
+    }
+    struct ClientSocket *bot;
+    if(!strcmp(argv[0], "1")) {
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(!stricmp(bot->user->nick, argv[1])) break;
+        }
+    } else {
+        struct ClientSocket *low_bot;
+        int botid = resolve_botalias(argv[1]);
+        if(botid == -1)
+            botid = atoi(argv[1]);
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->botid == botid) {
+                if(bot->flags & SOCKET_FLAG_PREFERRED) break;
+                low_bot = bot;
+            }
+        }
+        if(!bot)
+            bot = low_bot;
+    }
+    if(!bot) {
+        qserver_put(client, "R 0 :Bot not found");
+        return;
+    }
+    putsock(bot, "%s", argv[2]);
+    qserver_put(client, "R 1");
+}
diff --git a/src/QServer.h b/src/QServer.h
new file mode 100644 (file)
index 0000000..fc188c1
--- /dev/null
@@ -0,0 +1,26 @@
+/* QServer.h - NeonServ v5.3
+ * 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 _QServer_h
+#define _QServer_h
+
+#include "main.h"
+
+void qserver_init();
+void qserver_loop();
+void qserver_free();
+
+#endif
\ No newline at end of file
index 107d50eef806d9b8f31f816c9a9bd10ec24f8a27..e8d366aa0d7141696c51b302cc900f2b961fa3c2 100644 (file)
@@ -36,6 +36,7 @@
 #include "commands.h"
 #include "ConfigParser.h"
 #include "ssl.h"
+#include "QServer.h"
 
 time_t start_time;
 static int running, hard_restart;
@@ -50,6 +51,7 @@ pthread_mutex_t whohandler_sync, whohandler_mass_sync;
 
 void cleanup() {
     free_sockets();
+    qserver_free();
     free_parser();
     free_UserNode();
     free_ChanNode();
@@ -156,6 +158,7 @@ main:
     register_commands();
     init_bots();
     init_DBHelper();
+    qserver_init();
     
     load_languages();
     int update_minutes = get_int_field("statistics.frequency");
@@ -177,6 +180,7 @@ main:
     while(running) {
         timeq_tick();
         loop_bots();
+        qserver_loop();
         queue_loop();
         usleep(usleep_delay);
     }
@@ -195,6 +199,7 @@ main:
         loop_bots();
         clearTempUsers();
         destroyEvents();
+        qserver_loop();
         queue_loop();
     }
     #endif