Statistics
| Branch: | Tag: | Revision:

root / libsylph / procheader.c @ aebfd4cc

History | View | Annotate | Download (18.3 KB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2011 Hiroyuki Yamamoto
4
 */
5

    
6
#ifdef HAVE_CONFIG_H
7
#  include "config.h"
8
#endif
9

    
10
#include <glib.h>
11
#include <stdio.h>
12
#include <string.h>
13
#include <stdlib.h>
14
#include <time.h>
15
#include <sys/stat.h>
16

    
17
#include "procheader.h"
18
#include "procmsg.h"
19
#include "codeconv.h"
20
#include "utils.h"
21

    
22
#define BUFFSIZE        8192
23

    
24
gint procheader_get_one_field(gchar *buf, size_t len, FILE *fp,
25
                              HeaderEntry hentry[])
26
{
27
        gint nexthead;
28
        gint hnum = 0;
29
        HeaderEntry *hp = NULL;
30

    
31
        if (hentry != NULL) {
32
                /* skip non-required headers */
33
                do {
34
                        do {
35
                                if (fgets(buf, len, fp) == NULL)
36
                                        return -1;
37
                                if (buf[0] == '\r' || buf[0] == '\n')
38
                                        return -1;
39
                        } while (buf[0] == ' ' || buf[0] == '\t');
40

    
41
                        for (hp = hentry, hnum = 0; hp->name != NULL;
42
                             hp++, hnum++) {
43
                                if (!g_ascii_strncasecmp(hp->name, buf,
44
                                                         strlen(hp->name)))
45
                                        break;
46
                        }
47
                } while (hp->name == NULL);
48
        } else {
49
                if (fgets(buf, len, fp) == NULL) return -1;
50
                if (buf[0] == '\r' || buf[0] == '\n') return -1;
51
        }
52

    
53
        /* unfold the specified folded line */
54
        if (hp && hp->unfold) {
55
                gboolean folded = FALSE;
56
                gchar *bufp = buf + strlen(buf);
57

    
58
                for (; bufp > buf &&
59
                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
60
                     bufp--)
61
                        *(bufp - 1) = '\0';
62

    
63
                while (1) {
64
                        nexthead = fgetc(fp);
65

    
66
                        /* folded */
67
                        if (nexthead == ' ' || nexthead == '\t')
68
                                folded = TRUE;
69
                        else if (nexthead == EOF)
70
                                break;
71
                        else if (folded == TRUE) {
72
                                if ((len - (bufp - buf)) <= 2) break;
73

    
74
                                if (nexthead == '\n') {
75
                                        folded = FALSE;
76
                                        continue;
77
                                }
78

    
79
                                /* replace return code on the tail end
80
                                   with space */
81
                                *bufp++ = ' ';
82
                                *bufp++ = nexthead;
83
                                *bufp = '\0';
84

    
85
                                /* concatenate next line */
86
                                if (fgets(bufp, len - (bufp - buf), fp)
87
                                    == NULL) break;
88
                                bufp += strlen(bufp);
89

    
90
                                for (; bufp > buf &&
91
                                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
92
                                     bufp--)
93
                                        *(bufp - 1) = '\0';
94

    
95
                                folded = FALSE;
96
                        } else {
97
                                ungetc(nexthead, fp);
98
                                break;
99
                        }
100
                }
101

    
102
                return hnum;
103
        }
104

    
105
        while (1) {
106
                nexthead = fgetc(fp);
107
                if (nexthead == ' ' || nexthead == '\t') {
108
                        size_t buflen = strlen(buf);
109

    
110
                        /* concatenate next line */
111
                        if ((len - buflen) > 2) {
112
                                gchar *p = buf + buflen;
113

    
114
                                *p++ = nexthead;
115
                                *p = '\0';
116
                                buflen++;
117
                                if (fgets(p, len - buflen, fp) == NULL)
118
                                        break;
119
                        } else
120
                                break;
121
                } else {
122
                        if (nexthead != EOF)
123
                                ungetc(nexthead, fp);
124
                        break;
125
                }
126
        }
127

    
128
        /* remove trailing return code */
129
        strretchomp(buf);
130

    
131
        return hnum;
132
}
133

    
134
gchar *procheader_get_unfolded_line(gchar *buf, size_t len, FILE *fp)
135
{
136
        gboolean folded = FALSE;
137
        gint nexthead;
138
        gchar *bufp;
139

    
140
        if (fgets(buf, len, fp) == NULL) return NULL;
141
        if (buf[0] == '\r' || buf[0] == '\n') return NULL;
142
        bufp = buf + strlen(buf);
143

    
144
        for (; bufp > buf &&
145
             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
146
             bufp--)
147
                *(bufp - 1) = '\0';
148

    
149
        while (1) {
150
                nexthead = fgetc(fp);
151

    
152
                /* folded */
153
                if (nexthead == ' ' || nexthead == '\t')
154
                        folded = TRUE;
155
                else if (nexthead == EOF)
156
                        break;
157
                else if (folded == TRUE) {
158
                        if ((len - (bufp - buf)) <= 2) break;
159

    
160
                        if (nexthead == '\n') {
161
                                folded = FALSE;
162
                                continue;
163
                        }
164

    
165
                        /* replace return code on the tail end
166
                           with space */
167
                        *bufp++ = ' ';
168
                        *bufp++ = nexthead;
169
                        *bufp = '\0';
170

    
171
                        /* concatenate next line */
172
                        if (fgets(bufp, len - (bufp - buf), fp)
173
                            == NULL) break;
174
                        bufp += strlen(bufp);
175

    
176
                        for (; bufp > buf &&
177
                             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
178
                             bufp--)
179
                                *(bufp - 1) = '\0';
180

    
181
                        folded = FALSE;
182
                } else {
183
                        ungetc(nexthead, fp);
184
                        break;
185
                }
186
        }
187

    
188
        /* remove trailing return code */
189
        strretchomp(buf);
190

    
191
        return buf;
192
}
193

    
194
GSList *procheader_get_header_list_from_file(const gchar *file)
195
{
196
        FILE *fp;
197
        GSList *hlist;
198

    
199
        if ((fp = g_fopen(file, "rb")) == NULL) {
200
                FILE_OP_ERROR(file, "procheader_get_header_list_from_file: fopen");
201
                return NULL;
202
        }
203

    
204
        hlist = procheader_get_header_list(fp);
205

    
206
        fclose(fp);
207
        return hlist;
208
}
209

    
210
GSList *procheader_get_header_list(FILE *fp)
211
{
212
        gchar buf[BUFFSIZE];
213
        gchar *p;
214
        GSList *hlist = NULL;
215
        Header *header;
216

    
217
        g_return_val_if_fail(fp != NULL, NULL);
218

    
219
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) {
220
                if (*buf == ':') continue;
221
                for (p = buf; *p && *p != ' '; p++) {
222
                        if (*p == ':') {
223
                                header = g_new(Header, 1);
224
                                header->name = g_strndup(buf, p - buf);
225
                                p++;
226
                                while (*p == ' ' || *p == '\t') p++;
227
                                header->body = conv_unmime_header(p, NULL);
228

    
229
                                hlist = g_slist_append(hlist, header);
230
                                break;
231
                        }
232
                }
233
        }
234

    
235
        return hlist;
236
}
237

    
238
GSList *procheader_get_header_list_from_msginfo(MsgInfo *msginfo)
239
{
240
        GSList *hlist = NULL;
241

    
242
        g_return_val_if_fail(msginfo != NULL, NULL);
243

    
244
        if (msginfo->subject)
245
                hlist = procheader_add_header_list(hlist, "Subject",
246
                                                   msginfo->subject);
247
        if (msginfo->from)
248
                hlist = procheader_add_header_list(hlist, "From",
249
                                                   msginfo->from);
250
        if (msginfo->to)
251
                hlist = procheader_add_header_list(hlist, "To", msginfo->to);
252
        if (msginfo->cc)
253
                hlist = procheader_add_header_list(hlist, "Cc", msginfo->cc);
254
        if (msginfo->newsgroups)
255
                hlist = procheader_add_header_list(hlist, "Newsgroups",
256
                                                   msginfo->newsgroups);
257
        if (msginfo->date)
258
                hlist = procheader_add_header_list(hlist, "Date",
259
                                                   msginfo->date);
260

    
261
        return hlist;
262
}
263

    
264
GSList *procheader_add_header_list(GSList *hlist, const gchar *header_name,
265
                                  const gchar *body)
