1 /*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2002 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * $Id$
34 */
35
36 #include "mailmbox_parse.h"
37
38 #include "mailmbox.h"
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <string.h>
43 #include <stdlib.h>
44
45 #define UID_HEADER "X-LibEtPan-UID:"
46
47 #include "utils.h"
48
49 #ifndef TRUE
50 #define TRUE 1
51 #endif
52
53 #ifndef FALSE
54 #define FALSE 0
55 #endif
56
57 enum {
58 UNSTRUCTURED_START,
59 UNSTRUCTURED_CR,
60 UNSTRUCTURED_LF,
61 UNSTRUCTURED_WSP,
62 UNSTRUCTURED_OUT
63 };
64
65 static inline int
claws_mailmbox_fields_parse(char * str,size_t length,size_t * index,uint32_t * puid,size_t * phlen)66 claws_mailmbox_fields_parse(char * str, size_t length,
67 size_t * index,
68 uint32_t * puid,
69 size_t * phlen)
70 {
71 size_t cur_token;
72 int r;
73 size_t hlen;
74 size_t uid;
75 int end;
76
77 cur_token = * index;
78
79 end = FALSE;
80 uid = 0;
81 while (!end) {
82 size_t begin;
83
84 begin = cur_token;
85
86 r = mailimf_ignore_field_parse(str, length, &cur_token);
87 switch (r) {
88 case MAILIMF_NO_ERROR:
89 if (str[begin] == 'X') {
90
91 if (strncasecmp(str + begin, UID_HEADER, strlen(UID_HEADER)) == 0) {
92 begin += strlen(UID_HEADER);
93
94 while (str[begin] == ' ')
95 begin ++;
96
97 uid = strtoul(str + begin, NULL, 10);
98 }
99 }
100
101 break;
102 case MAILIMF_ERROR_PARSE:
103 default:
104 end = TRUE;
105 break;
106 }
107 }
108
109 hlen = cur_token - * index;
110
111 * phlen = hlen;
112 * puid = uid;
113 * index = cur_token;
114
115 return MAILMBOX_NO_ERROR;
116 }
117
118 enum {
119 IN_MAIL,
120 FIRST_CR,
121 FIRST_LF,
122 SECOND_CR,
123 SECOND_LF,
124 PARSING_F,
125 PARSING_R,
126 PARSING_O,
127 PARSING_M,
128 OUT_MAIL
129 };
130
131
132
133
134 static inline int
claws_mailmbox_single_parse(char * str,size_t length,size_t * index,size_t * pstart,size_t * pstart_len,size_t * pheaders,size_t * pheaders_len,size_t * pbody,size_t * pbody_len,size_t * psize,size_t * ppadding,uint32_t * puid)135 claws_mailmbox_single_parse(char * str, size_t length,
136 size_t * index,
137 size_t * pstart,
138 size_t * pstart_len,
139 size_t * pheaders,
140 size_t * pheaders_len,
141 size_t * pbody,
142 size_t * pbody_len,
143 size_t * psize,
144 size_t * ppadding,
145 uint32_t * puid)
146 {
147 size_t cur_token;
148 size_t start;
149 size_t start_len;
150 size_t headers;
151 size_t headers_len;
152 size_t body;
153 size_t end;
154 size_t next;
155 size_t message_length;
156 uint32_t uid;
157 int r;
158 #if 0
159 int in_mail_data;
160 #endif
161 #if 0
162 size_t begin;
163 #endif
164
165 int state;
166
167 cur_token = * index;
168
169 if (cur_token >= length)
170 return MAILMBOX_ERROR_PARSE;
171
172 start = cur_token;
173 start_len = 0;
174 headers = cur_token;
175
176 if (cur_token + 5 < length) {
177 if (strncmp(str + cur_token, "From ", 5) == 0) {
178 cur_token += 5;
179 while (str[cur_token] != '\n') {
180 cur_token ++;
181 if (cur_token >= length)
182 break;
183 }
184 if (cur_token < length) {
185 cur_token ++;
186 headers = cur_token;
187 start_len = headers - start;
188 }
189 }
190 }
191
192 next = length;
193
194 r = claws_mailmbox_fields_parse(str, length, &cur_token,
195 &uid, &headers_len);
196 if (r != MAILMBOX_NO_ERROR)
197 return r;
198
199 /* save position */
200 #if 0
201 begin = cur_token;
202 #endif
203
204 mailimf_crlf_parse(str, length, &cur_token);
205
206 #if 0
207 if (str[cur_token] == 'F') {
208 printf("start !\n");
209 printf("%50.50s\n", str + cur_token);
210 getchar();
211 }
212 #endif
213
214 body = cur_token;
215
216 /* restore position */
217 /* cur_token = begin; */
218
219 state = FIRST_LF;
220
221 end = length;
222
223 #if 0
224 in_mail_data = 0;
225 #endif
226 while (state != OUT_MAIL) {
227
228 if (cur_token >= length) {
229 if (state == IN_MAIL)
230 end = length;
231 next = length;
232 break;
233 }
234
235 switch(state) {
236 case IN_MAIL:
237 switch(str[cur_token]) {
238 case '\r':
239 state = FIRST_CR;
240 break;
241 case '\n':
242 state = FIRST_LF;
243 break;
244 case 'F':
245 if (cur_token == body) {
246 end = cur_token;
247 next = cur_token;
248 state = PARSING_F;
249 }
250 break;
251 #if 0
252 default:
253 in_mail_data = 1;
254 break;
255 #endif
256 }
257 break;
258
259 case FIRST_CR:
260 end = cur_token;
261 switch(str[cur_token]) {
262 case '\r':
263 state = SECOND_CR;
264 break;
265 case '\n':
266 state = FIRST_LF;
267 break;
268 default:
269 state = IN_MAIL;
270 #if 0
271 in_mail_data = 1;
272 #endif
273 break;
274 }
275 break;
276
277 case FIRST_LF:
278 end = cur_token;
279 switch(str[cur_token]) {
280 case '\r':
281 state = SECOND_CR;
282 break;
283 case '\n':
284 state = SECOND_LF;
285 break;
286 default:
287 state = IN_MAIL;
288 #if 0
289 in_mail_data = 1;
290 #endif
291 break;
292 }
293 break;
294
295 case SECOND_CR:
296 switch(str[cur_token]) {
297 case '\r':
298 end = cur_token;
299 break;
300 case '\n':
301 state = SECOND_LF;
302 break;
303 case 'F':
304 next = cur_token;
305 state = PARSING_F;
306 break;
307 default:
308 state = IN_MAIL;
309 #if 0
310 in_mail_data = 1;
311 #endif
312 break;
313 }
314 break;
315
316 case SECOND_LF:
317 switch(str[cur_token]) {
318 case '\r':
319 state = SECOND_CR;
320 break;
321 case '\n':
322 end = cur_token;
323 break;
324 case 'F':
325 next = cur_token;
326 state = PARSING_F;
327 break;
328 default:
329 state = IN_MAIL;
330 #if 0
331 in_mail_data = 1;
332 #endif
333 break;
334 }
335 break;
336
337 case PARSING_F:
338 switch(str[cur_token]) {
339 case 'r':
340 state = PARSING_R;
341 break;
342 default:
343 state = IN_MAIL;
344 #if 0
345 in_mail_data = 1;
346 #endif
347 break;
348 }
349 break;
350
351 case PARSING_R:
352 switch(str[cur_token]) {
353 case 'o':
354 state = PARSING_O;
355 break;
356 default:
357 state = IN_MAIL;
358 #if 0
359 in_mail_data = 1;
360 #endif
361 break;
362 }
363 break;
364
365 case PARSING_O:
366 switch(str[cur_token]) {
367 case 'm':
368 state = PARSING_M;
369 break;
370 default:
371 state = IN_MAIL;
372 #if 0
373 in_mail_data = 1;
374 #endif
375 break;
376 }
377 break;
378
379 case PARSING_M:
380 switch(str[cur_token]) {
381 case ' ':
382 state = OUT_MAIL;
383 break;
384 default:
385 state = IN_MAIL;
386 break;
387 }
388 break;
389 }
390
391 cur_token ++;
392 }
393
394 message_length = end - start;
395
396 * pstart = start;
397 * pstart_len = start_len;
398 * pheaders = headers;
399 * pheaders_len = headers_len;
400 * pbody = body;
401 * pbody_len = end - body;
402 * psize = message_length;
403 * ppadding = next - end;
404 * puid = uid;
405
406 * index = next;
407
408 return MAILMBOX_NO_ERROR;
409 }
410
411
412 int
claws_mailmbox_parse_additionnal(struct claws_mailmbox_folder * folder,size_t * index)413 claws_mailmbox_parse_additionnal(struct claws_mailmbox_folder * folder,
414 size_t * index)
415 {
416 size_t cur_token;
417
418 size_t start;
419 size_t start_len;
420 size_t headers;
421 size_t headers_len;
422 size_t body;
423 size_t body_len;
424 size_t size;
425 size_t padding;
426 uint32_t uid;
427 int r;
428 int res;
429
430 uint32_t max_uid;
431 uint32_t first_index;
432 unsigned int i;
433 unsigned int j;
434
435 cur_token = * index;
436
437 /* remove temporary UID that we will parse */
438
439 first_index = carray_count(folder->mb_tab);
440
441 for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
442 struct claws_mailmbox_msg_info * info;
443
444 info = carray_get(folder->mb_tab, i);
445
446 if (info->msg_start < cur_token) {
447 continue;
448 }
449
450 if (!info->msg_written_uid) {
451 chashdatum key;
452
453 key.data = &info->msg_uid;
454 key.len = sizeof(info->msg_uid);
455
456 chash_delete(folder->mb_hash, &key, NULL);
457 carray_delete_fast(folder->mb_tab, i);
458 claws_mailmbox_msg_info_free(info);
459 if (i < first_index)
460 first_index = i;
461 }
462 }
463
464 /* make a sequence in the table */
465
466 max_uid = folder->mb_written_uid;
467
468 i = 0;
469 j = 0;
470 while (i < carray_count(folder->mb_tab)) {
471 struct claws_mailmbox_msg_info * info;
472
473 info = carray_get(folder->mb_tab, i);
474 if (info != NULL) {
475 carray_set(folder->mb_tab, j, info);
476
477 if (info->msg_uid > max_uid)
478 max_uid = info->msg_uid;
479
480 info->msg_index = j;
481 j ++;
482 }
483 i ++;
484 }
485 carray_set_size(folder->mb_tab, j);
486
487 /* parse content */
488
489 first_index = j;
490
491 while (1) {
492 struct claws_mailmbox_msg_info * info;
493 chashdatum key;
494 chashdatum data;
495
496 r = claws_mailmbox_single_parse(folder->mb_mapping, folder->mb_mapping_size,
497 &cur_token,
498 &start, &start_len,
499 &headers, &headers_len,
500 &body, &body_len,
501 &size, &padding, &uid);
502 if (r == MAILMBOX_NO_ERROR) {
503 /* do nothing */
504 }
505 else if (r == MAILMBOX_ERROR_PARSE) {
506 break;
507 } else {
508 res = r;
509 goto err;
510 }
511
512 key.data = &uid;
513 key.len = sizeof(uid);
514
515 r = chash_get(folder->mb_hash, &key, &data);
516 if (r == 0) {
517 info = data.data;
518
519 if (!info->msg_written_uid) {
520 /* some new mail has been written and override an
521 existing temporary UID */
522
523 chash_delete(folder->mb_hash, &key, NULL);
524 info->msg_uid = 0;
525
526 if (info->msg_index < first_index)
527 first_index = info->msg_index;
528 }
529 else
530 uid = 0;
531 }
532
533 if (uid > max_uid)
534 max_uid = uid;
535
536 r = claws_mailmbox_msg_info_update(folder,
537 start, start_len, headers, headers_len,
538 body, body_len, size, padding, uid);
539 if (r != MAILMBOX_NO_ERROR) {
540 debug_print("claws_mailmbox_msg_info_update failed with %d\n", r);
541 res = r;
542 goto err;
543 }
544 }
545
546 * index = cur_token;
547
548 folder->mb_written_uid = max_uid;
549
550 /* attribute uid */
551
552 for(i = first_index ; i < carray_count(folder->mb_tab) ; i ++) {
553 struct claws_mailmbox_msg_info * info;
554 chashdatum key;
555 chashdatum data;
556
557 info = carray_get(folder->mb_tab, i);
558
559 if (info->msg_uid != 0) {
560 continue;
561 }
562
563 max_uid ++;
564 info->msg_uid = max_uid;
565
566 key.data = &info->msg_uid;
567 key.len = sizeof(info->msg_uid);
568 data.data = info;
569 data.len = 0;
570
571 r = chash_set(folder->mb_hash, &key, &data, NULL);
572 if (r < 0) {
573 debug_print("chash_set failed with %d\n", r);
574 res = MAILMBOX_ERROR_MEMORY;
575 goto err;
576 }
577 }
578
579 folder->mb_max_uid = max_uid;
580
581 return MAILMBOX_NO_ERROR;
582
583 err:
584 return res;
585 }
586
flush_uid(struct claws_mailmbox_folder * folder)587 static void flush_uid(struct claws_mailmbox_folder * folder)
588 {
589 unsigned int i;
590
591 for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
592 struct claws_mailmbox_msg_info * info;
593
594 info = carray_get(folder->mb_tab, i);
595 if (info != NULL)
596 claws_mailmbox_msg_info_free(info);
597 }
598
599 chash_clear(folder->mb_hash);
600 carray_set_size(folder->mb_tab, 0);
601 }
602
claws_mailmbox_parse(struct claws_mailmbox_folder * folder)603 int claws_mailmbox_parse(struct claws_mailmbox_folder * folder)
604 {
605 int r;
606 int res;
607 size_t cur_token;
608
609 flush_uid(folder);
610
611 cur_token = 0;
612
613 r = claws_mailmbox_parse_additionnal(folder, &cur_token);
614
615 if (r != MAILMBOX_NO_ERROR) {
616 res = r;
617 goto err;
618 }
619
620 return MAILMBOX_NO_ERROR;
621
622 err:
623 return res;
624 }
625