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