modified time-queue system and added cmd_addtimeban
authorpk910 <philipp@zoelle1.de>
Wed, 14 Sep 2011 22:59:57 +0000 (00:59 +0200)
committerpk910 <philipp@zoelle1.de>
Wed, 14 Sep 2011 23:02:21 +0000 (01:02 +0200)
bot_NeonServ.c
cmd_neonserv_addtimeban.c [new file with mode: 0644]
cmd_neonserv_delban.c
timeq.c
timeq.h

index 502d7cb5cb446f5a6b4c780c087108db75ff6a74..24441fb84104b7dc9b774433781630d0f7aa9490 100644 (file)
@@ -167,9 +167,14 @@ static const struct default_language_entry msgtab[] = {
     {"NS_UNREGISTER_DONE", "\002%s\002 unregistered."},
     {"NS_RECOVER_DONE", "\002%s\002 has been recovered."},
     {"NS_RESYNC_DONE", "Synchronized users in \002%s\002 with the userlist."},
+    {"NS_TIMEBAN_DURATION_TOO_SHORT", "You must specify a ban duration of at least %d seconds."},
+    {"NS_TIMEBAN_DONE", "Banned \002%s\002 from %s for %s. (matching %d users)"},
     {NULL, NULL}
 };
 
+//define some usefull functions :D
+static TIMEQ_CALLBACK(channel_ban_timeout);
+
 /*
 INCLUDE ALL CMD's HERE
 */
@@ -207,7 +212,7 @@ INCLUDE ALL CMD's HERE
 #include "cmd_neonserv_unsuspend.c"
 #include "cmd_neonserv_wipeinfo.c"
 #include "cmd_neonserv_addban.c"
-//#include "cmd_neonserv_addtimeban.c"
+#include "cmd_neonserv_addtimeban.c"
 #include "cmd_neonserv_delban.c"
 #include "cmd_neonserv_bans.c"
 //#include "cmd_neonserv_open.c"
@@ -313,6 +318,33 @@ static void start_bots() {
             }
         }
     }
+    
+    //load all timed bans
+    printf_mysql_query("SELECT `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_timeout` > 0");
+    res = mysql_use();
+    char nameBuf[20];
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(atol(row[1]) - time(0) > 0) {
+            sprintf(nameBuf, "ban_%s", row[0]);
+            timeq_add_name(nameBuf, atol(row[1]) - time(0), channel_ban_timeout, strdup(row[0]));
+        } else {
+            //timed out
+            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[0]);
+        }
+    }
+}
+
+static TIMEQ_CALLBACK(channel_ban_timeout) {
+    char *str_banid = data;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `ban_mask` FROM `bans` WHERE `ban_id` = '%s'", str_banid);
+    res = mysql_use();
+    if((row = mysql_fetch_row(res)) != NULL) {
+        //TODO: unban if mask is still banned
+        printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", str_banid);
+    }
+    free(str_banid);
 }
 
 void init_NeonServ() {
@@ -354,6 +386,7 @@ void init_NeonServ() {
     register_command(BOTID, "topic",        neonserv_cmd_topic,     0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_changetopic", 0);
     register_command(BOTID, "chanservsync", neonserv_cmd_chanservsync, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,"500",                 0);
     register_command(BOTID, "resync",       neonserv_cmd_resync,    0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_canresync",   0);
+    register_command(BOTID, "addtimeban",   neonserv_cmd_addtimeban,2, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,  "#channel_staticban",   0);
     
     register_command(BOTID, "trace",        neonserv_cmd_trace,     1, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,                                                   NULL,                   400);
     register_command(BOTID, "register",     neonserv_cmd_register,  2, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG,              NULL,                   100);
diff --git a/cmd_neonserv_addtimeban.c b/cmd_neonserv_addtimeban.c
new file mode 100644 (file)
index 0000000..b21a834
--- /dev/null
@@ -0,0 +1,120 @@
+
+/*
+* argv[0]    nick|*auth|*!*@mask
+* argv[1]    time
+* argv[2-*]  reason
+*/
+static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup);
+static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason);
+
+struct neonserv_cmd_addtimeban_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *mask;
+    int duration;
+    char *reason;
+};
+
+static CMD_BIND(neonserv_cmd_addtimeban) {
+    int duration = strToTime(user, argv[1]);
+    if(duration < 30) {
+        reply(getTextBot(), user, "NS_TIMEBAN_DURATION_TOO_SHORT", 30);
+        return;
+    }
+    struct neonserv_cmd_addtimeban_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->mask = strdup(argv[0]);
+    cache->duration = duration;
+    if(argc > 2) {
+        cache->reason = strdup(merge_argv(argv, 2, argc));
+    } else
+        cache->reason = NULL;
+    get_userlist(chan, neonserv_cmd_addtimeban_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup) {
+    struct neonserv_cmd_addtimeban_cache *cache = data;
+    neonserv_cmd_addtimeban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mask, cache->duration, (cache->reason ? cache->reason : "Bye."));
+    free(cache->mask);
+    if(cache->reason)
+        free(cache->reason);
+    free(cache);
+}
+
+static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason) {
+    int match_count = 0;
+    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    mask = make_banmask(mask, hostmask_buffer);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+        if(!match(mask, usermask)) {
+            if(isNetworkService(chanuser->user)) {
+                reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                return;
+            }
+            if(isUserProtected(chan, cuser, user)) {
+                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                return;
+            }
+            match_count++;
+            if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
+                reply(textclient, user, "NS_LAME_MASK", mask);
+                return;
+            }
+        }
+    }
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    //check if the provided mask is already banned by another ban
+    char *ban = getBanAffectingMask(chan, mask);
+    if(ban != NULL) {
+        reply(textclient, user, "NS_BAN_ALREADY_ADDED", mask, chan->name);
+        return;
+    }
+    //check if the provided mask affects any existing bans
+    printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!match(mask, row[0])) {
+            //remove the ban
+            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
+        }
+    }
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    int userid;
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL)
+        userid = atoi(row[0]);
+    else
+        return;
+    //add the ban
+    printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(mask), (unsigned long) (time(0) + duration), userid, escape_string(reason));
+    int banid = (int) mysql_insert_id(mysql_conn);
+    putsock(client, "MODE %s +b %s", chan->name, mask);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+        if(!match(mask, usermask)) {
+            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+        }
+    }
+    char nameBuf[MAXLEN];
+    char banidBuf[20];
+    sprintf(nameBuf, "ban_%d", banid);
+    sprintf(banidBuf, "%d", banid);
+    timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
+    reply(textclient, user, "NS_ADDTIMEBAN_DONE", mask, chan->name, timeToStr(user, duration, 2, nameBuf), match_count);
+    logEvent(event);
+}
index 2bd56997609407864311d83b76bfb87ba8001490..016008bb8cb09519d495998233fa15ebfe3f75d0 100644 (file)
@@ -16,11 +16,16 @@ static CMD_BIND(neonserv_cmd_delban) {
         return;
     }
     //check if the provided mask affects any existing bans
