added full half-op support
[NeonServV5.git] / src / cmd_neonserv_resync.c
1 /* cmd_neonserv_resync.c - NeonServ v5.3
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "cmd_neonserv.h"
19
20 /*
21 * argv[0] - (optional) usermask
22 * argv[1] - (optional) min access
23 * argv[2] - (optional) max access
24 * argv[1/3] - (optional) FORCE (override NoAutoOp)
25 */
26 static USERLIST_CALLBACK(neonserv_cmd_resync_userlist_lookup);
27 static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access, char override_noautoop);
28
29 struct neonserv_cmd_resync_cache {
30     struct ClientSocket *client, *textclient;
31     struct UserNode *user;
32     char *usermask;
33     int min_access;
34     int max_access;
35     char override_noautoop;
36 };
37
38 CMD_BIND(neonserv_cmd_resync) {
39     int min_access = 0, max_access = 500;
40     char *usermask = NULL;
41     char override_noautoop = 0;
42     if(argc > 0) {
43         usermask = argv[0];
44         if(argc > 2) {
45             min_access = atoi(argv[1]);
46             max_access = atoi(argv[2]);
47             if(argc > 3)
48                 override_noautoop = (!stricmp(argv[3], "FORCE") ? 1 : 0);
49         } else if(argc > 1)
50             override_noautoop = (!stricmp(argv[1], "FORCE") ? 1 : 0);
51     }
52     struct neonserv_cmd_resync_cache *cache = malloc(sizeof(*cache));
53     if (!cache) {
54         perror("malloc() failed");
55         return;
56     }
57     cache->client = client;
58     cache->textclient = getTextBot();
59     cache->user = user;
60     cache->usermask = (usermask ? strdup(usermask) : NULL);
61     cache->min_access = min_access;
62     cache->max_access = max_access;
63     cache->override_noautoop = override_noautoop;
64     get_userlist_with_invisible(chan, neonserv_cmd_resync_userlist_lookup, cache);
65 }
66
67 static USERLIST_CALLBACK(neonserv_cmd_resync_userlist_lookup) {
68     struct neonserv_cmd_resync_cache *cache = data;
69     neonserv_cmd_resync_async1(cache->client, cache->textclient, cache->user, chan, cache->usermask, cache->min_access, cache->max_access, cache->override_noautoop);
70     if(cache->usermask)
71         free(cache->usermask);
72     free(cache);
73 }
74
75 static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access, char override_noautoop) {
76     MYSQL_RES *res;
77     MYSQL_ROW row, defaults = NULL;
78     int i;
79     int resync_op = 1;
80     int with_halfop = get_int_field("General.have_halfop");
81     int resync_halfop = with_halfop;
82     int resync_voice = 1;
83     if(usermask && usermask[0] == '@') {
84         resync_voice = 0;
85         resync_halfop = 0;
86         usermask++;
87         if(!*usermask) usermask = NULL;
88     } else if(usermask && with_halfop && usermask[0] == 'h') {
89         resync_op = 0;
90         resync_voice = 0;
91         usermask++;
92         if(!*usermask) usermask = NULL;
93     } else if(usermask && usermask[0] == '+') {
94         resync_op = 0;
95         resync_halfop = 0;
96         usermask++;
97         if(!*usermask) usermask = NULL;
98     }
99     struct ChanUser *chanuser;
100     int db_enfops, db_enfhalfop, db_enfvoice;
101     printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_gethalfop` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
102     row = mysql_fetch_row(mysql_use());
103     if(row[0] == NULL || row[1] == NULL) {
104         printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_gethalfop` FROM `channels` WHERE `channel_name` = 'defaults'");
105         defaults = mysql_fetch_row(mysql_use());
106     }
107     db_enfops = atoi((row[0] ? row[0] : defaults[0]));
108     db_enfvoice = atoi((row[1] ? row[1] : defaults[1]));
109     db_enfhalfop = (with_halfop ? atoi((row[2] ? row[2] : defaults[2])) : 0);
110     printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' ORDER BY `chanuser_access` DESC, `user_user` ASC", chan->channel_id);
111     res = mysql_use();
112     char *db_users[mysql_num_rows(res)];
113     int db_access[mysql_num_rows(res)];
114     int db_flags[mysql_num_rows(res)];
115     int db_count = 0;
116     while ((row = mysql_fetch_row(res)) != NULL) {
117         db_users[db_count] = row[1];
118         db_access[db_count] = atoi(row[0]);
119         db_flags[db_count] = atoi(row[2]);
120         db_count++;
121     }
122     int caccess, cflags;
123     struct ModeBuffer *modeBuf;
124     modeBuf = initModeBuffer(client, chan);
125     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
126         caccess = 0;
127         cflags = 0;
128         if((chanuser->user->flags & USERFLAG_ISAUTHED)) {
129             for(i = 0; i < db_count; i++) {
130                 if(!stricmp(db_users[i], chanuser->user->auth)) {
131                     caccess = db_access[i];
132                     cflags = db_flags[i];
133                     if(cflags & DB_CHANUSER_SUSPENDED)
134                         caccess = 0;
135                     break;
136                 }
137             }
138         }
139         if((usermask && *usermask && match(usermask, chanuser->user->nick)) || caccess < min_access || caccess > max_access) continue;
140         if(caccess >= db_enfops) {
141             if(!(chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
142                 modeBufferOp(modeBuf, chanuser->user->nick);
143         } else if(with_halfop && caccess >= db_enfhalfop) {
144             if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
145                 modeBufferDeop(modeBuf, chanuser->user->nick);
146             if(!(chanuser->flags & CHANUSERFLAG_HALFOPPED) && resync_halfop && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
147                 modeBufferHalfop(modeBuf, chanuser->user->nick);
148         } else if(caccess >= db_enfvoice) {
149             if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
150                 modeBufferDeop(modeBuf, chanuser->user->nick);
151             if((chanuser->flags & CHANUSERFLAG_HALFOPPED) && resync_halfop && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
152                 modeBufferDehalfop(modeBuf, chanuser->user->nick);
153             if(!(chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
154                 modeBufferVoice(modeBuf, chanuser->user->nick);
155         } else {
156             if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
157                 modeBufferDeop(modeBuf, chanuser->user->nick);
158             if((chanuser->flags & CHANUSERFLAG_HALFOPPED) && resync_halfop && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
159                 modeBufferDehalfop(modeBuf, chanuser->user->nick);
160             if((chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
161                 modeBufferDevoice(modeBuf, chanuser->user->nick);
162         }
163         
164     }
165     freeModeBuffer(modeBuf);
166     reply(textclient, user, "NS_RESYNC_DONE", chan->name);
167 }