Statistics
| Revision:

root / src / procheader.c @ 190

History | View | Annotate | Download (16.9 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program 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
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "prefs_common.h"
36
#include "utils.h"
37
38
#define BUFFSIZE        8192
39
40
gint procheader_get_one_field(gchar *buf, size_t len, FILE *fp,
41
                              HeaderEntry hentry[])
42
{
43
        gint nexthead;
44
        gint hnum = 0;
45
        HeaderEntry *hp = NULL;
46
47
        if (hentry != NULL) {
48
                /* skip non-required headers */
49
                do {
50
                        do {
51
                                if (fgets(buf, len, fp) == NULL)
52
                                        return -1;
53
                                if (buf[0] == '\r' || buf[0] == '\n')
54
                                        return -1;
55
                        } while (buf[0] == ' ' || buf[0] == '\t');
56
57
                        for (hp = hentry, hnum = 0; hp->name != NULL;
58
                             hp++, hnum++) {
59
                                if (!strncasecmp(hp->name, buf,
60
                                                 strlen(hp->name)))
61
                                        break;
62
                        }
63
                } while (hp->name == NULL);
64
        } else {
65
                if (fgets(buf, len, fp) == NULL) return -1;
66
                if (buf[0] == '\r' || buf[0] == '\n') return -1;
67
        }
68
69
        /* unfold the specified folded line */
70
        if (hp && hp->unfold) {
71
                gboolean folded = FALSE;
72
                gchar *bufp = buf + strlen(buf);
73
74
                for (; bufp > buf &&
75
                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
76
                     bufp--)
77
                        *(bufp - 1) = '\0';
78
79
                while (1) {
80
                        nexthead = fgetc(fp);
81
82
                        /* folded */
83
                        if (nexthead == ' ' || nexthead == '\t')
84
                                folded = TRUE;
85
                        else if (nexthead == EOF)
86
                                break;
87
                        else if (folded == TRUE) {
88
                                if ((len - (bufp - buf)) <= 2) break;
89
90
                                if (nexthead == '\n') {
91
                                        folded = FALSE;
92
                                        continue;
93
                                }
94
95
                                /* replace return code on the tail end
96
                                   with space */
97
                                *bufp++ = ' ';
98
                                *bufp++ = nexthead;
99
                                *bufp = '\0';
100
101
                                /* concatenate next line */
102
                                if (fgets(bufp, len - (bufp - buf), fp)
103
                                    == NULL) break;
104
                                bufp += strlen(bufp);
105
106
                                for (; bufp > buf &&
107
                                     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
108
                                     bufp--)
109
                                        *(bufp - 1) = '\0';
110
111
                                folded = FALSE;
112
                        } else {
113
                                ungetc(nexthead, fp);
114
                                break;
115
                        }
116
                }
117
118
                return hnum;
119
        }
120
121
        while (1) {
122
                nexthead = fgetc(fp);
123
                if (nexthead == ' ' || nexthead == '\t') {
124
                        size_t buflen = strlen(buf);
125
126
                        /* concatenate next line */
127
                        if ((len - buflen) > 2) {
128
                                gchar *p = buf + buflen;
129
130
                                *p++ = nexthead;
131
                                *p = '\0';
132
                                buflen++;
133
                                if (fgets(p, len - buflen, fp) == NULL)
134
                                        break;
135
                        } else
136
                                break;
137
                } else {
138
                        if (nexthead != EOF)
139
                                ungetc(nexthead, fp);
140
                        break;
141
                }
142
        }
143
144
        /* remove trailing return code */
145
        strretchomp(buf);
146
147
        return hnum;
148
}
149
150
gchar *procheader_get_unfolded_line(gchar *buf, size_t len, FILE *fp)
151
{
152
        gboolean folded = FALSE;
153
        gint nexthead;
154
        gchar *bufp;
155
156
        if (fgets(buf, len, fp) == NULL) return NULL;
157
        if (buf[0] == '\r' || buf[0] == '\n') return NULL;
158
        bufp = buf + strlen(buf);
159
160
        for (; bufp > buf &&
161
             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
162
             bufp--)
163
                *(bufp - 1) = '\0';
164
165
        while (1) {
166
                nexthead = fgetc(fp);
167
168
                /* folded */
169
                if (nexthead == ' ' || nexthead == '\t')
170
                        folded = TRUE;
171
                else if (nexthead == EOF)
172
                        break;
173
                else if (folded == TRUE) {
174
                        if ((len - (bufp - buf)) <= 2) break;
175
176
                        if (nexthead == '\n') {
177
                                folded = FALSE;
178
                                continue;
179
                        }
180
181
                        /* replace return code on the tail end
182
                           with space */
183
                        *bufp++ = ' ';
184
                        *bufp++ = nexthead;
185
                        *bufp = '\0';
186
187
                        /* concatenate next line */
188
                        if (fgets(bufp, len - (bufp - buf), fp)
189
                            == NULL) break;
190
                        bufp += strlen(bufp);
191
192
                        for (; bufp > buf &&
193
                             (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
194
                             bufp--)
195
                                *(bufp - 1) = '\0';
196
197
                        folded = FALSE;
198
                } else {
199
                        ungetc(nexthead, fp);
200
                        break;
201
                }
202
        }
203
204
        /* remove trailing return code */
205
        strretchomp(buf);
206
207
        return buf;
208
}
209
210
GSList *procheader_get_header_list_from_file(const gchar *file)
211
{
212
        FILE *fp;
213
        GSList *hlist;
214
215
        if ((fp = fopen(file, "rb")) == NULL) {
216
                FILE_OP_ERROR(file, "fopen");
217
                return NULL;
218
        }
219
220
        hlist = procheader_get_header_list(fp);
221
222
        fclose(fp);
223
        return hlist;
224
}
225
226
GSList *procheader_get_header_list(FILE *fp)
227
{
228
        gchar buf[BUFFSIZE];
229
        gchar *p;
230
        GSList *hlist = NULL;
231
        Header *header;
232
233
        g_return_val_if_fail(fp != NULL, NULL);
234
235
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) {
236
                if (*buf == ':') continue;
237
                for (p = buf; *p && *p != ' '; p++) {
238
                        if (*p == ':') {
239
                                header = g_new(Header, 1);
240
                                header->name = g_strndup(buf, p - buf);
241
                                p++;
242
                                while (*p == ' ' || *p == '\t') p++;
243
                                header->body = conv_unmime_header(p, NULL);
244
245
                                hlist = g_slist_append(hlist, header);
246
                                break;
247
                        }
248
                }
249
        }
250
251
        return hlist;
252
}
253
254
GSList *procheader_add_header_list(GSList *hlist, const gchar *header_name,
255
                                  const gchar *body)
256
{
257
        Header *header;
258
259
        g_return_val_if_fail(header_name != NULL, hlist);
260
261
        header = g_new(Header, 1);
262
        header->name = g_strdup(header_name);
263
        header->body = g_strdup(body);
264
265
        return g_slist_append(hlist, header);
266
}
267
268
GSList *procheader_merge_header_list(GSList *hlist1, GSList *hlist2)
269
{
270
        GSList *cur;
271
272
        for (cur = hlist2; cur != NULL; cur = cur->next) {
273
                Header *header = (Header *)cur->data;
274
                if (procheader_find_header_list(hlist1, header->name) < 0)
275
                        hlist1 = g_slist_append(hlist1, header);
276
        }
277
278
        return hlist1;
279
}
280
281
gint procheader_find_header_list(GSList *hlist, const gchar *header_name)
282
{
283
        GSList *cur;
284
        gint index = 0;
285
        Header *header;
286
287
        g_return_val_if_fail(header_name != NULL, -1);
288
289
        for (cur = hlist; cur != NULL; cur = cur->next, index++) {
290
                header = (Header *)cur->data;
291
                if (g_strcasecmp(header->name, header_name) == 0)
292
                        return index;
293
        }
294
295
        return -1;
296
}
297
298
GPtrArray *procheader_get_header_array(FILE *fp, const gchar *encoding)
299
{
300
        gchar buf[BUFFSIZE];
301
        gchar *p;
302
        GPtrArray *headers;
303
        Header *header;
304
305
        g_return_val_if_fail(fp != NULL, NULL);
306
307
        headers = g_ptr_array_new();
308
309
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) {
310
                if (*buf == ':') continue;
311
                for (p = buf; *p && *p != ' '; p++) {
312
                        if (*p == ':') {
313
                                header = g_new(Header, 1);
314
                                header->name = g_strndup(buf, p - buf);
315
                                p++;
316
                                while (*p == ' ' || *p == '\t') p++;
317
                                header->body = conv_unmime_header(p, encoding);
318
319
                                g_ptr_array_add(headers, header);
320
                                break;
321
                        }
322
                }
323
        }
324
325
        return headers;
326
}
327
328
GPtrArray *procheader_get_header_array_asis(FILE *fp, const gchar *encoding)
329
{
330
        gchar buf[BUFFSIZE];
331
        gchar *p;
332
        GPtrArray *headers;
333
        Header *header;
334
335
        g_return_val_if_fail(fp != NULL, NULL);
336
337
        headers = g_ptr_array_new();
338
339
        while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
340
                if (*buf == ':') continue;
341
                for (p = buf; *p && *p != ' '; p++) {
342
                        if (*p == ':') {
343
                                header = g_new(Header, 1);
344
                                header->name = g_strndup(buf, p - buf);
345
                                p++;
346
                                header->body = conv_unmime_header(p, encoding);
347
348
                                g_ptr_array_add(headers, header);
349
                                break;
350
                        }
351
                }
352
        }
