fixed colors in cmd_neonserv_nicklist.c
[NeonServV5.git] / src / modules / NeonServ.mod / cmd_neonserv_nicklist.c
index de0a8345738050fc646dd77cc83586d65823bd04..5043f42fc653fe338c4bba74c5a38d85053762a4 100644 (file)
@@ -1,4 +1,4 @@
-/* cmd_neonserv_nicklist.c - NeonServ v5.4
+/* cmd_neonserv_nicklist.c - NeonServ v5.6
  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
  * 
  * This program is free software: you can redistribute it and/or modify
 * 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_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask, int flags);
 static void neonserv_cmd_nicklist_synchronize_user(struct ChanNode *chan, struct UserNode *user, int access);
 
+#define NEONSERV_CMD_NICKLIST_FLAG_SYNCUSERS  0x01
+#define NEONSERV_CMD_NICKLIST_FLAG_NOWHO      0x02
+#define NEONSERV_CMD_NICKLIST_FLAG_VISCOUNT   0x04
+
 struct neonserv_cmd_nicklist_cache {
     struct ClientSocket *client, *textclient;
     struct UserNode *user;
     struct Event *event;
     char *nickmask;
-    int syncusers;
+    int flags;
 };
 
 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;
+    int flags = 0;
+    while(argc) {
+        if(!stricmp(argv[0], "sync")) {
+            if(!checkChannelAccess(user, chan, "channel_canadd", 0)) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(textclient, user, "NS_ACCESS_DENIED");
+                    return;
+                }
             }
-        }
+            flags |= NEONSERV_CMD_NICKLIST_FLAG_SYNCUSERS;
+            event->flags |= CMDFLAG_LOG;
+        } else if(argc && !stricmp(argv[0], "nowho") && isGodMode(user)) {
+            flags |= NEONSERV_CMD_NICKLIST_FLAG_NOWHO;
+        } else if(argc && !stricmp(argv[0], "viscount") && isGodMode(user)) {
+            flags |= NEONSERV_CMD_NICKLIST_FLAG_VISCOUNT;
+        } else
+            break;
         argv++;
         argc--;
-        syncusers = 1;
-        event->flags |= CMDFLAG_LOG;
     }
-    if(argc && !stricmp(argv[0], "nowho") && isGodMode(user)) {
-        argv++;
-        argc--;
-        neonserv_cmd_nicklist_async1(client, getTextBot(), user, chan, event, (argc ? argv[0] : NULL), syncusers);
+    if(flags & NEONSERV_CMD_NICKLIST_FLAG_NOWHO) {
+        neonserv_cmd_nicklist_async1(client, textclient, user, chan, event, (argc ? argv[0] : NULL), flags);
         return;
     }
     struct neonserv_cmd_nicklist_cache *cache = malloc(sizeof(*cache));
@@ -61,44 +70,88 @@ CMD_BIND(neonserv_cmd_nicklist) {
         return;
     }
     cache->client = client;
-    cache->textclient = getTextBot();
+    cache->textclient = textclient;
     cache->user = user;
     cache->event = event;
     if(argc) {
         cache->nickmask = strdup(argv[0]);
     } else
         cache->nickmask = NULL;
-    cache->syncusers = syncusers;
+    cache->flags = flags;
     get_userlist_with_invisible(chan, module_id, 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);
+    neonserv_cmd_nicklist_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask, cache->flags);
     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) {
+static int neonserv_cmd_nicklist_sort_flags[] = { 
+    CHANUSERFLAG_OPPED | CHANUSERFLAG_HALFOPPED | CHANUSERFLAG_VOICED,
+    CHANUSERFLAG_OPPED | CHANUSERFLAG_HALFOPPED,
+    CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED,
+    CHANUSERFLAG_OPPED,
+    CHANUSERFLAG_HALFOPPED | CHANUSERFLAG_VOICED,
+    CHANUSERFLAG_HALFOPPED,
+    CHANUSERFLAG_VOICED,
+    CHANUSERFLAG_INVISIBLE,
+    0
+};
+
+static int neonserv_cmd_nicklist_sort(const void *a, const void *b) {
+    const struct ChanUser *chanuser_a = *((struct ChanUser * const *) a);
+    const struct ChanUser *chanuser_b = *((struct ChanUser * const *) b); 
+    int i_a = 0, i_b = 0;
+    while((chanuser_a->flags & (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED | CHANUSERFLAG_INVISIBLE)) != neonserv_cmd_nicklist_sort_flags[i_a] && neonserv_cmd_nicklist_sort_flags[i_a])
+        i_a++;
+    while((chanuser_b->flags & (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED | CHANUSERFLAG_INVISIBLE)) != neonserv_cmd_nicklist_sort_flags[i_b] && neonserv_cmd_nicklist_sort_flags[i_b])
+        i_b++;
+    if(i_a == i_b) {
+        return stricmp(chanuser_a->user->nick, chanuser_b->user->nick);
+    } else
+        return i_a - i_b;
+}
+
+static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask, int flags) {
     MYSQL_RES *res;
     MYSQL_ROW row, defaults = NULL;
     struct Table *table;
-    table = table_init(3, chan->usercount + 1, 0);
-    char *content[3];
+    char *content[4];
+    int userlistlen, i, j;
+    int db_enfops, db_enfvoice;
+    int caccess, synced_user, accessbufpos;
+    struct ChanUser *chanusers[chan->usercount];
+    struct ChanUser *chanuser;
+    struct ClientSocket *bot;
+    int chanuser_count;
+    char statebuf[5];
+    char accessbuf[50];
+    char viscountbuf[5];
+    int uaccess;
+    
+    i = 3;
+    if(flags & NEONSERV_CMD_NICKLIST_FLAG_VISCOUNT) {
+        i++;
+        content[3] = "VisCount";
+    }
+    table = table_init(i, chan->usercount + 1, 0);
     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;
+    userlistlen = mysql_num_rows(res);
+    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) {
@@ -107,106 +160,130 @@ static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct Cli
     }
     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_HALFOPPED | CHANUSERFLAG_VOICED,
-            CHANUSERFLAG_OPPED | CHANUSERFLAG_HALFOPPED,
-            CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED,
-            CHANUSERFLAG_OPPED,
-            CHANUSERFLAG_HALFOPPED | CHANUSERFLAG_VOICED,
-            CHANUSERFLAG_HALFOPPED,
-            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_HALFOPPED)) 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);
-                                sprintf(accessbuf, "\00309%d\003", uaccess);
-                                synced_user = 1;
+    
+    chanuser_count = 0;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+        chanusers[chanuser_count++] = chanuser;
+    }
+    qsort(chanusers, chanuser_count, sizeof(struct ChanUser *), neonserv_cmd_nicklist_sort);
+    
+    caccess = getChannelAccess(user, chan);
+    synced_user = 0;
+    for(i = 0; i < chanuser_count; i++) {
+        chanuser = chanusers[i];
+        
+        content[0] = chanuser->user->nick;
+        
+        j = 0;
+        if((chanuser->flags & CHANUSERFLAG_INVISIBLE)) statebuf[j++] = '<';
+        if((chanuser->flags & CHANUSERFLAG_OPPED)) statebuf[j++] = '@';
+        if((chanuser->flags & CHANUSERFLAG_HALFOPPED)) statebuf[j++] = '%';
+        if((chanuser->flags & CHANUSERFLAG_VOICED)) statebuf[j++] = '+';
+        statebuf[j++] = '\0';
+        content[1] = statebuf;
+        
+        uaccess = 0;
+        if(chanuser->user->flags & USERFLAG_ISAUTHED) {
+            for(j = 0; j < userlistlen; j++) {
+                if(!stricmp(chanuser->user->auth, userlist[j][1])) {
+                    uaccess = atoi(userlist[j][0]);
+                    if((((chanuser->flags & CHANUSERFLAG_OPPED) && uaccess < db_enfops) || ((chanuser->flags & CHANUSERFLAG_VOICED) && uaccess < db_enfvoice)) && !isNetworkService(chanuser->user)) {
+                        if(flags & NEONSERV_CMD_NICKLIST_FLAG_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 {
-                                synced_user = 1;
-                                sprintf(accessbuf, "\00307%d\003", uaccess);
+                                //fail...
+                                accessbufpos = sprintf(accessbuf, "\00307%d\003", uaccess);
+                                break;
                             }
-                        } 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;
-                    }
+                            neonserv_cmd_nicklist_synchronize_user(chan, chanuser->user, uaccess);
+                            accessbufpos = sprintf(accessbuf, "\00309%d\003", uaccess);
+                            synced_user = 1;
+                        } else {
+                            synced_user = 1;
+                            accessbufpos = sprintf(accessbuf, "\00307%d\003", uaccess);
+                        }
+                    } else if((uaccess >= db_enfops && !(chanuser->flags & CHANUSERFLAG_OPPED)) || (uaccess >= db_enfvoice && !(chanuser->flags & CHANUSERFLAG_OPPED_OR_VOICED)))
+                        accessbufpos = sprintf(accessbuf, "\00303%d\003", uaccess);
+                    else
+                        accessbufpos = 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 || isGodMode(user))) {
-                        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);
-                        sprintf(accessbuf, "\00309%d\003", uaccess);
-                        synced_user = 1;
-                    } else if(uaccess) {
-                        sprintf(accessbuf, "\003040\003");
-                    }
+        }
+        if(!uaccess && (chanuser->flags & CHANUSERFLAG_OPPED_OR_VOICED) && !isNetworkService(chanuser->user)) {
+            if(flags & NEONSERV_CMD_NICKLIST_FLAG_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 || isGodMode(user))) {
+                    if(db_enfvoice >= caccess)
+                        event->flags |= CMDFLAG_OPLOG;
+                    uaccess = db_enfvoice;
                 } else {
+                    uaccess = 0;
+                    accessbufpos = sprintf(accessbuf, "\003040\003");
+                }
+                if(uaccess && (chanuser->user->flags & USERFLAG_ISAUTHED)) {
+                    neonserv_cmd_nicklist_synchronize_user(chan, chanuser->user, uaccess);
+                    accessbufpos = sprintf(accessbuf, "\00309%d\003", uaccess);
                     synced_user = 1;
-                    sprintf(accessbuf, "\003040\003");
+                } else if(uaccess) {
+                    accessbufpos = sprintf(accessbuf, "\003040\003");
                 }
-            } else if(!uaccess)
-                sprintf(accessbuf, "0");
-            content[2] = accessbuf;
-            table_add(table, content);
+            } else {
+                synced_user = 1;
+                if(((chanuser->flags & CHANUSERFLAG_OPPED) && db_enfops > caccess) || ((chanuser->flags & CHANUSERFLAG_VOICED) && db_enfvoice > caccess))
+                    accessbufpos = sprintf(accessbuf, "\003040\003");
+                else
+                    accessbufpos = sprintf(accessbuf, "0");
+            }
+        } else if(!uaccess)
+            accessbufpos = sprintf(accessbuf, "0");
+        j = 0;
+        if(isBot(chanuser->user)) {
+            //check if bot is secret
+            for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+                if(bot->user == chanuser->user)
+                    break;
+            }
+            if(bot && !(bot->flags & SOCKET_FLAG_SECRET_BOT)) {
+                if(j)
+                    accessbufpos += sprintf(accessbuf+accessbufpos, ", ");
+                else {
+                    accessbufpos += sprintf(accessbuf+accessbufpos, " (");
+                    j = 1;
+                }
+                accessbufpos += sprintf(accessbuf+accessbufpos, "%s", get_language_string(user, "NS_NICKLIST_ACCESS_BOT"));
+            }
         }
-    } while(sort_flags != 0);
+        if(chanuser->user->flags & USERFLAG_ISIRCOP) {
+            if(j)
+                accessbufpos += sprintf(accessbuf+accessbufpos, ", ");
+            else {
+                accessbufpos += sprintf(accessbuf+accessbufpos, " (");
+                j = 1;
+            }
+            accessbufpos += sprintf(accessbuf+accessbufpos, "%s", get_language_string(user, "NS_NICKLIST_ACCESS_OPER"));
+        }
+        if(j)
+            accessbufpos += sprintf(accessbuf+accessbufpos, ")");
+        content[2] = accessbuf;
+        if(flags & NEONSERV_CMD_NICKLIST_FLAG_VISCOUNT) {
+            sprintf(viscountbuf, "%d", chanuser->visCount);
+            content[3] = viscountbuf;
+        }
+        table_add(table, content);
+    }
+    
     //send the table
     char **table_lines = table_end(table);
     for(i = 0; i < table->entrys; i++) {
@@ -217,7 +294,7 @@ static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct Cli
     reply(textclient, user, "NS_TABLE_COUNT", table->length - 1);
     table_free(table);
     if(synced_user) {
-        if(!syncusers)
+        if(!(flags & NEONSERV_CMD_NICKLIST_FLAG_SYNCUSERS))
             reply(textclient, user, "NS_NICKLIST_SYNC", db_enfops, db_enfvoice);
         else
             logEvent(event);