From: pk910 Date: Tue, 21 Aug 2012 23:34:06 +0000 (+0200) Subject: Merge branch 'master' into IOMultiplexer X-Git-Tag: v5.5~9^2~14 X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=commitdiff_plain;h=4b9de3472bf8bb35214bd3c31289b7c601304686;hp=c99b8d5951fe6429844c8cb5ff94213bb625ad95 Merge branch 'master' into IOMultiplexer --- diff --git a/database.sql b/database.sql index bb4ea6b..d378118 100644 --- a/database.sql +++ b/database.sql @@ -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, diff --git a/database.upgrade.sql b/database.upgrade.sql index b7c9ac1..bb26d92 100644 --- a/database.upgrade.sql +++ b/database.upgrade.sql @@ -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 diff --git a/src/ChanUser.c b/src/ChanUser.c index d82fc1d..24bdaf8 100644 --- a/src/ChanUser.c +++ b/src/ChanUser.c @@ -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 diff --git a/src/ClientSocket.h b/src/ClientSocket.h index 38768b1..f4fc57a 100644 --- a/src/ClientSocket.h +++ b/src/ClientSocket.h @@ -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 diff --git a/src/IRCParser.c b/src/IRCParser.c index 156afb3..f9e79e0 100644 --- a/src/IRCParser.c +++ b/src/IRCParser.c @@ -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); } } diff --git a/src/WHOHandler.c b/src/WHOHandler.c index 7a8a354..1378678 100644 --- a/src/WHOHandler.c +++ b/src/WHOHandler.c @@ -30,7 +30,7 @@ #define WHOQUEUETYPE_CHECKTYPE 0x07 #define WHOQUEUETYPE_FOUND 0x08 -#define MAXCALLBACKS 3 +#define MAXCALLBACKS 10 struct WHOQueueEntry { char type; diff --git a/src/bots.c b/src/bots.c index 5097e8d..ef55ef6 100644 --- a/src/bots.c +++ b/src/bots.c @@ -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); diff --git a/src/modules/DummyServ.mod/bot_DummyServ.c b/src/modules/DummyServ.mod/bot_DummyServ.c index 259e640..ade73ac 100644 --- a/src/modules/DummyServ.mod/bot_DummyServ.c +++ b/src/modules/DummyServ.mod/bot_DummyServ.c @@ -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]); diff --git a/src/modules/NeonBackup.mod/bot_NeonBackup.c b/src/modules/NeonBackup.mod/bot_NeonBackup.c index b16c387..f9d8261 100644 --- a/src/modules/NeonBackup.mod/bot_NeonBackup.c +++ b/src/modules/NeonBackup.mod/bot_NeonBackup.c @@ -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]); diff --git a/src/modules/NeonFun.mod/bot_NeonFun.c b/src/modules/NeonFun.mod/bot_NeonFun.c index b0c2cae..c159322 100644 --- a/src/modules/NeonFun.mod/bot_NeonFun.c +++ b/src/modules/NeonFun.mod/bot_NeonFun.c @@ -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; diff --git a/src/modules/NeonHelp.mod/bot_NeonHelp.c b/src/modules/NeonHelp.mod/bot_NeonHelp.c index 7170dbd..e35d85b 100644 --- a/src/modules/NeonHelp.mod/bot_NeonHelp.c +++ b/src/modules/NeonHelp.mod/bot_NeonHelp.c @@ -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; diff --git a/src/modules/NeonServ.mod/bot_NeonServ.c b/src/modules/NeonServ.mod/bot_NeonServ.c index 050e71c..4ba6381 100644 --- a/src/modules/NeonServ.mod/bot_NeonServ.c +++ b/src/modules/NeonServ.mod/bot_NeonServ.c @@ -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]); diff --git a/src/modules/NeonServ.mod/cmd_neonserv_nicklist.c b/src/modules/NeonServ.mod/cmd_neonserv_nicklist.c index 3e858d0..1287ad6 100644 --- a/src/modules/NeonServ.mod/cmd_neonserv_nicklist.c +++ b/src/modules/NeonServ.mod/cmd_neonserv_nicklist.c @@ -22,37 +22,46 @@ * 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); diff --git a/src/modules/NeonSpam.mod/bot_NeonSpam.c b/src/modules/NeonSpam.mod/bot_NeonSpam.c index eace7b7..2ef3c74 100644 --- a/src/modules/NeonSpam.mod/bot_NeonSpam.c +++ b/src/modules/NeonSpam.mod/bot_NeonSpam.c @@ -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]); diff --git a/src/modules/global.mod/cmd_global_bots.c b/src/modules/global.mod/cmd_global_bots.c index 6af36a4..c4d345d 100644 --- a/src/modules/global.mod/cmd_global_bots.c +++ b/src/modules/global.mod/cmd_global_bots.c @@ -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]); diff --git a/src/modules/global.mod/cmd_global_setbot.c b/src/modules/global.mod/cmd_global_setbot.c index 32ccce5..0017de2 100644 --- a/src/modules/global.mod/cmd_global_setbot.c +++ b/src/modules/global.mod/cmd_global_setbot.c @@ -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; diff --git a/src/mysqlConn.c b/src/mysqlConn.c index 6fe11e7..e766410 100644 --- a/src/mysqlConn.c +++ b/src/mysqlConn.c @@ -16,7 +16,7 @@ */ #include "mysqlConn.h" -#define DATABASE_VERSION "19" +#define DATABASE_VERSION "20" static void show_mysql_error(); diff --git a/src/tools.c b/src/tools.c index 3ad8a41..23f3b59 100644 --- a/src/tools.c +++ b/src/tools.c @@ -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