353
354
        return headers;
355
}
356
357
void procheader_header_list_destroy(GSList *hlist)
358
{
359
        Header *header;
360
361
        while (hlist != NULL) {
362
                header = hlist->data;
363
                procheader_header_free(header);
364
                hlist = g_slist_remove(hlist, header);
365
        }
366
}
367
368
void procheader_header_array_destroy(GPtrArray *harray)
369
{
370
        gint i;
371
        Header *header;
372
373
        for (i = 0; i < harray->len; i++) {
374
                header = g_ptr_array_index(harray, i);
375
                procheader_header_free(header);
376
        }
377
378
        g_ptr_array_free(harray, TRUE);
379
}
380
381
void procheader_header_free(Header *header)
382
{
383
        if (!header) return;
384
385
        g_free(header->name);
386
        g_free(header->body);
387
        g_free(header);
388
}
389
390
void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[])
391
{
392
        gchar buf[BUFFSIZE];
393
        HeaderEntry *hp;
394
        gint hnum;
395
        gchar *p;
396
397
        if (hentry == NULL) return;
398
399
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
400
               != -1) {
401
                hp = hentry + hnum;
402
403
                p = buf + strlen(hp->name);
404
                while (*p == ' ' || *p == '\t') p++;
405
406
                if (hp->body == NULL)
407
                        hp->body = g_strdup(p);
408
                else if (!strcasecmp(hp->name, "To:") ||
409
                         !strcasecmp(hp->name, "Cc:")) {
410
                        gchar *tp = hp->body;
411
                        hp->body = g_strconcat(tp, ", ", p, NULL);
412
                        g_free(tp);
413
                }
414
        }
