Merge branch 'master' into IOMultiplexer
authorpk910 <philipp@zoelle1.de>
Tue, 21 Aug 2012 23:34:06 +0000 (01:34 +0200)
committerpk910 <philipp@zoelle1.de>
Tue, 21 Aug 2012 23:34:06 +0000 (01:34 +0200)
18 files changed:
database.sql
database.upgrade.sql
src/ChanUser.c
src/ClientSocket.h
src/IRCParser.c
src/WHOHandler.c
src/bots.c
src/modules/DummyServ.mod/bot_DummyServ.c
src/modules/NeonBackup.mod/bot_NeonBackup.c
src/modules/NeonFun.mod/bot_NeonFun.c
src/modules/NeonHelp.mod/bot_NeonHelp.c
src/modules/NeonServ.mod/bot_NeonServ.c
src/modules/NeonServ.mod/cmd_neonserv_nicklist.c
src/modules/NeonSpam.mod/bot_NeonSpam.c
src/modules/global.mod/cmd_global_bots.c
src/modules/global.mod/cmd_global_setbot.c
src/mysqlConn.c
src/tools.c

index bb4ea6bb7dfbe5d5f20c319387a54b12fc26d771..d3781181034f7a3bc4f115b9ec8fc7626309ab4a 100644 (file)
@@ -38,6 +38,7 @@ CREATE TABLE IF NOT EXISTS `bots` (
   `botclass` int(10) NOT NULL,
   `textbot` tinyint(1) NOT NULL,
   `queue` tinyint(1) NOT NULL,
+  `secret` tinyint(1) NOT NULL,
   `defaulttrigger` varchar(10) NOT NULL,
   `max_channels` int(5) NOT NULL,
   `register_priority` int(2) NOT NULL,
index b7c9ac115b3e645779b9aa6556668cc6c46a20b2..bb26d92bdfcddccd2a0cfb79869e5db3be1eda5b 100644 (file)
@@ -182,3 +182,7 @@ ADD `oper_pass` VARCHAR( 50 ) NULL AFTER `oper_user`;
 ALTER TABLE `users` ADD `user_block_invites` TINYINT NOT NULL AFTER `user_reply_privmsg`;
 
 -- version: 19
+
+ALTER TABLE `bots` ADD `secret` TINYINT( 1 ) NOT NULL AFTER `queue`;
+
+-- version: 20
index d82fc1de2c3aecc50378da431d2bf075aaee762d..24bdaf8fd0c6991573ea07e7fc3f2af9f6c4b4ca 100644 (file)
@@ -123,18 +123,16 @@ void delChanUser(struct ChanUser *chanuser, int do_freeChanUser) {
     SYNCHRONIZE(cache_sync);
     struct ChanUser *cchanuser, *last;
     //remove it from the user's channel-list
-    if(!(chanuser->flags & CHANUSERFLAG_INVISIBLE)) {
-        last = NULL;
-        for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
-            if(cchanuser == chanuser) {
-                if(last) 
-                    last->next_chan = chanuser->next_chan;
-                else
-                    chanuser->user->channel = chanuser->next_chan;
-                break;
-            } else
-                last = cchanuser;
-        }
+    last = NULL;
+    for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
+        if(cchanuser == chanuser) {
+            if(last) 
+                last->next_chan = chanuser->next_chan;
+            else
+                chanuser->user->channel = chanuser->next_chan;
+            break;
+        } else
+            last = cchanuser;
     }
 
     //remove it from the channel's user-list
index 38768b19715a154c9e76091c9b2836bb55c4b03a..f4fc57ab49b30b8951f59da950277819017a83ab 100644 (file)
@@ -31,6 +31,7 @@
 #define SOCKET_FLAG_CHANGENICK     0x800
 #define SOCKET_FLAG_REQUEST_INVITE 0x1000
 #define SOCKET_FLAG_REQUEST_OP     0x2000
+#define SOCKET_FLAG_SECRET_BOT     0x4000
 
 #define SOCKET_HAVE_BOTCLASSVALUE1 0x10000000
 #define SOCKET_HAVE_BOTCLASSVALUE2 0x20000000
index 156afb3c04245e7524ed5801f8bef7c05d703679..f9e79e0c127c720b34a67f96db5217334d0a2738 100644 (file)
@@ -99,8 +99,34 @@ static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char *
     }
 }
 
