added cmd_nicklist
authorpk910 <philipp@zoelle1.de>
Wed, 14 Dec 2011 19:15:24 +0000 (20:15 +0100)
committerpk910 <philipp@zoelle1.de>
Wed, 14 Dec 2011 20:10:58 +0000 (21:10 +0100)
Makefile.am
src/bot_NeonServ.c
src/cmd_neonserv.h
src/cmd_neonserv_nicklist.c [new file with mode: 0644]
src/commands.c
src/tools.c

index b12943ed91a79bac6b3bca56dd2bf063f717e27c..0cfac1755d81b7b836415069e1e14a5e62bc4084 100644 (file)
@@ -119,6 +119,7 @@ neonserv_SOURCES = src/version.c \
       src/cmd_global_reload.c \
       src/cmd_global_restart.c \
       src/cmd_global_die.c \
       src/cmd_global_reload.c \
       src/cmd_global_restart.c \
       src/cmd_global_die.c \
+      src/cmd_neonserv_nicklist.c \
       src/cmd_funcmds.c \
       src/ConfigParser.c
 
       src/cmd_funcmds.c \
       src/ConfigParser.c
 
index 613487aa300a6e75039965cc068f74865489ebb5..83f131926e9bb0bb6f38775af7a16e330947707e 100644 (file)
@@ -340,6 +340,10 @@ static const struct default_language_entry msgtab[] = {
     {"NS_BOTS_FLAGS", "Flags"},
     {"NS_BOTS_CHANNELS", "Channels"},
     {"NS_BOTS_TRIGGER", "Trigger"},
     {"NS_BOTS_FLAGS", "Flags"},
     {"NS_BOTS_CHANNELS", "Channels"},
     {"NS_BOTS_TRIGGER", "Trigger"},
+    {"NS_NICKLIST_NICK", "Nick"},
+    {"NS_NICKLIST_STATE", "State"},
+    {"NS_NICKLIST_ACCESS", "Access"},
+    {"NS_NICKLIST_SYNC", "use `nicklist sync` to fix all red and orange entrys in the list above (add opped users with 200 and voiced with 100 access)"},
     {NULL, NULL}
 };
 
     {NULL, NULL}
 };
 
index 334a0029f68614c74486e8d2658d0902aa7d6b20..e624ed4973a22dc89a48c052f17d11c20334f686 100644 (file)
@@ -74,6 +74,7 @@ CMD_BIND(neonserv_cmd_mdeluser);
 CMD_BIND(neonserv_cmd_mode);
 CMD_BIND(neonserv_cmd_move);
 CMD_BIND(neonserv_cmd_myaccess);
 CMD_BIND(neonserv_cmd_mode);
 CMD_BIND(neonserv_cmd_move);
 CMD_BIND(neonserv_cmd_myaccess);
+CMD_BIND(neonserv_cmd_nicklist);
 CMD_BIND(neonserv_cmd_noregister);
 CMD_BIND(neonserv_cmd_op);
 CMD_BIND(neonserv_cmd_opall);
 CMD_BIND(neonserv_cmd_noregister);
 CMD_BIND(neonserv_cmd_op);
 CMD_BIND(neonserv_cmd_opall);
