Statistics
| Branch: | Tag: | Revision:

root / libsylph / procheader.c @ 8d7dcace

History | View | Annotate | Download (19 KB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2007 Hiroyuki Yamamoto
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19

    
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23

    
24
#include <glib.h>
25
#include <stdio.h>
26
#include <string.h>
27
#include <stdlib.h>
28
#include <time.h>
29
#include <sys/stat.h>
30

    
31
#include "procheader.h"
32
#include "procmsg.h"
33
#include "codeconv.h"
34
#include "utils.h"
35

    
36
#define BUFFSIZE        8192
37

    
38
gint procheader_get_one_field(gchar *buf, size_t len, FILE *fp,
39
                              HeaderEntry hentry[])
40
{
41
        gint nexthead;
42
        gint hnum = 0;
43
        HeaderEntry *hp = NULL;
44

    
45
        if (hentry != NULL) {
46
                /* skip non-required headers */
47
                do {
48
                        do {
49
                                if (fgets(buf, len, fp) == NULL)
50
                                        return -1;
51
                                if (buf[0] == '\r' || buf[0] == '\n')
52
                                        return -1;
53
                        } while (buf[0] == ' ' || buf[0] == '\t');
54

    
55
                        for (hp = hentry, hnum = 0; hp->name != NULL;
56
                             hp++, hnum++) {
57
                                if (!g_ascii_strncasecmp(hp->name, buf,
58
                                                         strlen(hp->name)))
59
                                        break;
60
                        }
61
                } while (hp->name == NULL);
62
        } else {
63
                if (fgets(buf, len, fp) == NULL) return -1;
64
                if (buf[0] == '\r' || buf[0] == '\n') return -1;
65
        }
66

    
67
        /* unfold the specified folded line */
68
        if (hp && hp->unfold) {
69
                gboolean folded = FALSE;
70
                gchar *bufp = buf + strlen(buf);
71

    
72
                for (; bufp > buf &&
73
                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
74
                     bufp--)
75
                        *(bufp - 1) = '\0';
76

    
77
                while (1) {
78
                        nexthead = fgetc(fp);
79

    
80
                        /* folded */
81
                        if (nexthead == ' ' || nexthead == '\t')
82
                                folded = TRUE;
83
                        else if (nexthead == EOF)
84
                                break;
85
                        else if (folded == TRUE) {
86
                                if ((len - (bufp - buf)) <= 2) break;
87

    
88
                                if (nexthead == '\n') {
89
                                        folded = FALSE;
90
                                        continue;
91
                                }
92

    
93
                                /* replace return code on the tail end
94
                                   with space */
95
                                *bufp++ = ' ';
96
                                *bufp++ = nexthead;
97
                                *bufp = '\0';
98

    
99
                                /* concatenate next line */
100
                                if (fgets(bufp, len - (bufp - buf), fp)
101
                                    == NULL) break;
102
                                bufp += strlen(bufp);
103

    
104
                                for (; bufp > buf &&
105
                                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
106
                                     bufp--)
107
                                        *(bufp - 1) = '\0';
108

    
109
                                folded = FALSE;
110
                        } else {
111
                                ungetc(nexthead, fp);
112
                                break;
113
                        }
114
                }
115

    
116
                return hnum;
117
        }
118

    
119
        while (1) {
120
                nexthead = fgetc(fp);
121
                if (nexthead == ' ' || nexthead == '\t') {
122
                        size_t buflen = strlen(buf);
123

    
124
                        /* concatenate next line */
125
                        if ((len - buflen) > 2) {
126
                                gchar *p = buf + buflen;
127

    
128
                                *p++ = nexthead;
129
                                *p = '\0';
130
                                buflen++;
131
                                if (fgets(p, len - buflen, fp) == NULL)
132
                                        break;
133
                        } else
134
                                break;
135
                } else {
136
                        if (nexthead != EOF)
137
                                ungetc(nexthead, fp);
138
                        break;
139
                }
140
        }
141

    
142
        /* remove trailing return code */
143
        strretchomp(buf);
144

    
145
        return hnum;
146
}
147

    
148
gchar *procheader_get_unfolded_line(gchar *buf, size_t len, FILE *fp)
149
{
150
        gboolean folded = FALSE;
151
        gint nexthead;
152
        gchar *bufp;
153

    
154
        if (fgets(buf, len, fp) == NULL) return NULL;
155
        if (buf[0] == '\r' || buf[0] == '\n') return NULL;
156
        bufp = buf + strlen(buf);
157

    
158
        for (; bufp > buf &&
159
             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
160
             bufp--)
161
                *(bufp - 1) = '\0';
162

    
163
        while (1) {
164
                nexthead = fgetc(fp);
165

    
166
                /* folded */
167
                if (nexthead == ' ' || nexthead == '\t')
168
                        folded = TRUE;
169
                else if (nexthead == EOF)
170
                        break;
171
                else if (folded == TRUE) {
172
                        if ((len - (bufp - buf)) <= 2) break;
173

    
174
                        if (nexthead == '\n') {
175
                                folded = FALSE;
176
                                continue;
177
                        }
178

    
179
                        /* replace return code on the tail end
180
                           with space */
181
                        *bufp++ = ' ';
182
                        *bufp++ = nexthead;
183
                        *bufp = '\0';
184

    
185
                        /* concatenate next line */
186
                        if (fgets(bufp, len - (bufp - buf), fp)
187
                            == NULL) break;
188
                        bufp += strlen(bufp);
189

    
190
                        for (; bufp > buf &&
191
                             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
192
                             bufp--)
193
                                *(bufp - 1) = '\0';
194

    
195
                        folded = FALSE;
196
                } else {
197
                        ungetc(nexthead, fp);
198
                        break;
199
                }
200
        }
201

    
202
        /* remove trailing return code */
203
        strretchomp(buf);
204

    
205
        return buf;
206
}
207

    
208
GSList *procheader_get_header_list_from_file(const gchar *file)
209
{
210
        FILE *fp;
211
        GSList *hlist;
212

    
213
        if ((fp = g_fopen(file, "rb")) == NULL) {
214
                FILE_OP_ERROR(file, "procheader_get_header_list_from_file: fopen");
215
                return NULL;
216
        }
217

    
218
        hlist = procheader_get_header_list(fp);
219

    
220
        fclose(fp);
221
        return hlist;
222
}
223

    
224
GSList *procheader_get_header_list(FILE *fp)
225
{
226
        gchar buf[BUFFSIZE];
227
        gchar *p;
228
        GSList *hlist = NULL;
229
        Header *header;
230

    
231
        g_return_val_if_fail(fp != NULL, NULL);
232

    
233
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) {
234
                if (*buf == ':') continue;
235
                for (p = buf; *p && *p != ' '; p++) {
236
                        if (*p == ':') {
237
                                header = g_new(Header, 1);
238
                                header->name = g_strndup(buf, p - buf);
239
                                p++;
240
                                while (*p == ' ' || *p == '\t') p++;
241
                                header->body = conv_unmime_header(p, NULL);
242

    
243
                                hlist = g_slist_append(hlist, header);
244
                                break;
245
                        }
246
                }
247
        }
248

    
249
        return hlist;
250
}
251

    
252
GSList *procheader_get_header_list_from_msginfo(MsgInfo *msginfo)
253
{
254
        GSList *hlist = NULL;
255

    
256
        g_return_val_if_fail(msginfo != NULL, NULL);
257

    
258
        if (msginfo->subject)
259
                hlist = procheader_add_header_list(hlist, "Subject",
260
                                                   msginfo->subject);
261
        if (msginfo->from)
262
                hlist = procheader_add_header_list(hlist, "From",
263
                                                   msginfo->from);
264
        if (msginfo->to)
265
                hlist = procheader_add_header_list(hlist, "To", msginfo->to);
266
        if (msginfo->cc)
267
                hlist = procheader_add_header_list(hlist, "Cc", msginfo->cc);
268
        if (msginfo->newsgroups)
269
                hlist = procheader_add_header_list(hlist, "Newsgroups",
270
                                                   msginfo->newsgroups);
271
        if (msginfo->date)
272
                hlist = procheader_add_header_list(hlist, "Date",
273
                                                   msginfo->date);
274

    
275
        return hlist;
276
}
277

    
278
GSList *procheader_add_header_list(GSList *hlist, const gchar *header_name,
279
                                  const gchar *body)
