Statistics
| Revision:

root / libsylph / procheader.c @ 3281

History | View | Annotate | Download (21.2 KB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2013 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 <glib/gi18n.h>
26
#include <stdio.h>
27
#include <string.h>
28
#include <stdlib.h>
29
#include <time.h>
30
#include <sys/stat.h>
31

    
32
#include "procheader.h"
33
#include "procmsg.h"
34
#include "codeconv.h"
35
#include "displayheader.h"
36
#include "prefs_common.h"
37
#include "utils.h"
38

    
39
#define BUFFSIZE        8192
40

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

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

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

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

    
75
                for (; bufp > buf &&
76
                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
77
                     bufp--)
78
                        *(bufp - 1) = '\0';
79

    
80
                while (1) {
81
                        nexthead = fgetc(fp);
82

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

    
91
                                if (nexthead == '\n') {
92
                                        folded = FALSE;
93
                                        continue;
94
                                }
95

    
96
                                /* replace return code on the tail end
97
                                   with space */
98
                                *bufp++ = ' ';
99
                                *bufp++ = nexthead;
100
                                *bufp = '\0';
101

    
102
                                /* concatenate next line */
103
                                if (fgets(bufp, len - (bufp - buf), fp)
104
                                    == NULL) break;
105
                                bufp += strlen(bufp);
106

    
107
                                for (; bufp > buf &&
108
                                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
109
                                     bufp--)
110
                                        *(bufp - 1) = '\0';
111

    
112
                                folded = FALSE;
113
                        } else {
114
                                ungetc(nexthead, fp);
115
                                break;
116
                        }
117
                }
118

    
119
                return hnum;
120
        }
121

    
122
        while (1) {
123
                nexthead = fgetc(fp);
124
                if (nexthead == ' ' || nexthead == '\t') {
125
                        size_t buflen = strlen(buf);
126

    
127
                        /* concatenate next line */
128
                        if ((len - buflen) > 2) {
129
                                gchar *p = buf + buflen;
130

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

    
145
        /* remove trailing return code */
146
        strretchomp(buf);
147

    
148
        return hnum;
149
}
150

    
151
gchar *procheader_get_unfolded_line(gchar *buf, size_t len, FILE *fp)
152
{
153
        gboolean folded = FALSE;
154
        gint nexthead;
155
        gchar *bufp;
156

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

    
161
        for (; bufp > buf &&
162
             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
163
             bufp--)
164
                *(bufp - 1) = '\0';
165

    
166
        while (1) {
167
                nexthead = fgetc(fp);
168

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

    
177
                        if (nexthead == '\n') {
178
                                folded = FALSE;
179
                                continue;
180
                        }
181

    
182
                        /* replace return code on the tail end
183
                           with space */
184
                        *bufp++ = ' ';
185
                        *bufp++ = nexthead;
186
                        *bufp = '\0';
187

    
188
                        /* concatenate next line */
189
                        if (fgets(bufp, len - (bufp - buf), fp)
190
                            == NULL) break;
191
                        bufp += strlen(bufp);
192

    
193
                        for (; bufp > buf &&
194
                             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
195
                             bufp--)
196
                                *(bufp - 1) = '\0';
197

    
198
                        folded = FALSE;
199
                } else {
200
                        ungetc(nexthead, fp);
201
                        break;
202
                }
203
        }
204

    
205
        /* remove trailing return code */
206
        strretchomp(buf);
207

    
208
        return buf;
209
}
210

    
211
GSList *procheader_get_header_list_from_file(const gchar *file)
212
{
213
        FILE *fp;
214
        GSList *hlist;
215

    
216
        if ((fp = g_fopen(file, "rb")) == NULL) {
217
                FILE_OP_ERROR(file, "procheader_get_header_list_from_file: fopen");
218
                return NULL;
219
        }
220

    
221
        hlist = procheader_get_header_list(fp);
222

    
223
        fclose(fp);
224
        return hlist;
225
}
226

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

    
234
        g_return_val_if_fail(fp != NULL, NULL);
235

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

    
246
                                hlist = g_slist_append(hlist, header);
247
                                break;
248
                        }
249
                }
250
        }
251

    
252
        return hlist;
253
}
254

    
255
GSList *procheader_get_header_list_from_msginfo(MsgInfo *msginfo)
256
{
257
        GSList *hlist = NULL;
258

    
259
        g_return_val_if_fail(msginfo != NULL, NULL);
260

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

    
278
        return hlist;
279
}
280

    
281
GSList *procheader_add_header_list(GSList *hlist, const gchar *header_name,
282
                                  const gchar *body)
