added +-ov to cmd_mode
[NeonServV5.git] / cmd_neonserv_mode.c
1
2 /*
3 * argv[0] - modes
4 * argv[1-*] - parameters
5 */
6 static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup);
7 static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode);
8
9 struct neonserv_cmd_mode_cache {
10     struct ClientSocket *client, *textclient;
11     struct UserNode *user;
12     struct Event *event;
13     char *mode;
14 };
15
16 static CMD_BIND(neonserv_cmd_mode) {
17     struct neonserv_cmd_mode_cache *cache = malloc(sizeof(*cache));
18     if (!cache) {
19         perror("malloc() failed");
20         return;
21     }
22     cache->client = client;
23     cache->textclient = getTextBot();
24     cache->user = user;
25     cache->event = event;
26     cache->mode = strdup(merge_argv(argv, 0, argc));
27     get_userlist_with_invisible(chan, neonserv_cmd_mode_userlist_lookup, cache);
28 }
29
30 static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup) {
31     struct neonserv_cmd_mode_cache *cache = data;
32     neonserv_cmd_mode_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mode);
33     free(cache->mode);
34     free(cache);
35 }
36
37 static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode) {
38     MYSQL_ROW row, defaults = NULL;
39     int i, arg, add = 1;
40     unsigned int modetype;
41     int db_canop, db_canvoice, db_canban, db_enfmodes;
42     struct ModeNode *modelock = createModeNode(NULL), *changemodes = createModeNode(NULL);
43     struct ModeBuffer *modeBuf;
44     modeBuf = initModeBuffer(client, chan);
45     printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
46     row = mysql_fetch_row(mysql_use());
47     if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL) {
48         printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
49         defaults = mysql_fetch_row(mysql_use());
50     }
51     db_canop = atoi((row[0] ? row[0] : defaults[0]));
52     db_canvoice = atoi((row[1] ? row[1] : defaults[1]));
53     db_canban = atoi((row[2] ? row[2] : defaults[2]));
54     db_enfmodes = atoi((row[3] ? row[3] : defaults[3]));
55     if(row[4])
56         parseModeString(modelock, row[4]);
57     else if(defaults[4])
58         parseModeString(modelock, defaults[4]);
59     int uaccess = getChannelAccess(user, chan, 0);
60     char *a, *b = mode;
61     char *argv[MAXNUMPARAMS];
62     char *carg;
63     char tmp[MAXLEN];
64     int argc = 0;
65     do {
66         a = strstr(b, " ");
67         if(a) *a = '\0';
68         argv[argc++] = b;
69         if(argc == MAXNUMPARAMS) break;
70         if(a) b = a+1;
71     } while(a);
72     arg = 0;
73     while(arg < argc) {
74         char *modeStr = argv[arg++];
75         for(i = 0; i < strlen(modeStr); i++) {
76             switch(modeStr[i]) {
77                 case '+':
78                     add = 1;
79                     break;
80                 case '-':
81                     add = 0;
82                     break;
83                 case 'o':
84                 case 'v':
85                     if(arg == argc) {
86                         reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
87                         return;
88                     }
89                     carg = argv[arg++];
90                     if(uaccess < (modeStr[i] == 'o' ? db_canop : db_canvoice)) {
91                         reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
92                         if(modeStr[i] == 'o') db_canop = -1;
93                         else db_canvoice = -1;
94                         break;
95                     }
96                     if((modeStr[i] == 'o' ? db_canop : db_canvoice) == -1) break;
97                     struct UserNode *cuser;
98                     struct ChanUser *chanuser;
99                     cuser = searchUserByNick(carg);
100                     if(!cuser) {
101                         //check for an invisible user
102                         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
103                             if(!stricmp(chanuser->user->nick, carg)) {
104                                 cuser = chanuser->user;
105                                 break;
106                             }
107                         }
108                         if(!cuser) break;
109                     } else {
110                         chanuser = getChanUser(cuser, chan);
111                         if(!chanuser) break;
112                     }
113                     if(!(add ^ (chanuser->flags & (modeStr[i] == 'o' ? CHANUSERFLAG_OPPED : CHANUSERFLAG_VOICED)))) break;
114                     if(!add) {
115                         //check protection
116                         if(modeStr[i] == 'o' && isNetworkService(cuser)) {
117                             reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
118                             break;
119                         }
120                         if(isUserProtected(chan, cuser, user)) {
121                             reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
122                             break;
123                         }
124                     }
125                     modeBufferSet(modeBuf, add, modeStr[i], carg);
126                     break;
127                 case 'b':
128                     
129                     break;
130                 default:
131                     modetype = getModeType(modelock, modeStr[i]);
132                     if(modetype == 0) {
133                         reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
134                         return;
135                     }
136                     if(isModeAffected(modelock, modeStr[i]) && add == !isModeSet(modelock, modeStr[i]) && uaccess < db_enfmodes) {
137                         if(isGodMode(user))
138                             event->flags |= CMDFLAG_OPLOG;
139                         else {
140                             getFullModeString(modelock, tmp);
141                             reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
142                             return;
143                         }
144                     }
145                     if(add && (modetype & CHANNEL_MODE_TYPE) != CHANNEL_MODE_TYPE_D) {
146                         if(arg == argc) {
147                             reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
148                             return;
149                         }
150                         carg = argv[arg++];
151                         if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
152                             char *modelock_val = getModeValue(modelock, modeStr[i]);
153                             if(stricmp(carg, modelock_val)) {
154                                 if(isGodMode(user))
155                                     event->flags |= CMDFLAG_OPLOG;
156                                 else {
157                                     getFullModeString(modelock, tmp);
158                                     reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
159                                     return;
160                                 }
161                             }
162                         }
163                         if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
164                             int *modelock_val = getModeValue(modelock, modeStr[i]);
165                             if(atoi(carg) != *modelock_val) {
166                                 if(isGodMode(user))
167                                     event->flags |= CMDFLAG_OPLOG;
168                                 else {
169                                     getFullModeString(modelock, tmp);
170                                     reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
171                                     return;
172                                 }
173                             }
174                         }
175                     } else
176                         carg = NULL;
177                     if((modetype & CHANNEL_MODE_TYPE) == CHANNEL_MODE_TYPE_D && isModeSet(chan->modes, modeStr[i]) == add)
178                         break;
179                     if(!isModeAffected(changemodes, modeStr[i])) {
180                         if(!add && (modetype & CHANNEL_MODE_KEY)) {
181                             if(isModeSet(chan->modes, modeStr[i])) {
182                                 char *current_val = getModeValue(chan->modes, modeStr[i]);
183                                 carg = current_val;
184                             }
185                         }
186                         if(parseMode(changemodes, add, modeStr[i], carg)) {
187                             if(carg) {
188                                 if(add && (modetype & CHANNEL_MODE_KEY) && isModeSet(chan->modes, modeStr[i])) {
189                                     char *current_val = getModeValue(chan->modes, modeStr[i]);
190                                     modeBufferSet(modeBuf, 0, modeStr[i], current_val);
191                                     flushModeBuffer(modeBuf);
192                                 }
193                                 if(!add && !isModeSet(chan->modes, modeStr[i])) break;
194                                 modeBufferSet(modeBuf, add, modeStr[i], carg);
195                             } else {
196                                 modeBufferSimpleMode(modeBuf, add, modeStr[i]);
197                             }
198                         } else {
199                             reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
200                             return;
201                         }
202                     }
203                     break;
204             }
205         }
206     }
207     getFullModeString(changemodes, tmp);
208     freeModeBuffer(modeBuf);
209     if(strcmp(tmp, "+"))
210         reply(textclient, user, "NS_MODE_DONE", tmp);
211     
212     logEvent(event);
213     freeModeNode(modelock);
214     freeModeNode(changemodes);
215 }