1 /*
2 * This file contains string parsing functions.
3 *
4 * All functions advance the input after the successfully parsed token, or
5 * to the next non-delimiter if no token could be successfully parsed.
6 * All functions return pointer to static data which may not be freed.
7 *
8 * climm Copyright (C) © 2001-2010 Rüdiger Kuhlmann
9 *
10 * climm is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 dated June, 1991.
13 *
14 * climm is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 * License for more details.
18 *
19 * In addition, as a special exception permission is granted to link the
20 * code of this release of climm with the OpenSSL project's "OpenSSL"
21 * library, and distribute the linked executables. You must obey the GNU
22 * General Public License in all respects for all of the code used other
23 * than "OpenSSL". If you modify this file, you may extend this exception
24 * to your version of the file, but you are not obligated to do so. If you
25 * do not wish to do so, delete this exception statement from your version
26 * of this file.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this package; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31 * 02111-1307, USA.
32 *
33 * $Id: util_parse.c 2864 2010-03-16 22:48:25Z kuhlmann $
34 */
35
36 #include "climm.h"
37 #include "util_str.h"
38 #include "util_parse.h"
39 #include "contact.h"
40 #include "connection.h"
41
42 /*
43 * Parses the next word, respecting double quotes, and interpreting
44 * \x##, \# and comments (#).
45 */
s_parse_s(const char ** input,const char * sep)46 strc_t s_parse_s (const char **input, const char *sep)
47 {
48 static str_s str;
49 strc_t parsed;
50 const char *p = *input;
51 char *q;
52 int s = 0;
53
54 while (*p && strchr (sep, *p))
55 p++;
56 if (*p == '#')
57 {
58 while (*p)
59 p++;
60 }
61 *input = p;
62 if (!*p)
63 return NULL;
64
65 s_init (&str, p, 0);
66
67 q = str.txt;
68 parsed = &str;
69 if (!q)
70 return NULL;
71
72 if (*p == '"')
73 {
74 s = 1;
75 p++;
76 }
77 while (*p)
78 {
79 if (*p == '\\')
80 {
81 p++;
82 if (*p == 'x' && p[1] && p[2])
83 {
84 p++;
85 *q = (*p >= '0' && *p <= '9' ? *p - '0' : *p >= 'a' && *p <= 'f' ? *p - 'a' + 10 : *p - 'A' + 10) << 4;
86 p++;
87 *q |= *p >= '0' && *p <= '9' ? *p - '0' : *p >= 'a' && *p <= 'f' ? *p - 'a' + 10 : *p - 'A' + 10;
88 p++, q++;
89 continue;
90 }
91 else if (*p)
92 {
93 *(q++) = *(p++);
94 continue;
95 }
96 }
97 if (*p == '"' && s)
98 {
99 *q = '\0';
100 *input = p + 1;
101 str.len = q - str.txt;
102 return parsed;
103 }
104 if (!s && strchr (sep, *p))
105 break;
106 *(q++) = *(p++);
107 }
108 *q = '\0';
109 *input = p;
110 str.len = q - str.txt;
111 return parsed;
112 }
113
is_valid_icq_name(char * t)114 int is_valid_icq_name (char *t)
115 {
116 if (!*t)
117 return 0;
118 for ( ; *t; t++)
119 if (*t < '0' || *t > '9')
120 return 0;
121 return 1;
122 }
123
is_valid_aim_name(char * t)124 int is_valid_aim_name (char *t)
125 {
126 if (!*t)
127 return 0;
128 if (*t >= '0' && *t <= '9')
129 return 0;
130 for ( ; *t; t++)
131 {
132 if ((*t < '0' || *t > '9') && (*t < 'a' || *t > 'z') && (*t < 'A' || *t > 'Z'))
133 return 0;
134 if (*t >= 'A' && *t <= 'Z')
135 t += 'a' - 'A';
136 }
137 return 1;
138 }
139
is_valid_xmpp_name(char * txt)140 int is_valid_xmpp_name (char *txt)
141 {
142 char *at, *slash;
143
144 if (!*txt)
145 return 0;
146 if (!(at = strchr (txt, '@')))
147 return 0;
148 if (strchr (at + 1, '@'))
149 return 0;
150 slash = strchr (txt, '/');
151 if (slash && slash != strchr (at, '/'))
152 return 0;
153 return 1;
154 }
155
is_valid_msn_name(char * txt)156 int is_valid_msn_name (char *txt)
157 {
158 char *at;
159
160 if (!*txt)
161 return 0;
162 if (!(at = strchr (txt, '@')))
163 return 0;
164 if (strchr (at + 1, '@'))
165 return 0;
166 return 1;
167 }
168
169 /*
170 * Parses a nick, UIN or screen name.
171 */
s_parsenick_s(const char ** input,const char * sep,BOOL any,Server * serv,const char ** alias)172 Contact *s_parsenick_s (const char **input, const char *sep, BOOL any, Server *serv, const char **alias)
173 {
174 ContactGroup *cg;
175 Contact *r, *parsed;
176 const char *p = *input;
177 strc_t t;
178 UDWORD max, l, ll, i;
179
180 while (*p && strchr (sep, *p))
181 p++;
182 *input = p;
183 if (!*p)
184 return NULL;
185
186 if ((t = s_parse_s (&p, sep)) && strncmp (t->txt, *input, t->len))
187 {
188 if ((parsed = ContactFind (serv, t->txt)))
189 {
190 *input = p;
191 if (alias)
192 *alias = t->txt;
193 return parsed;
194 }
195 }
196 p = *input;
197
198 if (serv->type == TYPE_SERVER && !strncasecmp (p, "AIM:", 4))
199 {
200 const char *pp;
201 p += 4;
202 pp = p;
203 t = s_parse (&p);
204 if (t && (*pp == '"' || is_valid_aim_name (t->txt)))
205 {
206 *input = p;
207 if (alias)
208 *alias = t->txt;
209 return ContactScreen (serv, t->txt);
210 }
211 p = *input;
212 }
213
214 if (serv->type == TYPE_MSN_SERVER && !strncasecmp (p, "MSN:", 4))
215 {
216 p += 4;
217 t = s_parse (&p);
218 if (t && is_valid_msn_name (t->txt))
219 {
220 *input = p;
221 if (alias)
222 *alias = t->txt;
223 return ContactScreen (serv, t->txt);
224 }
225 p = *input;
226 }
227
228 if (serv->type == TYPE_XMPP_SERVER &&
229 (!strncasecmp (p, "JABBER:", 7) || !strncasecmp (p, "XMPP:", 5)))
230 {
231 p += (*p == 'J') ? 7 : 5;
232 t = s_parse (&p);
233 if (t && is_valid_xmpp_name (t->txt))
234 {
235 *input = p;
236 if (alias)
237 *alias = t->txt;
238 return ContactScreen (serv, t->txt);
239 }
240 p = *input;
241 }
242
243 if (serv->type == TYPE_SERVER && !strncasecmp (p, "ICQ:", 4))
244 {
245 p += 4;
246 t = s_parse (&p);
247 if (t && is_valid_icq_name (t->txt))
248 {
249 *input = p;
250 if (alias)
251 *alias = t->txt;
252 return ContactScreen (serv, t->txt);
253 }
254 p = *input;
255 }
256
257 max = 0;
258 parsed = NULL;
259 ll = strlen (p);
260 cg = serv->contacts;
261 for (i = 0; (r = ContactIndex (cg, i)); i++)
262 {
263 ContactAlias *ca;
264
265 l = strlen (r->nick);
266 if (l > max && l <= ll && (!p[l] || strchr (sep, p[l])) && !strncasecmp (p, r->nick, l))
267 {
268 parsed = r;
269 max = strlen (r->nick);
270 if (alias)
271 *alias = r->nick;
272 }
273
274 for (ca = r->alias; ca; ca = ca->more)
275 {
276 l = strlen (ca->alias);
277 if (l > max && l <= ll && (!p[l] || strchr (sep, p[l])) && !strncasecmp (p, ca->alias, l))
278 {
279 parsed = r;
280 max = strlen (ca->alias);
281 if (alias)
282 *alias = ca->alias;
283 }
284 }
285 }
286 if (max)
287 {
288 *input = p + max;
289 return parsed;
290 }
291
292 t = s_parse (&p);
293 if (!t)
294 return NULL;
295
296 if (serv->type == TYPE_MSN_SERVER && is_valid_msn_name (t->txt))
297 {
298 *input = p;
299 if (alias)
300 *alias = t->txt;
301 return ContactScreen (serv, t->txt);
302 }
303
304 if (serv->type == TYPE_XMPP_SERVER && is_valid_xmpp_name (t->txt))
305 {
306 *input = p;
307 if (alias)
308 *alias = t->txt;
309 return ContactScreen (serv, t->txt);
310 }
311
312 if (serv->type == TYPE_SERVER && is_valid_icq_name (t->txt))
313 {
314 *input = p;
315 if (alias)
316 *alias = t->txt;
317 return ContactScreen (serv, t->txt);
318 }
319
320 if (!any)
321 return NULL;
322
323 for (i = 0; (serv = ServerNr (i)); i++)
324 if ((r = s_parsenick_s (input, sep, 0, serv, alias)))
325 return r;
326
327 return NULL;
328 }
329
330 /*
331 * Parses a contact group by name.
332 */
s_parsecg_s(const char ** input,const char * sep,BOOL any,Server * serv)333 ContactGroup *s_parsecg_s (const char **input, const char *sep, BOOL any, Server *serv)
334 {
335 ContactGroup *cg;
336 const char *p = *input;
337 strc_t t;
338 UDWORD l, i;
339
340 while (*p && strchr (sep, *p))
341 p++;
342 *input = p;
343
344 if (!*p)
345 return NULL;
346
347 if ((t = s_parse_s (&p, sep)))
348 {
349 for (i = 0; (cg = ContactGroupIndex (i)); i++)
350 {
351 if (cg->serv == serv && cg->name && !strcmp (cg->name, t->txt))
352 {
353 *input = p;
354 return cg;
355 }
356 }
357 }
358 p = *input;
359
360 for (i = 0; (cg = ContactGroupIndex (i)); i++)
361 {
362 if (!cg->name || !*cg->name)
363 continue;
364 l = strlen (cg->name);
365 if (cg->serv == serv && !strncmp (cg->name, p, l)
366 && (strchr (sep, p[l]) || !p[l]))
367 {
368 *input = p + l + (p[l] ? 1 : 0);
369 return cg;
370 }
371 }
372 if (!any)
373 return NULL;
374
375 for (i = 0; (serv = ServerNr (i)); i++)
376 if ((cg = s_parsecg_s (input, sep, 0, serv)))
377 return cg;
378
379 return NULL;
380 }
381
382 /*
383 * Parses nicks and contact groups.
384 */
s_parselist_s(const char ** input,BOOL rem,BOOL any,Server * serv)385 ContactGroup *s_parselist_s (const char **input, BOOL rem, BOOL any, Server *serv)
386 {
387 static ContactGroup *scg = NULL;
388 ContactGroup *cg;
389 Contact *cont;
390 const char *p = *input;
391 strc_t par;
392 UDWORD i, one = 0;
393
394 if (scg)
395 ContactGroupD (scg);
396 scg = ContactGroupC (NULL, 0, "");
397 scg->temp = 1; /* ContactD will not compact contacts on temporary lists! */
398 while (*p)
399 {
400 while (*p && strchr (DEFAULT_SEP, *p))
401 p++;
402 if ((cg = s_parsecg_s (&p, MULTI_SEP, 0, serv)))
403 {
404 for (i = 0; (cont = ContactIndex (cg, i)); i++)
405 if (!ContactHas (scg, cont))
406 ContactAdd (scg, cont);
407 }
408 else if ((cont = s_parsenick_s (&p, MULTI_SEP, 0, serv, NULL)))
409 {
410 if (!ContactHas (scg, cont))
411 ContactAdd (scg, cont);
412 }
413 else if (any && (cg = s_parsecg_s (&p, MULTI_SEP, 1, serv)))
414 {
415 for (i = 0; (cont = ContactIndex (cg, i)); i++)
416 if (!ContactHas (scg, cont))
417 ContactAdd (scg, cont);
418 }
419 else if (any && (cont = s_parsenick_s (&p, MULTI_SEP, 1, serv, NULL)))
420 {
421 if (!ContactHas (scg, cont))
422 ContactAdd (scg, cont);
423 }
424 else if ((par = s_parse (&p)))
425 {
426 rl_printf (i18n (2523, "%s not recognized as a nick name.\n"), s_wordquote (par->txt));
427 if (!rem)
428 break;
429 one = 1;
430 continue;
431 }
432 else
433 break;
434 if (!rem && *p != ',')
435 break;
436 if (*p)
437 p++;
438 }
439
440 if ((one || ContactIndex (scg, 0)) && (rem || strchr (DEFAULT_SEP, *p)))
441 {
442 *input = p;
443 return scg;
444 }
445 return NULL;
446 }
447
448 /*
449 * Parses the remainder of the input, translates \x## and \#.
450 */
s_parserem_s(const char ** input,const char * sep)451 char *s_parserem_s (const char **input, const char *sep)
452 {
453 static char *t = NULL;
454 const char *p = *input;
455
456 while (*p && strchr (sep, *p))
457 p++;
458 *input = p;
459 if (!*p)
460 return NULL;
461
462 s_repl (&t, p);
463 while (*p)
464 p++;
465 return t;
466 }
467
468 /*
469 * Parses a number.
470 */
s_parseint_s(const char ** input,UDWORD * parsed,const char * sep,int flags)471 const char *s_parseint_s (const char **input, UDWORD *parsed, const char *sep, int flags)
472 {
473 static str_s str;
474 const char *p = *input;
475 const char *st;
476 UDWORD nr, sig;
477
478 while (*p && strchr (sep, *p))
479 p++;
480 *input = p;
481 if (*p == '#' && flags & 4)
482 {
483 while (*p)
484 p++;
485 }
486 if (!*p)
487 {
488 *parsed = 0;
489 return NULL;
490 }
491
492 nr = 0;
493 sig = 1;
494
495 st = p;
496 if (*p == '+')
497 {
498 p++;
499 while (*p == '0')
500 p++;
501 st = p;
502 }
503 else if (*p == '-' && flags & 1)
504 {
505 sig = -1;
506 p++;
507 }
508 s_init (&str, st, 0);
509
510 while (*p && *p >= '0' && *p <= '9')
511 {
512 nr = nr * 10 + (*p - '0');
513 p++;
514 }
515 if (!nr && *p == 'x' && flags & 2)
516 {
517 p++;
518 while (*p && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
519 {
520 nr = nr * 16 + (*p >= '0' && *p <= '9' ? *p - '0' : *p >= 'a' && *p <= 'f' ? *p - 'a' + 10 : *p - 'A' + 10);
521 p++;
522 }
523 }
524 if (*p && !strchr (sep, *p))
525 {
526 *parsed = 0;
527 return NULL;
528 }
529 *input = p;
530 *parsed = nr * sig;
531 str.txt[p - st] = 0;
532 return str.txt;
533 }
534
535 /*
536 * Parses a keyword.
537 */
s_parsekey_s(const char ** input,const char * keyword,const char * sep)538 BOOL s_parsekey_s (const char **input, const char *keyword, const char *sep)
539 {
540 const char *p = *input;
541
542 while (*p && strchr (sep, *p))
543 p++;
544 *input = p;
545
546 while (*keyword == *p && *p)
547 keyword++, p++;
548
549 if (*keyword)
550 return FALSE;
551
552 if (*p && !strchr (sep, *p))
553 return FALSE;
554
555 *input = p;
556 return TRUE;
557 }
558
559