280
{
281
        Header *header;
282

    
283
        g_return_val_if_fail(header_name != NULL, hlist);
284

    
285
        header = g_new(Header, 1);
286
        header->name = g_strdup(header_name);
287
        header->body = g_strdup(body);
288

    
289
        return g_slist_append(hlist, header);
290
}
291

    
292
GSList *procheader_copy_header_list(GSList *hlist)
293
{
294
        GSList *newlist = NULL, *cur;
295

    
296
        for (cur = hlist; cur != NULL; cur = cur->next) {
297
                Header *header = (Header *)cur->data;
298
                newlist = procheader_add_header_list(newlist, header->name,
299
                                                     header->body);
300
        }
301

    
302
        return newlist;
303
}
304

    
305
GSList *procheader_merge_header_list(GSList *hlist1, GSList *hlist2)
306
{
307
        GSList *cur;
308

    
309
        for (cur = hlist2; cur != NULL; cur = cur->next) {
310
                Header *header = (Header *)cur->data;
311
                if (procheader_find_header_list(hlist1, header->name) < 0)
312
                        hlist1 = g_slist_append(hlist1, header);
313
        }
314

    
315
        return hlist1;
316
}
317

    
318
GSList *procheader_merge_header_list_dup(GSList *hlist1, GSList *hlist2)
319
{
320
        GSList *list, *cur;
321

    
322
        list = procheader_copy_header_list(hlist1);
323

    
324
        for (cur = hlist2; cur != NULL; cur = cur->next) {
325
                Header *header = (Header *)cur->data;
326
                if (procheader_find_header_list(list, header->name) < 0)
327
                        list = procheader_add_header_list(list, header->name,
328
                                                          header->body);
329
        }
330

    
331
        return list;
332
}
333

    
334
gint procheader_find_header_list(GSList *hlist, const gchar *header_name)
335
{
336
        GSList *cur;
337
        gint index = 0;
338
        Header *header;
339

    
340
        g_return_val_if_fail(header_name != NULL, -1);
341

    
342
        for (cur = hlist; cur != NULL; cur = cur->next, index++) {
343
                header = (Header *)cur->data;
344
                if (g_ascii_strcasecmp(header->name, header_name) == 0)
345
                        return index;
346
        }
347

    
348
        return -1;
349
}
350

    
351
GPtrArray *procheader_get_header_array(FILE *fp, const gchar *encoding)
352
{
353
        gchar buf[BUFFSIZE];
354
        gchar *p;
355
        GPtrArray *headers;
356
        Header *header;
357

    
358
        g_return_val_if_fail(fp != NULL, NULL);
359

    
360
        headers = g_ptr_array_new();
361

    
362
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) {
363
                if (*buf == ':') continue;
364
                for (p = buf; *p && *p != ' '; p++) {
365
                        if (*p == ':') {
366
                                header = g_new(Header, 1);
367
                                header->name = g_strndup(buf, p - buf);
368
                                p++;
369
                                while (*p == ' ' || *p == '\t') p++;
370
                                header->body = conv_unmime_header(p, encoding);
371

    
372
                                g_ptr_array_add(headers, header);
373
                                break;
374
                        }
375
                }
376
        }