+static void increase_viscount_butone(struct ChanNode *chan, struct ChanUser *ignore) {
+    struct ChanUser *chanuser;
+    
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(chanuser == ignore)
+            continue;
+        chanuser->visCount++;
+    }
+}
+
+static void decrease_viscount_butone(struct ChanNode *chan, struct ChanUser *ignore) {
+    struct ChanUser *chanuser, *next_chanuser;
+    
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next_chanuser) {
+        next_chanuser = getChannelUsers(chan, chanuser);
+        if(chanuser == ignore)
+            continue;
+        chanuser->visCount--;
+        if(chanuser->visCount <= 0)
+            delChanUser(chanuser, 1);
+    }
+}
+
 static USERLIST_CALLBACK(got_channel_userlist) {
     struct ChanUser *chanuser = data;
+    
+    increase_viscount_butone(chanuser->chan, chanuser);
+    
     event_join(chanuser);
 }
 
@@ -144,12 +170,28 @@ static IRC_CMD(raw_join) {
         
         event_registered(user, from);
         user->flags &= ~USERFLAG_WAS_REGISTERING;
+    } else if(!(chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+        if(!isBot(user)) {
+            DESYNCHRONIZE(cache_sync);
+            return 1; //ignore join
+        }
+        
+        chanuser = addChanUser(chan, user);
+        chanuser->visCount = 1;
+        
+        if(isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible
+            chanuser->flags |= CHANUSERFLAG_INVISIBLE;
+        
+        get_userlist_with_invisible(chan, 0, got_channel_userlist, chanuser);
     } else if(!isUserOnChan(user, chan)) {
         //join user to an existing channel
         chanuser = addChanUser(chan, user);
         chanuser->visCount = 1;
-        if(isBot(user) && isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible
-            chanuser->flags |= CHANUSERFLAG_INVISIBLE;
+        if(isBot(user)) {
+            if(isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible
+                chanuser->flags |= CHANUSERFLAG_INVISIBLE;
+            increase_viscount_butone(chan, chanuser);
+        }
         
         event_join(chanuser);
         
@@ -167,6 +209,10 @@ static IRC_CMD(raw_join) {
         //user is already in the channel
         chanuser = getChanUser(user, chan);
         chanuser->visCount++;
+        
+        if(isBot(user) && !(chanuser->flags & CHANUSERFLAG_INVISIBLE))
+            increase_viscount_butone(chan, chanuser);
+        
         //if multiple bots see the user, it can't be invisible
         chanuser->flags &= ~CHANUSERFLAG_INVISIBLE;
     }
@@ -222,6 +268,8 @@ static IRC_CMD(raw_part) {
         DESYNCHRONIZE(cache_sync);
         return 0;
     }
+    if(isBot(user) && user == client->user) 
+        decrease_viscount_butone(chan, chanuser);
     chanuser->visCount--;
     if(chanuser->visCount == 0) {
         delChanUser(chanuser, 0); //not free, yet!
@@ -278,6 +326,8 @@ static IRC_CMD(raw_kick) {
         DESYNCHRONIZE(cache_sync);
         return 0;
     }
+    if(isBot(target) && target == client->user) 
+        decrease_viscount_butone(chan, chanuser);
     chanuser->visCount--;
     if(chanuser->visCount == 0) {
         delChanUser(chanuser, 0); //not free, yet!
@@ -346,7 +396,7 @@ static IRC_CMD(raw_quit) {
     for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next_chanuser) {
         next_chanuser = getUserChannels(user, chanuser);
         chanuser->visCount--;
-        if(chanuser->visCount == 0) {
+        if(chanuser->visCount <= 0) {
             delChanUser(chanuser, 0); //not free, yet!
             event_part(chanuser, 1, argv[0]);
             if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING))
@@ -382,12 +432,13 @@ void bot_disconnect(struct ClientSocket *client) {
         struct ChanUser *chanuser, *next_chanuser;
         for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next_chanuser) {
             next_chanuser = getUserChannels(user, chanuser);
+            decrease_viscount_butone(chanuser->chan, chanuser);
             chanuser->visCount--;
-            if(chanuser->visCount == 0) {
+            if(chanuser->visCount <= 0) {
                 delChanUser(chanuser, 0); //not free, yet!
                 event_part(chanuser, 1, "QUIT");
-                if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING))
-                    check_full_rejoin(chanuser->chan);
+                if(chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST)
+                    checkChannelVisibility(chanuser->chan);
                 freeChanUser(chanuser);
             }
         }
index 7a8a3548ea359fa5aee74e48fc84e25e1d4ab8f5..13786787b1187f68b4a5ea18d8c8f373fc545554 100644 (file)
@@ -30,7 +30,7 @@
 #define WHOQUEUETYPE_CHECKTYPE 0x07
 #define WHOQUEUETYPE_FOUND     0x08
 
-#define MAXCALLBACKS 3
+#define MAXCALLBACKS 10
 
 struct WHOQueueEntry {
     char type;
index 5097e8d47e26cd111b78acdfac54744a04847630..ef55ef656e1b78b4a3c4c7c9255f647496559e80 100644 (file)
@@ -40,7 +40,7 @@ static void start_zero_bots() {
     MYSQL_RES *res, *res2;
     MYSQL_ROW row;
     
-    printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '0' AND `active` = '1'");
+    printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '0' AND `active` = '1'");
     res = mysql_use();
     
     while ((row = mysql_fetch_row(res)) != NULL) {
@@ -48,6 +48,7 @@ static void start_zero_bots() {
         client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
         client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
         client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+        client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
         client->botid = 0;
         client->clientid = atoi(row[7]);
         connect_socket(client);
index 259e640bdb8d318404cf74ce15ac57e31fb325a9..ade73ac809aca5a1ebbe9db5bc704260a662f992 100644 (file)
@@ -75,7 +75,7 @@ static void start_bots(int type) {
     MYSQL_ROW row;
     
     if(type == MODSTATE_STARTSTOP) {
-        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
         res = mysql_use();
         
         while ((row = mysql_fetch_row(res)) != NULL) {
@@ -83,6 +83,7 @@ static void start_bots(int type) {
             client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
             client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
             client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+            client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
             client->flags |= SOCKET_FLAG_SILENT;
             client->botid = BOTID;
             client->clientid = atoi(row[7]);
index b16c387eccab83927dff99e0be18866ccaba84d6..f9d82616d3dfe7cf613374cce9379fc747d0087e 100644 (file)
@@ -88,7 +88,7 @@ static void start_bots(int type) {
     MYSQL_ROW row;
     
     if(type == MODSTATE_STARTSTOP) {
-        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
         res = mysql_use();
         
         while ((row = mysql_fetch_row(res)) != NULL) {
@@ -96,6 +96,7 @@ static void start_bots(int type) {
             client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
             client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
             client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+            client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
             client->flags |= SOCKET_FLAG_REQUEST_INVITE | SOCKET_FLAG_REQUEST_OP;
             client->botid = BOTID;
             client->clientid = atoi(row[7]);
index b0c2cae65f57d2293a66298117a5956741123082..c1593221e28b44c5766042b193b35ee91d41fde7 100644 (file)
@@ -92,7 +92,7 @@ static void start_bots(int type) {
     MYSQL_ROW row;
     
     if(type == MODSTATE_STARTSTOP) {
-        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
         res = mysql_use();
         
         while ((row = mysql_fetch_row(res)) != NULL) {
@@ -100,6 +100,7 @@ static void start_bots(int type) {
             client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
             client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
             client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+            client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
             client->flags |= SOCKET_FLAG_SILENT;
             client->flags |= SOCKET_FLAG_REQUEST_INVITE | SOCKET_FLAG_REQUEST_OP;
             client->botid = BOTID;
index 7170dbd82d1c3685287e68afd70a5da93faa84da..e35d85b5f06c91f08023ccf706b10d231c62d86b 100644 (file)
@@ -122,7 +122,7 @@ static void start_bots(int type) {
     MYSQL_ROW row;
     
     if(type == MODSTATE_STARTSTOP) {
-        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
         res = mysql_use();
         
         while ((row = mysql_fetch_row(res)) != NULL) {
@@ -130,6 +130,7 @@ static void start_bots(int type) {
             client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
             client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
             client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+            client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
             client->flags |= SOCKET_FLAG_SILENT;
             client->flags |= SOCKET_FLAG_REQUEST_INVITE | SOCKET_FLAG_REQUEST_OP;
             client->botid = BOTID;
index 050e71c884e7d17e956af0dc397f0e084f2db082..4ba6381e6a9f0ec79b6b535a98b9420268cca46e 100644 (file)
@@ -359,6 +359,8 @@ static const struct default_language_entry msgtab[] = {
     {"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 %d and voiced with %d access)"},
+    {"NS_NICKLIST_ACCESS_BOT", "Bot"},
+    {"NS_NICKLIST_ACCESS_OPER", "Operator"},
     {"NS_SETBOT_UNKNOWN", "`%d` is an unknown botid."}, /* {ARGS: 50} */
     {"NS_SETBOT_HEADER", "$bSettings for botid `%d`:$b"}, /* {ARGS: 50} */
     {"NS_SETBOT_SETTING", "$b%s$b is an unknown bot setting."}, /* {ARGS: "strangeSetting"} */
@@ -465,13 +467,14 @@ static void start_bots(int type) {
     MYSQL_ROW row;
     
     if(type == MODSTATE_STARTSTOP) {
-        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
         res = mysql_use();
         while ((row = mysql_fetch_row(res)) != NULL) {
             client = create_socket(row[3], atoi(row[4]), row[10], row[5], row[0], row[1], row[2]);
             client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
             client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
             client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+            client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
             client->flags |= SOCKET_FLAG_REQUEST_INVITE | SOCKET_FLAG_REQUEST_OP;
             client->botid = BOTID;
             client->clientid = atoi(row[7]);
index 3e858d0f2a49ad43820e77feaba587c272c76fb3..1287ad6c993ba8714738c64dc3b6b2d4b73e30d2 100644 (file)
 * 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(textclient, 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, textclient, 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));
@@ -68,37 +77,81 @@ CMD_BIND(neonserv_cmd_nicklist) {
         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,127 @@ 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;
+                accessbufpos = sprintf(accessbuf, "\003040\003");
+            }
+        } 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 +291,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);
index eace7b7071f1feb6d3c5901f650966aa674c4e87..2ef3c74900d65bedee22b80a476bcf38aa2db3ca 100644 (file)
@@ -152,7 +152,7 @@ static void start_bots(int type) {
     MYSQL_ROW row;
     
     if(type == MODSTATE_STARTSTOP) {
-        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+        printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind`, `secret` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
         res = mysql_use();
         
         while ((row = mysql_fetch_row(res)) != NULL) {
@@ -160,6 +160,7 @@ static void start_bots(int type) {
             client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
             client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0);
             client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0);
+            client->flags |= (strcmp(row[11], "0") ? SOCKET_FLAG_SECRET_BOT : 0);
             client->flags |= SOCKET_FLAG_REQUEST_INVITE | SOCKET_FLAG_REQUEST_OP;
             client->botid = BOTID;
             client->clientid = atoi(row[7]);
index 6af36a45804ef09ee82b661b9a3fcabe8e81791a..c4d345d774a376e03039fc5b1420c08f77b1e52d 100644 (file)
@@ -25,7 +25,7 @@ CMD_BIND(global_cmd_bots) {
     struct Table *table;
     MYSQL_RES *res, *res2;
     MYSQL_ROW row, row2;
-    printf_mysql_query("SELECT `active`, `nick`, `server`, `port`, `pass`, `botclass`, `textbot`, `queue`, `defaulttrigger`, `max_channels`, `register_priority`, `id` FROM `bots`");
+    printf_mysql_query("SELECT `active`, `nick`, `server`, `port`, `pass`, `botclass`, `textbot`, `queue`, `defaulttrigger`, `max_channels`, `register_priority`, `id`, `secret` FROM `bots`");
     res = mysql_use();
     table = table_init(7, mysql_num_rows(res) + 1, 0);
     char *content[7];
@@ -54,6 +54,8 @@ CMD_BIND(global_cmd_bots) {
             botflags[flagspos++] = 't';
         if(!strcmp(row[7], "1"))
             botflags[flagspos++] = 'q';
+        if(!strcmp(row[12], "1"))
+            botflags[flagspos++] = 's';
         botflags[flagspos] = '\0';
         content[4] = botflags;
         printf_mysql_query("SELECT COUNT(*) FROM `bot_channels` WHERE `botid` = '%s'", row[11]);
index 32ccce5793f29276a0e131fc00331a7f30ede947..0017de2b79cd3fcf598365ec6c3bf7e32798f86b 100644 (file)
@@ -35,6 +35,7 @@ static int global_cmd_setbot_serverpass(struct ClientSocket *textclient, struct
 static int global_cmd_setbot_class(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
 static int global_cmd_setbot_queue(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
 static int global_cmd_setbot_prefered(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
+static int global_cmd_setbot_secret(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
 static int global_cmd_setbot_maxchan(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
 static int global_cmd_setbot_priority(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
 static int global_cmd_setbot_trigger(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value);
@@ -43,7 +44,7 @@ CMD_BIND(global_cmd_setbot) {
     MYSQL_RES *res;
     MYSQL_ROW row;
     int botid = atoi(argv[0]);
-    printf_mysql_query("SELECT `active`, `nick`, `server`, `port`, `pass`, `botclass`, `textbot`, `queue`, `defaulttrigger`, `max_channels`, `register_priority`, `bind`, `ident`, `realname`, `ssl`, `id` FROM `bots` WHERE `id` = '%d'", botid);
+    printf_mysql_query("SELECT `active`, `nick`, `server`, `port`, `pass`, `botclass`, `textbot`, `queue`, `defaulttrigger`, `max_channels`, `register_priority`, `bind`, `ident`, `realname`, `ssl`, `id`, `secret` FROM `bots` WHERE `id` = '%d'", botid);
     res = mysql_use();
     if(!(row = mysql_fetch_row(res))) {
         reply(textclient, user, "NS_SETBOT_UNKNOWN", botid);
@@ -68,6 +69,7 @@ CMD_BIND(global_cmd_setbot) {
         else if(!stricmp(argv[1], "botclass")) log_event = global_cmd_setbot_class(textclient, user, row, value);
         else if(!stricmp(argv[1], "queue")) log_event = global_cmd_setbot_queue(textclient, user, row, value);
         else if(!stricmp(argv[1], "prefered")) log_event = global_cmd_setbot_prefered(textclient, user, row, value);
+        else if(!stricmp(argv[1], "secret")) log_event = global_cmd_setbot_secret(textclient, user, row, value);
         else if(!stricmp(argv[1], "maxchan")) log_event = global_cmd_setbot_maxchan(textclient, user, row, value);
         else if(!stricmp(argv[1], "priority")) log_event = global_cmd_setbot_priority(textclient, user, row, value);
         else if(!stricmp(argv[1], "trigger")) log_event = global_cmd_setbot_trigger(textclient, user, row, value);
@@ -97,6 +99,7 @@ CMD_BIND(global_cmd_setbot) {
         global_cmd_setbot_class(textclient, user, row, NULL);
         global_cmd_setbot_queue(textclient, user, row, NULL);
         global_cmd_setbot_prefered(textclient, user, row, NULL);
+        global_cmd_setbot_secret(textclient, user, row, NULL);
         global_cmd_setbot_maxchan(textclient, user, row, NULL);
         global_cmd_setbot_priority(textclient, user, row, NULL);
         global_cmd_setbot_trigger(textclient, user, row, NULL);
@@ -476,6 +479,35 @@ static int global_cmd_setbot_prefered(struct ClientSocket *textclient, struct Us
     return ret;
 }
 
+static int global_cmd_setbot_secret(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value) {
+    int val = (strcmp(bot[16], "0") ? 1 : 0);
+    int ret = 0;
+    if(value) {
+        if(!strcmp(value, "0") || !stricmp(value, "off") || !stricmp(value, get_language_string(user, "NS_SET_OFF"))) {
+            val = 0;
+        } else if(!strcmp(value, "1") || !stricmp(value, "on") || !stricmp(value, get_language_string(user, "NS_SET_ON"))) {
+            val = 1;
+        } else {
+            reply(textclient, user, "NS_SET_INVALID_BOOLEAN", value);
+            return 0;
+        }
+        struct ClientSocket *client;
+        for(client = getBots(0, NULL); client; client = getBots(0, client)) {
+            if(client->clientid == atoi(bot[15])) {
+                if(val)
+                    client->flags |= SOCKET_FLAG_SECRET_BOT;
+                else
+                    client->flags &= ~SOCKET_FLAG_SECRET_BOT;
+                break;
+            }
+        }
+        printf_mysql_query("UPDATE `bots` SET `secret` = '%d' WHERE `id` = '%s'", val, bot[15]);
+        ret = 1;
+    }
+    reply(textclient, user, "\002SECRET     \002 %s", get_language_string(user, (val ? "NS_SET_ON" : "NS_SET_OFF")));
+    return ret;
+}
+
 static int global_cmd_setbot_maxchan(struct ClientSocket *textclient, struct UserNode *user, MYSQL_ROW bot, char *value) {
     int val = atoi(bot[9]);
     int ret = 0;
index 6fe11e723d8a44aa89288df03ce18582ed14e3cb..e76641044d7f69f719f12266dd79684be50a1be3 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "mysqlConn.h"
-#define DATABASE_VERSION "19"
+#define DATABASE_VERSION "20"
 
 static void show_mysql_error();
 
index 3ad8a41f532600f3b01bbf84169b69d3fdeb875a..23f3b59efaa194eb7ea2d9ee4582a3ba8fd1cf65 100644 (file)
@@ -204,7 +204,7 @@ char **table_end(struct Table *table) {
                     if(table->contents[row][col][i] == '\002') j++;
                     else if(table->contents[row][col][i] == '\003') {
                         j++;
-                        for(k = 1; k < 2; k++) {
+                        for(k = 1; k <= 2; k++) {
                             if(isdigit(table->contents[row][col][i+k]))
                                 j++;
                             else