From bb679ff347dbaab788e62d4fe2f8ad6eb0bd910a Mon Sep 17 00:00:00 2001 From: pk910 Date: Wed, 14 Dec 2011 20:15:24 +0100 Subject: [PATCH] added cmd_nicklist --- Makefile.am | 1 + src/bot_NeonServ.c | 4 + src/cmd_neonserv.h | 1 + src/cmd_neonserv_nicklist.c | 243 ++++++++++++++++++++++++++++++++++++ src/commands.c | 1 + src/tools.c | 14 ++- 6 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 src/cmd_neonserv_nicklist.c diff --git a/Makefile.am b/Makefile.am index b12943e..0cfac17 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,6 +119,7 @@ neonserv_SOURCES = src/version.c \ src/cmd_global_reload.c \ src/cmd_global_restart.c \ src/cmd_global_die.c \ + src/cmd_neonserv_nicklist.c \ src/cmd_funcmds.c \ src/ConfigParser.c diff --git a/src/bot_NeonServ.c b/src/bot_NeonServ.c index 613487a..83f1319 100644 --- a/src/bot_NeonServ.c +++ b/src/bot_NeonServ.c @@ -340,6 +340,10 @@ static const struct default_language_entry msgtab[] = { {"NS_BOTS_FLAGS", "Flags"}, {"NS_BOTS_CHANNELS", "Channels"}, {"NS_BOTS_TRIGGER", "Trigger"}, + {"NS_NICKLIST_NICK", "Nick"}, + {"NS_NICKLIST_STATE", "State"}, + {"NS_NICKLIST_ACCESS", "Access"}, + {"NS_NICKLIST_SYNC", "use `nicklist sync` to fix all red and orange entrys in the list above (add opped users with 200 and voiced with 100 access)"}, {NULL, NULL} }; diff --git a/src/cmd_neonserv.h b/src/cmd_neonserv.h index 334a002..e624ed4 100644 --- a/src/cmd_neonserv.h +++ b/src/cmd_neonserv.h @@ -74,6 +74,7 @@ CMD_BIND(neonserv_cmd_mdeluser); CMD_BIND(neonserv_cmd_mode); CMD_BIND(neonserv_cmd_move); CMD_BIND(neonserv_cmd_myaccess); +CMD_BIND(neonserv_cmd_nicklist); CMD_BIND(neonserv_cmd_noregister); CMD_BIND(neonserv_cmd_op); CMD_BIND(neonserv_cmd_opall); diff --git a/src/cmd_neonserv_nicklist.c b/src/cmd_neonserv_nicklist.c new file mode 100644 index 0000000..1a337c0 --- /dev/null +++ b/src/cmd_neonserv_nicklist.c @@ -0,0 +1,243 @@ +/* cmd_neonserv_nicklist.c - NeonServ v5.2 + * Copyright (C) 2011 Philipp Kreil (pk910) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cmd_neonserv.h" + +/* +* argv[0] "force" +* argv[1] (optional) nick mask +*/ +static USERLIST_CALLBACK(neonserv_cmd_nicklist_userlist_lookup); +static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask, int syncusers); +static void neonserv_cmd_nicklist_synchronize_user(struct ChanNode *chan, struct UserNode *user, int access, int new); + +struct neonserv_cmd_nicklist_cache { + struct ClientSocket *client, *textclient; + struct UserNode *user; + struct Event *event; + char *nickmask; + int syncusers; +}; + +CMD_BIND(neonserv_cmd_nicklist) { + int syncusers = 0; + if(argc && !stricmp(argv[0], "sync")) { + if(!checkChannelAccess(user, chan, "channel_canadd", 0)) { + if(isGodMode(user)) { + event->flags |= CMDFLAG_OPLOG; + } else { + reply(getTextBot(), user, "NS_ACCESS_DENIED"); + return; + } + } + argv++; + argc--; + syncusers = 1; + event->flags |= CMDFLAG_LOG; + } + struct neonserv_cmd_nicklist_cache *cache = malloc(sizeof(*cache)); + if (!cache) { + perror("malloc() failed"); + return; + } + cache->client = client; + cache->textclient = getTextBot(); + cache->user = user; + cache->event = event; + if(argc) { + cache->nickmask = strdup(argv[0]); + } else + cache->nickmask = NULL; + cache->syncusers = syncusers; + get_userlist_with_invisible(chan, neonserv_cmd_nicklist_userlist_lookup, cache); +} + +static USERLIST_CALLBACK(neonserv_cmd_nicklist_userlist_lookup) { + struct neonserv_cmd_nicklist_cache *cache = data; + neonserv_cmd_nicklist_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask, cache->syncusers); + if(cache->nickmask) + free(cache->nickmask); + free(cache); +} + +static void neonserv_cmd_nicklist_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask, int syncusers) { + MYSQL_RES *res; + MYSQL_ROW row, defaults = NULL; + struct Table *table; + table = table_init(3, chan->usercount + 1, 0); + char *content[3]; + content[0] = get_language_string(user, "NS_NICKLIST_NICK"); + content[1] = get_language_string(user, "NS_NICKLIST_STATE"); + content[2] = get_language_string(user, "NS_NICKLIST_ACCESS"); + table_add(table, content); + printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d'", chan->channel_id); + res = mysql_use(); + int userlistlen = mysql_num_rows(res); + int i = 0; + MYSQL_ROW userlist[userlistlen]; + while ((row = mysql_fetch_row(res)) != NULL) { + userlist[i++] = row; + } + int db_enfops, db_enfvoice; + printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id); + row = mysql_fetch_row(mysql_use()); + if(row[0] == NULL || row[1] == NULL) { + printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'"); + defaults = mysql_fetch_row(mysql_use()); + } + db_enfops = atoi((row[0] ? row[0] : defaults[0])); + db_enfvoice = atoi((row[1] ? row[1] : defaults[1])); + int caccess = getChannelAccess(user, chan); + int synced_user = 0; + struct ChanUser *chanuser; + int sort_nicklist[] = { + CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED, + CHANUSERFLAG_OPPED, + CHANUSERFLAG_VOICED, + CHANUSERFLAG_INVISIBLE, + 0 + }; + int *sort_pos = sort_nicklist; + int sort_flags; + do { + sort_flags = *(sort_pos++); + char statebuf[5]; + char accessbuf[9]; + int uaccess; + int stateset = 0; + for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) { + if((chanuser->flags & (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED | CHANUSERFLAG_INVISIBLE)) != sort_flags) continue; + if(nickmask && match(nickmask, chanuser->user->nick)) continue; + if(!stateset) { + if((chanuser->flags & CHANUSERFLAG_INVISIBLE)) statebuf[stateset++] = '<'; + if((chanuser->flags & CHANUSERFLAG_OPPED)) statebuf[stateset++] = '@'; + if((chanuser->flags & CHANUSERFLAG_VOICED)) statebuf[stateset++] = '+'; + statebuf[stateset++] = '\0'; + } + content[0] = chanuser->user->nick; + content[1] = statebuf; + uaccess = 0; + if(chanuser->user->flags & USERFLAG_ISAUTHED) { + for(i = 0; i < userlistlen; i++) { + if(!stricmp(chanuser->user->auth, userlist[i][1])) { + uaccess = atoi(userlist[i][0]); + if((((chanuser->flags & CHANUSERFLAG_OPPED) && uaccess < db_enfops) || ((chanuser->flags & CHANUSERFLAG_VOICED) && uaccess < db_enfvoice)) && !isNetworkService(chanuser->user)) { + if(syncusers) { + if((chanuser->flags & CHANUSERFLAG_OPPED) && (db_enfops < caccess || isGodMode(user))) { + if(db_enfops >= caccess) + event->flags |= CMDFLAG_OPLOG; + uaccess = db_enfops; + } else if((chanuser->flags & CHANUSERFLAG_VOICED) && (caccess < db_enfvoice || isGodMode(user))) { + if(db_enfvoice >= caccess) + event->flags |= CMDFLAG_OPLOG; + uaccess = db_enfvoice; + } else { + //fail... + sprintf(accessbuf, "\00307%d\003", uaccess); + break; + } + neonserv_cmd_nicklist_synchronize_user(chan, chanuser->user, uaccess, 0); + sprintf(accessbuf, "\00309%d\003", uaccess); + synced_user = 1; + } else { + synced_user = 1; + sprintf(accessbuf, "\00307%d\003", uaccess); + } + } else if((uaccess >= db_enfops && !(chanuser->flags & CHANUSERFLAG_OPPED)) || (uaccess >= db_enfvoice && !(chanuser->flags & CHANUSERFLAG_OPPED_OR_VOICED))) + sprintf(accessbuf, "\00303%d\003", uaccess); + else + sprintf(accessbuf, "%d", uaccess); + break; + } + } + } + if(!uaccess && (chanuser->flags & CHANUSERFLAG_OPPED_OR_VOICED) && !isNetworkService(chanuser->user)) { + if(syncusers) { + if((chanuser->flags & CHANUSERFLAG_OPPED) && (db_enfops < caccess || isGodMode(user))) { + if(db_enfops >= caccess) + event->flags |= CMDFLAG_OPLOG; + uaccess = db_enfops; + } else if((chanuser->flags & CHANUSERFLAG_VOICED) && db_enfvoice < caccess) { + if(db_enfvoice >= caccess) + event->flags |= CMDFLAG_OPLOG; + uaccess = db_enfvoice; + } else { + uaccess = 0; + sprintf(accessbuf, "\003040\003"); + } + if(uaccess && (chanuser->user->flags & USERFLAG_ISAUTHED)) { + neonserv_cmd_nicklist_synchronize_user(chan, chanuser->user, uaccess, 1); + sprintf(accessbuf, "\00309%d\003", uaccess); + synced_user = 1; + } else if(uaccess) { + sprintf(accessbuf, "\003040\003"); + } + } else { + synced_user = 1; + sprintf(accessbuf, "\003040\003"); + } + } else if(!uaccess) + sprintf(accessbuf, "0"); + content[2] = accessbuf; + table_add(table, content); + } + } while(sort_flags != 0); + //send the table + char **table_lines = table_end(table); + for(i = 0; i < table->entrys; i++) { + reply(textclient, user, table_lines[i]); + } + if(table->length == 1) + reply(textclient, user, "NS_TABLE_NONE"); + reply(textclient, user, "NS_TABLE_COUNT", table->length - 1); + table_free(table); + if(synced_user) { + if(!syncusers) + reply(textclient, user, "NS_NICKLIST_SYNC"); + else + logEvent(event); + } +} + +static void neonserv_cmd_nicklist_synchronize_user(struct ChanNode *chan, struct UserNode *user, int caccess, int new) { + if(!(user->flags & USERFLAG_ISAUTHED)) return; + MYSQL_RES *res; + MYSQL_ROW row; + int userid; + printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth)); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + userid = atoi(row[0]); + } else { + printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(user->auth)); + userid = (int) mysql_insert_id(mysql_conn); + } + if(new) { + //just add + printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chan->channel_id, userid, caccess); + } else { + //check if already added + printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + //clvl + if(atoi(row[0]) >= caccess) return; + printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '%d' WHERE `chanuser_id` = '%s'", caccess, row[1]); + } else + printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chan->channel_id, userid, caccess); + } +} diff --git a/src/commands.c b/src/commands.c index ec5902c..548cb4c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -106,6 +106,7 @@ void register_commands() { USER_COMMAND("events", neonserv_cmd_events, 0, "1", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH); USER_COMMAND("info", neonserv_cmd_info, 0, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); USER_COMMAND("extscript", neonserv_cmd_extscript, 0, NULL, CMDFLAG_EMPTY_ARGS | CMDFLAG_CHAN_PARAM); + USER_COMMAND("nicklist", neonserv_cmd_nicklist, 0, "1", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH); #undef USER_COMMAND #define OPER_COMMAND(NAME,FUNCTION,PARAMCOUNT,GACCESS,FLAGS) register_command(1, NAME, FUNCTION, PARAMCOUNT, NULL, GACCESS, FLAGS) diff --git a/src/tools.c b/src/tools.c index 71cd40d..2c047ad 100644 --- a/src/tools.c +++ b/src/tools.c @@ -180,7 +180,7 @@ int table_set_bold(struct Table *table, int collum, int bold) { } char **table_end(struct Table *table) { - int row, col, tablewidth = 0, pos,i; + int row, col, tablewidth = 0, pos,i,j,k; if(!table->entrys) return NULL; for(col = 0; col < table->width; col++) { tablewidth += table->maxwidth[col]+1; @@ -196,11 +196,23 @@ char **table_end(struct Table *table) { if(table->col_flags[col] & TABLE_FLAG_COL_BOLD) table->table_lines[row][pos++] = '\002'; i = 0; + j = 0; if(table->contents[row][col]) { for(; i < strlen(table->contents[row][col]); i++) { table->table_lines[row][pos++] = table->contents[row][col][i]; + if(table->contents[row][col][i] == '\002') j++; + else if(table->contents[row][col][i] == '\003') { + j++; + for(k = 1; k < 2; k++) { + if(isdigit(table->contents[row][col][i+k])) + j++; + else + break; + } + } } } + i -= j; if(col < table->width-1) { for(;i < table->maxwidth[col]; i++) { table->table_lines[row][pos++] = ' '; -- 2.20.1