266
{
267
        Header *header;
268

    
269
        g_return_val_if_fail(header_name != NULL, hlist);
270

    
271
        header = g_new(Header, 1);
272
        header->name = g_strdup(header_name);
273
        header->body = g_strdup(body);
274

    
275
        return g_slist_append(hlist, header);
276
}
277

    
278
GSList *procheader_copy_header_list(GSList *hlist)
279
{
280
        GSList *newlist = NULL, *cur;
281

    
282
        for (cur = hlist; cur != NULL; cur = cur->next) {
283
                Header *header = (Header *)cur->data;
284
                newlist = procheader_add_header_list(newlist, header->name,
285
                                                     header->body);
286
        }
287

    
288
        return newlist;
289
}
290

    
291
GSList *procheader_merge_header_list(GSList *hlist1, GSList *hlist2)
292
{
293
        GSList *cur;
294

    
295
        for (cur = hlist2; cur != NULL; cur = cur->next) {
296
                Header *header = (Header *)cur->data;
297
                if (procheader_find_header_list(hlist1, header->name) < 0)
298
                        hlist1 = g_slist_append(hlist1, header);
299
        }
300

    
301
        return hlist1;
302
}
303

    
304
GSList *procheader_merge_header_list_dup(GSList *hlist1, GSList *hlist2)
305
{
306
        GSList *list, *cur;
307

    
308
        list = procheader_copy_header_list(hlist1);
309

    
310
        for (cur = hlist2; cur != NULL; cur = cur->next) {
311
                Header *header = (Header *)cur->data;
312
                if (procheader_find_header_list(list, header->name) < 0)
313
                        list = procheader_add_header_list(list, header->name,
314
                                                          header->body);
315
        }
316

    
317
        return list;
318
}
319

    
320
gint procheader_find_header_list(GSList *hlist, const gchar *header_name)
321
{
322
        GSList *cur;
323
        gint index = 0;
324
        Header *header;
325

    
326
        g_return_val_if_fail(header_name != NULL, -1);
327

    
328
        for (cur = hlist; cur != NULL; cur = cur->next, index++) {
329
                header = (Header *)cur->data;
330
                if (g_ascii_strcasecmp(header->name, header_name) == 0)
331
                        return index;
332
        }
333

    
334
        return -1;
335
}
336

    
337
GPtrArray *procheader_get_header_array(FILE *fp, const gchar *encoding)
338
{
339
        gchar buf[BUFFSIZE];
340
        gchar *p;
341
        GPtrArray *headers;
342
        Header *header;
343

    
344
        g_return_val_if_fail(fp != NULL, NULL);
345

    
346
        headers = g_ptr_array_new();
347

    
348
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) {
349
                if (*buf == ':') continue;
350
                for (p = buf; *p && *p != ' '; p++) {
351
                        if (*p == ':') {
352
                                header = g_new(Header, 1);
353
                                header->name = g_strndup(buf, p - buf);
354
                                p++;
355
                                while (*p == ' ' || *p == '\t') p++;
356
                                header->body = conv_unmime_header(p, encoding);
357

    
358
                                g_ptr_array_add(headers, header);
359
                                break;
360
                        }
361
                }
362
        }