diff --git a/src/cmd_neonserv_nicklist.c b/src/cmd_neonserv_nicklist.c
new file mode 100644 (file)
index 0000000..1a337c0
--- /dev/null
@@ -0,0 +1,243 @@
+/* cmd_neonserv_nicklist.c - NeonServ v5.2
+ * Copyright (C) 2011  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 "cmd_neonserv.h"
+
+/*
+* argv[0]    "force"
+* argv[1]    (optional) nick mask
+*/
+static USERLIST_CALLBACK(neonserv_cmd_nicklist_userlist_lookup);
+static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask, int syncusers);
+static void neonserv_cmd_nicklist_synchronize_user(struct ChanNode *chan, struct UserNode *user, int access, int new);
+
+struct neonserv_cmd_nicklist_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nickmask;
+    int syncusers;
+};
+
+CMD_BIND(neonserv_cmd_nicklist) {
+    int syncusers = 0;
+    if(argc && !stricmp(argv[0], "sync")) {
+        if(!checkChannelAccess(user, chan, "channel_canadd", 0)) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_ACCESS_DENIED");
+                return;
+            }
+        }
+        argv++;
+        argc--;
+        syncusers = 1;
+        event->flags |= CMDFLAG_LOG;
+    }
+    struct neonserv_cmd_nicklist_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    if(argc) {
+        cache->nickmask = strdup(argv[0]);
+    } else
+        cache->nickmask = NULL;
+    cache->syncusers = syncusers;
+    get_userlist_with_invisible(chan, neonserv_cmd_nicklist_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_nicklist_userlist_lookup) {
+    struct neonserv_cmd_nicklist_cache *cache = data;
+    neonserv_cmd_nicklist_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask, cache->syncusers);
+    if(cache->nickmask)
+        free(cache->nickmask);
+    free(cache);
+}
+
+static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask, int syncusers) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, defaults = NULL;
+    struct Table *table;
+    table = table_init(3, chan->usercount + 1, 0);
+    char *content[3];
+    content[0] = get_language_string(user, "NS_NICKLIST_NICK");
+    content[1] = get_language_string(user, "NS_NICKLIST_STATE");
+    content[2] = get_language_string(user, "NS_NICKLIST_ACCESS");
+    table_add(table, content);
+    printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d'", chan->channel_id);
+    res = mysql_use();
+    int userlistlen = mysql_num_rows(res);
+    int i = 0;
+    MYSQL_ROW userlist[userlistlen];
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        userlist[i++] = row;
+    }
+    int db_enfops, db_enfvoice;
+    printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    row = mysql_fetch_row(mysql_use());
+    if(row[0] == NULL || row[1] == NULL) {
+        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+        defaults = mysql_fetch_row(mysql_use());
+    }
+    db_enfops = atoi((row[0] ? row[0] : defaults[0]));
+    db_enfvoice = atoi((row[1] ? row[1] : defaults[1]));
+    int caccess = getChannelAccess(user, chan);
+    int synced_user = 0;
+    struct ChanUser *chanuser;
+    int sort_nicklist[] = { 
+            CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED,
+            CHANUSERFLAG_OPPED,
+            CHANUSERFLAG_VOICED,
+            CHANUSERFLAG_INVISIBLE,
+            0
+        };
+    int *sort_pos = sort_nicklist;
+    int sort_flags;
+    do {
+        sort_flags = *(sort_pos++);
+        char statebuf[5];
+        char accessbuf[9];
+        int uaccess;
+        int stateset = 0;
+        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+            if((chanuser->flags & (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED | CHANUSERFLAG_INVISIBLE)) != sort_flags) continue;
+            if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+            if(!stateset) {
+                if((chanuser->flags & CHANUSERFLAG_INVISIBLE)) statebuf[stateset++] = '<';
+                if((chanuser->flags & CHANUSERFLAG_OPPED)) statebuf[stateset++] = '@';
+                if((chanuser->flags & CHANUSERFLAG_VOICED)) statebuf[stateset++] = '+';
+                statebuf[stateset++] = '\0';
+            }
+            content[0] = chanuser->user->nick;
+            content[1] = statebuf;
+            uaccess = 0;
+            if(chanuser->user->flags & USERFLAG_ISAUTHED) {
+                for(i = 0; i < userlistlen; i++) {
+                    if(!stricmp(chanuser->user->auth, userlist[i][1])) {
+                        uaccess = atoi(userlist[i][0]);
+                        if((((chanuser->flags & CHANUSERFLAG_OPPED) && uaccess < db_enfops) || ((chanuser->flags & CHANUSERFLAG_VOICED) && uaccess < db_enfvoice)) && !isNetworkService(chanuser->user)) {
+                            if(syncusers) {
+                                if((chanuser->flags & CHANUSERFLAG_OPPED) && (db_enfops < caccess || isGodMode(user))) {
+                                    if(db_enfops >= caccess)
+                                        event->flags |= CMDFLAG_OPLOG;
+                                    uaccess = db_enfops;
+                                } else if((chanuser->flags & CHANUSERFLAG_VOICED) && (caccess < db_enfvoice || isGodMode(user))) {
+                                    if(db_enfvoice >= caccess)
+                                        event->flags |= CMDFLAG_OPLOG;
+                                    uaccess = db_enfvoice;
+                                } else {
+                                    //fail...
+                                    sprintf(accessbuf, "\00307%d\003", uaccess);
+                                    break;
+                                }
+                                neonserv_cmd_nicklist_synchronize_user(chan, chanuser->user, uaccess, 0);
+                                sprintf(accessbuf, "\00309%d\003", uaccess);
+                                synced_user = 1;
+                            } else {
+                                synced_user = 1;
+                                sprintf(accessbuf, "\00307%d\003", uaccess);
+                            }
+                        } else if((uaccess >= db_enfops && !(chanuser->flags & CHANUSERFLAG_OPPED)) || (uaccess >= db_enfvoice && !(chanuser->flags & CHANUSERFLAG_OPPED_OR_VOICED)))
+                            sprintf(accessbuf, "\00303%d\003", uaccess);
+                        else
+                            sprintf(accessbuf, "%d", uaccess);
+                        break;
+                    }
+                }
+            }
+            if(!uaccess && (chanuser->flags & CHANUSERFLAG_OPPED_OR_VOICED) && !isNetworkService(chanuser->user)) {
+                if(syncusers) {
+                    if((chanuser->flags & CHANUSERFLAG_OPPED) && (db_enfops < caccess || isGodMode(user))) {
+                        if(db_enfops >= caccess)
+                            event->flags |= CMDFLAG_OPLOG;
+                        uaccess = db_enfops;
+                    } else if((chanuser->flags & CHANUSERFLAG_VOICED) && db_enfvoice < caccess) {
+                        if(db_enfvoice >= caccess)
+                            event->flags |= CMDFLAG_OPLOG;
+                        uaccess = db_enfvoice;
+                    } else {
+                        uaccess = 0;
+                        sprintf(accessbuf, "\003040\003");
+                    }
+                    if(uaccess && (chanuser->user->flags & USERFLAG_ISAUTHED)) {
+                        neonserv_cmd_nicklist_synchronize_user(chan, chanuser->user, uaccess, 1);
+                        sprintf(accessbuf, "\00309%d\003", uaccess);
+                        synced_user = 1;
+                    } else if(uaccess) {
+                        sprintf(accessbuf, "\003040\003");
+                    }
+                } else {
+                    synced_user = 1;
+                    sprintf(accessbuf, "\003040\003");
+                }
+            } else if(!uaccess)
+                sprintf(accessbuf, "0");
+            content[2] = accessbuf;
+            table_add(table, content);
+        }
+    } while(sort_flags != 0);
+    //send the table
+    char **table_lines = table_end(table);
+    for(i = 0; i < table->entrys; i++) {
+        reply(textclient, user, table_lines[i]);
+    }
+    if(table->length == 1)
+        reply(textclient, user, "NS_TABLE_NONE");
+    reply(textclient, user, "NS_TABLE_COUNT", table->length - 1);
+    table_free(table);
+    if(synced_user) {
+        if(!syncusers)
+            reply(textclient, user, "NS_NICKLIST_SYNC");
+        else
+            logEvent(event);
+    }
+}
+
+static void neonserv_cmd_nicklist_synchronize_user(struct ChanNode *chan, struct UserNode *user, int caccess, int new) {
+    if(!(user->flags & USERFLAG_ISAUTHED)) return;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    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]);
+    } else {
+        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(user->auth));
+        userid = (int) mysql_insert_id(mysql_conn);
+    }
+    if(new) {
+        //just add
+        printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chan->channel_id, userid, caccess);
+    } else {
+        //check if already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            //clvl
+            if(atoi(row[0]) >= caccess) return;
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '%d' WHERE `chanuser_id` = '%s'", caccess, row[1]);
+        } else 
+            printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chan->channel_id, userid, caccess);
+    }
+}
index ec5902c967719cddf6f020faebfb385f0ba45f46..548cb4ca68e8bcf4cd91019732e0f68bdb723e65 100644 (file)
@@ -106,6 +106,7 @@ void register_commands() {
     USER_COMMAND("events",       neonserv_cmd_events,    0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
     USER_COMMAND("info",         neonserv_cmd_info,      0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
     USER_COMMAND("extscript",    neonserv_cmd_extscript, 0, NULL,                   CMDFLAG_EMPTY_ARGS | CMDFLAG_CHAN_PARAM);
     USER_COMMAND("events",       neonserv_cmd_events,    0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
     USER_COMMAND("info",         neonserv_cmd_info,      0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
     USER_COMMAND("extscript",    neonserv_cmd_extscript, 0, NULL,                   CMDFLAG_EMPTY_ARGS | CMDFLAG_CHAN_PARAM);
+    USER_COMMAND("nicklist",     neonserv_cmd_nicklist,  0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
     #undef USER_COMMAND
     
     #define OPER_COMMAND(NAME,FUNCTION,PARAMCOUNT,GACCESS,FLAGS) register_command(1, NAME, FUNCTION, PARAMCOUNT, NULL, GACCESS, FLAGS)
     #undef USER_COMMAND
     
     #define OPER_COMMAND(NAME,FUNCTION,PARAMCOUNT,GACCESS,FLAGS) register_command(1, NAME, FUNCTION, PARAMCOUNT, NULL, GACCESS, FLAGS)
index 71cd40d756b6858f272bb5d123cc60a8c8d4d821..2c047adaeaa0170d17c9f8ced0bcf23006e42342 100644 (file)
@@ -180,7 +180,7 @@ int table_set_bold(struct Table *table, int collum, int bold) {
 }
 
 char **table_end(struct Table *table) {
 }
 
 char **table_end(struct Table *table) {
-    int row, col, tablewidth = 0, pos,i;
+    int row, col, tablewidth = 0, pos,i,j,k;
     if(!table->entrys) return NULL;
     for(col = 0; col < table->width; col++) {
         tablewidth += table->maxwidth[col]+1;
     if(!table->entrys) return NULL;
     for(col = 0; col < table->width; col++) {
         tablewidth += table->maxwidth[col]+1;
@@ -196,11 +196,23 @@ char **table_end(struct Table *table) {
             if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
                 table->table_lines[row][pos++] = '\002';
             i = 0;
             if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
                 table->table_lines[row][pos++] = '\002';
             i = 0;
+            j = 0;
             if(table->contents[row][col]) {
                 for(; i < strlen(table->contents[row][col]); i++) {
                     table->table_lines[row][pos++] = table->contents[row][col][i];
             if(table->contents[row][col]) {
                 for(; i < strlen(table->contents[row][col]); i++) {
                     table->table_lines[row][pos++] = table->contents[row][col][i];
+                    if(table->contents[row][col][i] == '\002') j++;
+                    else if(table->contents[row][col][i] == '\003') {
+                        j++;
+                        for(k = 1; k < 2; k++) {
+                            if(isdigit(table->contents[row][col][i+k]))
+                                j++;
+                            else 
+                                break;
+                        }
+                    }
                 }
             }
                 }
             }
+            i -= j;
             if(col < table->width-1) {
                 for(;i < table->maxwidth[col]; i++) {
                     table->table_lines[row][pos++] = ' ';
             if(col < table->width-1) {
                 for(;i < table->maxwidth[col]; i++) {
                     table->table_lines[row][pos++] = ' ';