283
{
284
        Header *header;
285

    
286
        g_return_val_if_fail(header_name != NULL, hlist);
287

    
288
        header = g_new(Header, 1);
289
        header->name = g_strdup(header_name);
290
        header->body = g_strdup(body);
291

    
292
        return g_slist_append(hlist, header);
293
}
294

    
295
GSList *procheader_copy_header_list(GSList *hlist)
296
{
297
        GSList *newlist = NULL, *cur;
298

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

    
305
        return newlist;
306
}
307

    
308
GSList *procheader_merge_header_list(GSList *hlist1, GSList *hlist2)
309
{
310
        GSList *cur;
311

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

    
318
        return hlist1;
319
}
320

    
321
GSList *procheader_merge_header_list_dup(GSList *hlist1, GSList *hlist2)
322
{
323
        GSList *list, *cur;
324

    
325
        list = procheader_copy_header_list(hlist1);
326

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

    
334
        return list;
335
}
336

    
337
gint procheader_find_header_list(GSList *hlist, const gchar *header_name)
338
{
339
        GSList *cur;
340
        gint index = 0;
341
        Header *header;
342

    
343
        g_return_val_if_fail(header_name != NULL, -1);
344

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

    
351
        return -1;
352
}
353

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

    
361
        g_return_val_if_fail(fp != NULL, NULL);
362

    
363
        headers = g_ptr_array_new();
364

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

    
375
                                g_ptr_array_add(headers, header);
376
                                break;
377
                        }
378
                }
379
        }
380

    
381
        return headers;
382
}
383

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

    
391
        g_return_val_if_fail(fp != NULL, NULL);
392

    
393
        headers = g_ptr_array_new();
394

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

    
404
                                g_ptr_array_add(headers, header);
405
                                break;
406
                        }
407
                }
408
        }
409

    
410
        return headers;
411
}
412

    
413
GPtrArray *procheader_get_header_array_for_display(FILE *fp,
414
                                                   const gchar *encoding)
415
{
416
        GPtrArray *headers, *sorted_headers;
417
        GSList *disphdr_list;
418
        Header *header;
419
        gint i;
420

    
421
        g_return_val_if_fail(fp != NULL, NULL);
422

    
423
        headers = procheader_get_header_array_asis(fp, encoding);
424

    
425
        sorted_headers = g_ptr_array_new();
426

    
427
        for (disphdr_list = prefs_common.disphdr_list; disphdr_list != NULL;
428
             disphdr_list = disphdr_list->next) {
429
                DisplayHeaderProp *dp =
430
                        (DisplayHeaderProp *)disphdr_list->data;
431

    
432
                for (i = 0; i < headers->len; i++) {
433
                        header = g_ptr_array_index(headers, i);
434

    
435
                        if (!g_ascii_strcasecmp(header->name, dp->name)) {
436
                                if (dp->hidden)
437
                                        procheader_header_free(header);
438
                                else
439
                                        g_ptr_array_add(sorted_headers, header);
440

    
441
                                g_ptr_array_remove_index(headers, i);
442
                                i--;
443
                        }
444
                }
445
        }
446

    
447
        if (prefs_common.show_other_header) {
448
                for (i = 0; i < headers->len; i++) {
449
                        header = g_ptr_array_index(headers, i);
450
                        g_ptr_array_add(sorted_headers, header);
451
                }
452
                g_ptr_array_free(headers, TRUE);
453
        } else
454
                procheader_header_array_destroy(headers);
455

    
456
        return sorted_headers;
457
}
458

    
459
void procheader_header_list_destroy(GSList *hlist)
460
{
461
        Header *header;
462

    
463
        while (hlist != NULL) {
464
                header = hlist->data;
465
                procheader_header_free(header);
466
                hlist = g_slist_remove(hlist, header);
467
        }
468
}
469

    
470
void procheader_header_array_destroy(GPtrArray *harray)
471
{
472
        gint i;
473
        Header *header;
474

    
475
        for (i = 0; i < harray->len; i++) {
476
                header = g_ptr_array_index(harray, i);
477
                procheader_header_free(header);
478
        }
479

    
480
        g_ptr_array_free(harray, TRUE);
481
}
482

    
483
void procheader_header_free(Header *header)
484
{
485
        if (!header) return;
486

    
487
        g_free(header->name);
488
        g_free(header->body);
489
        g_free(header);
490
}
491

    
492
void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[])
493
{
494
        gchar buf[BUFFSIZE];
495
        HeaderEntry *hp;
496
        gint hnum;
497
        gchar *p;
498

    
499
        if (hentry == NULL) return;
500

    
501
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
502
               != -1) {
503
                hp = hentry + hnum;
504

    
505
                p = buf + strlen(hp->name);
506
                while (*p == ' ' || *p == '\t') p++;
507

    
508
                if (hp->body == NULL)
509
                        hp->body = g_strdup(p);
510
                else if (!g_ascii_strcasecmp(hp->name, "To:") ||
511
                         !g_ascii_strcasecmp(hp->name, "Cc:")) {
512
                        gchar *tp = hp->body;
513
                        hp->body = g_strconcat(tp, ", ", p, NULL);
514
                        g_free(tp);
515
                }
516
        }
