--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+ }
+}