415
}
416
417
MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags,
418
                               gboolean full)
419
{
420
        struct stat s;
421
        FILE *fp;
422
        MsgInfo *msginfo;
423
424
        if (stat(file, &s) < 0) {
425
                FILE_OP_ERROR(file, "stat");
426
                return NULL;
427
        }
428
        if (!S_ISREG(s.st_mode))
429
                return NULL;
430
431
        if ((fp = fopen(file, "rb")) == NULL) {
432
                FILE_OP_ERROR(file, "fopen");
433
                return NULL;
434
        }
435
436
        msginfo = procheader_parse_stream(fp, flags, full);
437
        fclose(fp);
438
439
        if (msginfo) {
440
                msginfo->size = s.st_size;
441
                msginfo->mtime = s.st_mtime;
442
        }
443
444
        return msginfo;
445
}
446
447
MsgInfo *procheader_parse_str(const gchar *str, MsgFlags flags, gboolean full)
448
{
449
        FILE *fp;
450
        MsgInfo *msginfo;
451
452
        if ((fp = str_open_as_stream(str)) == NULL)
453
                return NULL;
454
455
        msginfo = procheader_parse_stream(fp, flags, full);
456
        fclose(fp);
457
        return msginfo;
458
}
459
460
enum
461
{
462
        H_DATE                = 0,
463
        H_FROM                = 1,
464
        H_TO                = 2,
465
        H_NEWSGROUPS        = 3,
466
        H_SUBJECT        = 4,
467
        H_MSG_ID        = 5,
468
        H_REFERENCES        = 6,
469
        H_IN_REPLY_TO        = 7,
470
        H_CONTENT_TYPE        = 8,
471
        H_SEEN                = 9,
472
        H_CC                = 10,
473
        H_X_FACE        = 11
474
};
475
476
MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full)
477
{
478
        static HeaderEntry hentry_full[] = {{"Date:",                NULL, FALSE},
479
                                           {"From:",                NULL, TRUE},
480
                                           {"To:",                NULL, TRUE},
481
                                           {"Newsgroups:",        NULL, TRUE},
482
                                           {"Subject:",                NULL, TRUE},
483
                                           {"Message-Id:",        NULL, FALSE},
484
                                           {"References:",        NULL, FALSE},
485
                                           {"In-Reply-To:",        NULL, FALSE},
486
                                           {"Content-Type:",        NULL, FALSE},
487
                                           {"Seen:",                NULL, FALSE},
488
                                           {"Cc:",                NULL, TRUE},
489
                                           {"X-Face:",                NULL, FALSE},
490
                                           {NULL,                NULL, FALSE}};
491
492
        static HeaderEntry hentry_short[] = {{"Date:",                NULL, FALSE},
493
                                            {"From:",                NULL, TRUE},
494
                                            {"To:",                NULL, TRUE},
495
                                            {"Newsgroups:",        NULL, TRUE},
496
                                            {"Subject:",        NULL, TRUE},
497
                                            {"Message-Id:",        NULL, FALSE},
498
                                            {"References:",        NULL, FALSE},
499
                                            {"In-Reply-To:",        NULL, FALSE},
500
                                            {"Content-Type:",        NULL, FALSE},
501
                                            {"Seen:",                NULL, FALSE},
502
                                            {NULL,                NULL, FALSE}};
503
504
        MsgInfo *msginfo;
505
        gchar buf[BUFFSIZE];
506
        gchar *reference = NULL;
507
        gchar *p, *q;
508
        gchar *hp;
509
        HeaderEntry *hentry;
510
        gint hnum;
511
        gchar *from = NULL, *to = NULL, *subject = NULL, *cc = NULL;
512
        gchar *charset = NULL;
513
514
        hentry = full ? hentry_full : hentry_short;
515
516
        if (MSG_IS_QUEUED(flags)) {
517
                while (fgets(buf, sizeof(buf), fp) != NULL)
518
                        if (buf[0] == '\r' || buf[0] == '\n') break;
519
        }
520
521
        msginfo = g_new0(MsgInfo, 1);
522
        msginfo->flags = flags;
523
        msginfo->references = NULL;
524
        msginfo->inreplyto = NULL;
525
526
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
527
               != -1) {
528
                hp = buf + strlen(hentry[hnum].name);
529
                while (*hp == ' ' || *hp == '\t') hp++;
530
531
                switch (hnum) {
532
                case H_DATE:
533
                        if (msginfo->date) break;
534
                        msginfo->date_t =
535
                                procheader_date_parse(NULL, hp, 0);
536
                        msginfo->date = g_strdup(hp);
537
                        break;
538
                case H_FROM:
539
                        if (from) break;
540
                        from = g_strdup(hp);
541
                        break;
542
                case H_TO:
543
                        if (to) {
544
                                p = to;
545
                                to = g_strconcat(p, ", ", hp, NULL);
546
                                g_free(p);
547
                        } else
548
                                to = g_strdup(hp);
549
                        break;
550
                case H_NEWSGROUPS:
551
                        if (msginfo->newsgroups) {
552
                                p = msginfo->newsgroups;
553
                                msginfo->newsgroups =
554
                                        g_strconcat(p, ",", hp, NULL);
555
                                g_free(p);
556
                        } else
557
                                msginfo->newsgroups = g_strdup(buf + 12);
558
                        break;
559
                case H_SUBJECT:
560
                        if (msginfo->subject) break;
561
                        subject = g_strdup(hp);
562
                        break;
563
                case H_MSG_ID:
564
                        if (msginfo->msgid) break;
565
566
                        extract_parenthesis(hp, '<', '>');
567
                        remove_space(hp);
568
                        msginfo->msgid = g_strdup(hp);
569
                        break;
570
                case H_REFERENCES:
571
                        msginfo->references =
572
                                references_list_prepend(msginfo->references,
573
                                                        hp);
574
                        if (msginfo->references && !reference)
575
                                reference = g_strdup((gchar *)msginfo->references->data);
576
                        break;
577
                case H_IN_REPLY_TO:
578
                        if (!reference) {
579
                                eliminate_parenthesis(hp, '(', ')');
580
                                if ((p = strrchr(hp, '<')) != NULL &&
581
                                    strchr(p + 1, '>') != NULL) {
582
                                        extract_parenthesis(p, '<', '>');
583
                                        remove_space(p);
584
                                        if (*p != '\0')
585
                                                reference = g_strdup(p);
586
                                }
587
                        }
588
                        break;
589
                case H_CONTENT_TYPE:
590
                        if (!g_strncasecmp(hp, "multipart", 9)) {
591
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME);
592
                        } else if (!charset) {
593
                                procmime_scan_content_type_str
594
                                        (hp, NULL, &charset, NULL, NULL);
595
                        }
596
                        break;
597
                case H_SEEN:
598
                        /* mnews Seen header */
599
                        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD);
