Mercurial > masqmail
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 } |