Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-common / core / fe-settings.c
1 /*
2  fe-settings.c : irssi
3
4     Copyright (C) 1999 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "signals.h"
24 #include "commands.h"
25 #include "servers.h"
26 #include "misc.h"
27 #include "lib-config/iconfig.h"
28 #include "settings.h"
29
30 #include "levels.h"
31 #include "printtext.h"
32 #include "keyboard.h"
33
34 static void set_print(SETTINGS_REC *rec)
35 {
36         char *value;
37
38         value = settings_get_print(rec);
39         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_SET_ITEM,
40                     rec->key, value);
41         g_free(value);
42 }
43
44 static void set_print_pattern(const char *pattern)
45 {
46         GSList *sets, *tmp;
47         const char *last_section;
48
49         last_section = "";
50         sets = settings_get_sorted();
51         for (tmp = sets; tmp != NULL; tmp = tmp->next) {
52                 SETTINGS_REC *rec = tmp->data;
53
54                 if (stristr(rec->key, pattern) == NULL)
55                         continue;
56                 if (strcmp(last_section, rec->section) != 0) {
57                         /* print section */
58                         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
59                                     TXT_SET_TITLE, rec->section);
60                         last_section = rec->section;
61                 }
62                 set_print(rec);
63         }
64         g_slist_free(sets);
65 }
66
67 static void set_boolean(const char *key, const char *value)
68 {
69         char *stripped_value;
70         stripped_value = g_strdup(value);
71         g_strstrip(stripped_value);
72
73         if (g_ascii_strcasecmp(stripped_value, "ON") == 0)
74                 settings_set_bool(key, TRUE);
75         else if (g_ascii_strcasecmp(stripped_value, "OFF") == 0)
76                 settings_set_bool(key, FALSE);
77         else if (g_ascii_strcasecmp(stripped_value, "TOGGLE") == 0)
78                 settings_set_bool(key, !settings_get_bool(key));
79         else
80                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE);
81
82     g_free(stripped_value);
83 }
84
85 static void set_int(const char *key, const char *value)
86 {
87         char *endp;
88         long longval;
89         int error;
90
91         errno = 0;
92         longval = strtol(value, &endp, 10);
93         error = errno;
94         while (i_isspace(*endp))
95                 endp++;
96         if (error != 0 || *endp != '\0' || longval < INT_MIN || longval > INT_MAX)
97                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_INVALID_NUMBER);
98         else
99                 settings_set_int(key, (int)longval);
100 }
101
102 /* SYNTAX: SET [-clear | -default] [<key> [<value>]] */
103 static void cmd_set(char *data)
104 {
105         GHashTable *optlist;
106         char *key, *value;
107         void *free_arg;
108         int clear, set_default;
109         SETTINGS_REC *rec;
110
111         if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTIONS,
112                             "set", &optlist, &key, &value))
113                 return;
114
115         clear = g_hash_table_lookup(optlist, "clear") != NULL;
116         set_default = g_hash_table_lookup(optlist, "default") != NULL;
117
118         if (*key == '\0')
119                 clear = set_default = FALSE;
120
121         if (!(clear || set_default || *value != '\0'))
122                 set_print_pattern(key);
123         else {
124                 rec = settings_get_record(key);
125                 if (rec != NULL) {
126                         /* change the setting */
127                         switch (rec->type) {
128                         case SETTING_TYPE_BOOLEAN:
129                                 if (clear)
130                                         settings_set_bool(key, FALSE);
131                                 else if (set_default)
132                                         settings_set_bool(key, rec->default_value.v_bool);
133                                 else
134                                         set_boolean(key, value);
135                                 break;
136                         case SETTING_TYPE_INT:
137                                 if (clear)
138                                         settings_set_int(key, 0);
139                                 else if (set_default)
140                                         settings_set_int(key, rec->default_value.v_int);
141                                 else
142                                         set_int(key, value);
143                                 break;
144                         case SETTING_TYPE_STRING:
145                                 settings_set_str(key, clear ? "" :
146                                                  set_default ? rec->default_value.v_string :
147                                                  value);
148                                 break;
149                         case SETTING_TYPE_TIME:
150                                 if (!settings_set_time(key, clear ? "0" :
151                                                        set_default ? rec->default_value.v_string : value))
152                                         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
153                                                     TXT_INVALID_TIME);
154                                 break;
155                         case SETTING_TYPE_LEVEL:
156                                 if (!settings_set_level(key, clear ? "" :
157                                                         set_default ? rec->default_value.v_string : value))
158                                         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
159                                                     TXT_INVALID_LEVEL);
160                                 break;
161                         case SETTING_TYPE_SIZE:
162                                 if (!settings_set_size(key, clear ? "0" :
163                                                        set_default ? rec->default_value.v_string : value))
164                                         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
165                                                     TXT_INVALID_SIZE);
166                                 break;
167                         }
168                         signal_emit("setup changed", 0);
169                         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
170                                     TXT_SET_TITLE, rec->section);
171                         set_print(rec);
172                 } else
173                         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
174                                     TXT_SET_UNKNOWN, key);
175         }
176
177         cmd_params_free(free_arg);
178 }
179
180 /* SYNTAX: TOGGLE <key> [on|off|toggle] */
181 static void cmd_toggle(const char *data)
182 {
183         char *key, *value;
184         void *free_arg;
185         int type;
186
187         if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &key, &value))
188                 return;
189
190         if (*key == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
191
192         type = settings_get_type(key);
193         if (type == -1)
194                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_SET_UNKNOWN, key);
195         else if (type != SETTING_TYPE_BOOLEAN)
196                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_SET_NOT_BOOLEAN, key);
197         else {
198                 set_boolean(key, *value != '\0' ? value : "TOGGLE");
199                 set_print(settings_get_record(key));
200                 signal_emit("setup changed", 0);
201         }
202
203         cmd_params_free(free_arg);
204 }
205
206 static int config_key_compare(CONFIG_NODE *node1, CONFIG_NODE *node2)
207 {
208         return g_strcasecmp(node1->key, node2->key);
209 }
210
211 static void show_aliases(const char *alias)
212 {
213         CONFIG_NODE *node;
214         GSList *tmp, *list;
215         int aliaslen;
216
217         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_ALIASLIST_HEADER);
218
219         node = iconfig_node_traverse("aliases", FALSE);
220         tmp = node == NULL ? NULL : config_node_first(node->value);
221
222         /* first get the list of aliases sorted */
223         list = NULL;
224         aliaslen = strlen(alias);
225         for (; tmp != NULL; tmp = config_node_next(tmp)) {
226                 CONFIG_NODE *node = tmp->data;
227
228                 if (node->type != NODE_TYPE_KEY)
229                         continue;
230
231                 if (aliaslen != 0 && g_strncasecmp(node->key, alias, aliaslen) != 0)
232                         continue;
233
234                 list = g_slist_insert_sorted(list, node, (GCompareFunc) config_key_compare);
235         }
236
237         /* print the aliases */
238         for (tmp = list; tmp != NULL; tmp = tmp->next) {
239                 CONFIG_NODE *node = tmp->data;
240
241                 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_ALIASLIST_LINE,
242                             node->key, node->value);
243         }
244         g_slist_free(list);
245
246         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_ALIASLIST_FOOTER);
247 }
248
249 static void alias_remove(const char *alias)
250 {
251         if (iconfig_get_str("aliases", alias, NULL) == NULL)
252                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_ALIAS_NOT_FOUND, alias);
253         else {
254                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_ALIAS_REMOVED, alias);
255                 iconfig_set_str("aliases", alias, NULL);
256
257                 signal_emit("alias removed", 1, alias);
258         }
259 }
260
261 /* SYNTAX: ALIAS [[-]<alias> [<command>]] */
262 static void cmd_alias(const char *data)
263 {
264         char *alias, *value;
265         void *free_arg;
266
267         g_return_if_fail(data != NULL);
268
269         if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &alias, &value))
270                 return;
271
272         if (*alias == '-') {
273                 if (alias[1] != '\0') alias_remove(alias+1);
274         } else if (*alias == '\0' || *value == '\0')
275                 show_aliases(alias);
276         else {
277                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_ALIAS_ADDED, alias);
278                 iconfig_set_str("aliases", alias, value);
279                 signal_emit("alias added", 2, alias, value);
280         }
281         cmd_params_free(free_arg);
282 }
283
284 /* SYNTAX: UNALIAS <alias> */
285 static void cmd_unalias(const char *data)
286 {
287         char *alias;
288         void *free_arg;
289
290         g_return_if_fail(data != NULL);
291
292         if (!cmd_get_params(data, &free_arg, 1, &alias))
293                 return;
294         if (*alias == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
295
296         alias_remove(alias);
297         cmd_params_free(free_arg);
298 }
299
300 /* SYNTAX: RELOAD [<file>] */
301 static void cmd_reload(const char *data)
302 {
303         const char *fname;
304
305         fname = *data == '\0' ? get_irssi_config() : data;
306
307         if (settings_reread(fname)) {
308                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
309                             TXT_CONFIG_RELOADED, fname);
310         }
311 }
312
313 static void settings_save_fe(const char *fname)
314 {
315         if (settings_save(fname, FALSE /* not autosaved */)) {
316                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
317                             TXT_CONFIG_SAVED, fname);
318         }
319 }
320
321 static void settings_save_confirm(const char *line, char *fname)
322 {
323         if (i_toupper(line[0]) == 'Y')
324                 settings_save_fe(fname);
325         g_free(fname);
326 }
327
328 /* SYNTAX: SAVE [<file>] */
329 static void cmd_save(const char *data)
330 {
331         GHashTable *optlist;
332         char *format, *fname;
333         void *free_arg;
334
335         if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
336                             "save", &optlist, &fname))
337                 return;
338
339         if (*fname == '\0')
340                 fname = mainconfig->fname;
341
342         if (!irssi_config_is_changed(fname))
343                 settings_save_fe(fname);
344         else {
345                 /* config file modified outside irssi */
346                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
347                             TXT_CONFIG_MODIFIED, fname);
348
349                 format = format_get_text(MODULE_NAME, NULL, NULL, NULL,
350                                          TXT_OVERWRITE_CONFIG);
351                 keyboard_entry_redirect((SIGNAL_FUNC) settings_save_confirm,
352                                         format, 0, g_strdup(fname));
353                 g_free(format);
354         }
355
356         cmd_params_free(free_arg);
357 }
358
359 static void settings_clean_confirm(const char *line)
360 {
361         if (i_toupper(line[0]) == 'Y')
362                 settings_clean_invalid();
363 }
364
365 static void sig_settings_errors(const char *msg)
366 {
367         printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", msg);
368         keyboard_entry_redirect((SIGNAL_FUNC) settings_clean_confirm,
369                                 "Remove unknown settings from config file (Y/n)?",
370                                 0, NULL);
371 }
372
373 void fe_settings_init(void)
374 {
375         command_bind("set", NULL, (SIGNAL_FUNC) cmd_set);
376         command_bind("toggle", NULL, (SIGNAL_FUNC) cmd_toggle);
377         command_bind("alias", NULL, (SIGNAL_FUNC) cmd_alias);
378         command_bind("unalias", NULL, (SIGNAL_FUNC) cmd_unalias);
379         command_bind("reload", NULL, (SIGNAL_FUNC) cmd_reload);
380         command_bind("save", NULL, (SIGNAL_FUNC) cmd_save);
381         command_set_options("set", "clear default");
382
383         signal_add("settings errors", (SIGNAL_FUNC) sig_settings_errors);
384 }
385
386 void fe_settings_deinit(void)
387 {
388         command_unbind("set", (SIGNAL_FUNC) cmd_set);
389         command_unbind("toggle", (SIGNAL_FUNC) cmd_toggle);
390         command_unbind("alias", (SIGNAL_FUNC) cmd_alias);
391         command_unbind("unalias", (SIGNAL_FUNC) cmd_unalias);
392         command_unbind("reload", (SIGNAL_FUNC) cmd_reload);
393         command_unbind("save", (SIGNAL_FUNC) cmd_save);
394
395         signal_remove("settings errors", (SIGNAL_FUNC) sig_settings_errors);
396 }