600
                        break;
601
                case H_CC:
602
                        if (cc) {
603
                                p = cc;
604
                                cc = g_strconcat(p, ", ", hp, NULL);
605
                                g_free(p);
606
                        } else
607
                                cc = g_strdup(hp);
608
                        break;
609
                case H_X_FACE:
610
                        if (msginfo->xface) break;
611
                        msginfo->xface = g_strdup(hp);
612
                        break;
613
                default:
614
                        break;
615
                }
616
        }
617
618
        if (from) {
619
                msginfo->from = conv_unmime_header(from, charset);
620
                msginfo->fromname = procheader_get_fromname(msginfo->from);
621
                g_free(from);
622
        }
623
        if (to) {
624
                msginfo->to = conv_unmime_header(to, charset);
625
                g_free(to);
626
        }
627
        if (subject) {
628
                msginfo->subject = conv_unmime_header(subject, charset);
629
                g_free(subject);
630
        }
631
        if (cc) {
632
                msginfo->cc = conv_unmime_header(cc, charset);
633
                g_free(cc);
634
        }
635
636
        msginfo->inreplyto = reference;
637
638
        g_free(charset);
639
640
        return msginfo;
641
}
642
643
gchar *procheader_get_fromname(const gchar *str)
644
{
645
        gchar *tmp, *name;
646
647
        Xstrdup_a(tmp, str, return NULL);
648
649
        if (*tmp == '\"') {
650
                extract_quote(tmp, '\"');
651
                g_strstrip(tmp);
652
        } else if (strchr(tmp, '<')) {
653
                eliminate_parenthesis(tmp, '<', '>');
654
                g_strstrip(tmp);
655
                if (*tmp == '\0') {
656
                        strcpy(tmp, str);
657
                        extract_parenthesis(tmp, '<', '>');
658
                        g_strstrip(tmp);
659
                }
660
        } else if (strchr(tmp, '(')) {
661
                extract_parenthesis(tmp, '(', ')');
662
                g_strstrip(tmp);
663
        }
664
665
        if (*tmp == '\0')
666
                name = g_strdup(str);
667
        else
668
                name = g_strdup(tmp);
669
670
        return name;
671
}
672
673
static gint procheader_scan_date_string(const gchar *str,
674
                                        gchar *weekday, gint *day,
675
                                        gchar *month, gint *year,
676
                                        gint *hh, gint *mm, gint *ss,
677
                                        gchar *zone)
