Statistics
| Revision:

root / libsylph / procheader.c @ 2366

History | View | Annotate | Download (20.3 kB)

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