363

    
364
        return headers;
365
}
366

    
367
GPtrArray *procheader_get_header_array_asis(FILE *fp, const gchar *encoding)
368
{
369
        gchar buf[BUFFSIZE];
370
        gchar *p;
371
        GPtrArray *headers;
372
        Header *header;
373

    
374
        g_return_val_if_fail(fp != NULL, NULL);
375

    
376
        headers = g_ptr_array_new();
377

    
378
        while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
379
                if (*buf == ':') continue;
380
                for (p = buf; *p && *p != ' '; p++) {
381
                        if (*p == ':') {
382
                                header = g_new(Header, 1);
383
                                header->name = g_strndup(buf, p - buf);
384
                                p++;
385
                                header->body = conv_unmime_header(p, encoding);
386

    
387
                                g_ptr_array_add(headers, header);
388
                                break;
389
                        }
390
                }
391
        }
392

    
393
        return headers;
394
}
395

    
396
void procheader_header_list_destroy(GSList *hlist)
397
{
398
        Header *header;
399

    
400
        while (hlist != NULL) {
401
                header = hlist->data;
402
                procheader_header_free(header);
403
                hlist = g_slist_remove(hlist, header);
404
        }
405
}
406

    
407
void procheader_header_array_destroy(GPtrArray *harray)
408
{
409
        gint i;
410
        Header *header;
411

    
412
        for (i = 0; i < harray->len; i++) {
413
                header = g_ptr_array_index(harray, i);
414
                procheader_header_free(header);
415
        }
416

    
417
        g_ptr_array_free(harray, TRUE);
418
}
419

    
420
void procheader_header_free(Header *header)
421
{
422
        if (!header) return;
423

    
424
        g_free(header->name);
425
        g_free(header->body);
426
        g_free(header);
427
}
428

    
429
void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[])
430
{
431
        gchar buf[BUFFSIZE];
432
        HeaderEntry *hp;
433
        gint hnum;
434
        gchar *p;
435

    
436
        if (hentry == NULL) return;
437

    
438
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
439
               != -1) {
440
                hp = hentry + hnum;
441

    
442
                p = buf + strlen(hp->name);
443
                while (*p == ' ' || *p == '\t') p++;
444

    
445
                if (hp->body == NULL)
446
                        hp->body = g_strdup(p);
447
                else if (!g_ascii_strcasecmp(hp->name, "To:") ||
448
                         !g_ascii_strcasecmp(hp->name, "Cc:")) {
449
                        gchar *tp = hp->body;
450
                        hp->body = g_strconcat(tp, ", ", p, NULL);
451
                        g_free(tp);
452
                }
453
        }