678
{
679
        gint result;
680
681
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s",
682
                        weekday, day, month, year, hh, mm, ss, zone);
683
        if (result == 8) return 0;
684
685
        result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s",
686
                        weekday, day, month, year, hh, mm, ss, zone);
687
        if (result == 8) return 0;
688
689
        result = sscanf(str, "%d %9s %d %2d:%2d:%2d %5s",
690
                        day, month, year, hh, mm, ss, zone);
691
        if (result == 7) return 0;
692
693
        *zone = '\0';
694
        result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d",
695
                        weekday, day, month, year, hh, mm, ss);
696
        if (result == 7) return 0;
697
698
        result = sscanf(str, "%d %9s %d %2d:%2d:%2d",
699
                        day, month, year, hh, mm, ss);
700
        if (result == 6) return 0;
701
702
        *ss = 0;
703
        result = sscanf(str, "%10s %d %9s %d %2d:%2d %5s",
704
                        weekday, day, month, year, hh, mm, zone);
705
        if (result == 7) return 0;
706
707
        result = sscanf(str, "%d %9s %d %2d:%2d %5s",
708
                        day, month, year, hh, mm, zone);
709
        if (result == 6) return 0;
710
711
        *zone = '\0';
712
        result = sscanf(str, "%10s %d %9s %d %2d:%2d",
713
                        weekday, day, month, year, hh, mm);