377

    
378
        return headers;
379
}
380

    
381
GPtrArray *procheader_get_header_array_asis(FILE *fp, const gchar *encoding)
382
{
383
        gchar buf[BUFFSIZE];
384
        gchar *p;
385
        GPtrArray *headers;
386
        Header *header;
387

    
388
        g_return_val_if_fail(fp != NULL, NULL);
389

    
390
        headers = g_ptr_array_new();
391

    
392
        while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
393
                if (*buf == ':') continue;
394
                for (p = buf; *p && *p != ' '; p++) {
395
                        if (*p == ':') {
396
                                header = g_new(Header, 1);
397
                                header->name = g_strndup(buf, p - buf);
398
                                p++;
399
                                header->body = conv_unmime_header(p, encoding);
400

    
401
                                g_ptr_array_add(headers, header);
402
                                break;
403
                        }
404
                }
405
        }
406

    
407
        return headers;
408
}
409

    
410
void procheader_header_list_destroy(GSList *hlist)
411
{
412
        Header *header;
413

    
414
        while (hlist != NULL) {
415
                header = hlist->data;
416
                procheader_header_free(header);
417
                hlist = g_slist_remove(hlist, header);
418
        }
419
}
420

    
421
void procheader_header_array_destroy(GPtrArray *harray)
422
{
423
        gint i;
424
        Header *header;
425

    
426
        for (i = 0; i < harray->len; i++) {
427
                header = g_ptr_array_index(harray, i);
428
                procheader_header_free(header);
429
        }
430

    
431
        g_ptr_array_free(harray, TRUE);
432
}
433

    
434
void procheader_header_free(Header *header)
435
{
436
        if (!header) return;
437

    
438
        g_free(header->name);
439
        g_free(header->body);
440
        g_free(header);
441
}
442

    
443
void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[])
444
{
445
        gchar buf[BUFFSIZE];
446
        HeaderEntry *hp;
447
        gint hnum;
448
        gchar *p;
449

    
450
        if (hentry == NULL) return;
451

    
452
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
453
               != -1) {
454
                hp = hentry + hnum;
455

    
456
                p = buf + strlen(hp->name);
457
                while (*p == ' ' || *p == '\t') p++;
458

    
459
                if (hp->body == NULL)
460
                        hp->body = g_strdup(p);
461
                else if (!g_ascii_strcasecmp(hp->name, "To:") ||
462
                         !g_ascii_strcasecmp(hp->name, "Cc:")) {
463
                        gchar *tp = hp->body;
464
                        hp->body = g_strconcat(tp, ", ", p, NULL);
465
                        g_free(tp);
466
                }
467
        }