517
}
518

    
519
MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags,
520
                               gboolean full)
521
{
522
        struct stat s;
523
        FILE *fp;
524
        MsgInfo *msginfo;
525

    
526
        if (g_stat(file, &s) < 0) {
527
                FILE_OP_ERROR(file, "stat");
528
                return NULL;
529
        }
530
        if (!S_ISREG(s.st_mode))
531
                return NULL;
532

    
533
        if ((fp = g_fopen(file, "rb")) == NULL) {
534
                FILE_OP_ERROR(file, "procheader_parse_file: fopen");
535
                return NULL;
536
        }
537

    
538
        msginfo = procheader_parse_stream(fp, flags, full);
539
        fclose(fp);
540

    
541
        if (msginfo) {
542
                msginfo->size = s.st_size;
543
                msginfo->mtime = s.st_mtime;
544
        }
545

    
546
        return msginfo;
547
}
548

    
549
MsgInfo *procheader_parse_str(const gchar *str, MsgFlags flags, gboolean full)
550
{
551
        FILE *fp;
552
        MsgInfo *msginfo;
553

    
554
        if ((fp = str_open_as_stream(str)) == NULL)
555
                return NULL;
556

    
557
        msginfo = procheader_parse_stream(fp, flags, full);
558
        fclose(fp);
559
        return msginfo;
560
}
561

    
562
enum
563
{
564
        H_DATE                = 0,
565
        H_FROM                = 1,
566
        H_TO                = 2,
567
        H_NEWSGROUPS        = 3,
568
        H_SUBJECT        = 4,
569
        H_MSG_ID        = 5,
570
        H_REFERENCES        = 6,
571
        H_IN_REPLY_TO        = 7,
572
        H_CONTENT_TYPE        = 8,
573
        H_SEEN                = 9,
574
        H_CC                = 10,
575
        H_X_FACE        = 11
576
};
577

    
578
MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full)
579
{
580
        static HeaderEntry hentry_full[] = {{"Date:",                NULL, FALSE},
581
                                           {"From:",                NULL, TRUE},
582
                                           {"To:",                NULL, TRUE},
583
                                           {"Newsgroups:",        NULL, TRUE},
584
                                           {"Subject:",                NULL, TRUE},
585
                                           {"Message-Id:",        NULL, FALSE},
586
                                           {"References:",        NULL, FALSE},
587
                                           {"In-Reply-To:",        NULL, FALSE},
588
                                           {"Content-Type:",        NULL, FALSE},
589
                                           {"Seen:",                NULL, FALSE},
590
                                           {"Cc:",                NULL, TRUE},
591
                                           {"X-Face:",                NULL, FALSE},
592
                                           {NULL,                NULL, FALSE}};
593

    
594
        static HeaderEntry hentry_short[] = {{"Date:",                NULL, FALSE},
595
                                            {"From:",                NULL, TRUE},
596
                                            {"To:",                NULL, TRUE},
597
                                            {"Newsgroups:",        NULL, TRUE},
598
                                            {"Subject:",        NULL, TRUE},
599
                                            {"Message-Id:",        NULL, FALSE},
600
                                            {"References:",        NULL, FALSE},
601
                                            {"In-Reply-To:",        NULL, FALSE},
602
                                            {"Content-Type:",        NULL, FALSE},
603
                                            {"Seen:",                NULL, FALSE},
604
                                            {NULL,                NULL, FALSE}};
605

    
606
        MsgInfo *msginfo;
607
        gchar buf[BUFFSIZE];
608
        gchar *p;
609
        gchar *hp;
610
        HeaderEntry *hentry;
611
        gint hnum;
612
        gchar *from = NULL, *to = NULL, *subject = NULL, *cc = NULL;
613
        gchar *charset = NULL;
614

    
615
        hentry = full ? hentry_full : hentry_short;
616

    
617
        if (MSG_IS_QUEUED(flags)) {
618
                while (fgets(buf, sizeof(buf), fp) != NULL)
619
                        if (buf[0] == '\r' || buf[0] == '\n') break;
620
        }
621

    
622
        msginfo = g_new0(MsgInfo, 1);
623
        msginfo->flags = flags;
624
        msginfo->references = NULL;
625
        msginfo->inreplyto = NULL;
626

    
627
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
628
               != -1) {
629
                hp = buf + strlen(hentry[hnum].name);
630
                while (*hp == ' ' || *hp == '\t') hp++;
631

    
632
                switch (hnum) {
633
                case H_DATE:
634
                        if (msginfo->date) break;
635
                        msginfo->date_t =
636
                                procheader_date_parse(NULL, hp, 0);
637
                        msginfo->date = g_strdup(hp);
638
                        break;
639
                case H_FROM:
640
                        if (from) break;
641
                        from = g_strdup(hp);
642
                        break;
643
                case H_TO:
644
                        if (to) {
645
                                p = to;
646
                                to = g_strconcat(p, ", ", hp, NULL);
647
                                g_free(p);
648
                        } else
649
                                to = g_strdup(hp);
650
                        break;
651
                case H_NEWSGROUPS:
652
                        if (msginfo->newsgroups) {
653
                                p = msginfo->newsgroups;
654
                                msginfo->newsgroups =
655
                                        g_strconcat(p, ",", hp, NULL);
656
                                g_free(p);
657
                        } else
658
                                msginfo->newsgroups = g_strdup(buf + 12);
659
                        break;
660
                case H_SUBJECT:
661
                        if (msginfo->subject) break;
662
                        subject = g_strdup(hp);
663
                        break;
664
                case H_MSG_ID:
665
                        if (msginfo->msgid) break;
666

    
667
                        extract_parenthesis(hp, '<', '>');
668
                        remove_space(hp);
669
                        msginfo->msgid = g_strdup(hp);
670
                        break;
671
                case H_REFERENCES:
672
                        msginfo->references =
673
                                references_list_prepend(msginfo->references,
674
                                                        hp);
675
                        break;
676
                case H_IN_REPLY_TO:
677
                        if (msginfo->inreplyto) break;
678

    
679
                        eliminate_parenthesis(hp, '(', ')');
680
                        if ((p = strrchr(hp, '<')) != NULL &&
681
                            strchr(p + 1, '>') != NULL) {
682
                                extract_parenthesis(p, '<', '>');
683
                                remove_space(p);
684
                                if (*p != '\0')
685
                                        msginfo->inreplyto = g_strdup(p);
686
                        }
687
                        break;
688
                case H_CONTENT_TYPE:
689
                        if (!g_ascii_strncasecmp(hp, "multipart", 9)) {
690
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME);
691
                        } else {
692
                                if (!g_ascii_strncasecmp(hp, "text/html", 9)) {
693
                                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME_HTML);
694
                                }
695
                                if (!charset) {
696
                                        procmime_scan_content_type_str
697
                                                (hp, NULL, &charset, NULL, NULL);
698
                                }
699
                        }