714
        if (result == 6) return 0;
715
716
        result = sscanf(str, "%d %9s %d %2d:%2d",
717
                        day, month, year, hh, mm);
718
        if (result == 5) return 0;
719
720
        return -1;
721
}
722
723
time_t procheader_date_parse(gchar *dest, const gchar *src, gint len)
724
{
725
        static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
726
        gchar weekday[11];
727
        gint day;
728
        gchar month[10];
729
        gint year;
730
        gint hh, mm, ss;
731
        gchar zone[6];
732
        GDateMonth dmonth = G_DATE_BAD_MONTH;
733
        struct tm t;
734
        gchar *p;
735
        time_t timer;
736
        time_t tz_offset;
737
738
        if (procheader_scan_date_string(src, weekday, &day, month, &year,
739
                                        &hh, &mm, &ss, zone) < 0) {
740
                g_warning("Invalid date: %s\n", src);
741
                if (dest && len > 0)
742
                        strncpy2(dest, src, len);
743
                return 0;
744
        }
745
746
        /* Y2K compliant :) */
747
        if (year < 1000) {
748
                if (year < 50)
749
                        year += 2000;
750
                else
751
                        year += 1900;
752
        }
753
754
        month[3] = '\0';
755
        for (p = monthstr; *p != '\0'; p += 3) {
756
                if (!strncasecmp(p, month, 3)) {
757
                        dmonth = (gint)(p - monthstr) / 3 + 1;
758
                        break;
759
                }
760
        }
761
        if (*p == '\0')
762
                g_warning("Invalid month: %s\n", month);
763
764
        t.tm_sec = ss;
765
        t.tm_min = mm;
766
        t.tm_hour = hh;
767
        t.tm_mday = day;
768
        t.tm_mon = dmonth - 1;
769
        t.tm_year = year - 1900;
770
        t.tm_wday = 0;
771
        t.tm_yday = 0;
772
        t.tm_isdst = -1;
773
774
        timer = mktime(&t);
775
        tz_offset = remote_tzoffset_sec(zone);
776
        if (tz_offset != -1)
777
                timer += tzoffset_sec(&timer) - tz_offset;
778
779
        if (dest)
780
                procheader_date_get_localtime(dest, len, timer);
781
782
        return timer;
783
}
784
785
void procheader_date_get_localtime(gchar *dest, gint len, const time_t timer)
786
{
787
        struct tm *lt;
788
        gchar *default_format = "%y/%m/%d(%a) %H:%M";
789
        gchar *tmp, *buf;
790
791
        Xalloca(tmp, len + 1, dest[0] = '\0'; return;);
792
793
        lt = localtime(&timer);
794
795
        if (prefs_common.date_format)
796
                strftime(tmp, len, prefs_common.date_format, lt);
797
        else
798
                strftime(tmp, len, default_format, lt);
799
800
        buf = conv_localetodisp(tmp, NULL);
801
        strncpy2(dest, buf, len);
802
        g_free(buf);
803
}