468
}
469

    
470
MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags,
471
                               gboolean full)
472
{
473
        struct stat s;
474
        FILE *fp;
475
        MsgInfo *msginfo;
476

    
477
        if (g_stat(file, &s) < 0) {
478
                FILE_OP_ERROR(file, "stat");
479
                return NULL;
480
        }
481
        if (!S_ISREG(s.st_mode))
482
                return NULL;
483

    
484
        if ((fp = g_fopen(file, "rb")) == NULL) {
485
                FILE_OP_ERROR(file, "procheader_parse_file: fopen");
486
                return NULL;
487
        }
488

    
489
        msginfo = procheader_parse_stream(fp, flags, full);
490
        fclose(fp);
491

    
492
        if (msginfo) {
493
                msginfo->size = s.st_size;
494
                msginfo->mtime = s.st_mtime;
495
        }
496

    
497
        return msginfo;
498
}
499

    
500
MsgInfo *procheader_parse_str(const gchar *str, MsgFlags flags, gboolean full)
501
{
502
        FILE *fp;
503
        MsgInfo *msginfo;
504

    
505
        if ((fp = str_open_as_stream(str)) == NULL)
506
                return NULL;
507

    
508
        msginfo = procheader_parse_stream(fp, flags, full);
509
        fclose(fp);
510
        return msginfo;
511
}
512

    
513
enum
514
{
515
        H_DATE                = 0,
516
        H_FROM                = 1,
517
        H_TO                = 2,
518
        H_NEWSGROUPS        = 3,
519
        H_SUBJECT        = 4,
520
        H_MSG_ID        = 5,
521
        H_REFERENCES        = 6,
522
        H_IN_REPLY_TO        = 7,
523
        H_CONTENT_TYPE        = 8,
524
        H_SEEN                = 9,
525
        H_CC                = 10,
526
        H_X_FACE        = 11
527
};
528

    
529
MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full)
530
{
531
        static HeaderEntry hentry_full[] = {{"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
                                           {"Cc:",                NULL, TRUE},
542
                                           {"X-Face:",                NULL, FALSE},
543
                                           {NULL,                NULL, FALSE}};
544

    
545
        static HeaderEntry hentry_short[] = {{"Date:",                NULL, FALSE},
546
                                            {"From:",                NULL, TRUE},
547
                                            {"To:",                NULL, TRUE},
548
                                            {"Newsgroups:",        NULL, TRUE},
549
                                            {"Subject:",        NULL, TRUE},
550
                                            {"Message-Id:",        NULL, FALSE},
551
                                            {"References:",        NULL, FALSE},
552
                                            {"In-Reply-To:",        NULL, FALSE},
553
                                            {"Content-Type:",        NULL, FALSE},
554
                                            {"Seen:",                NULL, FALSE},
555
                                            {NULL,                NULL, FALSE}};
556

    
557
        MsgInfo *msginfo;
558
        gchar buf[BUFFSIZE];
559
        gchar *p;
560
        gchar *hp;
561
        HeaderEntry *hentry;
562
        gint hnum;
563
        gchar *from = NULL, *to = NULL, *subject = NULL, *cc = NULL;
564
        gchar *charset = NULL;
565

    
566
        hentry = full ? hentry_full : hentry_short;
567

    
568
        if (MSG_IS_QUEUED(flags)) {
569
                while (fgets(buf, sizeof(buf), fp) != NULL)
570
                        if (buf[0] == '\r' || buf[0] == '\n') break;
571
        }
572

    
573
        msginfo = g_new0(MsgInfo, 1);
574
        msginfo->flags = flags;
575
        msginfo->references = NULL;
576
        msginfo->inreplyto = NULL;
577

    
578
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
579
               != -1) {
580
                hp = buf + strlen(hentry[hnum].name);
581
                while (*hp == ' ' || *hp == '\t') hp++;
582

    
583
                switch (hnum) {
584
                case H_DATE:
585
                        if (msginfo->date) break;
586
                        msginfo->date_t =
587
                                procheader_date_parse(NULL, hp, 0);
588
                        msginfo->date = g_strdup(hp);
589
                        break;
590
                case H_FROM:
591
                        if (from) break;
592
                        from = g_strdup(hp);
593
                        break;
594
                case H_TO:
595
                        if (to) {
596
                                p = to;
597
                                to = g_strconcat(p, ", ", hp, NULL);
598
                                g_free(p);
599
                        } else
600
                                to = g_strdup(hp);
601
                        break;
602
                case H_NEWSGROUPS:
603
                        if (msginfo->newsgroups) {
604
                                p = msginfo->newsgroups;
605
                                msginfo->newsgroups =
606
                                        g_strconcat(p, ",", hp, NULL);
607
                                g_free(p);
608
                        } else
609
                                msginfo->newsgroups = g_strdup(buf + 12);
610
                        break;
611
                case H_SUBJECT:
612
                        if (msginfo->subject) break;
613
                        subject = g_strdup(hp);
614
                        break;
615
                case H_MSG_ID:
616
                        if (msginfo->msgid) break;
617

    
618
                        extract_parenthesis(hp, '<', '>');
619
                        remove_space(hp);
620
                        msginfo->msgid = g_strdup(hp);
621
                        break;
622
                case H_REFERENCES:
623
                        msginfo->references =
624
                                references_list_prepend(msginfo->references,
625
                                                        hp);
626
                        break;
627
                case H_IN_REPLY_TO:
628
                        if (msginfo->inreplyto) break;
629

    
630
                        eliminate_parenthesis(hp, '(', ')');
631
                        if ((p = strrchr(hp, '<')) != NULL &&
632
                            strchr(p + 1, '>') != NULL) {
633
                                extract_parenthesis(p, '<', '>');
634
                                remove_space(p);
635
                                if (*p != '\0')
636
                                        msginfo->inreplyto = g_strdup(p);
637
                        }
638
                        break;
639
                case H_CONTENT_TYPE:
640
                        if (!g_ascii_strncasecmp(hp, "multipart", 9)) {
641
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME);
642
                        } else if (!charset) {
643
                                procmime_scan_content_type_str
644
                                        (hp, NULL, &charset, NULL, NULL);
645
                        }
646
                        break;
647
                case H_SEEN:
648
                        /* mnews Seen header */
649
                        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD);
650
                        break;
651
                case H_CC:
652
                        if (cc) {
653
                                p = cc;
654
                                cc = g_strconcat(p, ", ", hp, NULL);
655
                                g_free(p);
656
                        } else
657
                                cc = g_strdup(hp);
658
                        break;
659
                case H_X_FACE:
660
                        if (msginfo->xface) break;
661
                        msginfo->xface = g_strdup(hp);
662
                        break;
663
                default:
664
                        break;
665
                }
