added experimental multi thread support
[NeonServV5.git] / src / DBHelper.c
index fec30a256e570fe7f4bb2d590b5feb24cfc3d44f..4f3dd757262d0150e93a3966731b163d6712ee92 100644 (file)
@@ -1,5 +1,5 @@
-/* DBHelper.c - NeonServ v5.0
- * Copyright (C) 2011  Philipp Kreil (pk910)
+/* DBHelper.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
 #include "mysqlConn.h"
 #include "lang.h"
 #include "tools.h"
+#include "IRCEvents.h"
+#include "HandleInfoHandler.h"
 
 void _loadUserSettings(struct UserNode *user) {
+    SYNCHRONIZE(cache_sync);
     MYSQL_RES *res;
     MYSQL_ROW row;
-    printf_mysql_query("SELECT `user_lang`, `user_reply_privmsg`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    printf_mysql_query("SELECT `user_lang`, `user_reply_privmsg`, `user_god`, `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
     res = mysql_use();
     if ((row = mysql_fetch_row(res)) != NULL) {
         user->language = get_language_by_tag(row[0]);
@@ -35,9 +38,12 @@ void _loadUserSettings(struct UserNode *user) {
             user->flags |= USERFLAG_REPLY_PRIVMSG;
         if(strcmp(row[2], "0"))
             user->flags |= USERFLAG_GOD_MODE;
+        user->user_id = atoi(row[3]);
+        user->flags |= USERFLAG_HAS_USERID;
     } else
         user->language = get_default_language();
     user->flags |= USERFLAG_LOADED_SETTINGS;
+    DESYNCHRONIZE(cache_sync);
 }
 
 int isGodMode(struct UserNode *user) {
@@ -45,29 +51,34 @@ int isGodMode(struct UserNode *user) {
     return (user->flags & USERFLAG_GOD_MODE);
 }
 
-int getChannelAccess(struct UserNode *user, struct ChanNode *chan, int override) {
+int getChannelAccess(struct UserNode *user, struct ChanNode *chan) {
     if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
     loadChannelSettings(chan);
     if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
     MYSQL_RES *res;
     MYSQL_ROW row;
     int caccess = 0;
-    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        if(strcmp(row[2], "0") && override) 
-            caccess = atoi(row[1]);
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%s' AND `chanuser_cid` = '%d'", row[0], chan->channel_id);
-        //
+    int userid;
+    if(user->flags & USERFLAG_HAS_USERID)
+        userid = user->user_id;
+    else {
+        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
         res = mysql_use();
         if ((row = mysql_fetch_row(res)) != NULL) {
-            int cflags = atoi(row[1]);
-            if(!(cflags & DB_CHANUSER_SUSPENDED) && atoi(row[0]) > caccess)
-                caccess = atoi(row[0]);
-        }
-        return caccess;
+            userid = atoi(row[0]);
+            user->user_id = userid;
+            user->flags |= USERFLAG_HAS_USERID;
+        } else
+            return 0;
     }
-    return 0;
+    printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%d' AND `chanuser_cid` = '%d'", userid, chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        int cflags = atoi(row[1]);
+        if(!(cflags & DB_CHANUSER_SUSPENDED) && atoi(row[0]) > caccess)
+            caccess = atoi(row[0]);
+    }
+    return caccess;
 }
 
 char *getChanDefault(char *channel_setting) {
@@ -79,7 +90,7 @@ char *getChanDefault(char *channel_setting) {
     return row[0];
 }
 
-int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *channel_setting, int allow_override, int allow_501) {
+int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *channel_setting, int allow_501) {
     loadChannelSettings(chan);
     if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
     if((user->flags & USERFLAG_ISIRCOP)) return 1;
@@ -92,10 +103,21 @@ int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *chann
     if(require_access == 0) return 1;
     if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
     int caccess = 0;
-    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%s' AND `chanuser_cid` = '%d'", row[0], chan->channel_id);
+    int userid;
+    if(user->flags & USERFLAG_HAS_USERID)
+        userid = user->user_id;
+    else {
+        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            userid = atoi(row[0]);
+            user->user_id = userid;
+            user->flags |= USERFLAG_HAS_USERID;
+        } else
+            userid = -1;
+    }
+    if(userid > -1) {
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%d' AND `chanuser_cid` = '%d'", userid, chan->channel_id);
         res = mysql_use();
         if ((row = mysql_fetch_row(res)) != NULL) {
             int cflags = atoi(row[1]);
@@ -109,6 +131,7 @@ int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *chann
 }
 
 void _loadChannelSettings(struct ChanNode *chan) {
+    SYNCHRONIZE(cache_sync);
     MYSQL_RES *res;
     MYSQL_ROW row;
     printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(chan->name));
@@ -118,6 +141,7 @@ void _loadChannelSettings(struct ChanNode *chan) {
         chan->channel_id = atoi(row[0]);
     }
     chan->flags |= CHANFLAG_REQUESTED_CHANINFO;
+    DESYNCHRONIZE(cache_sync);
 }
 
 //TODO: fix performance: we should cache the user access
@@ -145,11 +169,11 @@ int isUserProtected(struct ChanNode *chan, struct UserNode *victim, struct UserN
     if(protection == 3) return 0;
     
     /* Don't protect if the victim isn't added to the channel, unless we are to protect non-users also. */
-    int victim_access = getChannelAccess(victim, chan, 0);
+    int victim_access = getChannelAccess(victim, chan);
     if (!victim_access && protection != 0) return 0;
     
     /* Protect if the aggressor isn't a user because at this point, the aggressor can only be less than or equal to the victim. */
-    int issuer_access = getChannelAccess(issuer, chan, 0);
+    int issuer_access = getChannelAccess(issuer, chan);
     if (!issuer_access) return 1;
     
     /* If the aggressor was a user, then the victim can't be helped. */
@@ -223,3 +247,61 @@ int renameAccount(char *oldauth, char *newauth) {
     }
     return 0;
 }
+
+static AUTHLOOKUP_CALLBACK(event_user_registered_auth_lookup);
+
+struct event_user_registered_cache {
+    struct UserNode *new_user;
+    char *oldauth;
+};
+
+static int event_user_registered(struct UserNode *old_user, struct UserNode *new_user) {
+    //check if there is a fakehost on both sides...
+    if(!isFakeHost(old_user->host) || !isFakeHost(new_user->host)) return 0;
+    //extract user names
+    char oldauth[AUTHLEN], newauth[AUTHLEN];
+    char *p;
+    if((p = strstr(old_user->host, "."))) {
+        *p = '\0';
+        strcpy(oldauth, old_user->host);
+        *p = '.';
+    }
+    if((p = strstr(new_user->host, "."))) {
+        *p = '\0';
+        strcpy(newauth, new_user->host);
+        *p = '.';
+    }
+    if(!stricmp(oldauth, newauth))
+        return 0;
+    //check if we know this user; then check the new auth
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(oldauth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        struct event_user_registered_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return 1;
+        }
+        cache->new_user = new_user;
+        cache->oldauth = strdup(oldauth);
+        lookup_authname(newauth, event_user_registered_auth_lookup, cache);
+    }
+    return 1;
+}
+
+static AUTHLOOKUP_CALLBACK(event_user_registered_auth_lookup) {
+    struct event_user_registered_cache *cache = data;
+    if(exists) {
+        renameAccount(cache->oldauth, auth);
+        strcpy(cache->new_user->auth, auth);
+        cache->new_user->flags |= USERFLAG_ISAUTHED;
+    }
+    free(cache->oldauth);
+}
+
+void init_DBHelper() {
+    bind_registered(event_user_registered);
+}
+