700
                        break;
701
                case H_SEEN:
702
                        /* mnews Seen header */
703
                        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD);
704
                        break;
705
                case H_CC:
706
                        if (cc) {
707
                                p = cc;
708
                                cc = g_strconcat(p, ", ", hp, NULL);
709
                                g_free(p);
710
                        } else
711
                                cc = g_strdup(hp);
712
                        break;
713
                case H_X_FACE:
714
                        if (msginfo->xface) break;
715
                        msginfo->xface = g_strdup(hp);
716
                        break;
717
                default:
718
                        break;
719
                }
720
        }
721

    
722
        if (from) {
723
                msginfo->from = conv_unmime_header(from, charset);
724
                subst_control(msginfo->from, ' ');
725
                msginfo->fromname = procheader_get_fromname(msginfo->from);
726
                g_free(from);
727
        }
728
        if (to) {
729
                msginfo->to = conv_unmime_header(to, charset);
730
                subst_control(msginfo->to, ' ');
731
                g_free(to);
732
        }
733
        if (subject) {
734
                msginfo->subject = conv_unmime_header(subject, charset);
735
                subst_control(msginfo->subject, ' ');
736
                g_free(subject);
737
        }
738
        if (cc) {
739
                msginfo->cc = conv_unmime_header(cc, charset);
740
                subst_control(msginfo->cc, ' ');
741
                g_free(cc);
742
        }