454
}
455

    
456
MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags,
457
                               gboolean full)
458
{
459
        struct stat s;
460
        FILE *fp;
461
        MsgInfo *msginfo;
462

    
463
        if (g_stat(file, &s) < 0) {
464
                FILE_OP_ERROR(file, "stat");
465
                return NULL;
466
        }
467
        if (!S_ISREG(s.st_mode))
468
                return NULL;
469

    
470
        if ((fp = g_fopen(file, "rb")) == NULL) {
471
                FILE_OP_ERROR(file, "procheader_parse_file: fopen");
472
                return NULL;
473
        }
474

    
475
        msginfo = procheader_parse_stream(fp, flags, full);
476
        fclose(fp);
477

    
478
        if (msginfo) {
479
                msginfo->size = s.st_size;
480
                msginfo->mtime = s.st_mtime;
481
        }
482

    
483
        return msginfo;
484
}
485

    
486
MsgInfo *procheader_parse_str(const gchar *str, MsgFlags flags, gboolean full)
487
{
488
        FILE *fp;
489
        MsgInfo *msginfo;
490

    
491
        if ((fp = str_open_as_stream(str)) == NULL)
492
                return NULL;
493

    
494
        msginfo = procheader_parse_stream(fp, flags, full);
495
        fclose(fp);
496
        return msginfo;
497
}
498

    
499
enum
500
{
501
        H_DATE                = 0,
502
        H_FROM                = 1,
503
        H_TO                = 2,
504
        H_NEWSGROUPS        = 3,
505
        H_SUBJECT        = 4,
506
        H_MSG_ID        = 5,
507
        H_REFERENCES        = 6,
508
        H_IN_REPLY_TO        = 7,
509
        H_CONTENT_TYPE        = 8,
510
        H_SEEN                = 9,
511
        H_CC                = 10,
512
        H_X_FACE        = 11
513
};
514

    
515
MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full)
516
{
517
        static HeaderEntry hentry_full[] = {{"Date:",                NULL, FALSE},
518
                                           {"From:",                NULL, TRUE},
519
                                           {"To:",                NULL, TRUE},
520
                                           {"Newsgroups:",        NULL, TRUE},
521
                                           {"Subject:",                NULL, TRUE},
522
                                           {"Message-Id:",        NULL, FALSE},
523
                                           {"References:",        NULL, FALSE},
524
                                           {"In-Reply-To:",        NULL, FALSE},
525
                                           {"Content-Type:",        NULL, FALSE},
526
                                           {"Seen:",                NULL, FALSE},
527
                                           {"Cc:",                NULL, TRUE},
528
                                           {"X-Face:",                NULL, FALSE},
529
                                           {NULL,                NULL, FALSE}};
530

    
531
        static HeaderEntry hentry_short[] = {{"Date:",                NULL, FALSE},
532
                                            {"From:",                NULL, TRUE},
533
                                            {"To:",                NULL, TRUE},
534
                                            {"Newsgroups:",        NULL, TRUE},
535
                                            {"Subject:",        NULL, TRUE},
536
                                            {"Message-Id:",        NULL, FALSE},
537
                                            {"References:",        NULL, FALSE},
538
                                            {"In-Reply-To:",        NULL, FALSE},
539
                                            {"Content-Type:",        NULL, FALSE},
540
                                            {"Seen:",                NULL, FALSE},
541
                                            {NULL,                NULL, FALSE}};
542

    
543
        MsgInfo *msginfo;
544
        gchar buf[BUFFSIZE];
545
        gchar *p;
546
        gchar *hp;
547
        HeaderEntry *hentry;
548
        gint hnum;
549
        gchar *from = NULL, *to = NULL, *subject = NULL, *cc = NULL;
550
        gchar *charset = NULL;
551

    
552
        hentry = full ? hentry_full : hentry_short;
553

    
554
        if (MSG_IS_QUEUED(flags)) {
555
                while (fgets(buf, sizeof(buf), fp) != NULL)
556
                        if (buf[0] == '\r' || buf[0] == '\n') break;
557
        }
558

    
559
        msginfo = g_new0(MsgInfo, 1);
560
        msginfo->flags = flags;
561
        msginfo->references = NULL;
562
        msginfo->inreplyto = NULL;
563

    
564
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
565
               != -1) {
566
                hp = buf + strlen(hentry[hnum].name);
567
                while (*hp == ' ' || *hp == '\t') hp++;
568

    
569
                switch (hnum) {
570
                case H_DATE:
571
                        if (msginfo->date) break;
572
                        msginfo->date_t =
573
                                procheader_date_parse(NULL, hp, 0);
574
                        msginfo->date = g_strdup(hp);
575
                        break;
576
                case H_FROM:
577
                        if (from) break;
578
                        from = g_strdup(hp);
579
                        break;
580
                case H_TO:
581
                        if (to) {
582
                                p = to;
583
                                to = g_strconcat(p, ", ", hp, NULL);
584
                                g_free(p);
585
                        } else
586
                                to = g_strdup(hp);
587
                        break;
588
                case H_NEWSGROUPS:
589
                        if (msginfo->newsgroups) {
590
                                p = msginfo->newsgroups;
591
                                msginfo->newsgroups =
592
                                        g_strconcat(p, ",", hp, NULL);
593
                                g_free(p);
594
                        } else
595
                                msginfo->newsgroups = g_strdup(buf + 12);
596
                        break;
597
                case H_SUBJECT:
598
                        if (msginfo->subject) break;
599
                        subject = g_strdup(hp);
600
                        break;
601
                case H_MSG_ID:
602
                        if (msginfo->msgid) break;
603

    
604
                        extract_parenthesis(hp, '<', '>');
605
                        remove_space(hp);
606
                        msginfo->msgid = g_strdup(hp);
607
                        break;
608
                case H_REFERENCES:
609
                        msginfo->references =
610
                                references_list_prepend(msginfo->references,
611
                                                        hp);
612
                        break;
613
                case H_IN_REPLY_TO:
614
                        if (msginfo->inreplyto) break;
615

    
616
                        eliminate_parenthesis(hp, '(', ')');
617
                        if ((p = strrchr(hp, '<')) != NULL &&
618
                            strchr(p + 1, '>') != NULL) {
619
                                extract_parenthesis(p, '<', '>');
620
                                remove_space(p);
621
                                if (*p != '\0')
622
                                        msginfo->inreplyto = g_strdup(p);
623
                        }
624
                        break;
625
                case H_CONTENT_TYPE:
626
                        if (!g_ascii_strncasecmp(hp, "multipart", 9)) {
627
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME);
628
                        } else if (!charset) {
629
                                procmime_scan_content_type_str
630
                                        (hp, NULL, &charset, NULL, NULL);
631
                        }
632
                        break;
633
                case H_SEEN:
634
                        /* mnews Seen header */
635
                        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD);
