tried to reorder the program structure and build process
[NeonServV5.git] / src / cmd_neonserv_mode.c
1
2 #include "cmd_neonserv.h"
3
4 /*
5 * argv[0] - modes
6 * argv[1-*] - parameters
7 */
8 static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup);
9 static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode);
10
11 struct neonserv_cmd_mode_cache {
12     struct ClientSocket *client, *textclient;
13     struct UserNode *user;
14     struct Event *event;
15     char *mode;
16 };
17
18 CMD_BIND(neonserv_cmd_mode) {
19     struct neonserv_cmd_mode_cache *cache = malloc(sizeof(*cache));
20     if (!cache) {
21         perror("malloc() failed");
22         return;
23     }
24     cache->client = client;
25     cache->textclient = getTextBot();
26     cache->user = user;
27     cache->event = event;
28     cache->mode = strdup(merge_argv(argv, 0, argc));
29     get_userlist_with_invisible(chan, neonserv_cmd_mode_userlist_lookup, cache);
30 }
31
32 static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup) {
33     struct neonserv_cmd_mode_cache *cache = data;
34     neonserv_cmd_mode_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mode);
35     free(cache->mode);
36     free(cache);
37 }
38
39 static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode) {
40     MYSQL_ROW row, defaults = NULL;
41     int i, arg, add = 1, skip = 0;
42     unsigned int modetype;
43     int db_canop, db_canvoice, db_canban, db_enfmodes;
44     struct ModeNode *modelock = createModeNode(NULL), *changemodes = createModeNode(NULL);
45     struct ModeBuffer *modeBuf;
46     struct UserNode *cuser;
47     struct ChanUser *chanuser;
48     modeBuf = initModeBuffer(client, chan);
49     printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
50     row = mysql_fetch_row(mysql_use());
51     if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL) {
52         printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
53         defaults = mysql_fetch_row(mysql_use());
54     }
55     db_canop = atoi((row[0] ? row[0] : defaults[0]));
56     db_canvoice = atoi((row[1] ? row[1] : defaults[1]));
57     db_canban = atoi((row[2] ? row[2] : defaults[2]));
58     db_enfmodes = atoi((row[3] ? row[3] : defaults[3]));
59     if(row[4])
60         parseModeString(modelock, row[4]);
61     else if(defaults[4])
62         parseModeString(modelock, defaults[4]);
63     int uaccess = getChannelAccess(user, chan, 0);
64     char *a, *b = mode;
65     char *argv[MAXNUMPARAMS];
66     char *carg;
67     char tmp[MAXLEN];
68     int argc = 0;
69     do {
70         a = strstr(b, " ");
71         if(a) *a = '\0';
72         argv[argc++] = b;
73         if(argc == MAXNUMPARAMS) break;
74         if(a) b = a+1;
75     } while(a);
76     arg = 0;
77     while(arg < argc) {
78         char *modeStr = argv[arg++];
79         for(i = 0; i < strlen(modeStr); i++) {
80             switch(modeStr[i]) {
81                 case '+':
82                     add = 1;
83                     break;
84                 case '-':
85                     add = 0;
86                     break;
87                 case 'o':
88                 case 'v':
89                     if(arg == argc) {
90                         reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
91                         return;
92                     }
93                     carg = argv[arg++];
94                     if(modeStr[i] == 'o') {
95                         if(uaccess < db_canop) {
96                             reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
97                             db_canop = -1;
98                             break;
99                         }
100                         if(db_canop == -1) break;
101                     } else {
102                         if(uaccess < db_canvoice) {
103                             reply(textclient, user, "NS_MODE_ENFVOICE", chan->name);
104                             db_canvoice = -1;
105                             break;
106                         }
107                         if(db_canvoice == -1) break;
108                     }
109                     cuser = searchUserByNick(carg);
110                     if(!cuser) {
111                         //check for an invisible user
112                         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
113                             if(!stricmp(chanuser->user->nick, carg)) {
114                                 cuser = chanuser->user;
115                                 break;
116                             }
117                         }
118                         if(!cuser) break;
119                     } else {
120                         chanuser = getChanUser(cuser, chan);
121                         if(!chanuser) break;
122                     }
123                     if(!(add ^ (chanuser->flags & (modeStr[i] == 'o' ? CHANUSERFLAG_OPPED : CHANUSERFLAG_VOICED)))) break;
124                     if(!add) {
125                         //check protection
126                         if(modeStr[i] == 'o' && isNetworkService(cuser)) {
127                             reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
128                             break;
129                         }
130                         if(isUserProtected(chan, cuser, user)) {
131                             reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
132                             break;
133                         }
134                     }
135                     modeBufferSet(modeBuf, add, modeStr[i], carg);
136                     break;
137                 case 'b':
138                     if(arg == argc) {
139                         reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
140                         return;
141                     }
142                     carg = argv[arg++];
143                     if(uaccess < db_canban) {
144                         reply(textclient, user, "NS_MODE_CANBAN", chan->name);
145                         db_canban = -1;
146                         break;
147                     }
148                     if(db_canban == -1) break;
149                     char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
150                     char usermask[NICKLEN+USERLEN+HOSTLEN+3];
151                     struct BanNode *ban;
152                     int match_count = 0;
153                     carg = make_banmask(carg, hostmask_buffer);
154                     if(add) {
155                         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
156                             cuser = chanuser->user;
157                             sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
158                             if(!match(carg, usermask)) {
159                                 if(isNetworkService(chanuser->user)) {
160                                     reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
161                                     skip = 1;
162                                     break;
163                                 }
164                                 if(isUserProtected(chan, cuser, user)) {
165                                     reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
166                                     skip = 1;
167                                     break;
168                                 }
169                                 match_count++;
170                                 if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
171                                     skip = 1;
172                                     reply(textclient, user, "NS_LAME_MASK", carg);
173                                     break;
174                                 }
175                             }
176                         }
177                     } else {
178                         skip = 1;
179                         for(ban = chan->bans; ban; ban = ban->next) {
180                             if(!match(carg, ban->mask)) {
181                                 skip = 0;
182                                 break;
183                             }
184                         }
185                     }
186                     if(!skip) {
187                         modeBufferSet(modeBuf, add, 'b', carg);
188                     }
189                     break;
190                 default:
191                     modetype = getModeType(modelock, modeStr[i]);
192                     if(modetype == 0) {
193                         reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
194                         return;
195                     }
196                     if(isModeAffected(modelock, modeStr[i]) && add == !isModeSet(modelock, modeStr[i]) && uaccess < db_enfmodes) {
197                         if(isGodMode(user))
198                             event->flags |= CMDFLAG_OPLOG;
199                         else {
200                             getFullModeString(modelock, tmp);
201                             reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
202                             return;
203                         }
204                     }
205                     if(add && (modetype & CHANNEL_MODE_TYPE) != CHANNEL_MODE_TYPE_D) {
206                         if(arg == argc) {
207                             reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
208                             return;
209                         }
210                         carg = argv[arg++];
211                         if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
212                             char *modelock_val = getModeValue(modelock, modeStr[i]);
213                             if(stricmp(carg, modelock_val)) {
214                                 if(isGodMode(user))
215                                     event->flags |= CMDFLAG_OPLOG;
216                                 else {
217                                     getFullModeString(modelock, tmp);
218                                     reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
219                                     return;
220                                 }
221                             }
222                         }
223                         if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
224                             int *modelock_val = getModeValue(modelock, modeStr[i]);
225                             if(atoi(carg) != *modelock_val) {
226                                 if(isGodMode(user))
227                                     event->flags |= CMDFLAG_OPLOG;
228                                 else {
229                                     getFullModeString(modelock, tmp);
230                                     reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
231                                     return;
232                                 }
233                             }
234                         }
235                     } else
236                         carg = NULL;
237                     if((modetype & CHANNEL_MODE_TYPE) == CHANNEL_MODE_TYPE_D && isModeSet(chan->modes, modeStr[i]) == add)
238                         break;
239                     if(!isModeAffected(changemodes, modeStr[i])) {
240                         if(!add && (modetype & CHANNEL_MODE_KEY)) {
241                             if(isModeSet(chan->modes, modeStr[i])) {
242                                 char *current_val = getModeValue(chan->modes, modeStr[i]);
243                                 carg = current_val;
244                             }
245                         }
246                         if(parseMode(changemodes, add, modeStr[i], carg)) {
247                             if(carg) {
248                                 if(add && (modetype & CHANNEL_MODE_KEY) && isModeSet(chan->modes, modeStr[i])) {
249                                     char *current_val = getModeValue(chan->modes, modeStr[i]);
250                                     modeBufferSet(modeBuf, 0, modeStr[i], current_val);
251                                     flushModeBuffer(modeBuf);
252                                 }
253                                 if(!add && !isModeSet(chan->modes, modeStr[i])) break;
254                                 modeBufferSet(modeBuf, add, modeStr[i], carg);
255                             } else {
256                                 modeBufferSimpleMode(modeBuf, add, modeStr[i]);
257                             }
258                         } else {
259                             reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
260                             return;
261                         }
262                     }
263                     break;
264             }
265         }
266     }
267     getFullModeString(changemodes, tmp);
268     freeModeBuffer(modeBuf);
269     if(strcmp(tmp, "+"))
270         reply(textclient, user, "NS_MODE_DONE", tmp);
271     
272     logEvent(event);
273     freeModeNode(modelock);
274     freeModeNode(changemodes);
275 }