666
        }
667

    
668
        if (from) {
669
                msginfo->from = conv_unmime_header(from, charset);
670
                subst_control(msginfo->from, ' ');
671
                msginfo->fromname = procheader_get_fromname(msginfo->from);
672
                g_free(from);
673
        }
674
        if (to) {
675
                msginfo->to = conv_unmime_header(to, charset);
676
                subst_control(msginfo->to, ' ');
677
                g_free(to);
678
        }
679
        if (subject) {
680
                msginfo->subject = conv_unmime_header(subject, charset);
681
                subst_control(msginfo->subject, ' ');
682
                g_free(subject);
683
        }
684
        if (cc) {
685
                msginfo->cc = conv_unmime_header(cc, charset);
686
                subst_control(msginfo->cc, ' ');
687
                g_free(cc);
688
        }
689

    
690
        if (!msginfo->inreplyto && msginfo->references)
691
                msginfo->inreplyto =
692
                        g_strdup((gchar *)msginfo->references->data);
693

    
694
        g_free(charset);
695

    
696
        return msginfo;
697
}
698

    
699
gchar *procheader_get_fromname(const gchar *str)
700
{
701
        gchar *tmp, *name;
702

    
703
        tmp = g_strdup(str);
704

    
705
        if (*tmp == '\"') {
706
                extract_quote_with_escape(tmp, '\"');
707
                g_strstrip(tmp);
708
        } else if (strchr(tmp, '<')) {
709
                eliminate_parenthesis(tmp, '<', '>');
710
                g_strstrip(tmp);
711
                if (*tmp == '\0') {
712
                        strcpy(tmp, str);
713
                        extract_parenthesis(tmp, '<', '>');
714
                        g_strstrip(tmp);
715
                }
716
        } else if (strchr(tmp, '(')) {
717
                extract_parenthesis_with_escape(tmp, '(', ')');
718
                g_strstrip(tmp);
719
        }
720

    
721
        if (*tmp == '\0') {
722
                g_free(tmp);
723
                name = g_strdup(str);
724
        } else
725
                name = tmp;
726

    
727
        return name;
728
}
729

    
730
gchar *procheader_get_toname(const gchar *str)
731
{
732
        GSList *addr_list, *cur;
733
        GString *toname;
734
        gchar *name;
735

    
736
        if (strchr(str, ',') == NULL)
737
                return procheader_get_fromname(str);
738

    
739
        addr_list = address_list_append_orig(NULL, str);
740
        toname = g_string_new(NULL);
741

    
742
        for (cur = addr_list; cur != NULL; cur = cur->next) {
743
                name = procheader_get_fromname((gchar *)cur->data);
744
                g_string_append(toname, name);
745
                g_free(name);
746
                if (cur->next)
747
                        g_string_append(toname, ", ");
748
        }
749

    
750
        slist_free_strings(addr_list);
751

    
752
        return g_string_free(toname, FALSE);
753
}
754

    
755
static gint procheader_scan_date_string(const gchar *str,
756
                                        gchar *weekday, gint *day,
757
                                        gchar *month, gint *year,
758
                                        gint *hh, gint *mm, gint *ss,
759
                                        gchar *zone)