636
                        break;
637
                case H_CC:
638
                        if (cc) {
639
                                p = cc;
640
                                cc = g_strconcat(p, ", ", hp, NULL);
641
                                g_free(p);
642
                        } else
643
                                cc = g_strdup(hp);
644
                        break;
645
                case H_X_FACE:
646
                        if (msginfo->xface) break;
647
                        msginfo->xface = g_strdup(hp);
648
                        break;
649
                default:
650
                        break;
651
                }
652
        }
653

    
654
        if (from) {
655
                msginfo->from = conv_unmime_header(from, charset);
656
                subst_control(msginfo->from, ' ');
657
                msginfo->fromname = procheader_get_fromname(msginfo->from);
658
                g_free(from);
659
        }
660
        if (to) {
661
                msginfo->to = conv_unmime_header(to, charset);
662
                subst_control(msginfo->to, ' ');
663
                g_free(to);
664
        }
665
        if (subject) {
666
                msginfo->subject = conv_unmime_header(subject, charset);
667
                subst_control(msginfo->subject, ' ');
668
                g_free(subject);
669
        }
670
        if (cc) {
671
                msginfo->cc = conv_unmime_header(cc, charset);
672
                subst_control(msginfo->cc, ' ');
673
                g_free(cc);
674
        }
675

    
676
        if (!msginfo->inreplyto && msginfo->references)
