From e882e640e4e36173bdc586ddc235fdb0d9d8e34d Mon Sep 17 00:00:00 2001 From: pk910 Date: Sun, 21 Aug 2011 06:19:14 +0200 Subject: [PATCH] added timeToStr and cmd_users --- DBHelper.h | 5 +- bot_NeonServ.c | 20 +++++++- cmd_neonserv_users.c | 108 +++++++++++++++++++++++++++++++++++++-- lang.c | 22 ++++++++ lang.h | 3 ++ main.c | 2 + modcmd.c | 2 +- tools.c | 118 ++++++++++++++++++++++++++++++++++--------- tools.h | 10 +++- 9 files changed, 256 insertions(+), 34 deletions(-) diff --git a/DBHelper.h b/DBHelper.h index cb99bc3..5c68b90 100644 --- a/DBHelper.h +++ b/DBHelper.h @@ -2,14 +2,13 @@ #define _DBHelper_h #include "main.h" +#include "ChanNode.h" +#include "UserNode.h" #define DB_CHANUSER_SUSPENDED 0x01 #define DB_CHANUSER_AUTOINVITE 0x02 #define DB_CHANUSER_NOAUTOOP 0x04 -struct ChanNode; -struct UserNode; - void _loadUserSettings(struct UserNode* user); #define loadUserSettings(USER) if((USER->flags & USERFLAG_ISAUTHED) && !(USER->flags & USERFLAG_LOADED_SETTINGS)) _loadUserSettings(USER) int isGodMode(struct UserNode *user); diff --git a/bot_NeonServ.c b/bot_NeonServ.c index feb1616..4cc7bde 100644 --- a/bot_NeonServ.c +++ b/bot_NeonServ.c @@ -29,6 +29,7 @@ static const struct default_language_entry msgtab[] = { {"NS_ACCESS_OUTRANKED", "You cannot give users access greater than or equal to your own."}, {"NS_USER_OUTRANKED", "\002%s\002 outranks you (command has no effect)."}, {"NS_ACCESS_DENIED", "Access denied."}, + {"NS_TABLE_NONE", " None"}, {"NS_CLVL_DONE", "%s now has access \002%d\002 in %s."}, {"NS_A_LACKS_ACCESS_BUT_GOD_NICK", "%s lacks access to %s but has \002security override\002 enabled."}, {"NS_A_LACKS_ACCESS_BUT_GOD_AUTH", "%s (%s) lacks access to %s but has \002security override\002 enabled."}, @@ -37,7 +38,22 @@ static const struct default_language_entry msgtab[] = { {"NS_A_ACCESS_NICK_GOD", "%s has access \002%d\002 in %s and has \002security override\002 enabled."}, {"NS_A_ACCESS_AUTH_GOD", "%s (%s) has access \002%d\002 in %s and has \002security override\002 enabled."}, {"NS_A_SUSPENDED", "\002%s\002's access to %s has been suspended."}, - {"NS_A_IS_IRCOP", "%s is an \002IRC operator\002." }, + {"NS_A_IS_IRCOP", "%s is an \002IRC operator\002."}, + {"NS_USERS_HEADER", "%s users from level %d to %d:"}, + {"NS_USERS_HEADER_MATCH", "%s users from level %d to %d matching %s:"}, + {"NS_USERS_HEADER_ACCESS", "Access"}, + {"NS_USERS_HEADER_ACCOUNT", "Accout"}, + {"NS_USERS_HEADER_SEEN", "Last Seen"}, + {"NS_USERS_HEADER_STATE", "Status"}, + {"NS_USERS_COUNT", "There are \002%d\002 users in %s from level %d to %d."}, + {"NS_USERS_COUNT_1", "There is \002%d\002 user in %s from level %d to %d."}, + {"NS_USERS_COUNT_MATCH", "There are \002%d\002 users in %s from level %d to %d. (\002%d\002 matching your request)"}, + {"NS_USERS_COUNT_MATCH_1", "There is \002%d\002 user in %s from level %d to %d. (\002%d\002 matching your request)"}, + {"NS_USERS_SEEN_HERE", "Here"}, + {"NS_USERS_SEEN_NEVER", "Never"}, + {"NS_USERS_STATE_SUSPENDED", "Suspended"}, + {"NS_USERS_STATE_NORMAL", "Normal"}, + {NULL, NULL} }; @@ -112,13 +128,13 @@ static void start_bots() { void init_NeonServ() { check_mysql(); - register_command(BOTID, "users", neonserv_cmd_users, 1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REQUIRE_AUTH); register_command(BOTID, "modes", neonserv_cmd_modes, 1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH); register_command(BOTID, "adduser", neonserv_cmd_adduser, 2, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH); register_command(BOTID, "deluser", neonserv_cmd_deluser, 1, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH); register_command(BOTID, "clvl", neonserv_cmd_clvl, 2, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH); register_command(BOTID, "a", neonserv_cmd_a, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + register_command(BOTID, "users", neonserv_cmd_users, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); start_bots(); bind_bot_ready(neonserv_bot_ready); diff --git a/cmd_neonserv_users.c b/cmd_neonserv_users.c index 3011259..a87aca5 100644 --- a/cmd_neonserv_users.c +++ b/cmd_neonserv_users.c @@ -1,8 +1,110 @@ +/* +* argv[0] - usermask +* argv[1] - min access +* argv[2] - max access +*/ +static USERLIST_CALLBACK(neonserv_cmd_users_userlist_lookup); +static void neonserv_cmd_users_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access); + +struct neonserv_cmd_users_cache { + struct ClientSocket *client, *textclient; + struct UserNode *user; + char *usermask; + int min_access; + int max_access; +}; + static CMD_BIND(neonserv_cmd_users) { + int min_access = 1, max_access = 500; + char *usermask = NULL; + if(argc > 0) + usermask = argv[0]; + if(argc > 2) { + min_access = atoi(argv[1]); + max_access = atoi(argv[2]); + } + struct neonserv_cmd_users_cache *cache = malloc(sizeof(*cache)); + if (!cache) { + perror("malloc() failed"); + return; + } + cache->client = client; + cache->textclient = getTextBot(); + cache->user = user; + cache->usermask = (usermask ? strdup(usermask) : NULL); + cache->min_access = min_access; + cache->max_access = max_access; + get_userlist(chan, neonserv_cmd_users_userlist_lookup, cache); +} + +static USERLIST_CALLBACK(neonserv_cmd_users_userlist_lookup) { + struct neonserv_cmd_users_cache *cache = data; + neonserv_cmd_users_async1(cache->client, cache->textclient, cache->user, chan, cache->usermask, cache->min_access, cache->max_access); + if(cache->usermask) + free(cache->usermask); + free(cache); +} + +static void neonserv_cmd_users_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access) { + MYSQL_RES *res; + MYSQL_ROW row; + int content_count = 0, cflags, is_here, caccess, i; + char seenstr[MAXLEN]; + struct Table *table; struct ChanUser *chanuser; - putsock(client, "PRIVMSG %s :[BOT JOIN] Users on this Channel:", chan->name); - for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) { - putsock(client, "PRIVMSG %s : %s!%s@%s [%s] rights: %d", chan->name, chanuser->user->nick, chanuser->user->ident, chanuser->user->host, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "*"), chanuser->flags); + printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_seen`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d'", chan->channel_id); + res = mysql_use(); + table = table_init(4, mysql_num_rows(res) + 1, 0); + if(usermask) + reply(textclient, user, "NS_USERS_HEADER_MATCH", chan->name, min_access, max_access, usermask); + else + reply(textclient, user, "NS_USERS_HEADER", chan->name, min_access, max_access); + char *content[4]; + content[0] = get_language_string(user, "NS_USERS_HEADER_ACCESS"); + content[1] = get_language_string(user, "NS_USERS_HEADER_ACCOUNT"); + content[2] = get_language_string(user, "NS_USERS_HEADER_SEEN"); + content[3] = get_language_string(user, "NS_USERS_HEADER_STATE"); + table_add(table, content); + while ((row = mysql_fetch_row(res)) != NULL) { + caccess = atoi(row[0]); + if((!usermask || match(usermask, row[1])) && caccess >= min_access && caccess <= max_access) { + content[0] = row[0]; + content[1] = row[1]; + is_here = 0; + for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) { + if((chanuser->user->flags & USERFLAG_ISAUTHED) && !strcmp(chanuser->user->auth, row[1])) { + is_here = 1; + break; + } + } + if(is_here) { + content[2] = get_language_string(user, "NS_USERS_SEEN_HERE"); + } else if(!strcmp(row[2], "0")) { + content[2] = get_language_string(user, "NS_USERS_SEEN_NEVER"); + } else { + timeToStr(user, (time(0) - atoi(row[2])), 2, seenstr); + content[2] = seenstr; //generate time + } + cflags = atoi(row[3]); + if(cflags & DB_CHANUSER_SUSPENDED) + content[3] = get_language_string(user, "NS_USERS_STATE_SUSPENDED"); + else + content[3] = get_language_string(user, "NS_USERS_STATE_NORMAL"); + content_count++; + table_add(table, content); + } + } + //send the table + char **table_lines = table_end(table); + for(i = 0; i < table->entrys; i++) { + reply(textclient, user, table_lines[i]); } + if(!content_count) + reply(textclient, user, "NS_TABLE_NONE"); + if(usermask || min_access != 1 || max_access != 500) + reply(textclient, user, (table->length == 2 ? "NS_USERS_COUNT_MATCH_1" : "NS_USERS_COUNT_MATCH"), table->length - 1, chan->name, min_access, max_access, content_count); + else + reply(textclient, user, (table->length == 2 ? "NS_USERS_COUNT_1" : "NS_USERS_COUNT"), table->length - 1, chan->name, min_access, max_access); + table_free(table); } diff --git a/lang.c b/lang.c index f10292d..2c18648 100644 --- a/lang.c +++ b/lang.c @@ -103,3 +103,25 @@ char *get_language_string(struct UserNode *user, const char* msg_ident) { } return NULL; } + +char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...) { + char *formatStr = get_language_string(user, msg_ident); + if(!formatStr) return NULL; + if(buffer == NULL) { + buffer = (char *)malloc((MAXLEN+1) * sizeof(char)); + if (!buffer) { + perror("malloc() failed"); + return NULL; + } + } + int pos; + va_list arg_list; + buffer[0] = '\0'; + va_start(arg_list, msg_ident); + pos = vsnprintf(buffer, MAXLEN - 2, formatStr, arg_list); + va_end(arg_list); + if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2; + buffer[pos] = '\n'; + buffer[pos+1] = '\0'; + return buffer; +} diff --git a/lang.h b/lang.h index b909bd7..f2dd4af 100644 --- a/lang.h +++ b/lang.h @@ -1,6 +1,8 @@ #ifndef _lang_h #define _lang_h +#include "main.h" + struct UserNode; struct default_language_entry { @@ -28,5 +30,6 @@ struct language* get_language_by_name(char *name); struct language* get_default_language(); void register_default_language_table(const struct default_language_entry *msgtab); char *get_language_string(struct UserNode *user, const char* msg_ident); +char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...); #endif \ No newline at end of file diff --git a/main.c b/main.c index 0fd282d..681f691 100644 --- a/main.c +++ b/main.c @@ -11,6 +11,7 @@ #include "mysqlConn.h" #include "HandleInfoHandler.h" #include "lang.h" +#include "tools.h" void cleanup() { free_sockets(); @@ -36,6 +37,7 @@ int main(void) init_bind(); init_modcmd(); init_handleinfohandler(); + init_tools(); init_bots(); time_t socket_wait; diff --git a/modcmd.c b/modcmd.c index 5c07fb4..03e56ac 100644 --- a/modcmd.c +++ b/modcmd.c @@ -299,7 +299,7 @@ int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, un cmdfunc->botid = botid; cmdfunc->name = strdup(name); cmdfunc->func = func; - cmdfunc->flags = 0; + cmdfunc->flags = flags; cmdfunc->paramcount = paramcount; cmdfunc->next = cmd_functions; cmd_functions = cmdfunc; diff --git a/tools.c b/tools.c index 7911e54..cb00985 100644 --- a/tools.c +++ b/tools.c @@ -1,4 +1,22 @@ #include "tools.h" +#include "UserNode.h" +#include "lang.h" + +static const struct default_language_entry msgtab[] = { + {"TIME_MASK_2_ITEMS", "%s and %s"}, + {"TIME_MASK_3_ITEMS", "%s, %s and %s"}, + {"TIME_YEAR", "%d year"}, + {"TIME_YEARS", "%d years"}, + {"TIME_DAY", "%d day"}, + {"TIME_DAYS", "%d days"}, + {"TIME_HOUR", "%d hour"}, + {"TIME_HOURS", "%d hours"}, + {"TIME_MINUTE", "%d minute"}, + {"TIME_MINUTES", "%d minutes"}, + {"TIME_SECOND", "%d second"}, + {"TIME_SECONDS", "%d seconds"}, + {NULL, NULL} +}; /* copied from IRCU 2.10.12 match.c */ /* @@ -77,25 +95,28 @@ struct Table *table_init(int width, int length, int flags) { struct Table *table = malloc(sizeof(*table)); table->contents = malloc(length * sizeof(*table->contents)); for(row = 0; row < length; row++) { - table->contents[row] = calloc(width, sizeof(*table->contents)); + table->contents[row] = calloc(width, sizeof(*table->contents[row])); } table->length = length; table->width = width; table->flags = flags; table->col_flags = calloc(length, sizeof(int)); - table->c_entry = 0; + table->entrys = 0; table->maxwidth = calloc(length, sizeof(int)); - table->table = NULL; + table->table_lines = NULL; + return table; } int table_add(struct Table *table, char **entry) { int col; + if(table->entrys == table->length) return 0; for(col = 0; col < table->width; col++) { - table->contents[table->c_entry][col] = ((table->flags & TABLE_FLAG_USE_POINTER) ? entry[col] : strdup(entry[col])); + table->contents[table->entrys][col] = ((table->flags & TABLE_FLAG_USE_POINTER) ? entry[col] : strdup(entry[col])); if(strlen(entry[col]) > table->maxwidth[col]) table->maxwidth[col] = strlen(entry[col]); } - table->c_entry++; + table->entrys++; + return 1; } int table_set_bold(struct Table *table, int collum, int bold) { @@ -103,44 +124,45 @@ int table_set_bold(struct Table *table, int collum, int bold) { table->col_flags[collum] |= TABLE_FLAG_COL_BOLD; else table->col_flags[collum] &= ~TABLE_FLAG_COL_BOLD; + return 1; } char **table_end(struct Table *table) { - int row, col, tablewidth, pos,i; - if(table->table) return table->table; - table->table = malloc(table->length * sizeof(*table->table)); + int row, col, tablewidth = 0, pos,i; + if(!table->entrys) return NULL; for(col = 0; col < table->width; col++) { tablewidth += table->maxwidth[col]+1; if(table->col_flags[col] & TABLE_FLAG_COL_BOLD) tablewidth += 2; } - for(row = 0; row < table->row; row++) { - table->table[row] = malloc(tablewidth * sizeof(*table->table[row])) + table->table_lines = malloc(table->entrys * sizeof(table->table_lines)); + for(row = 0; row < table->entrys; row++) { + table->table_lines[row] = malloc(tablewidth * sizeof(*table->table_lines[row])); pos = 0; for(col = 0; col < table->width; col++) { if(table->col_flags[col] & TABLE_FLAG_COL_BOLD) - table->table[row][pos++] = '\002'; + table->table_lines[row][pos++] = '\002'; for(i = 0; i < strlen(table->contents[row][col]); i++) { - table->table[row][pos++] = table->contents[row][col][i]; + table->table_lines[row][pos++] = table->contents[row][col][i]; } for(;i < table->maxwidth[col]; i++) { - table->table[row][pos++] = ' '; + table->table_lines[row][pos++] = ' '; } if(table->col_flags[col] & TABLE_FLAG_COL_BOLD) - table->table[row][pos++] = '\002'; + table->table_lines[row][pos++] = '\002'; if(col < table->width-1) - table->table[row][pos++] = ' '; + table->table_lines[row][pos++] = ' '; else - table->table[row][pos++] = '\0'; + table->table_lines[row][pos++] = '\0'; } } - return table->table; + return table->table_lines; } void table_free(struct Table *table) { int row, col; - for(row = 0; row < length; row++) { - if(!(table->flags & TABLE_FLAG_USE_POINTER)) { + for(row = 0; row < table->length; row++) { + if(!(table->flags & TABLE_FLAG_USE_POINTER) && table->entrys > row) { for(col = 0; col < table->width; col++) { free(table->contents[row][col]); } @@ -150,12 +172,62 @@ void table_free(struct Table *table) { free(table->contents); free(table->col_flags); free(table->maxwidth); - if(table->table) { - for(row = 0; row < length; row++) { - free(table->table[row]); + if(table->table_lines) { + for(row = 0; row < table->entrys; row++) { + free(table->table_lines[row]); } - free(table->table); + free(table->table_lines); } free(table); } +int timeToStr(struct UserNode *user, int seconds, int items, char *buf) { + char *item[items]; + int tmp, citem = 0; + if(citem != items && seconds >= 31536000) { //60*60*24*365 = 31536000 + + tmp = seconds / 31536000; + item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_YEAR" : "TIME_YEARS"), tmp); + seconds -= tmp * 31536000; + } + if(citem != items && seconds >= 86400) { //60*60*24 = 86400 + tmp = seconds / 86400; + item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_DAY" : "TIME_DAYS"), tmp); + seconds -= tmp * 86400; + } + if(citem != items && seconds >= 3600) { //60*60 = 86400 + tmp = seconds / 3600; + item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_HOUR" : "TIME_HOURS"), tmp); + seconds -= tmp * 3600; + } + if(citem != items && seconds >= 60) { + tmp = seconds / 60; + item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_MINUTE" : "TIME_MINUTES"), tmp); + seconds -= tmp * 60; + } + if(citem != items && seconds >= 1) { + item[citem++] = build_language_string(user, NULL, (seconds == 1 ? "TIME_SECOND" : "TIME_SECONDS"), seconds); + } + if(items == 2) { + build_language_string(user, buf, "TIME_MASK_2_ITEMS", item[0], item[1]); + } else if(items == 3) { + build_language_string(user, buf, "TIME_MASK_3_ITEMS", item[0], item[1], item[2]); + } else { + int i, ii, p = 0; + for(i = 0; i < items; i++) { + for(ii = 0; ii < strlen(item[i]); ii++) { + buf[p++] = item[i][ii]; + } + buf[p++] = ' '; + } + buf[p-1] = '\0'; + } + return 1; +} + + + + +void init_tools() { + register_default_language_table(msgtab); +} diff --git a/tools.h b/tools.h index 22c1301..f34787d 100644 --- a/tools.h +++ b/tools.h @@ -6,6 +6,8 @@ #define TABLE_FLAG_USE_POINTER 0x01 #define TABLE_FLAG_COL_BOLD 0x02 +struct UserNode; + struct Table { char ***contents; int length; @@ -13,10 +15,10 @@ struct Table { int flags; int *col_flags; - int c_entry; + int entrys; int *maxwidth; - char **table; //we just store this to free it in table_free + char **table_lines; //we just store this to free it in table_free }; int match(const char *mask, const char *name); @@ -27,4 +29,8 @@ int table_set_bold(struct Table *table, int collum, int bold); char **table_end(struct Table *table); void table_free(struct Table *table); +int timeToStr(struct UserNode *user, int seconds, int items, char *buf); + +void init_tools(); + #endif \ No newline at end of file -- 2.20.1