Merge branch 'development'
[NeonServV5.git] / src / WHOHandler.c
index 5ad4ce6f302bf53bb7f5db8e5742700312650242..5db3db6a3d58be68ad50a402308033f61d004c6c 100644 (file)
@@ -1,4 +1,4 @@
-/* WHOHandler.c - NeonServ v5.3
+/* WHOHandler.c - NeonServ v5.6
  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
  * 
  * This program is free software: you can redistribute it and/or modify
@@ -22,6 +22,8 @@
 #include "ModeNode.h"
 #include "ClientSocket.h"
 #include "IPNode.h"
+#include "modules.h"
+#include "log.h"
 
 #define WHOQUEUETYPE_ISONQUEUE 0x01
 #define WHOQUEUETYPE_USERLIST  0x02
@@ -29,7 +31,7 @@
 #define WHOQUEUETYPE_CHECKTYPE 0x07
 #define WHOQUEUETYPE_FOUND     0x08
 
-#define MAXCALLBACKS 3
+#define MAXCALLBACKS 10
 
 struct WHOQueueEntry {
     char type;
@@ -38,17 +40,10 @@ struct WHOQueueEntry {
     struct UserNode *user;
     struct WHOQueueEntry *next;
     void *callback[MAXCALLBACKS];
+    int module_id[MAXCALLBACKS];
     void *data[MAXCALLBACKS];
 };
 
-#ifdef HAVE_THREADS
-struct ParseOrder {
-    unsigned long tid;
-    struct ParseOrder *next;
-};
-struct ParseOrder *parse_order = NULL;
-#endif
-
 static int checkWHOID(struct ClientSocket *client, int whoid) {
     struct WHOQueueEntry *entry;
     for(entry = client->whoqueue_first; entry; entry = entry->next) {
@@ -71,7 +66,7 @@ static struct WHOQueueEntry* addWHOQueueEntry(struct ClientSocket *client) {
     struct WHOQueueEntry *entry = malloc(sizeof(*entry));
     if (!entry)
     {
-        perror("malloc() failed");
+        printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
         DESYNCHRONIZE(whohandler_sync);
         return NULL;
     }
@@ -122,43 +117,7 @@ void clear_whoqueue(struct ClientSocket *client) {
     DESYNCHRONIZE(whohandler_sync);
 }
 
-#if HAVE_THREADS
-void whohandler_start_of_recv(struct ClientSocket *client, unsigned long tid) {
-    SYNCHRONIZE(whohandler_sync);
-    struct ParseOrder *entry, *last;
-    for(last = parse_order; last; last = last->next) {
-        if(last->next == NULL)
-            break;
-    }
-    entry = malloc(sizeof(*entry));
-    entry->tid = tid;
-    entry->next = NULL;
-    if(last)
-        last->next = entry;
-    else
-        parse_order = entry;
-    DESYNCHRONIZE(whohandler_sync);
-}
-
-void whohandler_end_of_recv(struct ClientSocket *client, unsigned long tid) {
-    SYNCHRONIZE(whohandler_sync);
-    struct ParseOrder *entry, *last = NULL;
-    for(entry = parse_order; entry; entry = entry->next) {
-        if(entry->tid == tid) {
-            if(last)
-                last->next = entry->next;
-            else
-                parse_order = entry->next;
-            free(entry);
-            break;
-        } else
-            last = entry;
-    }
-    DESYNCHRONIZE(whohandler_sync);
-}
-#endif
-
-void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data) {
+void get_userlist(struct ChanNode *chan, int module_id, userlist_callback_t callback, void *data) {
     struct ClientSocket *bot;
     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
         if(isUserOnChan(bot->user, chan))
@@ -181,6 +140,7 @@ void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *dat
         entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
         entry->chan = chan;
         entry->callback[0] = callback;
+        entry->module_id[0] = module_id;
         int i;
         for(i = 1; i < MAXCALLBACKS; i++)
             entry->callback[i] = NULL;
@@ -192,7 +152,7 @@ void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *dat
         callback(bot, chan, data);
 }
 
-void _get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t callback, void *data, int force) {
+void _get_userlist_with_invisible(struct ChanNode *chan, int module_id, userlist_callback_t callback, void *data, int force) {
     struct ClientSocket *bot;
     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
         if(isUserOnChan(bot->user, chan))
@@ -216,6 +176,7 @@ void _get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t cal
         entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
         entry->chan = chan;
         entry->callback[0] = callback;
+        entry->module_id[0] = module_id;
         int i;
         for(i = 1; i < MAXCALLBACKS; i++)
             entry->callback[i] = NULL;
@@ -227,7 +188,7 @@ void _get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t cal
         callback(bot, chan, data);
 }
 
-void get_userauth(struct UserNode *user, userauth_callback_t callback, void *data) {
+void get_userauth(struct UserNode *user, int module_id, userauth_callback_t callback, void *data) {
     //check if we have already an active WHO for this user
     struct ClientSocket *bot, *whobot = NULL;
     struct WHOQueueEntry *entry;
@@ -238,6 +199,7 @@ void get_userauth(struct UserNode *user, userauth_callback_t callback, void *dat
                 for(i = 1; i < MAXCALLBACKS; i++) {
                     if(!entry->callback[i]) {
                         entry->callback[i] = callback;
+                        entry->module_id[i] = module_id;
                         entry->data[i] = data;
                         return;
                     }
@@ -254,7 +216,7 @@ void get_userauth(struct UserNode *user, userauth_callback_t callback, void *dat
         callback(bot, user->nick, NULL, data);
         return;
     }
-    if((user->flags & (USERFLAG_ISAUTHED | USERFLAG_ISIRCOP | USERFLAG_ISBOT | USERFLAG_ISSERVER)) || (time(0) - user->last_who) <= REWHO_TIMEOUT) {
+    if((user->flags & (USERFLAG_ISAUTHED | USERFLAG_ISSERVER)) || (time(0) - user->last_who) <= REWHO_TIMEOUT) {
         callback(bot, user->nick, user, data);
         return;
     }
@@ -263,6 +225,7 @@ void get_userauth(struct UserNode *user, userauth_callback_t callback, void *dat
     entry->user = user;
     user->flags |= USERFLAG_IS_ON_WHO_QUEUE;
     entry->callback[0] = callback;
+    entry->module_id[0] = module_id;
     int i;
     for(i = 1; i < MAXCALLBACKS; i++)
         entry->callback[i] = NULL;
@@ -286,9 +249,9 @@ static void _recv_whohandler_354(struct ClientSocket *client, char **argv, unsig
     struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, type, 0);
     if(entry == NULL) return;
     #ifdef HAVE_THREADS
-    unsigned long tid = syscall(SYS_gettid);
-    while(parse_order->tid != tid) {
-        usleep(5000); //5ms
+    unsigned int tid = (unsigned int) pthread_self_tid();
+    while(!clientsocket_parseorder_top(tid)) {
+        usleep(1000); //1ms
     }
     #endif
     if(entry->type & WHOQUEUETYPE_USERLIST) {
@@ -323,8 +286,8 @@ static void _recv_whohandler_354(struct ClientSocket *client, char **argv, unsig
         
         struct UserNode *user = getUserByNick(argv[5]);
         struct ChanUser *chanuser;
-        if((chanuserflags & CHANUSERFLAG_INVISIBLE) && (!user || !isBot(user))) {
-            user = createTempUser(argv[5]);
+        if((chanuserflags & CHANUSERFLAG_INVISIBLE) && (!user || (user && !isBot(user)))) {
+            user = createTempUser(argv[5]); //always add a temponary user to prevent cache problems when the user joins right now (while it's stored in our cache as being invisible)
             user->flags |= USERFLAG_ISTMPUSER;
             chan->flags |= CHANFLAG_HAVE_INVISIBLES;
             chanuser = addInvisibleChanUser(chan, user);
@@ -361,7 +324,8 @@ static void _recv_whohandler_354(struct ClientSocket *client, char **argv, unsig
         for(i = 0; i < MAXCALLBACKS; i++) {
             userauth_callback_t *callback = entry->callback[i];
             if(!callback) break;
-            callback(client, entry->user->nick, entry->user, entry->data[i]);
+            if(!entry->module_id[i] || module_loaded(entry->module_id[i]))
+                callback(client, entry->user->nick, entry->user, entry->data[i]);
         }
     }
 }
@@ -380,9 +344,9 @@ static void _recv_whohandler_315(struct ClientSocket *client, char **argv, unsig
     struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, type, 0);
     if(entry == NULL) return;
     #ifdef HAVE_THREADS
-    unsigned long tid = syscall(SYS_gettid);
-    while(parse_order->tid != tid) {
-        usleep(5000); //5ms
+    unsigned int tid = (unsigned int) pthread_self_tid();
+    while(!clientsocket_parseorder_top(tid)) {
+        usleep(1000); //1ms
     }
     #endif
     getNextWHOQueueEntry(client, type, 1);
@@ -394,7 +358,8 @@ static void _recv_whohandler_315(struct ClientSocket *client, char **argv, unsig
         for(i = 0; i < MAXCALLBACKS; i++) {
             callback = entry->callback[i];
             if(!callback) break;
-            callback(client, entry->chan, entry->data[i]);
+            if(!entry->module_id[i] || module_loaded(entry->module_id[i]))
+                callback(client, entry->chan, entry->data[i]);
         }
         if(entry->chan->flags & CHANFLAG_HAVE_INVISIBLES) {
             //remove all invisible users again
@@ -413,7 +378,8 @@ static void _recv_whohandler_315(struct ClientSocket *client, char **argv, unsig
             for(i = 0; i < MAXCALLBACKS; i++) {
                 callback = entry->callback[i];
                 if(!callback) break;
-                callback(client, entry->user->nick, NULL, entry->data[i]);
+                if(!entry->module_id[i] || module_loaded(entry->module_id[i]))
+                    callback(client, entry->user->nick, NULL, entry->data[i]);
             }
         }
         entry->user->flags &= ~USERFLAG_IS_ON_WHO_QUEUE;