677
                msginfo->inreplyto =
678
                        g_strdup((gchar *)msginfo->references->data);
679

    
680
        g_free(charset);
681

    
682
        return msginfo;
683
}
684

    
685
gchar *procheader_get_fromname(const gchar *str)
686
{
687
        gchar *tmp, *name;
688

    
689
        tmp = g_strdup(str);
690

    
691
        if (*tmp == '\"') {
692
                extract_quote_with_escape(tmp, '\"');
693
                g_strstrip(tmp);
694
        } else if (strchr(tmp, '<')) {
695
                eliminate_parenthesis(tmp, '<', '>');
696
                g_strstrip(tmp);
697
                if (*tmp == '\0') {
698
                        strcpy(tmp, str);
699
                        extract_parenthesis(tmp, '<', '>');
700
                        g_strstrip(tmp);
701
                }
702
        } else if (strchr(tmp, '(')) {
703
                extract_parenthesis_with_escape(tmp, '(', ')');
704
                g_strstrip(tmp);
705
        }
706

    
707
        if (*tmp == '\0') {
708
                g_free(tmp);
709
                name = g_strdup(str);
710
        } else
711
                name = tmp;
712

    
713
        return name;
714
}
715

    
716
gchar *procheader_get_toname(const gchar *str)
717
{
718
        GSList *addr_list, *cur;
719
        GString *toname;
720
        gchar *name;
721

    
722
        if (strchr(str, ',') == NULL)
723
                return procheader_get_fromname(str);
724

    
725
        addr_list = address_list_append_orig(NULL, str);
726
        toname = g_string_new(NULL);
727

    
728
        for (cur = addr_list; cur != NULL; cur = cur->next) {
729
                name = procheader_get_fromname((gchar *)cur->data);
730
                g_string_append(toname, name);
731
                g_free(name);
732
                if (cur->next)
733
                        g_string_append(toname, ", ");
734
        }
735

    
736
        slist_free_strings(addr_list);
737

    
738
        return g_string_free(toname, FALSE);
739
}
740

    
741
static gint procheader_scan_date_string(const gchar *str,
742
                                        gchar *weekday, gint *day,
743
                                        gchar *month, gint *year,
744
                                        gint *hh, gint *mm, gint *ss,
745
                                        gchar *zone)
746
{
747
        gint result;
748

    
749
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s",
750
                        weekday, day, month, year, hh, mm, ss, zone);
751
        if (result == 8) return 0;
752

    
753
        result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s",
754
                        weekday, day, month, year, hh, mm, ss, zone);
