changed Makefile; build all commands as an own file
[NeonServV5.git] / cmd_neonserv_set.c
1
2 #include "cmd_neonserv.h"
3
4 typedef char* neonserv_cmd_set_function(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
5 static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *argument);
6 static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
7 static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
8 static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
9 static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
10
11 #define NS_VALID_FUNCTION 0x01
12 #define NS_VALID_STRING   0x02
13 #define NS_VALID_ACCESS   0x04
14 #define NS_VALID_NO501    0x08
15 #define NS_VALID_OPTIONS  0x10
16 #define NS_VALID_NUMERIC  0x20
17 #define NS_VALID_BOOLEAN  0x40
18
19 #define NS_HAS_OPT  0x100 /* options (SET_OPTION_{NAME}_{VALUE}) */
20 #define NS_HAS_HELP 0x200 /* help    (SET_HELP_{NAME}) - only shown if help is requested */
21
22 static const struct {
23     const char *setting;
24     const char *chanfield;
25     unsigned int valid;
26     void *parameter;
27 } channel_settings[] = {
28     {"TRIGGER",         NULL,                   NS_VALID_FUNCTION,                  neonserv_cmd_set_trigger},
29     {"DEFAULTTOPIC",    "channel_defaulttopic", NS_VALID_STRING,                    NULL},
30     {"TOPICMASK",       "channel_topicmask",    NS_VALID_STRING,                    NULL},
31     {"ADVANCEDTOPIC",   "channel_exttopic",     NS_VALID_BOOLEAN | NS_HAS_OPT,      NULL},
32     {"GREETING",        "channel_greeting",     NS_VALID_STRING,                    NULL},
33     {"USERGREETING",    "channel_usergreeting", NS_VALID_STRING,                    NULL},
34     {"USERINFO",        "channel_userinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
35     {"WIPEINFO",        "channel_wipeinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
36     {"MODES",           "channel_modes",        NS_VALID_FUNCTION,                  neonserv_cmd_set_modes},
37     {"INVITEME",        "channel_getinvite",    NS_VALID_ACCESS,                    NULL},
38     {"GIVEOPS",         "channel_getop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
39     {"GIVEVOICE",       "channel_getvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
40     {"ENFOPS",          "channel_canop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
41     {"ENFVOICE",        "channel_canvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
42     {"KICK",            "channel_cankick",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
43     {"BAN",             "channel_canban",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
44     {"STATICBAN",       "channel_staticban",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
45     {"PUBCMD",          "channel_pubcmd",       NS_VALID_ACCESS,                    NULL},
46     {"ENFMODES",        "channel_enfmodes",     NS_VALID_ACCESS,                    NULL},
47     {"ENFTOPIC",        "channel_enftopic",     NS_VALID_ACCESS,                    NULL},
48     {"TOPICSNARF",      "channel_topicsnarf",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
49     {"CHANGETOPIC",     "channel_changetopic",  NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
50     {"SETTERS",         "channel_setters",      NS_VALID_ACCESS | NS_VALID_NO501 | NS_HAS_HELP, NULL},
51     {"ADDUSER",         "channel_canadd",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
52     {"DELUSER",         "channel_candel",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
53     {"CLVL",            "channel_canclvl",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
54     {"RESYNC",          "channel_canresync",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
55     {"SUSPEND",         "channel_cansuspend",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
56     {"NOTICEUSERS",     "channel_notice",       NS_VALID_ACCESS,                    NULL},
57     {"NOTICEREACTION",  "channel_noticereaction", NS_VALID_OPTIONS | NS_HAS_OPT,    "4"},
58     {"CTCPUSERS",       "channel_ctcp",         NS_VALID_ACCESS,                    NULL},
59     {"CTCPREACTION",    "channel_ctcpreaction", NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
60     {"PROTECT",         "channel_protect",      NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
61     {"TOYS",            "channel_toys",         NS_VALID_OPTIONS | NS_HAS_OPT,      "3"},
62     {"DYNLIMIT",        "channel_dynlimit",     NS_VALID_NUMERIC | NS_VALID_FUNCTION | NS_HAS_OPT, neonserv_cmd_set_dynlimit},
63     {"NODELETE",        "channel_nodelete",     NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_nodelete},
64     {NULL, NULL, 0, NULL}
65 };
66
67 #define MAX_QUERY_LEN 1024
68 CMD_BIND(neonserv_cmd_set) {
69     int i, j;
70     if(argc && !strcmp(argv[0], "defaults")) {
71         //reset channel settings
72         int uaccess = getChannelAccess(user, chan, 0);
73         if(uaccess < 500) {
74             if(isGodMode(user)) {
75                 event->flags |= CMDFLAG_OPLOG;
76             } else {
77                 reply(getTextBot(), user, "NS_SET_DEFAULTS_OWNER", chan->name);
78                 return;
79             }
80         }
81         int seed = 0;
82         char *tmp;
83         static char defaultskey[16];
84         for(tmp = user->auth; *tmp; tmp++)
85             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
86         for(tmp = chan->name; *tmp; tmp++)
87             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
88         sprintf(defaultskey, "%08x", seed);
89         if(argc > 1 && !strcmp(argv[1], defaultskey)) {
90             char query[MAX_QUERY_LEN];
91             int querypos = 0;
92             i = 0;
93             while(channel_settings[i].setting) {
94                 if(channel_settings[i].chanfield)
95                     querypos += sprintf(query + querypos, "`%s` = NULL, ", channel_settings[i].chanfield);
96                 i++;
97             }
98             if(querypos) {
99                 query[querypos-2] = '\0';
100             }
101             printf_mysql_query("UPDATE `channels` SET %s WHERE `channel_id` = '%d'", query, chan->channel_id);
102             reply(getTextBot(), user, "NS_SET_DEFAULTS_DONE", chan->name);
103             logEvent(event);
104         } else {
105             reply(getTextBot(), user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
106         }
107     } else if(argc && strcmp(argv[0], "help")) {
108         //find the correct command
109         i = 0;
110         j = 0;
111         char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
112         while(channel_settings[i].setting) {
113             if(!stricmp(channel_settings[i].setting, argv[0])) {
114                 //setting found
115                 if(channel_settings[i].valid & NS_VALID_FUNCTION) {
116                     neonserv_cmd_set_function *func = channel_settings[i].parameter;
117                     func(client, user, chan, event, channel_settings[i].setting, args);
118                 } else {
119                     neonserv_cmd_set_setting(client, user, chan, event, i, args);
120                 }
121                 j = 1;
122                 break;
123             }
124             i++;
125         }
126         if(j == 0) {
127             //unknown setting
128             reply(getTextBot(), user, "NS_SET_UNKNOWN_SETTING", argv[0]);
129         }
130     } else {
131         char query[MAX_QUERY_LEN], *value, *org_value, *tmp, nameBuf[64];
132         int querypos = 0;
133         MYSQL_RES *res, *defaults_res;
134         MYSQL_ROW row, defaults;
135         struct Table *table;
136         char *content[2];
137         i = 0;
138         while(channel_settings[i].setting) {
139             if(channel_settings[i].chanfield)
140                 querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield);
141             i++;
142         }
143         table = table_init(2, i, 0);
144         table_set_bold(table, 0, 1);
145         printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
146         defaults_res = mysql_use();
147         defaults = mysql_fetch_row(defaults_res);
148         printf_mysql_query("SELECT `channel_name` %s FROM `channels` WHERE `channel_id` = '%d'", query, chan->channel_id);
149         res = mysql_use();
150         row = mysql_fetch_row(res);
151         i = 0;
152         j = 0;
153         reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
154         while(channel_settings[i].setting) {
155             if(channel_settings[i].chanfield) {
156                 j++;
157                 org_value = (row[j] ? row[j] : defaults[j]);
158             } else if(channel_settings[i].valid & NS_VALID_FUNCTION) {
159                 neonserv_cmd_set_function *func = channel_settings[i].parameter;
160                 org_value = func(client, user, chan, event, NULL, NULL);
161             } else
162                 org_value = "0";
163             value = org_value;
164             if(channel_settings[i].valid & NS_VALID_BOOLEAN) {
165                 if(!strcmp(value, "0"))
166                     value = get_language_string(user, "NS_SET_OFF");
167                 else
168                     value = get_language_string(user, "NS_SET_ON");
169             }
170             strcpy(query, value);
171             querypos = strlen(query);
172             if(channel_settings[i].valid & NS_HAS_OPT) {
173                 sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[i].setting, org_value);
174                 tmp = get_language_string(user, nameBuf);
175                 if(tmp) {
176                     querypos += sprintf(query+querypos, " - %s", tmp);
177                 }
178             }
179             if(argc && channel_settings[i].valid & NS_HAS_HELP) {
180                 sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[i].setting);
181                 tmp = get_language_string(user, nameBuf);
182                 if(tmp) {
183                     querypos += sprintf(query+querypos, " - %s", tmp);
184                 }
185             }
186             content[0] = (char*)channel_settings[i].setting;
187             content[1] = query;
188             table_add(table, content);
189             i++;
190         }
191         char **table_lines = table_end(table);
192         for(i = 0; i < table->entrys; i++) {
193             reply(getTextBot(), user, table_lines[i]);
194         }
195         table_free(table);
196     }
197 }
198
199 static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *args) {
200     char *value;
201     char nameBuf[64];
202     //get current value
203     MYSQL_RES *res;
204     MYSQL_ROW row;
205     printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, chan->channel_id);
206     res = mysql_use();
207     row = mysql_fetch_row(res);
208     if(row[0] == NULL) {
209         printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_settings[setting].chanfield);
210         res = mysql_use();
211         row = mysql_fetch_row(res);
212     }
213     value = row[0];
214     if(args) {
215         //change the channel setting
216         //check the new argument
217         int valid = channel_settings[setting].valid;
218         if(valid & NS_VALID_STRING) {
219             if(!strcmp(args, "*")) {
220                 args = "";
221             }
222         }
223         if(valid & NS_VALID_ACCESS) {
224             int caccess = atoi(args);
225             int max = ((valid & NS_VALID_NO501) ? 500 : 501);
226             if(caccess < 0 || caccess > max) {
227                 reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
228                 return;
229             }
230             int uaccess = getChannelAccess(user, chan, 0);
231             if(uaccess == 500) uaccess++;
232             if(atoi(value) > uaccess) {
233                 if(isGodMode(user)) {
234                     event->flags |= CMDFLAG_OPLOG;
235                 } else {
236                     reply(getTextBot(), user, "NS_SET_CANNOT_SET");
237                     return;
238                 }
239             }
240             if(caccess > uaccess) {
241                 if(isGodMode(user)) {
242                     event->flags |= CMDFLAG_OPLOG;
243                 } else {
244                     reply(getTextBot(), user, "NS_SET_BADLEVEL");
245                     return;
246                 }
247             }
248             sprintf(nameBuf, "%d", caccess);
249             args = nameBuf;
250         }
251         if(valid & NS_VALID_OPTIONS) {
252             int options = atoi((char *) channel_settings[setting].parameter);
253             int coption = atoi(args);
254             if(coption < 0 || coption >= options) {
255                 reply(getTextBot(), user, "NS_SET_INVALID_OPTION", coption);
256                 int i;
257                 int nameBufPos = 0;
258                 if(valid & NS_HAS_OPT) {
259                     for(i = 0; i < options; i++) {
260                         sprintf(nameBuf, "NS_SET_OPTION_%s_%d", channel_settings[setting].setting, i);
261                         reply(getTextBot(), user, "\002%d\002 - %s", i, get_language_string(user, nameBuf));
262                     }
263                 } else {
264                     for(i = 0; i < options; i++) {
265                         nameBufPos += sprintf(nameBuf + nameBufPos, "\002%d\002, ", i);
266                     }
267                     if(nameBufPos) {
268                         nameBuf[nameBufPos-2] = '\0';
269                         reply(getTextBot(), user, nameBuf);
270                     }
271                 }
272                 return;
273             }
274         }
275         if(valid & NS_VALID_NUMERIC) {
276             sprintf(nameBuf, "%d", atoi(args));
277             args = nameBuf;
278         }
279         if(valid & NS_VALID_BOOLEAN) {
280             if(!strcmp(args, "0") || !stricmp(args, "off") || !stricmp(args, get_language_string(user, "NS_SET_OFF"))) {
281                 args = "0";
282             } else if(!strcmp(args, "1") || !stricmp(args, "on") || !stricmp(args, get_language_string(user, "NS_SET_ON"))) {
283                 args = "1";
284             } else {
285                 reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", args);
286                 return;
287             }
288         }
289         //valid - set it
290         value = args;
291         printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, escape_string(value), chan->channel_id);
292         logEvent(event);
293     }
294     reply(getTextBot(), user, "\002%s\002 %s", channel_settings[setting].setting, value);
295     if(channel_settings[setting].valid & NS_HAS_HELP) {
296          sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[setting].setting);
297          reply(getTextBot(), user, "  %s", get_language_string(user, nameBuf));
298     }
299 }
300
301 static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
302     char *trigger;
303     //get current trigger
304     MYSQL_RES *res;
305     MYSQL_ROW row;
306     printf_mysql_query("SELECT `trigger` FROM `bot_channels` WHERE `chanid` = '%d' AND `botid` = '%d'", chan->channel_id, client->clientid);
307     res = mysql_use();
308     row = mysql_fetch_row(res);
309     trigger = row[0];
310     if(argument) {
311         int uaccess = getChannelAccess(user, chan, 0);
312         if(uaccess < 500) {
313             if(isGodMode(user)) {
314                 event->flags |= CMDFLAG_OPLOG;
315             } else {
316                 reply(getTextBot(), user, "NS_SET_TRIGGER_OWNER", chan->name);
317                 return NULL;
318             }
319         }
320         if(strlen(argument) > 15)
321             argument[15] = '\0';
322         printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
323         trigger = argument;
324         changeChannelTrigger(client->botid, chan, trigger);
325         logEvent(event);
326     }
327     if(setting) {
328         reply(getTextBot(), user, "\002%s\002 %s", setting, trigger);
329     }
330     return trigger;
331 }
332
333 static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
334     char *value;
335     //get current value
336     MYSQL_RES *res;
337     MYSQL_ROW row;
338     printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
339     res = mysql_use();
340     row = mysql_fetch_row(res);
341     if(row[0] == NULL) {
342         printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
343         res = mysql_use();
344         row = mysql_fetch_row(res);
345     }
346     value = row[0];
347     if(argument) {
348         //change the channel setting
349         //TODO: parse, check and set modelock
350     }
351     if(setting) {
352         reply(getTextBot(), user, "\002%s\002 %s", setting, value);
353     }
354     return value;
355 }
356
357 static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
358     char *value;
359     char tmp[64];
360     //get current value
361     MYSQL_RES *res;
362     MYSQL_ROW row;
363     printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
364     res = mysql_use();
365     row = mysql_fetch_row(res);
366     if(row[0] == NULL) {
367         printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_name` = 'defaults'");
368         res = mysql_use();
369         row = mysql_fetch_row(res);
370     }
371     value = row[0];
372     if(argument) {
373         //change the channel setting
374         sprintf(tmp, "%d", atoi(argument));
375         argument = tmp;
376         printf_mysql_query("UPDATE `channels` SET `channel_dynlimit` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
377         if(strcmp(argument, "0"))
378             putsock(client, "MODE %s +l %d", chan->name, (chan->usercount + atoi(argument)));
379         else if(isModeSet(chan->modes, 'l'))
380             putsock(client, "MODE %s -l", chan->name);
381         value = argument;
382         logEvent(event);
383     }
384     if(setting) {
385         reply(getTextBot(), user, "\002%s\002 %s", setting, value);
386     }
387     return value;
388 }
389
390 static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
391     char *value;
392     //get current value
393     MYSQL_RES *res;
394     MYSQL_ROW row;
395     printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
396     res = mysql_use();
397     row = mysql_fetch_row(res);
398     if(row[0] == NULL) {
399         printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_name` = 'defaults'");
400         res = mysql_use();
401         row = mysql_fetch_row(res);
402     }
403     value = row[0];
404     if(argument && isGodMode(user)) {
405         //change the channel setting
406         if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
407             argument = "0";
408         } else if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
409             argument = "1";
410         } else {
411             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
412             return NULL;
413         }
414         printf_mysql_query("UPDATE `channels` SET `channel_nodelete` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
415         event->flags |= CMDFLAG_OPLOG;
416         value = argument;
417         logEvent(event);
418     }
419     if(setting) {
420         reply(getTextBot(), user, "\002%s\002 %s", setting, value);
421     }
422     return value;
423 }
424
425 #undef MAX_QUERY_LEN