-    printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+    char nameBuf[20];
+    printf_mysql_query("SELECT `ban_mask`, `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
     res = mysql_use();
     while ((row = mysql_fetch_row(res)) != NULL) {
         if(!match(mask, row[0])) {
             //remove the ban
+            if(strcmp(row[2], "0")) {
+                sprintf(nameBuf, "ban_%s", row[1]);
+                timeq_del_name(nameBuf);
+            }
             printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
             matching_bans++;
         }
diff --git a/timeq.c b/timeq.c
index 60d92f7edced2bd3ec549f84913e0398aed93bd4..c300cd452b73a8a80588164bcf545dba5ac24c90 100644 (file)
--- a/timeq.c
+++ b/timeq.c
@@ -27,6 +27,7 @@ struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *dat
     entry->execute = now + seconds;
     entry->callback = callback;
     entry->data = data;
+    entry->name = NULL;
     struct timeq_entry *next, *prev = NULL;
     for(next = timeq_events; next; next = next->next) {
         if(next->execute >= entry->execute)
@@ -44,6 +45,12 @@ struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *dat
     return entry;
 }
 
+struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data) {
+    struct timeq_entry *entry = timeq_add(seconds, callback, data);
+    entry->name = strdup(name);
+    return entry;
+}
+
 int timeq_del(struct timeq_entry* entry) {
     struct timeq_entry *centry, *last = NULL;
     for(centry = timeq_events; centry; centry = centry->next) {
@@ -52,6 +59,26 @@ int timeq_del(struct timeq_entry* entry) {
                 last->next = centry->next;
             else
                 timeq_events = centry->next;
+            if(centry->name)
+                free(centry->name);
+            free(centry);
+            return 1;
+        } else {
+            last = centry;
+        }
+    }
+    return 0;
+}
+
+int timeq_del_name(char *name) {
+    struct timeq_entry *centry, *last = NULL;
+    for(centry = timeq_events; centry; centry = centry->next) {
+        if(centry->name && !stricmp(centry->name, name)) {
+            if(last)
+                last->next = centry->next;
+            else
+                timeq_events = centry->next;
+            free(centry->name);
             free(centry);
             return 1;
         } else {
diff --git a/timeq.h b/timeq.h
index d683c9a52025b666a8f9054cfc7b776e94762c2d..334eb706309462f9fe01fad6efe1d91a049f1a3c 100644 (file)
--- a/timeq.h
+++ b/timeq.h
@@ -3,10 +3,11 @@
 
 #include "main.h"
 
-#define TIMEQ_CALLBACK(NAME) int NAME(UNUSED_ARG(void *data))
+#define TIMEQ_CALLBACK(NAME) void NAME(UNUSED_ARG(void *data))
 typedef TIMEQ_CALLBACK(timeq_callback_t);
 
 struct timeq_entry {
+    char *name;
     time_t execute;
     timeq_callback_t *callback;
     void *data;
@@ -16,6 +17,8 @@ struct timeq_entry {
 
 void timeq_tick();
 struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *data);
+struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data);
 int timeq_del(struct timeq_entry* entry);
+int timeq_del_name(char *name);
 
 #endif
\ No newline at end of file