760
{
761
        gint result;
762

    
763
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s",
764
                        weekday, day, month, year, hh, mm, ss, zone);
765
        if (result == 8) return 0;
766

    
767
        result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s",
768
                        weekday, day, month, year, hh, mm, ss, zone);
769
        if (result == 8) return 0;
770

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

    
775
        *zone = '\0';
776
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d",
777
                        weekday, day, month, year, hh, mm, ss);
778
        if (result == 7) return 0;
779

    
780
        result = sscanf(str, "%d %9s %d %2d:%2d:%2d",
781
                        day, month, year, hh, mm, ss);
782
        if (result == 6) return 0;
783

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

    
789
        result = sscanf(str, "%d %9s %d %2d:%2d %5s",
790
                        day, month, year, hh, mm, zone);
791
        if (result == 6) return 0;
792

    
793
        *zone = '\0';
794
        result = sscanf(str, "%10s %d %9s %d %2d:%2d",
795
                        weekday, day, month, year, hh, mm);
796
        if (result == 6) return 0;
797

    
798
        result = sscanf(str, "%d %9s %d %2d:%2d",
799
                        day, month, year, hh, mm);
800
        if (result == 5) return 0;
801

    
802
        return -1;
803
}
804

    
805
time_t procheader_date_parse(gchar *dest, const gchar *src, gint len)
806
{
807
        static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
808
        gchar weekday[11];
809
        gint day;
810
        gchar month[10];
811
        gint year;
812
        gint hh, mm, ss;
813
        gchar zone[6];
814
        GDateMonth dmonth = G_DATE_BAD_MONTH;
815
        struct tm t;
816
        gchar *p;
817
        time_t timer;
818
        time_t tz_offset;
819

    
820
        if (procheader_scan_date_string(src, weekday, &day, month, &year,
821
                                        &hh, &mm, &ss, zone) < 0) {
822
                if (dest && len > 0)
823
                        strncpy2(dest, src, len);
824
                return 0;
825
        }
826

    
827
        /* Y2K compliant :) */
828
        if (year < 1000) {
829
                if (year < 50)
830
                        year += 2000;
831
                else
832
                        year += 1900;
833
        }
834

    
835
        month[3] = '\0';
836
        for (p = monthstr; *p != '\0'; p += 3) {
837
                if (!g_ascii_strncasecmp(p, month, 3)) {
838
                        dmonth = (gint)(p - monthstr) / 3 + 1;
839
                        break;
840
                }
841
        }
842

    
843
        t.tm_sec = ss;
844
        t.tm_min = mm;
845
        t.tm_hour = hh;
846
        t.tm_mday = day;
847
        t.tm_mon = dmonth - 1;
848
        t.tm_year = year - 1900;
849
        t.tm_wday = 0;
850
        t.tm_yday = 0;
851
        t.tm_isdst = -1;
852

    
853
        timer = mktime(&t);
854
        if (timer == -1) {
855
                if (dest)
856
                        dest[0] = '\0';
857
                return 0;
858
        }
859

    
860
        tz_offset = remote_tzoffset_sec(zone);
861
        if (tz_offset != -1)
862
                timer += tzoffset_sec(&timer) - tz_offset;
863

    
864
        if (dest)
865
                procheader_date_get_localtime(dest, len, timer);
866

    
867
        return timer;
868
}
869

    
870
void procheader_date_get_localtime(gchar *dest, gint len, const time_t timer)
871
{
872
        struct tm *lt;
873
        gchar *default_format = "%y/%m/%d(%a) %H:%M";
874
        gchar *buf;
875
        gchar tmp[BUFFSIZE];
876

    
877
        lt = localtime(&timer);
878
        if (!lt) {
879
                g_warning("can't get localtime of %ld\n", timer);
880
                dest[0] = '\0';
881
                return;
882
        }
883

    
884
        strftime(tmp, sizeof(tmp), default_format, lt);
885

    
886
        buf = conv_localetodisp(tmp, NULL);
887
        strncpy2(dest, buf, len);
888
        g_free(buf);
889
}