743

    
744
        if (!msginfo->inreplyto && msginfo->references)
745
                msginfo->inreplyto =
746
                        g_strdup((gchar *)msginfo->references->data);
747

    
748
        if (MSG_IS_MIME(msginfo->flags)) {
749
                MimeInfo *mimeinfo, *part;
750
                gboolean has_html = FALSE;
751

    
752
                part = mimeinfo = procmime_scan_message_stream(fp);
753
                while (part) {
754
                        if (part->mime_type != MIME_TEXT &&
755
                            part->mime_type != MIME_TEXT_HTML &&
756
                            part->mime_type != MIME_MULTIPART)
757
                                break;
758
                        if (part->mime_type == MIME_TEXT_HTML)
759
                                has_html = TRUE;
760
                        part = procmime_mimeinfo_next(part);
761
                }
762

    
763
                if (has_html && !part) {
764
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME_HTML);
765
                }
766

    
767
                procmime_mimeinfo_free_all(mimeinfo);
768
        }
769

    
770
        g_free(charset);
771

    
772
        return msginfo;
773
}
774

    
775
gchar *procheader_get_fromname(const gchar *str)
776
{
777
        gchar *tmp, *name;
778

    
779
        tmp = g_strdup(str);
780

    
781
        if (*tmp == '\"') {
782
                extract_quote_with_escape(tmp, '\"');
783
                g_strstrip(tmp);
784
        } else if (strchr(tmp, '<')) {
785
                eliminate_parenthesis(tmp, '<', '>');
786
                g_strstrip(tmp);
787
                if (*tmp == '\0') {
788
                        strcpy(tmp, str);
789
                        extract_parenthesis(tmp, '<', '>');
790
                        g_strstrip(tmp);
791
                }
792
        } else if (strchr(tmp, '(')) {
793
                extract_parenthesis_with_escape(tmp, '(', ')');
794
                g_strstrip(tmp);
795
        }
796

    
797
        if (*tmp == '\0') {
798
                g_free(tmp);
799
                name = g_strdup(str);
800
        } else
801
                name = tmp;
802

    
803
        return name;
804
}
805

    
806
gchar *procheader_get_toname(const gchar *str)
807
{
808
        GSList *addr_list, *cur;
809
        GString *toname;
810
        gchar *name;
811

    
812
        if (strchr(str, ',') == NULL)
813
                return procheader_get_fromname(str);
814

    
815
        addr_list = address_list_append_orig(NULL, str);
816
        toname = g_string_new(NULL);
817

    
818
        for (cur = addr_list; cur != NULL; cur = cur->next) {
819
                name = procheader_get_fromname((gchar *)cur->data);
820
                g_string_append(toname, name);
821
                g_free(name);
822
                if (cur->next)
823
                        g_string_append(toname, ", ");
824
        }
825

    
826
        slist_free_strings(addr_list);
827

    
828
        return g_string_free(toname, FALSE);
829
}
830

    
831
static gint procheader_scan_date_string(const gchar *str,
832
                                        gchar *weekday, gint *day,
833
                                        gchar *month, gint *year,
834
                                        gint *hh, gint *mm, gint *ss,
835
                                        gchar *zone)
836
{
837
        gint result;
838

    
839
        *zone = '\0';
840
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s",
841
                        weekday, day, month, year, hh, mm, ss, zone);
842
        if (result >= 7) return 0;
843

    
844
        result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s",
845
                        weekday, day, month, year, hh, mm, ss, zone);
846
        if (result >= 7) return 0;
847

    
848
        result = sscanf(str, "%3s,%d %9s %d %2d.%2d.%2d %5s",
849
                        weekday, day, month, year, hh, mm, ss, zone);
850
        if (result >= 7) return 0;
851

    
852
        result = sscanf(str, "%3s %d, %9s %d %2d:%2d:%2d %5s",
853
                        weekday, day, month, year, hh, mm, ss, zone);
