1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2013 Wilmer van der Gaast and others *
5 \********************************************************************/
6
7 /* Some stuff to register, handle and save user preferences */
8
9 /*
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License with
21 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22 if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23 Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 #define BITLBEE_CORE
27 #include "bitlbee.h"
28
29 /* Used to use NULL for this, but NULL is actually a "valid" value. */
30 char *SET_INVALID = "nee";
31
set_add(set_t ** head,const char * key,const char * def,set_eval eval,void * data)32 set_t *set_add(set_t **head, const char *key, const char *def, set_eval eval, void *data)
33 {
34 set_t *s = set_find(head, key);
35
36 /* Possibly the setting already exists. If it doesn't exist yet,
37 we create it. If it does, we'll just change the default. */
38 if (!s) {
39 if ((s = *head)) {
40 /* Sorted insertion. Special-case insertion at the start. */
41 if (strcmp(key, s->key) < 0) {
42 s = g_new0(set_t, 1);
43 s->next = *head;
44 *head = s;
45 } else {
46 while (s->next && strcmp(key, s->next->key) > 0) {
47 s = s->next;
48 }
49 set_t *last_next = s->next;
50 s->next = g_new0(set_t, 1);
51 s = s->next;
52 s->next = last_next;
53 }
54 } else {
55 s = *head = g_new0(set_t, 1);
56 }
57 s->key = g_strdup(key);
58 }
59
60 if (s->def) {
61 g_free(s->def);
62 s->def = NULL;
63 }
64 if (def) {
65 s->def = g_strdup(def);
66 }
67
68 s->eval = eval;
69 s->data = data;
70
71 return s;
72 }
73
set_find(set_t ** head,const char * key)74 set_t *set_find(set_t **head, const char *key)
75 {
76 set_t *s = *head;
77
78 while (s) {
79 if (g_strcasecmp(s->key, key) == 0 ||
80 (s->old_key && g_strcasecmp(s->old_key, key) == 0)) {
81 break;
82 }
83 s = s->next;
84 }
85
86 return s;
87 }
88
set_getstr(set_t ** head,const char * key)89 char *set_getstr(set_t **head, const char *key)
90 {
91 set_t *s = set_find(head, key);
92
93 if (!s || (!s->value && !s->def)) {
94 return NULL;
95 }
96
97 return set_value(s);
98 }
99
set_getint(set_t ** head,const char * key)100 int set_getint(set_t **head, const char *key)
101 {
102 char *s = set_getstr(head, key);
103 int i = 0;
104
105 if (!s) {
106 return 0;
107 }
108
109 if (sscanf(s, "%d", &i) != 1) {
110 return 0;
111 }
112
113 return i;
114 }
115
set_getbool(set_t ** head,const char * key)116 int set_getbool(set_t **head, const char *key)
117 {
118 char *s = set_getstr(head, key);
119
120 if (!s) {
121 return 0;
122 }
123
124 return bool2int(s);
125 }
126
set_isvisible(set_t * set)127 int set_isvisible(set_t *set)
128 {
129 /* the default value is not stored in value, only in def */
130 return !((set->flags & SET_HIDDEN) ||
131 ((set->flags & SET_HIDDEN_DEFAULT) &&
132 (set->value == NULL)));
133 }
134
set_setstr(set_t ** head,const char * key,char * value)135 int set_setstr(set_t **head, const char *key, char *value)
136 {
137 set_t *s = set_find(head, key);
138 char *nv = value;
139
140 if (!s) {
141 /*
142 Used to do this, but it never really made sense.
143 s = set_add( head, key, NULL, NULL, NULL );
144 */
145 return 0;
146 }
147
148 if (value == NULL && (s->flags & SET_NULL_OK) == 0) {
149 return 0;
150 }
151
152 /* Call the evaluator. For invalid values, evaluators should now
153 return SET_INVALID, but previously this was NULL. Try to handle
154 that too if NULL is not an allowed value for this setting. */
155 if (s->eval && ((nv = s->eval(s, value)) == SET_INVALID ||
156 ((s->flags & SET_NULL_OK) == 0 && nv == NULL))) {
157 return 0;
158 }
159
160 if (s->value) {
161 g_free(s->value);
162 s->value = NULL;
163 }
164
165 /* If there's a default setting and it's equal to what we're trying to
166 set, stick with s->value = NULL. Otherwise, remember the setting. */
167 if (!s->def || (g_strcmp0(nv, s->def) != 0)) {
168 s->value = g_strdup(nv);
169 }
170
171 if (nv != value) {
172 g_free(nv);
173 }
174
175 return 1;
176 }
177
set_setint(set_t ** head,const char * key,int value)178 int set_setint(set_t **head, const char *key, int value)
179 {
180 char *s = g_strdup_printf("%d", value);
181 int retval = set_setstr(head, key, s);
182
183 g_free(s);
184 return retval;
185 }
186
set_del(set_t ** head,const char * key)187 void set_del(set_t **head, const char *key)
188 {
189 set_t *s = *head, *t = NULL;
190
191 while (s) {
192 if (g_strcasecmp(s->key, key) == 0) {
193 break;
194 }
195 s = (t = s)->next;
196 }
197 if (s) {
198 if (t) {
199 t->next = s->next;
200 } else {
201 *head = s->next;
202 }
203
204 g_free(s->key);
205 g_free(s->old_key);
206 g_free(s->value);
207 g_free(s->def);
208 g_free(s);
209 }
210 }
211
set_reset(set_t ** head,const char * key)212 int set_reset(set_t **head, const char *key)
213 {
214 set_t *s;
215
216 s = set_find(head, key);
217 if (s) {
218 return set_setstr(head, key, s->def);
219 }
220
221 return 0;
222 }
223
set_eval_int(set_t * set,char * value)224 char *set_eval_int(set_t *set, char *value)
225 {
226 char *s = value;
227
228 /* Allow a minus at the first position. */
229 if (*s == '-') {
230 s++;
231 }
232
233 for (; *s; s++) {
234 if (!g_ascii_isdigit(*s)) {
235 return SET_INVALID;
236 }
237 }
238
239 return value;
240 }
241
set_eval_bool(set_t * set,char * value)242 char *set_eval_bool(set_t *set, char *value)
243 {
244 return is_bool(value) ? value : SET_INVALID;
245 }
246
set_eval_list(set_t * set,char * value)247 char *set_eval_list(set_t *set, char *value)
248 {
249 GSList *options = set->eval_data, *opt;
250
251 for (opt = options; opt; opt = opt->next) {
252 if (strcmp(value, opt->data) == 0) {
253 return value;
254 }
255 }
256
257 /* TODO: It'd be nice to show the user a list of allowed values,
258 but we don't have enough context here to do that. May
259 want to fix that. */
260
261 return NULL;
262 }
263
set_eval_to_char(set_t * set,char * value)264 char *set_eval_to_char(set_t *set, char *value)
265 {
266 char *s = g_new(char, 3);
267
268 if (*value == ' ') {
269 strcpy(s, " ");
270 } else {
271 sprintf(s, "%c ", *value);
272 }
273
274 return s;
275 }
276
set_eval_oauth(set_t * set,char * value)277 char *set_eval_oauth(set_t *set, char *value)
278 {
279 account_t *acc = set->data;
280
281 if (bool2int(value) && strcmp(acc->pass, PASSWORD_PENDING) == 0) {
282 *acc->pass = '\0';
283 }
284
285 return set_eval_bool(set, value);
286 }
287