comparison src/parse.c @ 271:899175e8dff0

heavy refactoring in the small of parse.c I really hope I didn't change any behavior. This reminds me that we really need a test framework.
author markus schnalke <meillo@marmaro.de>
date Fri, 03 Dec 2010 13:05:59 -0300
parents a80ebfa16cd5
children 00724782b6c9
comparison
equal deleted inserted replaced
270:0c44b239c7fe 271:899175e8dff0
1 /* MasqMail 1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth 2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
3 4
4 This program is free software; you can redistribute it and/or modify 5 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or 7 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version. 8 (at your option) any later version.
42 #endif 43 #endif
43 44
44 p++; 45 p++;
45 while (*p && *p != ')') { 46 while (*p && *p != ')') {
46 p++; 47 p++;
47 if (*p == '(') 48 if (*p == '(') {
48 p = skip_comment(p); 49 p = skip_comment(p);
50 }
49 } 51 }
50 p++; 52 p++;
51 53
52 return p; 54 return p;
53 } 55 }
57 { 59 {
58 #ifdef PARSE_TEST 60 #ifdef PARSE_TEST
59 g_print("read_word: %s\n", p); 61 g_print("read_word: %s\n", p);
60 #endif 62 #endif
61 /* eat leading spaces */ 63 /* eat leading spaces */
62 while (*p && isspace(*p)) 64 while (*p && isspace(*p)) {
63 p++; 65 p++;
66 }
64 67
65 *b = p; 68 *b = p;
66 /* b = &p; */ 69 /* b = &p; */
67 if (*p == '\"') { 70 if (*p == '\"') {
68 /* quoted-string */ 71 /* quoted-string */
69 p++; 72 p++;
70 while (*p && (*p != '\"')) 73 while (*p && (*p != '\"')) {
71 p++; 74 p++;
75 }
72 p++; 76 p++;
73 } else { 77 } else {
74 /* atom */ 78 /* atom */
75 while (*p && !strchr(specials, *p) && !iscntrl(*p) && !isspace(*p)) 79 while (*p && !strchr(specials, *p) && !iscntrl(*p) && !isspace(*p)) {
76 p++; 80 p++;
81 }
77 } 82 }
78 *e = p; 83 *e = p;
79 return TRUE; 84 return TRUE;
80 } 85 }
81 86
86 91
87 #ifdef PARSE_TEST 92 #ifdef PARSE_TEST
88 g_print("read_word_with_dots: %s\n", p); 93 g_print("read_word_with_dots: %s\n", p);
89 #endif 94 #endif
90 while (TRUE) { 95 while (TRUE) {
91 if (!read_word(p, b, e)) 96 if (!read_word(p, b, e)) {
92 return FALSE; 97 return FALSE;
98 }
93 p = *e; 99 p = *e;
94 if (*p != '.') 100 if (*p != '.') {
95 break; 101 break;
102 }
96 p++; 103 p++;
97 } 104 }
98 *b = b0; 105 *b = b0;
99 *e = p; 106 *e = p;
100 return TRUE; 107 return TRUE;
106 #ifdef PARSE_TEST 113 #ifdef PARSE_TEST
107 g_print("read_domain: %s\n", p); 114 g_print("read_domain: %s\n", p);
108 #endif 115 #endif
109 *b = p; 116 *b = p;
110 if (*p != '[') { 117 if (*p != '[') {
111 while (isalnum(*p) || (*p == '-') || (*p == '.')) 118 while (isalnum(*p) || (*p == '-') || (*p == '.')) {
112 p++; 119 p++;
120 }
113 } else { 121 } else {
114 p++; 122 p++;
115 while (isalpha(*p) || (*p == '.')) 123 while (isalpha(*p) || (*p == '.')) {
116 p++; 124 p++;
125 }
117 if (*p != ']') { 126 if (*p != ']') {
118 parse_error = g_strdup_printf("']' expected at end of literal address %s", *b); 127 parse_error = g_strdup_printf("']' expected at end of literal address %s", *b);
119 return FALSE; 128 return FALSE;
120 } 129 }
121 p++; 130 p++;
142 parse_error = NULL; 151 parse_error = NULL;
143 } 152 }
144 153
145 /* leading spaces and angle brackets */ 154 /* leading spaces and angle brackets */
146 while (*p && (isspace(*p) || (*p == '<'))) { 155 while (*p && (isspace(*p) || (*p == '<'))) {
147 if (*p == '<') 156 if (*p == '<') {
148 angle_brackets++; 157 angle_brackets++;
149 p++; 158 }
150 } 159 p++;
151 160 }
152 if (*p) { 161
153 while (TRUE) { 162 if (!*p) {
154 if (read_word_with_dots(p, &b, &e)) { 163 return FALSE;
155 p = e; 164 }
156 #ifdef PARSE_TEST 165
157 g_print("after read_word_with_dots: %s\n", p); 166 while (TRUE) {
158 #endif 167 if (!read_word_with_dots(p, &b, &e)) {
159 /* eat white spaces and comments */ 168 return FALSE;
160 while ((*p && (isspace(*p))) || (*p == '(')) { 169 }
161 if (*p == '(') { 170
162 if (!(p = skip_comment(p))) { 171 p = e;
163 parse_error = g_strdup("missing right bracket ')'"); 172 #ifdef PARSE_TEST
164 return FALSE; 173 g_print("after read_word_with_dots: %s\n", p);
165 } 174 #endif
166 } else 175 /* eat white spaces and comments */
167 p++; 176 while ((*p && (isspace(*p))) || (*p == '(')) {
168 } 177 if (*p == '(') {
169 /* we now have a non-space char that is not 178 if (!(p = skip_comment(p))) {
170 the beginning of a comment */ 179 parse_error = g_strdup("missing right bracket ')'");
171
172 if (*p == '@') {
173 /* the last word was the local_part
174 of an addr-spec */
175 *local_begin = b;
176 *local_end = e;
177 #ifdef PARSE_TEST
178 g_print("found local part: %s\n", *local_begin);
179 #endif
180 if (*p == '@') {
181 p++; /* skip @ */
182 /* now the domain */
183 if (read_domain(p, &b, &e)) {
184 p = e;
185 *domain_begin = b;
186 *domain_end = e;
187 } else
188 return FALSE;
189 } else {
190 /* unqualified? */
191 *domain_begin = *domain_end = NULL;
192 }
193 break;
194 } else if (*p == '<') {
195 /* addr-spec follows */
196 while (isspace(*p) || (*p == '<')) {
197 if (*p == '<')
198 angle_brackets++;
199 p++;
200 }
201 if (read_word_with_dots(p, &b, &e)) {
202 p = e;
203 *local_begin = b;
204 *local_end = e;
205 #ifdef PARSE_TEST
206 g_print("found local part: %s\n", *local_begin);
207 #endif
208 } else
209 return FALSE;
210 if (*p == '@') {
211 p++;
212 if (read_domain(p, &b, &e)) {
213 p = e;
214 *domain_begin = b;
215 *domain_end = e;
216 } else
217 return FALSE;
218 } else {
219 /* may be unqualified address */
220 *domain_begin = *domain_end = NULL;
221 }
222 break;
223 } else if (!*p || *p == '>') {
224 *local_begin = b;
225 *local_end = e;
226 #ifdef PARSE_TEST
227 g_print("found local part: %s\n", *local_begin);
228 #endif
229 *domain_begin = *domain_end = NULL;
230 break;
231 } else if (strchr(specials, *p) || iscntrl(*p) || isspace(*p)) {
232 parse_error = g_strdup_printf("unexpected character: %c", *p);
233 return FALSE; 180 return FALSE;
234 } 181 }
235 } else 182 } else {
183 p++;
184 }
185 }
186 /* we now have a non-space char that is not
187 the beginning of a comment */
188
189 if (*p == '@') {
190 /* the last word was the local_part of an addr-spec */
191 *local_begin = b;
192 *local_end = e;
193 #ifdef PARSE_TEST
194 g_print("found local part: %s\n", *local_begin);
195 #endif
196 if (*p == '@') {
197 p++; /* skip @ */
198 /* now the domain */
199 if (!read_domain(p, &b, &e)) {
200 return FALSE;
201 }
202 p = e;
203 *domain_begin = b;
204 *domain_end = e;
205 } else {
206 /* unqualified? */
207 *domain_begin = *domain_end = NULL;
208 }
209 break;
210
211 } else if (*p == '<') {
212 /* addr-spec follows */
213 while (isspace(*p) || (*p == '<')) {
214 if (*p == '<') {
215 angle_brackets++;
216 }
217 p++;
218 }
219 if (!read_word_with_dots(p, &b, &e)) {
236 return FALSE; 220 return FALSE;
237 } 221 }
238 /* trailing spaces and angle brackets */ 222 p = e;
239 #ifdef PARSE_TEST 223 *local_begin = b;
240 g_print("down counting trailing '>'\n"); 224 *local_end = e;
241 #endif 225 #ifdef PARSE_TEST
242 while (*p && (isspace(*p) || (*p == '>'))) { 226 g_print("found local part: %s\n", *local_begin);
243 if (*p == '>') 227 #endif
244 angle_brackets--; 228 if (*p == '@') {
245 p++; 229 p++;
246 } 230 if (!read_domain(p, &b, &e)) {
247 231 return FALSE;
248 *address_end = p; 232 }
249 233 p = e;
250 if (angle_brackets != 0) { 234 *domain_begin = b;
251 if (angle_brackets > 0) 235 *domain_end = e;
252 parse_error = g_strdup("missing '>' at end of string"); 236 } else {
253 else 237 /* may be unqualified address */
254 parse_error = g_strdup("superfluous '>' at end of string"); 238 *domain_begin = *domain_end = NULL;
255 return FALSE; 239 }
256 } else { 240 break;
257 /* we successfully parsed the address */ 241
258 return TRUE; 242 } else if (!*p || *p == '>') {
259 } 243 *local_begin = b;
260 /* we never get here */ 244 *local_end = e;
261 } 245 #ifdef PARSE_TEST
262 return FALSE; 246 g_print("found local part: %s\n", *local_begin);
247 #endif
248 *domain_begin = *domain_end = NULL;
249 break;
250
251 } else if (strchr(specials, *p) || iscntrl(*p) || isspace(*p)) {
252 parse_error = g_strdup_printf("unexpected character: %c", *p);
253 return FALSE;
254 }
255 }
256
257 /* trailing spaces and angle brackets */
258 #ifdef PARSE_TEST
259 g_print("down counting trailing '>'\n");
260 #endif
261 while (*p && (isspace(*p) || (*p == '>'))) {
262 if (*p == '>') {
263 angle_brackets--;
264 }
265 p++;
266 }
267
268 *address_end = p;
269
270 if (angle_brackets > 0) {
271 parse_error = g_strdup("missing '>' at end of string");
272 return FALSE;
273 } else if (angle_brackets < 0) {
274 parse_error = g_strdup("superfluous '>' at end of string");
275 return FALSE;
276 }
277
278 /* we successfully parsed the address */
279 return TRUE;
263 } 280 }
264 281
265 gboolean 282 gboolean
266 parse_address_rfc821(gchar* string, gchar** local_begin, gchar** local_end, gchar** domain_begin, 283 parse_address_rfc821(gchar* string, gchar** local_begin, gchar** local_end, gchar** domain_begin,
267 gchar** domain_end, gchar** address_end) 284 gchar** domain_end, gchar** address_end)
280 parse_error = NULL; 297 parse_error = NULL;
281 } 298 }
282 299
283 /* leading spaces and angle brackets */ 300 /* leading spaces and angle brackets */
284 while (*p && (isspace(*p) || (*p == '<'))) { 301 while (*p && (isspace(*p) || (*p == '<'))) {
285 if (*p == '<') 302 if (*p == '<') {
286 angle_brackets++; 303 angle_brackets++;
287 p++; 304 }
288 } 305 p++;
289 306 }
290 if (*p) { 307
291 while (TRUE) { 308 if (!*p) {
292 if (read_word_with_dots(p, &b, &e)) { 309 return FALSE;
310 }
311
312 while (TRUE) {
313 if (!read_word_with_dots(p, &b, &e)) {
314 return FALSE;
315 }
316
317 p = e;
318 #ifdef PARSE_TEST
319 g_print("after read_word_with_dots: %s\n", p);
320 #endif
321 *local_begin = b;
322 *local_end = e;
323 #ifdef PARSE_TEST
324 g_print("found local part: %s\n", *local_begin);
325 g_print("local_end = %s\n", *local_end);
326 #endif
327 if (!(*p) || isspace(*p) || (*p == '>')) {
328 /* unqualified ? */
329 domain_begin = domain_end = NULL;
330 break;
331 } else if (*p == '@') {
332 p++;
333 if (read_domain(p, &b, &e)) {
293 p = e; 334 p = e;
294 #ifdef PARSE_TEST 335 *domain_begin = b;
295 g_print("after read_word_with_dots: %s\n", p); 336 *domain_end = e;
296 #endif 337 }
297 *local_begin = b; 338 break;
298 *local_end = e;
299 #ifdef PARSE_TEST
300 g_print("found local part: %s\n", *local_begin);
301 g_print("local_end = %s\n", *local_end);
302 #endif
303 if (!(*p) || isspace(*p) || (*p == '>')) {
304 /* unqualified ? */
305 domain_begin = domain_end = NULL;
306 break;
307 } else if (*p == '@') {
308 p++;
309 if (read_domain(p, &b, &e)) {
310 p = e;
311 *domain_begin = b;
312 *domain_end = e;
313 }
314 break;
315 } else {
316 parse_error = g_strdup_printf ("unexpected character after local part '%c'", *p);
317 return FALSE;
318 }
319 } else
320 return FALSE;
321 }
322
323 /* trailing spaces and angle brackets */
324 #ifdef PARSE_TEST
325 g_print("down counting trailing '>'\n");
326 #endif
327 while (*p && (isspace(*p) || (*p == '>'))) {
328 if (*p == '>')
329 angle_brackets--;
330 p++;
331 }
332 *address_end = p;
333
334 if (angle_brackets != 0) {
335 if (angle_brackets > 0)
336 parse_error = g_strdup("missing '>' at end of string");
337 else
338 parse_error = g_strdup("superfluous '>' at end of string");
339 return FALSE;
340 } else { 339 } else {
341 /* we successfully parsed the address */ 340 parse_error = g_strdup_printf ("unexpected character after local part '%c'", *p);
342 return TRUE; 341 return FALSE;
343 } 342 }
344 /* we never get here */ 343 }
345 } 344
346 return FALSE; 345 /* trailing spaces and angle brackets */
346 #ifdef PARSE_TEST
347 g_print("down counting trailing '>'\n");
348 #endif
349 while (*p && (isspace(*p) || (*p == '>'))) {
350 if (*p == '>') {
351 angle_brackets--;
352 }
353 p++;
354 }
355 *address_end = p;
356
357 if (angle_brackets > 0) {
358 parse_error = g_strdup("missing '>' at end of string");
359 return FALSE;
360 } else if (angle_brackets < 0) {
361 parse_error = g_strdup("superfluous '>' at end of string");
362 return FALSE;
363 }
364
365 /* we successfully parsed the address */
366 return TRUE;
347 } 367 }
348 368
349 /* 369 /*
350 allocate address, reading from string. 370 allocate address, reading from string.
351 On failure, returns NULL. 371 On failure, returns NULL.
358 _create_address(gchar * string, gchar ** end, gboolean is_rfc821) 378 _create_address(gchar * string, gchar ** end, gboolean is_rfc821)
359 { 379 {
360 gchar *loc_beg, *loc_end; 380 gchar *loc_beg, *loc_end;
361 gchar *dom_beg, *dom_end; 381 gchar *dom_beg, *dom_end;
362 gchar *addr_end; 382 gchar *addr_end;
363 383 gboolean ret;
364 if (string && (string[0] == 0)) { 384
385 if (string && (string[0] == '\0')) {
365 address *addr = g_malloc(sizeof(address)); 386 address *addr = g_malloc(sizeof(address));
366 addr->address = g_strdup(""); 387 addr->address = g_strdup("");
367 addr->local_part = g_strdup(""); 388 addr->local_part = g_strdup("");
368 addr->domain = g_strdup(""); /* 'NULL' address (failure notice), 389 /* 'NULL' address (failure notice),
369 "" makes sure it will not be qualified with a hostname */ 390 "" makes sure it will not be qualified with a hostname */
391 addr->domain = g_strdup("");
370 return addr; 392 return addr;
371 } 393 }
372 394
373 if (is_rfc821 395 if (is_rfc821) {
374 ? parse_address_rfc821(string, &loc_beg, &loc_end, &dom_beg, &dom_end, &addr_end) 396 ret = parse_address_rfc821(string, &loc_beg, &loc_end, &dom_beg, &dom_end, &addr_end);
375 : parse_address_rfc822(string, &loc_beg, &loc_end, &dom_beg, &dom_end, &addr_end)) 397 } else {
376 { 398 ret = parse_address_rfc822(string, &loc_beg, &loc_end, &dom_beg, &dom_end, &addr_end);
377 address *addr = g_malloc(sizeof(address)); 399 }
378 gchar *p = addr_end; 400 if (!ret) {
379 401 return NULL;
380 memset(addr, 0, sizeof(address)); 402 }
381 403
382 if (loc_beg[0] == '|') { 404 address *addr = g_malloc(sizeof(address));
383 parse_error = g_strdup("no pipe allowed for RFC 822/821 address"); 405 gchar *p = addr_end;
384 return NULL; 406
385 } 407 memset(addr, 0, sizeof(address));
386 408
387 while (*p && (*p != ',')) 409 if (loc_beg[0] == '|') {
388 p++; 410 parse_error = g_strdup("no pipe allowed for RFC 822/821 address");
389 addr->address = g_strndup(string, p - string); 411 return NULL;
390 412 }
391 addr->local_part = g_strndup(loc_beg, loc_end - loc_beg); 413
392 414 while (*p && (*p != ',')) {
393 #ifdef PARSE_TEST 415 p++;
394 g_print("addr->local_part = %s\n", addr->local_part); 416 }
395 #endif 417 addr->address = g_strndup(string, p - string);
396 418 addr->local_part = g_strndup(loc_beg, loc_end - loc_beg);
397 if (dom_beg != NULL) { 419
398 addr->domain = g_strndup(dom_beg, dom_end - dom_beg); 420 #ifdef PARSE_TEST
399 } else { 421 g_print("addr->local_part = %s\n", addr->local_part);
400 if (addr->local_part[0] == 0) 422 #endif
401 addr->domain = g_strdup(""); /* 'NULL' address (failure notice), 423
402 "" makes sure it will not be qualified with a hostname */ 424 if (dom_beg != NULL) {
403 else 425 addr->domain = g_strndup(dom_beg, dom_end - dom_beg);
404 addr->domain = NULL; 426 } else if (addr->local_part[0] == 0) {
405 } 427 /* 'NULL' address (failure notice),
406 428 "" makes sure it will not be qualified with a hostname */
407 if (end != NULL) 429 addr->domain = g_strdup("");
408 *end = p; 430 } else {
431 addr->domain = NULL;
432 }
433
434 if (end != NULL) {
435 *end = p;
436 }
409 437
410 #ifndef PARSE_TEST 438 #ifndef PARSE_TEST
411 addr_unmark_delivered(addr); 439 addr_unmark_delivered(addr);
412 #endif 440 #endif
413 441
414 return addr; 442 return addr;
415 }
416 return NULL;
417 } 443 }
418 444
419 address* 445 address*
420 create_address_rfc822(gchar * string, gchar ** end) 446 create_address_rfc822(gchar * string, gchar ** end)
421 { 447 {
434 gchar *p = string; 460 gchar *p = string;
435 gchar *end; 461 gchar *end;
436 462
437 while (*p) { 463 while (*p) {
438 address *addr = _create_address(p, &end, FALSE); 464 address *addr = _create_address(p, &end, FALSE);
439 if (addr) { 465 fprintf(stderr, "string: %s\n", p);
440 if (domain) 466
441 if (addr->domain == NULL) 467 if (!addr) {
442 addr->domain = g_strdup(domain); 468 break;
443 469 }
444 addr_list = g_list_append(addr_list, addr); 470
445 p = end; 471 fprintf(stderr, " addr: %s (%s<@>%s)\n", addr->address, addr->local_part, addr->domain);
446 } else 472 if (domain && !addr->domain) {
447 break; 473 addr->domain = g_strdup(domain);
448 while (*p == ',' || isspace(*p)) 474 }
449 p++; 475 fprintf(stderr, " %s (%s<@>%s)\n", addr->address, addr->local_part, addr->domain);
476
477 addr_list = g_list_append(addr_list, addr);
478 p = end;
479
480 while (*p == ',' || isspace(*p)) {
481 p++;
482 }
450 } 483 }
451 return addr_list; 484 return addr_list;
452 } 485 }