755
        if (result == 8) return 0;
756

    
757
        result = sscanf(str, "%d %9s %d %2d:%2d:%2d %5s",
758
                        day, month, year, hh, mm, ss, zone);
759
        if (result == 7) return 0;
760

    
761
        *zone = '\0';
762
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d",
763
                        weekday, day, month, year, hh, mm, ss);
764
        if (result == 7) return 0;
765

    
766
        result = sscanf(str, "%d %9s %d %2d:%2d:%2d",
767
                        day, month, year, hh, mm, ss);
768
        if (result == 6) return 0;
769

    
770
        *ss = 0;
771
        result = sscanf(str, "%10s %d %9s %d %2d:%2d %5s",
772
                        weekday, day, month, year, hh, mm, zone);
773
        if (result == 7) return 0;
774

    
775
        result = sscanf(str, "%d %9s %d %2d:%2d %5s",
776
                        day, month, year, hh, mm, zone);
777
        if (result == 6) return 0;
778

    
779
        *zone = '\0';
780
        result = sscanf(str, "%10s %d %9s %d %2d:%2d",
781
                        weekday, day, month, year, hh, mm);
782
        if (result == 6) return 0;
783

    
784
        result = sscanf(str, "%d %9s %d %2d:%2d",
785
                        day, month, year, hh, mm);
786
        if (result == 5) return 0;
787

    
788
        return -1;
789
}
790

    
791
time_t procheader_date_parse(gchar *dest, const gchar *src, gint len)
792
{
793
        static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
794
        gchar weekday[11];
795
        gint day;
796
        gchar month[10];
797
        gint year;
798
        gint hh, mm, ss;
799
        gchar zone[6];
800
        GDateMonth dmonth = G_DATE_BAD_MONTH;
801
        struct tm t;
802
        gchar *p;
803
        time_t timer;
804
        time_t tz_offset;
805

    
806
        if (procheader_scan_date_string(src, weekday, &day, month, &year,
807
                                        &hh, &mm, &ss, zone) < 0) {
808
                if (dest && len > 0)
809
                        strncpy2(dest, src, len);
810
                return 0;
811
        }
812

    
813
        /* Y2K compliant :) */
814
        if (year < 1000) {
815
                if (year < 50)
816
                        year += 2000;
817
                else
818
                        year += 1900;
819
        }
820

    
821
        month[3] = '\0';
822
        for (p = monthstr; *p != '\0'; p += 3) {
823
                if (!g_ascii_strncasecmp(p, month, 3)) {
824
                        dmonth = (gint)(p - monthstr) / 3 + 1;
825
                        break;
826
                }
827
        }
828

    
829
        t.tm_sec = ss;
830
        t.tm_min = mm;
831
        t.tm_hour = hh;
832
        t.tm_mday = day;
833
        t.tm_mon = dmonth - 1;
834
        t.tm_year = year - 1900;
835
        t.tm_wday = 0;
836
        t.tm_yday = 0;
837
        t.tm_isdst = -1;
838

    
839
        timer = mktime(&t);
840
        if (timer == -1) {
841
                if (dest)
842
                        dest[0] = '\0';
843
                return 0;
844
        }
845

    
846
        tz_offset = remote_tzoffset_sec(zone);
847
        if (tz_offset != -1)
848
                timer += tzoffset_sec(&timer) - tz_offset;
849

    
850
        if (dest)
851
                procheader_date_get_localtime(dest, len, timer);
852

    
853
        return timer;
854
}
855

    
856
void procheader_date_get_localtime(gchar *dest, gint len, const time_t timer)
857
{
858
        struct tm *lt;
859
        gchar *default_format = "%y/%m/%d(%a) %H:%M";
860
        gchar *buf;
861
        gchar tmp[BUFFSIZE];
862

    
863
        lt = localtime(&timer);
864
        if (!lt) {
865
                g_warning("can't get localtime of %ld\n", timer);
866
                dest[0] = '\0';
867
                return;
868
        }
869

    
870
        strftime(tmp, sizeof(tmp), default_format, lt);
871

    
872
        buf = conv_localetodisp(tmp, NULL);
873
        strncpy2(dest, buf, len);
874
        g_free(buf);
875
}