854
        if (result >= 7) return 0;
855

    
856
        result = sscanf(str, "%d %9s %d %2d:%2d:%2d %5s",
857
                        day, month, year, hh, mm, ss, zone);
858
        if (result >= 6) return 0;
859

    
860
        result = sscanf(str, "%d-%2s-%2d %2d:%2d:%2d",
861
                        year, month, day, hh, mm, ss);
862
        if (result == 6) return 0;
863

    
864
        *ss = 0;
865
        result = sscanf(str, "%10s %d %9s %d %2d:%2d %5s",
866
                        weekday, day, month, year, hh, mm, zone);
867
        if (result >= 6) return 0;
868

    
869
        result = sscanf(str, "%d %9s %d %2d:%2d %5s",
870
                        day, month, year, hh, mm, zone);
871
        if (result >= 5) return 0;
872

    
873
        return -1;
874
}
875

    
876
time_t procheader_date_parse(gchar *dest, const gchar *src, gint len)
877
{
878
        static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
879
        gchar weekday[11];
880
        gint day;
881
        gchar month[10];
882
        gint year;
883
        gint hh, mm, ss;
884
        gchar zone[6];
885
        GDateMonth dmonth = G_DATE_BAD_MONTH;
886
        struct tm t;
887
        gchar *p;
888
        time_t timer;
889
        time_t tz_offset;
890

    
891
        if (procheader_scan_date_string(src, weekday, &day, month, &year,
892
                                        &hh, &mm, &ss, zone) < 0) {
893
                g_warning("procheader_scan_date_string: date parse failed: %s", src);
894
                if (dest && len > 0)
895
                        strncpy2(dest, src, len);
896
                return 0;
897
        }
898

    
899
        /* Y2K compliant :) */
900
        if (year < 1000) {
901
                if (year < 50)
902
                        year += 2000;
903
                else
904
                        year += 1900;
905
        }
906

    
907
        month[3] = '\0';
908
        if (g_ascii_isdigit(month[0])) {
909
                dmonth = atoi(month);
910
        } else {
911
                for (p = monthstr; *p != '\0'; p += 3) {
912
                        if (!g_ascii_strncasecmp(p, month, 3)) {
913
                                dmonth = (gint)(p - monthstr) / 3 + 1;
914
                                break;
915
                        }
916
                }
917
        }
918

    
919
        t.tm_sec = ss;
920
        t.tm_min = mm;
921
        t.tm_hour = hh;
922
        t.tm_mday = day;
923
        t.tm_mon = dmonth - 1;
924
        t.tm_year = year - 1900;
925
        t.tm_wday = 0;
926
        t.tm_yday = 0;
927
        t.tm_isdst = -1;
928

    
929
        timer = mktime(&t);
930
        if (timer == -1) {
931
                if (year >= 2038) {
932
                        g_warning("mktime: date overflow: %s", src);
933
                        timer = G_MAXINT - 12 * 3600;
934
                } else {
935
                        g_warning("mktime: can't convert date: %s", src);
936
                        if (dest)
937
                                dest[0] = '\0';
938
                        return 0;
939
                }
940
        }
941

    
942
        if (timer < G_MAXINT - 12 * 3600) {
943
                tz_offset = remote_tzoffset_sec(zone);
944
                if (tz_offset != -1)
945
                        timer += tzoffset_sec(&timer) - tz_offset;
946
        }
947

    
948
        if (dest)
949
                procheader_date_get_localtime(dest, len, timer);
950

    
951
        return timer;
952
}
953

    
954
void procheader_date_get_localtime(gchar *dest, gint len, const time_t timer)
955
{
956
        struct tm *lt;
957
        gchar *default_format = "%y/%m/%d(%a) %H:%M";
958
        gchar *buf;
959
        gchar tmp[BUFFSIZE];
960

    
961
        lt = localtime(&timer);
962
        if (!lt) {
963
                g_warning("can't get localtime of %ld\n", timer);
964
                dest[0] = '\0';
965
                return;
966
        }
967

    
968
        if (prefs_common.date_format)
969
                strftime(tmp, sizeof(tmp), prefs_common.date_format, lt);
970
        else
971
                strftime(tmp, sizeof(tmp), default_format, lt);
972

    
973
        buf = conv_localetodisp(tmp, NULL);
974
        strncpy2(dest, buf, len);
975
        g_free(buf);
976
}