Statistics
| Revision:

root / libsylph / procmime.c @ 1973

History | View | Annotate | Download (38.2 kB)

1 1 hiro
/*
2 578 hiro
 * LibSylph -- E-Mail client library
3 1693 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 "defs.h"
25 1 hiro
26 1 hiro
#include <glib.h>
27 92 hiro
#include <glib/gi18n.h>
28 1 hiro
#include <stdio.h>
29 1 hiro
#include <string.h>
30 1 hiro
#include <locale.h>
31 1 hiro
#include <ctype.h>
32 1 hiro
33 1 hiro
#include "procmime.h"
34 1 hiro
#include "procheader.h"
35 1 hiro
#include "base64.h"
36 1 hiro
#include "quoted-printable.h"
37 1 hiro
#include "uuencode.h"
38 1 hiro
#include "html.h"
39 1 hiro
#include "codeconv.h"
40 1 hiro
#include "utils.h"
41 1 hiro
#include "prefs_common.h"
42 1 hiro
43 1593 hiro
#define MAX_MIME_LEVEL        64
44 1593 hiro
45 1 hiro
static GHashTable *procmime_get_mime_type_table        (void);
46 1 hiro
static GList *procmime_get_mime_type_list        (const gchar *file);
47 1 hiro
48 1 hiro
49 1 hiro
MimeInfo *procmime_mimeinfo_new(void)
50 1 hiro
{
51 1 hiro
        MimeInfo *mimeinfo;
52 1 hiro
53 1 hiro
        mimeinfo = g_new0(MimeInfo, 1);
54 1 hiro
        mimeinfo->mime_type     = MIME_UNKNOWN;
55 1 hiro
        mimeinfo->encoding_type = ENC_UNKNOWN;
56 1 hiro
57 1 hiro
        return mimeinfo;
58 1 hiro
}
59 1 hiro
60 1 hiro
void procmime_mimeinfo_free_all(MimeInfo *mimeinfo)
61 1 hiro
{
62 1 hiro
        while (mimeinfo != NULL) {
63 1 hiro
                MimeInfo *next;
64 1 hiro
65 1 hiro
                g_free(mimeinfo->encoding);
66 1 hiro
                g_free(mimeinfo->content_type);
67 1 hiro
                g_free(mimeinfo->charset);
68 1 hiro
                g_free(mimeinfo->name);
69 1 hiro
                g_free(mimeinfo->boundary);
70 1 hiro
                g_free(mimeinfo->content_disposition);
71 1 hiro
                g_free(mimeinfo->filename);
72 548 hiro
73 1 hiro
                g_free(mimeinfo->sigstatus);
74 1 hiro
                g_free(mimeinfo->sigstatus_full);
75 1 hiro
76 1 hiro
                procmime_mimeinfo_free_all(mimeinfo->sub);
77 1 hiro
                procmime_mimeinfo_free_all(mimeinfo->children);
78 1 hiro
                procmime_mimeinfo_free_all(mimeinfo->plaintext);
79 1 hiro
80 1 hiro
                next = mimeinfo->next;
81 1 hiro
                g_free(mimeinfo);
82 1 hiro
                mimeinfo = next;
83 1 hiro
        }
84 1 hiro
}
85 1 hiro
86 1 hiro
MimeInfo *procmime_mimeinfo_insert(MimeInfo *parent, MimeInfo *mimeinfo)
87 1 hiro
{
88 1 hiro
        MimeInfo *child = parent->children;
89 1 hiro
90 1 hiro
        if (!child)
91 1 hiro
                parent->children = mimeinfo;
92 1 hiro
        else {
93 1 hiro
                while (child->next != NULL)
94 1 hiro
                        child = child->next;
95 1 hiro
96 1 hiro
                child->next = mimeinfo;
97 1 hiro
        }
98 1 hiro
99 1 hiro
        mimeinfo->parent = parent;
100 1 hiro
        mimeinfo->level = parent->level + 1;
101 1 hiro
102 1 hiro
        return mimeinfo;
103 1 hiro
}
104 1 hiro
105 1325 hiro
#if 0
106 1 hiro
void procmime_mimeinfo_replace(MimeInfo *old, MimeInfo *new)
107 1 hiro
{
108 1 hiro
        MimeInfo *parent = old->parent;
109 1 hiro
        MimeInfo *child;
110 1 hiro
111 1 hiro
        g_return_if_fail(parent != NULL);
112 1 hiro
        g_return_if_fail(new->next == NULL);
113 1 hiro
114 1 hiro
        for (child = parent->children; child && child != old;
115 1 hiro
             child = child->next)
116 1 hiro
                ;
117 1 hiro
        if (!child) {
118 1 hiro
                g_warning("oops: parent can't find it's own child");
119 1 hiro
                return;
120 1 hiro
        }
121 1 hiro
        procmime_mimeinfo_free_all(old);
122 1 hiro
123 1 hiro
        if (child == parent->children) {
124 1 hiro
                new->next = parent->children->next;
125 1 hiro
                parent->children = new;
126 1 hiro
        } else {
127 1 hiro
                new->next = child->next;
128 1 hiro
                child = new;
129 1 hiro
        }
130 1 hiro
}
131 1325 hiro
#endif
132 1 hiro
133 1 hiro
MimeInfo *procmime_mimeinfo_next(MimeInfo *mimeinfo)
134 1 hiro
{
135 1 hiro
        if (!mimeinfo) return NULL;
136 1 hiro
137 1 hiro
        if (mimeinfo->children)
138 1 hiro
                return mimeinfo->children;
139 1 hiro
        if (mimeinfo->sub)
140 1 hiro
                return mimeinfo->sub;
141 1 hiro
        if (mimeinfo->next)
142 1 hiro
                return mimeinfo->next;
143 1 hiro
144 1 hiro
        if (mimeinfo->main) {
145 1 hiro
                mimeinfo = mimeinfo->main;
146 1 hiro
                if (mimeinfo->next)
147 1 hiro
                        return mimeinfo->next;
148 1 hiro
        }
149 1 hiro
150 1 hiro
        for (mimeinfo = mimeinfo->parent; mimeinfo != NULL;
151 1 hiro
             mimeinfo = mimeinfo->parent) {
152 1 hiro
                if (mimeinfo->next)
153 1 hiro
                        return mimeinfo->next;
154 1 hiro
                if (mimeinfo->main) {
155 1 hiro
                        mimeinfo = mimeinfo->main;
156 1 hiro
                        if (mimeinfo->next)
157 1 hiro
                                return mimeinfo->next;
158 1 hiro
                }
159 1 hiro
        }
160 1 hiro
161 1 hiro
        return NULL;
162 1 hiro
}
163 1 hiro
164 1 hiro
#if 0
165 1 hiro
void procmime_dump_mimeinfo(MimeInfo *mimeinfo)
166 1 hiro
{
167 1 hiro
        gint i;
168 1 hiro
169 1 hiro
        g_print("\n");
170 1 hiro
171 1 hiro
        for (; mimeinfo != NULL; mimeinfo = procmime_mimeinfo_next(mimeinfo)) {
172 1 hiro
                for (i = 0; i < mimeinfo->level; i++)
173 1 hiro
                        g_print("  ");
174 1 hiro
                g_print("%s%s\n", mimeinfo->main ? "sub: " : "",
175 1 hiro
                        mimeinfo->content_type);
176 1 hiro
        }
177 1 hiro
}
178 1 hiro
#endif
179 1 hiro
180 1 hiro
MimeInfo *procmime_scan_message(MsgInfo *msginfo)
181 1 hiro
{
182 1 hiro
        FILE *fp;
183 1 hiro
        MimeInfo *mimeinfo;
184 1 hiro
185 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
186 1 hiro
187 1 hiro
        if ((fp = procmsg_open_message_decrypted(msginfo, &mimeinfo)) == NULL)
188 1 hiro
                return NULL;
189 1 hiro
190 1 hiro
        if (mimeinfo) {
191 427 hiro
                mimeinfo->size = msginfo->size;
192 427 hiro
                mimeinfo->content_size = get_left_file_size(fp);
193 427 hiro
                if (mimeinfo->encoding_type == ENC_BASE64)
194 427 hiro
                        mimeinfo->content_size = mimeinfo->content_size / 4 * 3;
195 1 hiro
                if (mimeinfo->mime_type == MIME_MULTIPART ||
196 1 hiro
                    mimeinfo->mime_type == MIME_MESSAGE_RFC822)
197 1 hiro
                        procmime_scan_multipart_message(mimeinfo, fp);
198 1 hiro
        }
199 1 hiro
200 1 hiro
        fclose(fp);
201 1 hiro
202 1 hiro
        return mimeinfo;
203 1 hiro
}
204 1 hiro
205 1 hiro
void procmime_scan_multipart_message(MimeInfo *mimeinfo, FILE *fp)
206 1 hiro
{
207 1 hiro
        gchar *p;
208 1 hiro
        gchar *boundary;
209 1 hiro
        gint boundary_len = 0;
210 1593 hiro
        gchar *buf;
211 1 hiro
        glong fpos, prev_fpos;
212 1 hiro
213 1 hiro
        g_return_if_fail(mimeinfo != NULL);
214 1 hiro
        g_return_if_fail(mimeinfo->mime_type == MIME_MULTIPART ||
215 1 hiro
                         mimeinfo->mime_type == MIME_MESSAGE_RFC822);
216 1 hiro
217 1 hiro
        if (mimeinfo->mime_type == MIME_MULTIPART) {
218 1 hiro
                g_return_if_fail(mimeinfo->boundary != NULL);
219 1 hiro
                g_return_if_fail(mimeinfo->sub == NULL);
220 1 hiro
        }
221 1 hiro
        g_return_if_fail(fp != NULL);
222 1 hiro
223 1593 hiro
        buf = g_malloc(BUFFSIZE);
224 1593 hiro
225 1 hiro
        boundary = mimeinfo->boundary;
226 1 hiro
227 1 hiro
        if (boundary) {
228 1 hiro
                boundary_len = strlen(boundary);
229 1 hiro
230 1 hiro
                /* look for first boundary */
231 1593 hiro
                while ((p = fgets(buf, BUFFSIZE, fp)) != NULL)
232 1 hiro
                        if (IS_BOUNDARY(buf, boundary, boundary_len)) break;
233 1593 hiro
                if (!p) {
234 1593 hiro
                        g_free(buf);
235 1593 hiro
                        return;
236 1593 hiro
                }
237 1 hiro
        } else if (mimeinfo->parent && mimeinfo->parent->boundary) {
238 1 hiro
                boundary = mimeinfo->parent->boundary;
239 1 hiro
                boundary_len = strlen(boundary);
240 1 hiro
        }
241 1 hiro
242 1 hiro
        if ((fpos = ftell(fp)) < 0) {
243 1 hiro
                perror("ftell");
244 1593 hiro
                g_free(buf);
245 1 hiro
                return;
246 1 hiro
        }
247 1 hiro
248 1593 hiro
        debug_print("level = %d\n", mimeinfo->level);
249 1593 hiro
250 1 hiro
        for (;;) {
251 1 hiro
                MimeInfo *partinfo;
252 1 hiro
                gboolean eom = FALSE;
253 427 hiro
                glong content_pos;
254 427 hiro
                gboolean is_base64;
255 1 hiro
                gint len;
256 427 hiro
                guint b64_content_len = 0;
257 427 hiro
                gint b64_pad_len = 0;
258 1 hiro
259 1 hiro
                prev_fpos = fpos;
260 1 hiro
                debug_print("prev_fpos: %ld\n", fpos);
261 1 hiro
262 427 hiro
                /* scan part header */
263 1 hiro
                if (mimeinfo->mime_type == MIME_MESSAGE_RFC822) {
264 1 hiro
                        MimeInfo *sub;
265 1 hiro
266 1 hiro
                        mimeinfo->sub = sub = procmime_scan_mime_header(fp);
267 1 hiro
                        if (!sub) break;
268 1 hiro
269 1593 hiro
                        debug_print("message/rfc822 part (content-type: %s)\n",
270 1593 hiro
                                    sub->content_type);
271 1 hiro
                        sub->level = mimeinfo->level + 1;
272 1 hiro
                        sub->parent = mimeinfo->parent;
273 1 hiro
                        sub->main = mimeinfo;
274 1 hiro
275 1 hiro
                        partinfo = sub;
276 1 hiro
                } else {
277 1 hiro
                        partinfo = procmime_scan_mime_header(fp);
278 1 hiro
                        if (!partinfo) break;
279 1 hiro
                        procmime_mimeinfo_insert(mimeinfo, partinfo);
280 1 hiro
                        debug_print("content-type: %s\n",
281 1 hiro
                                    partinfo->content_type);
282 1 hiro
                }
283 1 hiro
284 427 hiro
                /* begin content */
285 427 hiro
                content_pos = ftell(fp);
286 427 hiro
                debug_print("content_pos: %ld\n", content_pos);
287 427 hiro
288 1 hiro
                if (partinfo->mime_type == MIME_MULTIPART ||
289 1 hiro
                    partinfo->mime_type == MIME_MESSAGE_RFC822) {
290 1593 hiro
                        if (partinfo->level < MAX_MIME_LEVEL)
291 1 hiro
                                procmime_scan_multipart_message(partinfo, fp);
292 1 hiro
                }
293 1 hiro
294 1 hiro
                /* look for next boundary */
295 1 hiro
                buf[0] = '\0';
296 427 hiro
                is_base64 = partinfo->encoding_type == ENC_BASE64;
297 1593 hiro
                while ((p = fgets(buf, BUFFSIZE, fp)) != NULL) {
298 1 hiro
                        if (IS_BOUNDARY(buf, boundary, boundary_len)) {
299 1 hiro
                                if (buf[2 + boundary_len]     == '-' &&
300 1 hiro
                                    buf[2 + boundary_len + 1] == '-')
301 1 hiro
                                        eom = TRUE;
302 1 hiro
                                break;
303 427 hiro
                        } else if (is_base64) {
304 427 hiro
                                const gchar *s;
305 427 hiro
                                for (s = buf; *s && *s != '\r' && *s != '\n';
306 427 hiro
                                     ++s)
307 427 hiro
                                        if (*s == '=')
308 427 hiro
                                                ++b64_pad_len;
309 427 hiro
                                b64_content_len += s - buf;
310 1 hiro
                        }
311 1 hiro
                }
312 1 hiro
                if (p == NULL) {
313 1 hiro
                        /* broken MIME, or single part MIME message */
314 1 hiro
                        buf[0] = '\0';
315 1 hiro
                        eom = TRUE;
316 1 hiro
                }
317 1 hiro
                debug_print("boundary: %s\n", buf);
318 1 hiro
319 1 hiro
                fpos = ftell(fp);
320 1 hiro
                debug_print("fpos: %ld\n", fpos);
321 1 hiro
322 1 hiro
                len = strlen(buf);
323 1 hiro
                partinfo->size = fpos - prev_fpos - len;
324 427 hiro
                if (is_base64)
325 427 hiro
                        partinfo->content_size =
326 427 hiro
                                b64_content_len / 4 * 3 - b64_pad_len;
327 427 hiro
                else
328 427 hiro
                        partinfo->content_size = fpos - content_pos - len;
329 1 hiro
                debug_print("partinfo->size: %d\n", partinfo->size);
330 427 hiro
                debug_print("partinfo->content_size: %d\n",
331 427 hiro
                            partinfo->content_size);
332 1 hiro
                if (partinfo->sub && !partinfo->sub->sub &&
333 1 hiro
                    !partinfo->sub->children) {
334 1 hiro
                        partinfo->sub->size =
335 1 hiro
                                fpos - partinfo->sub->fpos - strlen(buf);
336 1 hiro
                        debug_print("partinfo->sub->size: %d\n",
337 1 hiro
                                    partinfo->sub->size);
338 1 hiro
                }
339 1 hiro
340 1 hiro
                if (mimeinfo->mime_type == MIME_MESSAGE_RFC822) {
341 1 hiro
                        if (len > 0 && fseek(fp, fpos - len, SEEK_SET) < 0)
342 1 hiro
                                perror("fseek");
343 1 hiro
                        break;
344 1 hiro
                }
345 1 hiro
346 1 hiro
                if (eom) break;
347 1 hiro
        }
348 1593 hiro
349 1593 hiro
        g_free(buf);
350 1 hiro
}
351 1 hiro
352 1 hiro
void procmime_scan_encoding(MimeInfo *mimeinfo, const gchar *encoding)
353 1 hiro
{
354 1 hiro
        gchar *buf;
355 1 hiro
356 1 hiro
        Xstrdup_a(buf, encoding, return);
357 1 hiro
358 1 hiro
        g_free(mimeinfo->encoding);
359 1 hiro
360 1 hiro
        mimeinfo->encoding = g_strdup(g_strstrip(buf));
361 333 hiro
        if (!g_ascii_strcasecmp(buf, "7bit"))
362 1 hiro
                mimeinfo->encoding_type = ENC_7BIT;
363 333 hiro
        else if (!g_ascii_strcasecmp(buf, "8bit"))
364 1 hiro
                mimeinfo->encoding_type = ENC_8BIT;
365 333 hiro
        else if (!g_ascii_strcasecmp(buf, "quoted-printable"))
366 1 hiro
                mimeinfo->encoding_type = ENC_QUOTED_PRINTABLE;
367 333 hiro
        else if (!g_ascii_strcasecmp(buf, "base64"))
368 1 hiro
                mimeinfo->encoding_type = ENC_BASE64;
369 333 hiro
        else if (!g_ascii_strcasecmp(buf, "x-uuencode"))
370 1 hiro
                mimeinfo->encoding_type = ENC_X_UUENCODE;
371 1 hiro
        else
372 1 hiro
                mimeinfo->encoding_type = ENC_UNKNOWN;
373 1 hiro
374 1 hiro
}
375 1 hiro
376 1 hiro
void procmime_scan_content_type(MimeInfo *mimeinfo, const gchar *content_type)
377 1 hiro
{
378 1 hiro
        g_free(mimeinfo->content_type);
379 1 hiro
        g_free(mimeinfo->charset);
380 1 hiro
        g_free(mimeinfo->name);
381 144 hiro
        g_free(mimeinfo->boundary);
382 1 hiro
        mimeinfo->content_type = NULL;
383 1 hiro
        mimeinfo->charset      = NULL;
384 1 hiro
        mimeinfo->name         = NULL;
385 144 hiro
        mimeinfo->boundary     = NULL;
386 1 hiro
387 144 hiro
        procmime_scan_content_type_str(content_type, &mimeinfo->content_type,
388 144 hiro
                                       &mimeinfo->charset, &mimeinfo->name,
389 144 hiro
                                       &mimeinfo->boundary);
390 144 hiro
391 144 hiro
        mimeinfo->mime_type = procmime_scan_mime_type(mimeinfo->content_type);
392 144 hiro
        if (mimeinfo->mime_type == MIME_MULTIPART && !mimeinfo->boundary)
393 144 hiro
                mimeinfo->mime_type = MIME_TEXT;
394 144 hiro
}
395 144 hiro
396 1050 hiro
typedef struct
397 144 hiro
{
398 1050 hiro
        gchar *name;
399 1050 hiro
        gchar *value;
400 1050 hiro
} MimeParam;
401 144 hiro
402 1050 hiro
typedef struct
403 1050 hiro
{
404 1050 hiro
        gchar *hvalue;
405 1050 hiro
        GSList *plist;
406 1050 hiro
} MimeParams;
407 144 hiro
408 1050 hiro
static gchar *procmime_find_parameter_delimiter(const gchar *param,
409 1050 hiro
                                                const gchar **eq)
410 1050 hiro
{
411 1050 hiro
        register const gchar *p = param;
412 1050 hiro
        gboolean quoted = FALSE;
413 1050 hiro
        const gchar *delim = NULL;
414 1 hiro
415 1050 hiro
        while (*p) {
416 1050 hiro
                if (*p == '=')
417 1050 hiro
                        break;
418 1469 hiro
                else if (*p == ';' || *p == '\r' || *p == '\n') {
419 1050 hiro
                        delim = p;
420 1050 hiro
                        break;
421 1050 hiro
                }
422 1050 hiro
                ++p;
423 1050 hiro
        }
424 1050 hiro
        if (*p != '=') {
425 1050 hiro
                *eq = NULL;
426 1050 hiro
                return (gchar *)delim;
427 1050 hiro
        }
428 1050 hiro
        *eq = p;
429 1 hiro
430 1050 hiro
        ++p;
431 1469 hiro
        while (g_ascii_isspace(*p))
432 1469 hiro
                ++p;
433 1050 hiro
        if (*p == '"') {
434 1050 hiro
                quoted = TRUE;
435 1050 hiro
                ++p;
436 1050 hiro
        }
437 1050 hiro
438 1050 hiro
        while (*p) {
439 1050 hiro
                if (quoted == TRUE) {
440 1050 hiro
                        if (*p == '"')
441 1050 hiro
                                quoted = FALSE;
442 1469 hiro
                } else if (*p == ';' || *p == '\r' || *p == '\n') {
443 1050 hiro
                        delim = p;
444 1050 hiro
                        break;
445 1050 hiro
                }
446 1050 hiro
                ++p;
447 1050 hiro
        }
448 1050 hiro
449 1050 hiro
        return (gchar *)delim;
450 1050 hiro
}
451 1050 hiro
452 1050 hiro
static gchar *procmime_convert_value(const gchar *value, const gchar *charset)
453 1050 hiro
{
454 1050 hiro
        if (charset) {
455 1050 hiro
                gchar *utf8_value;
456 1050 hiro
457 1050 hiro
                utf8_value = conv_codeset_strdup(value, charset, CS_INTERNAL);
458 1050 hiro
                if (utf8_value)
459 1050 hiro
                        return utf8_value;
460 1050 hiro
        }
461 1050 hiro
462 1050 hiro
        return g_strdup(value);
463 1050 hiro
}
464 1050 hiro
465 1050 hiro
static MimeParams *procmime_parse_mime_parameter(const gchar *str)
466 1050 hiro
{
467 1050 hiro
        gchar *hvalue;
468 1050 hiro
        gchar *param, *name, *value;
469 1050 hiro
        gchar *charset = NULL, *lang = NULL;
470 1050 hiro
        const gchar *p, *delim;
471 1050 hiro
        gint count, prev_count;
472 1050 hiro
        gchar *cont_name;
473 1050 hiro
        gchar *cont_value;
474 1050 hiro
        MimeParam *mparam;
475 1050 hiro
        MimeParams *mparams;
476 1050 hiro
        GSList *plist = NULL;
477 1050 hiro
478 1050 hiro
        if ((p = strchr(str, ';')))
479 1050 hiro
                hvalue = g_strndup(str, p - str);
480 1050 hiro
        else
481 1050 hiro
                hvalue = g_strdup(str);
482 1050 hiro
483 1050 hiro
        g_strstrip(hvalue);
484 1050 hiro
485 1050 hiro
        mparams = g_new(MimeParams, 1);
486 1050 hiro
        mparams->hvalue = hvalue;
487 1050 hiro
        mparams->plist = NULL;
488 1050 hiro
489 1050 hiro
        if (!p)
490 1050 hiro
                return mparams;
491 1050 hiro
        ++p;
492 1050 hiro
        count = prev_count = -1;
493 1050 hiro
        cont_name = cont_value = NULL;
494 1050 hiro
495 1 hiro
        for (;;) {
496 1050 hiro
                gboolean encoded = FALSE;
497 1050 hiro
                gchar *begin;
498 1050 hiro
                gchar *dec_value;
499 1050 hiro
                const gchar *eq;
500 1050 hiro
                gchar *ast = NULL;
501 1 hiro
502 1050 hiro
                while (*p == ';' || g_ascii_isspace(*p))
503 1050 hiro
                        ++p;
504 1050 hiro
                if (*p == '\0')
505 1050 hiro
                        break;
506 1 hiro
507 1050 hiro
                delim = procmime_find_parameter_delimiter(p, &eq);
508 1050 hiro
                if (!eq)
509 1050 hiro
                        break;
510 1050 hiro
                if (delim)
511 1050 hiro
                        param = g_strndup(p, delim - p);
512 1050 hiro
                else
513 1050 hiro
                        param = g_strdup(p);
514 1 hiro
515 1050 hiro
                name = g_strndup(p, eq - p);
516 1469 hiro
                g_strchomp(name);
517 1050 hiro
                if (*name != '*' && (ast = strchr(name, '*'))) {
518 1050 hiro
                        const gchar *next = ast + 1;
519 1 hiro
520 1050 hiro
                        if (*next == '\0') {
521 1050 hiro
                                encoded = TRUE;
522 1050 hiro
                        } else if (g_ascii_isdigit(*next)) {
523 1050 hiro
                                count = atoi(next);
524 1050 hiro
                                while (g_ascii_isdigit(*next))
525 1050 hiro
                                        ++next;
526 1050 hiro
                                if (*next == '*')
527 1050 hiro
                                        encoded = TRUE;
528 1050 hiro
                                if (prev_count + 1 != count) {
529 1050 hiro
                                        g_warning("procmime_parse_mime_parameter(): invalid count: %s\n", str);
530 1050 hiro
                                        g_free(name);
531 1050 hiro
                                        g_free(param);
532 1050 hiro
                                        break;
533 1050 hiro
                                }
534 1050 hiro
                        } else {
535 1050 hiro
                                g_warning("procmime_parse_mime_parameter(): invalid name: %s\n", str);
536 1050 hiro
                                g_free(name);
537 1050 hiro
                                g_free(param);
538 1050 hiro
                                break;
539 1050 hiro
                        }
540 1050 hiro
541 1050 hiro
                        *ast = '\0';
542 1050 hiro
                }
543 1050 hiro
544 1050 hiro
                value = g_strdup(param + (eq - p) + 1);
545 1469 hiro
                g_strstrip(value);
546 1 hiro
                if (*value == '"')
547 1 hiro
                        extract_quote(value, '"');
548 1050 hiro
549 1050 hiro
                begin = value;
550 1050 hiro
551 1050 hiro
                if (encoded) {
552 1050 hiro
                        gchar *sq1, *sq2;
553 1050 hiro
554 1050 hiro
                        if ((sq1 = strchr(value, '\''))) {
555 1050 hiro
                                if (sq1 > value) {
556 1050 hiro
                                        if (charset)
557 1050 hiro
                                                g_free(charset);
558 1050 hiro
                                        charset = g_strndup(value, sq1 - value);
559 1050 hiro
                                }
560 1050 hiro
                                if ((sq2 = strchr(sq1 + 1, '\''))) {
561 1050 hiro
                                        if (sq2 > sq1 + 1) {
562 1050 hiro
                                                if (lang)
563 1050 hiro
                                                        g_free(lang);
564 1050 hiro
                                                lang = g_strndup(sq1 + 1,
565 1050 hiro
                                                                 sq2 - sq1 - 1);
566 1050 hiro
                                        }
567 1050 hiro
                                        begin = sq2 + 1;
568 1050 hiro
                                }
569 1050 hiro
                        }
570 1 hiro
                }
571 1 hiro
572 1050 hiro
#define CONCAT_CONT_VALUE(s)                                \
573 1050 hiro
{                                                        \
574 1050 hiro
        if (cont_value) {                                \
575 1050 hiro
                gchar *tmp;                                \
576 1050 hiro
                tmp = g_strconcat(cont_value, s, NULL);        \
577 1050 hiro
                g_free(cont_value);                        \
578 1050 hiro
                cont_value = tmp;                        \
579 1050 hiro
        } else                                                \
580 1050 hiro
                cont_value = g_strdup(s);                \
581 1050 hiro
}
582 1050 hiro
583 1050 hiro
                if (count >= 0) {
584 1050 hiro
                        if (count > 0 && cont_name) {
585 1050 hiro
                                if (strcmp(cont_name, name) != 0) {
586 1050 hiro
                                        g_warning("procmime_parse_mime_parameter(): mismatch parameter name: %s\n", str);
587 1050 hiro
                                        g_free(name);
588 1050 hiro
                                        g_free(value);
589 1050 hiro
                                        g_free(param);
590 1050 hiro
                                        break;
591 1050 hiro
                                }
592 1050 hiro
                        } else
593 1050 hiro
                                cont_name = g_strdup(name);
594 1050 hiro
595 1050 hiro
                        if (encoded) {
596 1050 hiro
                                dec_value = g_malloc(strlen(begin) + 1);
597 1052 hiro
                                decode_xdigit_encoded_str(dec_value, begin);
598 1050 hiro
                                CONCAT_CONT_VALUE(dec_value);
599 1050 hiro
                                g_free(dec_value);
600 1050 hiro
                        } else {
601 1050 hiro
                                CONCAT_CONT_VALUE(begin);
602 1050 hiro
                        }
603 1 hiro
                }
604 1 hiro
605 1050 hiro
#undef CONCAT_CONT_VALUE
606 1050 hiro
607 1050 hiro
                if (count == -1 && cont_name && cont_value) {
608 1050 hiro
                        mparam = g_new(MimeParam, 1);
609 1050 hiro
                        mparam->name = cont_name;
610 1050 hiro
                        cont_name = NULL;
611 1050 hiro
                        mparam->value = procmime_convert_value
612 1050 hiro
                                (cont_value, charset);
613 1050 hiro
                        g_free(cont_value);
614 1050 hiro
                        cont_value = NULL;
615 1050 hiro
                        plist = g_slist_prepend(plist, mparam);
616 1050 hiro
                }
617 1050 hiro
618 1050 hiro
                if (count == -1) {
619 1050 hiro
                        mparam = g_new(MimeParam, 1);
620 1050 hiro
                        mparam->name = name;
621 1050 hiro
                        if (encoded) {
622 1050 hiro
                                dec_value = g_malloc(strlen(begin) + 1);
623 1052 hiro
                                decode_xdigit_encoded_str(dec_value, begin);
624 1050 hiro
                                mparam->value = procmime_convert_value
625 1050 hiro
                                        (dec_value, charset);
626 1050 hiro
                                g_free(dec_value);
627 1050 hiro
                        } else {
628 1050 hiro
                                if (!ast &&
629 1050 hiro
                                    (!g_ascii_strcasecmp(name, "name") ||
630 1050 hiro
                                     !g_ascii_strcasecmp(name, "filename")))
631 1050 hiro
                                        mparam->value =
632 1050 hiro
                                                conv_unmime_header(begin, NULL);
633 1050 hiro
                                else
634 1050 hiro
                                        mparam->value = g_strdup(begin);
635 1050 hiro
                        }
636 1050 hiro
                        name = NULL;
637 1050 hiro
                        plist = g_slist_prepend(plist, mparam);
638 1050 hiro
                }
639 1050 hiro
640 1050 hiro
                g_free(name);
641 1050 hiro
                g_free(value);
642 1050 hiro
                g_free(param);
643 1050 hiro
644 1050 hiro
                prev_count = count;
645 1050 hiro
                count = -1;
646 1050 hiro
647 1050 hiro
                if (delim)
648 1050 hiro
                        p = delim + 1;
649 1050 hiro
                else
650 1050 hiro
                        break;
651 1 hiro
        }
652 1050 hiro
653 1050 hiro
        if (cont_name && cont_value) {
654 1050 hiro
                mparam = g_new(MimeParam, 1);
655 1050 hiro
                mparam->name = cont_name;
656 1050 hiro
                cont_name = NULL;
657 1050 hiro
                mparam->value = procmime_convert_value(cont_value, charset);
658 1050 hiro
                plist = g_slist_prepend(plist, mparam);
659 1050 hiro
        }
660 1050 hiro
661 1050 hiro
        g_free(cont_name);
662 1050 hiro
        g_free(cont_value);
663 1050 hiro
        g_free(lang);
664 1050 hiro
        g_free(charset);
665 1050 hiro
666 1050 hiro
        plist = g_slist_reverse(plist);
667 1050 hiro
        mparams->plist = plist;
668 1050 hiro
669 1050 hiro
        return mparams;
670 1 hiro
}
671 1 hiro
672 1050 hiro
static void procmime_mime_params_free(MimeParams *mparams)
673 1 hiro
{
674 1050 hiro
        GSList *cur;
675 1 hiro
676 1050 hiro
        if (!mparams)
677 1050 hiro
                return;
678 1 hiro
679 1050 hiro
        g_free(mparams->hvalue);
680 1050 hiro
        for (cur = mparams->plist; cur != NULL; cur = cur->next) {
681 1050 hiro
                MimeParam *mparam = (MimeParam *)cur->data;
682 1050 hiro
                g_free(mparam->name);
683 1050 hiro
                g_free(mparam->value);
684 1050 hiro
                g_free(mparam);
685 1050 hiro
        }
686 1050 hiro
        g_slist_free(mparams->plist);
687 1050 hiro
        g_free(mparams);
688 1050 hiro
}
689 1 hiro
690 1050 hiro
void procmime_scan_content_type_str(const gchar *content_type,
691 1050 hiro
                                    gchar **mime_type, gchar **charset,
692 1050 hiro
                                    gchar **name, gchar **boundary)
693 1050 hiro
{
694 1050 hiro
        MimeParams *mparams;
695 1050 hiro
        GSList *cur;
696 1 hiro
697 1050 hiro
        mparams = procmime_parse_mime_parameter(content_type);
698 1 hiro
699 1050 hiro
        if (mime_type)
700 1050 hiro
                *mime_type = g_strdup(mparams->hvalue);
701 1 hiro
702 1050 hiro
        for (cur = mparams->plist; cur != NULL; cur = cur->next) {
703 1050 hiro
                MimeParam *param = (MimeParam *)cur->data;
704 1050 hiro
                if (charset && !g_ascii_strcasecmp(param->name, "charset")) {
705 1050 hiro
                        *charset = g_strdup(param->value);
706 1050 hiro
                        charset = NULL;
707 1050 hiro
                } else if (name && !g_ascii_strcasecmp(param->name, "name")) {
708 1050 hiro
                        *name = g_strdup(param->value);
709 1050 hiro
                        name = NULL;
710 1050 hiro
                } else if (boundary &&
711 1050 hiro
                           !g_ascii_strcasecmp(param->name, "boundary")) {
712 1050 hiro
                        *boundary = g_strdup(param->value);
713 1050 hiro
                        boundary = NULL;
714 1050 hiro
                }
715 1050 hiro
        }
716 1 hiro
717 1050 hiro
        procmime_mime_params_free(mparams);
718 1050 hiro
}
719 1 hiro
720 1050 hiro
void procmime_scan_content_disposition(MimeInfo *mimeinfo,
721 1050 hiro
                                       const gchar *content_disposition)
722 1050 hiro
{
723 1050 hiro
        MimeParams *mparams;
724 1050 hiro
        GSList *cur;
725 1 hiro
726 1050 hiro
        mparams = procmime_parse_mime_parameter(content_disposition);
727 1050 hiro
728 1050 hiro
        mimeinfo->content_disposition = g_strdup(mparams->hvalue);
729 1050 hiro
730 1050 hiro
        for (cur = mparams->plist; cur != NULL; cur = cur->next) {
731 1050 hiro
                MimeParam *param = (MimeParam *)cur->data;
732 1050 hiro
                if (!g_ascii_strcasecmp(param->name, "filename")) {
733 1050 hiro
                        mimeinfo->filename = g_strdup(param->value);
734 1050 hiro
                        break;
735 1 hiro
                }
736 1050 hiro
        }
737 1 hiro
738 1050 hiro
        procmime_mime_params_free(mparams);
739 1 hiro
}
740 1 hiro
741 1 hiro
enum
742 1 hiro
{
743 1 hiro
        H_CONTENT_TRANSFER_ENCODING = 0,
744 1 hiro
        H_CONTENT_TYPE                    = 1,
745 1 hiro
        H_CONTENT_DISPOSITION            = 2
746 1 hiro
};
747 1 hiro
748 1 hiro
MimeInfo *procmime_scan_mime_header(FILE *fp)
749 1 hiro
{
750 1 hiro
        static HeaderEntry hentry[] = {{"Content-Transfer-Encoding:",
751 1 hiro
                                                          NULL, FALSE},
752 1 hiro
                                       {"Content-Type:", NULL, TRUE},
753 1 hiro
                                       {"Content-Disposition:",
754 1 hiro
                                                          NULL, TRUE},
755 1 hiro
                                       {NULL,                  NULL, FALSE}};
756 1 hiro
        gchar buf[BUFFSIZE];
757 1 hiro
        gint hnum;
758 1 hiro
        HeaderEntry *hp;
759 1 hiro
        MimeInfo *mimeinfo;
760 1 hiro
761 1 hiro
        g_return_val_if_fail(fp != NULL, NULL);
762 1 hiro
763 1 hiro
        mimeinfo = procmime_mimeinfo_new();
764 1 hiro
        mimeinfo->mime_type = MIME_TEXT;
765 1 hiro
        mimeinfo->encoding_type = ENC_7BIT;
766 1 hiro
        mimeinfo->fpos = ftell(fp);
767 1 hiro
768 1 hiro
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
769 1 hiro
               != -1) {
770 1 hiro
                hp = hentry + hnum;
771 1 hiro
772 1 hiro
                if (H_CONTENT_TRANSFER_ENCODING == hnum) {
773 1 hiro
                        procmime_scan_encoding
774 1 hiro
                                (mimeinfo, buf + strlen(hp->name));
775 1 hiro
                } else if (H_CONTENT_TYPE == hnum) {
776 1 hiro
                        procmime_scan_content_type
777 1 hiro
                                (mimeinfo, buf + strlen(hp->name));
778 1 hiro
                } else if (H_CONTENT_DISPOSITION == hnum) {
779 1 hiro
                        procmime_scan_content_disposition
780 1 hiro
                                (mimeinfo, buf + strlen(hp->name));
781 1 hiro
                }
782 1 hiro
        }
783 1 hiro
784 1 hiro
        if (mimeinfo->mime_type == MIME_APPLICATION_OCTET_STREAM &&
785 1 hiro
            mimeinfo->name) {
786 1 hiro
                const gchar *type;
787 1 hiro
                type = procmime_get_mime_type(mimeinfo->name);
788 1 hiro
                if (type)
789 1 hiro
                        mimeinfo->mime_type = procmime_scan_mime_type(type);
790 1 hiro
        }
791 1 hiro
792 1 hiro
        if (!mimeinfo->content_type)
793 1 hiro
                mimeinfo->content_type = g_strdup("text/plain");
794 1 hiro
795 1 hiro
        return mimeinfo;
796 1 hiro
}
797 1 hiro
798 1 hiro
FILE *procmime_decode_content(FILE *outfp, FILE *infp, MimeInfo *mimeinfo)
799 1 hiro
{
800 1 hiro
        gchar buf[BUFFSIZE];
801 1 hiro
        gchar *boundary = NULL;
802 1 hiro
        gint boundary_len = 0;
803 1 hiro
        gboolean tmp_file = FALSE;
804 784 hiro
        gboolean normalize_lbreak = FALSE;
805 784 hiro
        ContentType content_type;
806 1 hiro
807 1 hiro
        g_return_val_if_fail(infp != NULL, NULL);
808 1 hiro
        g_return_val_if_fail(mimeinfo != NULL, NULL);
809 1 hiro
810 1 hiro
        if (!outfp) {
811 1 hiro
                outfp = my_tmpfile();
812 1 hiro
                if (!outfp) {
813 1 hiro
                        perror("tmpfile");
814 1 hiro
                        return NULL;
815 1 hiro
                }
816 1 hiro
                tmp_file = TRUE;
817 1 hiro
        }
818 1 hiro
819 1 hiro
        if (mimeinfo->parent && mimeinfo->parent->boundary) {
820 1 hiro
                boundary = mimeinfo->parent->boundary;
821 1 hiro
                boundary_len = strlen(boundary);
822 1 hiro
        }
823 1 hiro
824 784 hiro
        content_type = procmime_scan_mime_type(mimeinfo->content_type);
825 784 hiro
        if (content_type == MIME_TEXT ||
826 784 hiro
            content_type == MIME_TEXT_HTML) {
827 784 hiro
                normalize_lbreak = TRUE;
828 784 hiro
        }
829 784 hiro
830 1 hiro
        if (mimeinfo->encoding_type == ENC_QUOTED_PRINTABLE) {
831 784 hiro
                FILE *tmpfp = outfp;
832 784 hiro
833 784 hiro
                if (normalize_lbreak) {
834 784 hiro
                        tmpfp = my_tmpfile();
835 784 hiro
                        if (!tmpfp) {
836 784 hiro
                                perror("tmpfile");
837 784 hiro
                                if (tmp_file) fclose(outfp);
838 784 hiro
                                return NULL;
839 784 hiro
                        }
840 784 hiro
                }
841 784 hiro
842 1 hiro
                while (fgets(buf, sizeof(buf), infp) != NULL &&
843 1 hiro
                       (!boundary ||
844 1 hiro
                        !IS_BOUNDARY(buf, boundary, boundary_len))) {
845 1 hiro
                        gint len;
846 1 hiro
                        len = qp_decode_line(buf);
847 784 hiro
                        fwrite(buf, len, 1, tmpfp);
848 1 hiro
                }
849 784 hiro
850 784 hiro
                if (normalize_lbreak) {
851 1154 hiro
                        if (fflush(tmpfp) == EOF) {
852 1154 hiro
                                perror("fflush");
853 1154 hiro
                                fclose(tmpfp);
854 1154 hiro
                                if (tmp_file) fclose(outfp);
855 1154 hiro
                                return NULL;
856 1154 hiro
                        }
857 784 hiro
                        rewind(tmpfp);
858 784 hiro
                        while (fgets(buf, sizeof(buf), tmpfp) != NULL) {
859 784 hiro
#ifdef G_OS_WIN32
860 784 hiro
                                strretchomp(buf);
861 784 hiro
                                fputs(buf, outfp);
862 784 hiro
                                fputs("\r\n", outfp);
863 784 hiro
#else
864 784 hiro
                                strcrchomp(buf);
865 784 hiro
                                fputs(buf, outfp);
866 784 hiro
#endif
867 784 hiro
                        }
868 784 hiro
                        fclose(tmpfp);
869 784 hiro
                }
870 1 hiro
        } else if (mimeinfo->encoding_type == ENC_BASE64) {
871 1 hiro
                gchar outbuf[BUFFSIZE];
872 1 hiro
                gint len;
873 1 hiro
                Base64Decoder *decoder;
874 1 hiro
                FILE *tmpfp = outfp;
875 1 hiro
876 784 hiro
                if (normalize_lbreak) {
877 1 hiro
                        tmpfp = my_tmpfile();
878 1 hiro
                        if (!tmpfp) {
879 1 hiro
                                perror("tmpfile");
880 1 hiro
                                if (tmp_file) fclose(outfp);
881 1 hiro
                                return NULL;
882 1 hiro
                        }
883 1 hiro
                }
884 1 hiro
885 1 hiro
                decoder = base64_decoder_new();
886 1 hiro
                while (fgets(buf, sizeof(buf), infp) != NULL &&
887 1 hiro
                       (!boundary ||
888 1 hiro
                        !IS_BOUNDARY(buf, boundary, boundary_len))) {
889 583 hiro
                        len = base64_decoder_decode(decoder, buf,
890 583 hiro
                                                    (guchar *)outbuf);
891 1 hiro
                        if (len < 0) {
892 1 hiro
                                g_warning("Bad BASE64 content\n");
893 1 hiro
                                break;
894 1 hiro
                        }
895 1 hiro
                        fwrite(outbuf, sizeof(gchar), len, tmpfp);
896 1 hiro
                }
897 1 hiro
                base64_decoder_free(decoder);
898 1 hiro
899 784 hiro
                if (normalize_lbreak) {
900 1154 hiro
                        if (fflush(tmpfp) == EOF) {
901 1154 hiro
                                perror("fflush");
902 1154 hiro
                                fclose(tmpfp);
903 1154 hiro
                                if (tmp_file) fclose(outfp);
904 1154 hiro
                                return NULL;
905 1154 hiro
                        }
906 1 hiro
                        rewind(tmpfp);
907 1 hiro
                        while (fgets(buf, sizeof(buf), tmpfp) != NULL) {
908 784 hiro
#ifdef G_OS_WIN32
909 784 hiro
                                strretchomp(buf);
910 784 hiro
                                fputs(buf, outfp);
911 784 hiro
                                fputs("\r\n", outfp);
912 784 hiro
#else
913 1 hiro
                                strcrchomp(buf);
914 1 hiro
                                fputs(buf, outfp);
915 784 hiro
#endif
916 1 hiro
                        }
917 1 hiro
                        fclose(tmpfp);
918 1 hiro
                }
919 1 hiro
        } else if (mimeinfo->encoding_type == ENC_X_UUENCODE) {
920 1 hiro
                gchar outbuf[BUFFSIZE];
921 1 hiro
                gint len;
922 1 hiro
                gboolean flag = FALSE;
923 1 hiro
924 1 hiro
                while (fgets(buf, sizeof(buf), infp) != NULL &&
925 1 hiro
                       (!boundary ||
926 1 hiro
                        !IS_BOUNDARY(buf, boundary, boundary_len))) {
927 1 hiro
                        if(!flag && strncmp(buf,"begin ", 6)) continue;
928 1 hiro
929 1 hiro
                        if (flag) {
930 1 hiro
                                len = fromuutobits(outbuf, buf);
931 1 hiro
                                if (len <= 0) {
932 1 hiro
                                        if (len < 0)
933 1 hiro
                                                g_warning("Bad UUENCODE content(%d)\n", len);
934 1 hiro
                                        break;
935 1 hiro
                                }
936 1 hiro
                                fwrite(outbuf, sizeof(gchar), len, outfp);
937 1 hiro
                        } else
938 1 hiro
                                flag = TRUE;
939 1 hiro
                }
940 1 hiro
        } else {
941 1 hiro
                while (fgets(buf, sizeof(buf), infp) != NULL &&
942 1 hiro
                       (!boundary ||
943 1 hiro
                        !IS_BOUNDARY(buf, boundary, boundary_len))) {
944 784 hiro
                        if (normalize_lbreak) {
945 784 hiro
#ifdef G_OS_WIN32
946 784 hiro
                                strretchomp(buf);
947 784 hiro
                                fputs(buf, outfp);
948 784 hiro
                                fputs("\r\n", outfp);
949 784 hiro
#else
950 780 hiro
                                strcrchomp(buf);
951 784 hiro
                                fputs(buf, outfp);
952 780 hiro
#endif
953 784 hiro
                        } else
954 784 hiro
                                fputs(buf, outfp);
955 1 hiro
                }
956 1 hiro
        }
957 1 hiro
958 1154 hiro
        if (fflush(outfp) == EOF)
959 1154 hiro
                perror("fflush");
960 1154 hiro
        if (ferror(outfp) != 0) {
961 1154 hiro
                g_warning("procmime_decode_content(): Can't write to temporary file\n");
962 1154 hiro
                if (tmp_file) fclose(outfp);
963 1154 hiro
                return NULL;
964 1154 hiro
        }
965 1154 hiro
966 1 hiro
        if (tmp_file) rewind(outfp);
967 1 hiro
        return outfp;
968 1 hiro
}
969 1 hiro
970 1 hiro
gint procmime_get_part(const gchar *outfile, const gchar *infile,
971 1 hiro
                       MimeInfo *mimeinfo)
972 1 hiro
{
973 97 hiro
        FILE *infp;
974 97 hiro
        gint ret;
975 1 hiro
976 1 hiro
        g_return_val_if_fail(outfile != NULL, -1);
977 1 hiro
        g_return_val_if_fail(infile != NULL, -1);
978 1 hiro
        g_return_val_if_fail(mimeinfo != NULL, -1);
979 1 hiro
980 478 hiro
        if ((infp = g_fopen(infile, "rb")) == NULL) {
981 1 hiro
                FILE_OP_ERROR(infile, "fopen");
982 1 hiro
                return -1;
983 1 hiro
        }
984 97 hiro
        ret = procmime_get_part_fp(outfile, infp, mimeinfo);
985 97 hiro
        fclose(infp);
986 97 hiro
987 97 hiro
        return ret;
988 97 hiro
}
989 97 hiro
990 97 hiro
gint procmime_get_part_fp(const gchar *outfile, FILE *infp, MimeInfo *mimeinfo)
991 97 hiro
{
992 97 hiro
        FILE *outfp;
993 97 hiro
        gchar buf[BUFFSIZE];
994 97 hiro
995 97 hiro
        g_return_val_if_fail(outfile != NULL, -1);
996 97 hiro
        g_return_val_if_fail(infp != NULL, -1);
997 97 hiro
        g_return_val_if_fail(mimeinfo != NULL, -1);
998 97 hiro
999 1 hiro
        if (fseek(infp, mimeinfo->fpos, SEEK_SET) < 0) {
1000 97 hiro
                FILE_OP_ERROR("procmime_get_part_fp()", "fseek");
1001 1 hiro
                return -1;
1002 1 hiro
        }
1003 478 hiro
        if ((outfp = g_fopen(outfile, "wb")) == NULL) {
1004 1 hiro
                FILE_OP_ERROR(outfile, "fopen");
1005 1 hiro
                return -1;
1006 1 hiro
        }
1007 1 hiro
1008 1 hiro
        while (fgets(buf, sizeof(buf), infp) != NULL)
1009 1 hiro
                if (buf[0] == '\r' || buf[0] == '\n') break;
1010 1 hiro
1011 1157 hiro
        if (procmime_decode_content(outfp, infp, mimeinfo) == NULL) {
1012 1157 hiro
                fclose(outfp);
1013 1157 hiro
                g_unlink(outfile);
1014 1157 hiro
                return -1;
1015 1157 hiro
        }
1016 1 hiro
1017 1 hiro
        if (fclose(outfp) == EOF) {
1018 1 hiro
                FILE_OP_ERROR(outfile, "fclose");
1019 478 hiro
                g_unlink(outfile);
1020 1 hiro
                return -1;
1021 1 hiro
        }
1022 1 hiro
1023 1 hiro
        return 0;
1024 1 hiro
}
1025 1 hiro
1026 601 hiro
gint procmime_get_all_parts(const gchar *dir, const gchar *infile,
1027 601 hiro
                            MimeInfo *mimeinfo)
1028 601 hiro
{
1029 601 hiro
        FILE *fp;
1030 601 hiro
        MimeInfo *partinfo;
1031 601 hiro
        gchar *base, *filename;
1032 601 hiro
1033 601 hiro
        g_return_val_if_fail(dir != NULL, -1);
1034 601 hiro
        g_return_val_if_fail(infile != NULL, -1);
1035 601 hiro
        g_return_val_if_fail(mimeinfo != NULL, -1);
1036 601 hiro
1037 601 hiro
        if (!is_dir_exist(dir)) {
1038 601 hiro
                g_warning("%s: directory not exist.\n", dir);
1039 601 hiro
                return -1;
1040 601 hiro
        }
1041 601 hiro
1042 601 hiro
        if ((fp = g_fopen(infile, "rb")) == NULL) {
1043 601 hiro
                FILE_OP_ERROR(infile, "fopen");
1044 601 hiro
                return -1;
1045 601 hiro
        }
1046 601 hiro
1047 601 hiro
        for (partinfo = mimeinfo; partinfo != NULL;
1048 601 hiro
             partinfo = procmime_mimeinfo_next(partinfo)) {
1049 601 hiro
                if (partinfo->filename || partinfo->name) {
1050 601 hiro
                        gint count = 1;
1051 601 hiro
1052 601 hiro
                        base = procmime_get_part_file_name(partinfo);
1053 601 hiro
                        filename = g_strconcat(dir, G_DIR_SEPARATOR_S, base,
1054 601 hiro
                                               NULL);
1055 601 hiro
1056 601 hiro
                        while (is_file_entry_exist(filename)) {
1057 601 hiro
                                gchar *base_alt;
1058 601 hiro
1059 601 hiro
                                base_alt = get_alt_filename(base, count++);
1060 601 hiro
                                g_free(filename);
1061 601 hiro
                                filename = g_strconcat
1062 601 hiro
                                        (dir, G_DIR_SEPARATOR_S, base_alt,
1063 601 hiro
                                         NULL);
1064 601 hiro
                                g_free(base_alt);
1065 601 hiro
                        }
1066 601 hiro
1067 601 hiro
                        procmime_get_part_fp(filename, fp, partinfo);
1068 601 hiro
1069 601 hiro
                        g_free(filename);
1070 601 hiro
                        g_free(base);
1071 601 hiro
                }
1072 601 hiro
        }
1073 601 hiro
1074 601 hiro
        fclose(fp);
1075 601 hiro
1076 601 hiro
        return 0;
1077 601 hiro
}
1078 601 hiro
1079 129 hiro
FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp,
1080 129 hiro
                                const gchar *encoding)
1081 1 hiro
{
1082 1 hiro
        FILE *tmpfp, *outfp;
1083 129 hiro
        const gchar *src_encoding;
1084 1 hiro
        gboolean conv_fail = FALSE;
1085 1 hiro
        gchar buf[BUFFSIZE];
1086 1 hiro
1087 1 hiro
        g_return_val_if_fail(mimeinfo != NULL, NULL);
1088 1 hiro
        g_return_val_if_fail(infp != NULL, NULL);
1089 1 hiro
        g_return_val_if_fail(mimeinfo->mime_type == MIME_TEXT ||
1090 1 hiro
                             mimeinfo->mime_type == MIME_TEXT_HTML, NULL);
1091 1 hiro
1092 1 hiro
        if (fseek(infp, mimeinfo->fpos, SEEK_SET) < 0) {
1093 1 hiro
                perror("fseek");
1094 1 hiro
                return NULL;
1095 1 hiro
        }
1096 1 hiro
1097 1 hiro
        while (fgets(buf, sizeof(buf), infp) != NULL)
1098 1 hiro
                if (buf[0] == '\r' || buf[0] == '\n') break;
1099 1 hiro
1100 1 hiro
        tmpfp = procmime_decode_content(NULL, infp, mimeinfo);
1101 1 hiro
        if (!tmpfp)
1102 1 hiro
                return NULL;
1103 1 hiro
1104 1 hiro
        if ((outfp = my_tmpfile()) == NULL) {
1105 1 hiro
                perror("tmpfile");
1106 1 hiro
                fclose(tmpfp);
1107 1 hiro
                return NULL;
1108 1 hiro
        }
1109 1 hiro
1110 702 hiro
        src_encoding = prefs_common.force_charset ? prefs_common.force_charset
1111 702 hiro
                : mimeinfo->charset ? mimeinfo->charset
1112 716 hiro
                : prefs_common.default_encoding;
1113 1 hiro
1114 1 hiro
        if (mimeinfo->mime_type == MIME_TEXT) {
1115 1 hiro
                while (fgets(buf, sizeof(buf), tmpfp) != NULL) {
1116 184 hiro
                        gchar *str;
1117 184 hiro
1118 129 hiro
                        str = conv_codeset_strdup(buf, src_encoding, encoding);
1119 1 hiro
                        if (str) {
1120 1 hiro
                                fputs(str, outfp);
1121 1 hiro
                                g_free(str);
1122 1 hiro
                        } else {
1123 1 hiro
                                conv_fail = TRUE;
1124 1 hiro
                                fputs(buf, outfp);
1125 1 hiro
                        }
1126 1 hiro
                }
1127 1 hiro
        } else if (mimeinfo->mime_type == MIME_TEXT_HTML) {
1128 1 hiro
                HTMLParser *parser;
1129 1 hiro
                CodeConverter *conv;
1130 184 hiro
                const gchar *str;
1131 1 hiro
1132 129 hiro
                conv = conv_code_converter_new(src_encoding, encoding);
1133 1 hiro
                parser = html_parser_new(tmpfp, conv);
1134 1 hiro
                while ((str = html_parse(parser)) != NULL) {
1135 1 hiro
                        fputs(str, outfp);
1136 1 hiro
                }
1137 1 hiro
                html_parser_destroy(parser);
1138 1 hiro
                conv_code_converter_destroy(conv);
1139 1 hiro
        }
1140 1 hiro
1141 1 hiro
        if (conv_fail)
1142 1 hiro
                g_warning(_("procmime_get_text_content(): Code conversion failed.\n"));
1143 1 hiro
1144 1 hiro
        fclose(tmpfp);
1145 1156 hiro
        if (fflush(outfp) == EOF) {
1146 1156 hiro
                perror("fflush");
1147 1156 hiro
                fclose(outfp);
1148 1156 hiro
                return NULL;
1149 1156 hiro
        }
1150 1 hiro
        rewind(outfp);
1151 1 hiro
1152 1 hiro
        return outfp;
1153 1 hiro
}
1154 1 hiro
1155 1 hiro
/* search the first text part of (multipart) MIME message,
1156 1 hiro
   decode, convert it and output to outfp. */
1157 129 hiro
FILE *procmime_get_first_text_content(MsgInfo *msginfo, const gchar *encoding)
1158 1 hiro
{
1159 1 hiro
        FILE *infp, *outfp = NULL;
1160 1 hiro
        MimeInfo *mimeinfo, *partinfo;
1161 1 hiro
1162 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1163 1 hiro
1164 1 hiro
        mimeinfo = procmime_scan_message(msginfo);
1165 1 hiro
        if (!mimeinfo) return NULL;
1166 1 hiro
1167 1 hiro
        if ((infp = procmsg_open_message(msginfo)) == NULL) {
1168 1 hiro
                procmime_mimeinfo_free_all(mimeinfo);
1169 1 hiro
                return NULL;
1170 1 hiro
        }
1171 1 hiro
1172 1 hiro
        partinfo = mimeinfo;
1173 1 hiro
        while (partinfo && partinfo->mime_type != MIME_TEXT)
1174 1 hiro
                partinfo = procmime_mimeinfo_next(partinfo);
1175 1 hiro
        if (!partinfo) {
1176 1 hiro
                partinfo = mimeinfo;
1177 1 hiro
                while (partinfo && partinfo->mime_type != MIME_TEXT_HTML)
1178 1 hiro
                        partinfo = procmime_mimeinfo_next(partinfo);
1179 1 hiro
        }
1180 1 hiro
1181 1 hiro
        if (partinfo)
1182 129 hiro
                outfp = procmime_get_text_content(partinfo, infp, encoding);
1183 1 hiro
1184 1 hiro
        fclose(infp);
1185 1 hiro
        procmime_mimeinfo_free_all(mimeinfo);
1186 1 hiro
1187 1 hiro
        return outfp;
1188 1 hiro
}
1189 1 hiro
1190 1 hiro
gboolean procmime_find_string_part(MimeInfo *mimeinfo, const gchar *filename,
1191 1 hiro
                                   const gchar *str, StrFindFunc find_func)
1192 1 hiro
{
1193 1 hiro
1194 1 hiro
        FILE *infp, *outfp;
1195 1 hiro
        gchar buf[BUFFSIZE];
1196 1 hiro
1197 1 hiro
        g_return_val_if_fail(mimeinfo != NULL, FALSE);
1198 1 hiro
        g_return_val_if_fail(mimeinfo->mime_type == MIME_TEXT ||
1199 1 hiro
                             mimeinfo->mime_type == MIME_TEXT_HTML, FALSE);
1200 1 hiro
        g_return_val_if_fail(str != NULL, FALSE);
1201 1 hiro
        g_return_val_if_fail(find_func != NULL, FALSE);
1202 1 hiro
1203 478 hiro
        if ((infp = g_fopen(filename, "rb")) == NULL) {
1204 1 hiro
                FILE_OP_ERROR(filename, "fopen");
1205 1 hiro
                return FALSE;
1206 1 hiro
        }
1207 1 hiro
1208 129 hiro
        outfp = procmime_get_text_content(mimeinfo, infp, NULL);
1209 1 hiro
        fclose(infp);
1210 1 hiro
1211 1 hiro
        if (!outfp)
1212 1 hiro
                return FALSE;
1213 1 hiro
1214 1 hiro
        while (fgets(buf, sizeof(buf), outfp) != NULL) {
1215 1 hiro
                strretchomp(buf);
1216 1 hiro
                if (find_func(buf, str)) {
1217 1 hiro
                        fclose(outfp);
1218 1 hiro
                        return TRUE;
1219 1 hiro
                }
1220 1 hiro
        }
1221 1 hiro
1222 1 hiro
        fclose(outfp);
1223 1 hiro
1224 1 hiro
        return FALSE;
1225 1 hiro
}
1226 1 hiro
1227 1 hiro
gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str,
1228 1 hiro
                              StrFindFunc find_func)
1229 1 hiro
{
1230 1 hiro
        MimeInfo *mimeinfo;
1231 1 hiro
        MimeInfo *partinfo;
1232 1 hiro
        gchar *filename;
1233 1 hiro
        gboolean found = FALSE;
1234 1 hiro
1235 1 hiro
        g_return_val_if_fail(msginfo != NULL, FALSE);
1236 1 hiro
        g_return_val_if_fail(str != NULL, FALSE);
1237 1 hiro
        g_return_val_if_fail(find_func != NULL, FALSE);
1238 1 hiro
1239 1 hiro
        filename = procmsg_get_message_file(msginfo);
1240 1 hiro
        if (!filename) return FALSE;
1241 1 hiro
        mimeinfo = procmime_scan_message(msginfo);
1242 1 hiro
1243 1 hiro
        for (partinfo = mimeinfo; partinfo != NULL;
1244 1 hiro
             partinfo = procmime_mimeinfo_next(partinfo)) {
1245 1 hiro
                if (partinfo->mime_type == MIME_TEXT ||
1246 1 hiro
                    partinfo->mime_type == MIME_TEXT_HTML) {
1247 1 hiro
                        if (procmime_find_string_part
1248 1 hiro
                                (partinfo, filename, str, find_func) == TRUE) {
1249 1 hiro
                                found = TRUE;
1250 1 hiro
                                break;
1251 1 hiro
                        }
1252 1 hiro
                }
1253 1 hiro
        }
1254 1 hiro
1255 1 hiro
        procmime_mimeinfo_free_all(mimeinfo);
1256 1 hiro
        g_free(filename);
1257 1 hiro
1258 1 hiro
        return found;
1259 1 hiro
}
1260 1 hiro
1261 162 hiro
gchar *procmime_get_part_file_name(MimeInfo *mimeinfo)
1262 162 hiro
{
1263 162 hiro
        gchar *base;
1264 162 hiro
        const gchar *base_;
1265 162 hiro
1266 162 hiro
        base_ = mimeinfo->filename ? mimeinfo->filename
1267 162 hiro
                : mimeinfo->name ? mimeinfo->name : "mimetmp";
1268 162 hiro
        base_ = g_basename(base_);
1269 162 hiro
        if (*base_ == '\0') base_ = "mimetmp";
1270 162 hiro
        base = conv_filename_from_utf8(base_);
1271 162 hiro
        subst_for_filename(base);
1272 162 hiro
1273 162 hiro
        return base;
1274 162 hiro
}
1275 162 hiro
1276 1 hiro
gchar *procmime_get_tmp_file_name(MimeInfo *mimeinfo)
1277 1 hiro
{
1278 1 hiro
        static guint32 id = 0;
1279 1 hiro
        gchar *base;
1280 1 hiro
        gchar *filename;
1281 1 hiro
        gchar f_prefix[10];
1282 1 hiro
1283 1 hiro
        g_return_val_if_fail(mimeinfo != NULL, NULL);
1284 1 hiro
1285 1 hiro
        g_snprintf(f_prefix, sizeof(f_prefix), "%08x.", id++);
1286 1 hiro
1287 1 hiro
        if (MIME_TEXT_HTML == mimeinfo->mime_type)
1288 109 hiro
                base = g_strdup("mimetmp.html");
1289 162 hiro
        else
1290 162 hiro
                base = procmime_get_part_file_name(mimeinfo);
1291 109 hiro
1292 1 hiro
        filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
1293 1 hiro
                               f_prefix, base, NULL);
1294 1 hiro
1295 109 hiro
        g_free(base);
1296 109 hiro
1297 1 hiro
        return filename;
1298 1 hiro
}
1299 1 hiro
1300 1 hiro
ContentType procmime_scan_mime_type(const gchar *mime_type)
1301 1 hiro
{
1302 1 hiro
        ContentType type;
1303 1 hiro
1304 333 hiro
        if (!g_ascii_strncasecmp(mime_type, "text/html", 9))
1305 1 hiro
                type = MIME_TEXT_HTML;
1306 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "text/", 5))
1307 1 hiro
                type = MIME_TEXT;
1308 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "message/rfc822", 14))
1309 1 hiro
                type = MIME_MESSAGE_RFC822;
1310 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "message/", 8))
1311 1 hiro
                type = MIME_TEXT;
1312 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "application/octet-stream",
1313 333 hiro
                                      24))
1314 1 hiro
                type = MIME_APPLICATION_OCTET_STREAM;
1315 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "application/", 12))
1316 1 hiro
                type = MIME_APPLICATION;
1317 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "multipart/", 10))
1318 1 hiro
                type = MIME_MULTIPART;
1319 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "image/", 6))
1320 1 hiro
                type = MIME_IMAGE;
1321 333 hiro
        else if (!g_ascii_strncasecmp(mime_type, "audio/", 6))
1322 1 hiro
                type = MIME_AUDIO;
1323 924 hiro
        else if (!g_ascii_strncasecmp(mime_type, "video/", 6))
1324 924 hiro
                type = MIME_VIDEO;
1325 333 hiro
        else if (!g_ascii_strcasecmp(mime_type, "text"))
1326 1 hiro
                type = MIME_TEXT;
1327 1 hiro
        else
1328 1 hiro
                type = MIME_UNKNOWN;
1329 1 hiro
1330 1 hiro
        return type;
1331 1 hiro
}
1332 1 hiro
1333 1 hiro
static GList *mime_type_list = NULL;
1334 1 hiro
1335 1 hiro
gchar *procmime_get_mime_type(const gchar *filename)
1336 1 hiro
{
1337 1 hiro
        static GHashTable *mime_type_table = NULL;
1338 1 hiro
        MimeType *mime_type;
1339 1 hiro
        const gchar *p;
1340 1 hiro
        gchar *ext;
1341 647 hiro
        static gboolean no_mime_type_table = FALSE;
1342 1 hiro
1343 647 hiro
        if (no_mime_type_table)
1344 647 hiro
                return NULL;
1345 647 hiro
1346 1 hiro
        if (!mime_type_table) {
1347 1 hiro
                mime_type_table = procmime_get_mime_type_table();
1348 647 hiro
                if (!mime_type_table) {
1349 647 hiro
                        no_mime_type_table = TRUE;
1350 647 hiro
                        return NULL;
1351 647 hiro
                }
1352 1 hiro
        }
1353 1 hiro
1354 1 hiro
        filename = g_basename(filename);
1355 1 hiro
        p = strrchr(filename, '.');
1356 1 hiro
        if (!p) return NULL;
1357 1 hiro
1358 1 hiro
        Xstrdup_a(ext, p + 1, return NULL);
1359 1 hiro
        g_strdown(ext);
1360 1 hiro
        mime_type = g_hash_table_lookup(mime_type_table, ext);
1361 1 hiro
        if (mime_type) {
1362 1 hiro
                gchar *str;
1363 1 hiro
1364 1 hiro
                str = g_strconcat(mime_type->type, "/", mime_type->sub_type,
1365 1 hiro
                                  NULL);
1366 1 hiro
                return str;
1367 1 hiro
        }
1368 1 hiro
1369 1 hiro
        return NULL;
1370 1 hiro
}
1371 1 hiro
1372 1 hiro
static GHashTable *procmime_get_mime_type_table(void)
1373 1 hiro
{
1374 1 hiro
        GHashTable *table = NULL;
1375 1 hiro
        GList *cur;
1376 1 hiro
        MimeType *mime_type;
1377 1 hiro
        gchar **exts;
1378 1 hiro
1379 1 hiro
        if (!mime_type_list) {
1380 1 hiro
                GList *list;
1381 1 hiro
                gchar *dir;
1382 1 hiro
1383 690 hiro
#ifdef G_OS_WIN32
1384 690 hiro
                dir = g_strconcat(get_startup_dir(),
1385 690 hiro
                                  G_DIR_SEPARATOR_S "etc" G_DIR_SEPARATOR_S
1386 690 hiro
                                  "mime.types", NULL);
1387 690 hiro
                mime_type_list = procmime_get_mime_type_list(dir);
1388 690 hiro
                g_free(dir);
1389 690 hiro
#else
1390 1 hiro
                mime_type_list =
1391 1 hiro
                        procmime_get_mime_type_list(SYSCONFDIR "/mime.types");
1392 1033 hiro
                if (!mime_type_list)
1393 1033 hiro
                        mime_type_list =
1394 1033 hiro
                                procmime_get_mime_type_list("/etc/mime.types");
1395 690 hiro
#endif
1396 484 hiro
                dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1397 484 hiro
                                  "mime.types", NULL);
1398 1 hiro
                list = procmime_get_mime_type_list(dir);
1399 1 hiro
                g_free(dir);
1400 1 hiro
                mime_type_list = g_list_concat(mime_type_list, list);
1401 1 hiro
1402 1 hiro
                if (!mime_type_list) {
1403 647 hiro
                        debug_print("mime.types not found\n");
1404 1 hiro
                        return NULL;
1405 1 hiro
                }
1406 1 hiro
        }
1407 1 hiro
1408 1 hiro
        table = g_hash_table_new(g_str_hash, g_str_equal);
1409 1 hiro
1410 1 hiro
        for (cur = mime_type_list; cur != NULL; cur = cur->next) {
1411 1 hiro
                gint i;
1412 1 hiro
                gchar *key;
1413 1 hiro
1414 1 hiro
                mime_type = (MimeType *)cur->data;
1415 1 hiro
1416 1 hiro
                if (!mime_type->extension) continue;
1417 1 hiro
1418 1 hiro
                exts = g_strsplit(mime_type->extension, " ", 16);
1419 1 hiro
                for (i = 0; exts[i] != NULL; i++) {
1420 1 hiro
                        /* make the key case insensitive */
1421 1 hiro
                        g_strdown(exts[i]);
1422 1 hiro
                        /* use previously dup'd key on overwriting */
1423 1 hiro
                        if (g_hash_table_lookup(table, exts[i]))
1424 1 hiro
                                key = exts[i];
1425 1 hiro
                        else
1426 1 hiro
                                key = g_strdup(exts[i]);
1427 1 hiro
                        g_hash_table_insert(table, key, mime_type);
1428 1 hiro
                }
1429 1 hiro
                g_strfreev(exts);
1430 1 hiro
        }
1431 1 hiro
1432 1 hiro
        return table;
1433 1 hiro
}
1434 1 hiro
1435 1 hiro
static GList *procmime_get_mime_type_list(const gchar *file)
1436 1 hiro
{
1437 1 hiro
        GList *list = NULL;
1438 1 hiro
        FILE *fp;
1439 1 hiro
        gchar buf[BUFFSIZE];
1440 457 hiro
        gchar *p;
1441 1 hiro
        gchar *delim;
1442 1 hiro
        MimeType *mime_type;
1443 1 hiro
1444 478 hiro
        if ((fp = g_fopen(file, "rb")) == NULL) return NULL;
1445 1 hiro
1446 1 hiro
        debug_print("Reading %s ...\n", file);
1447 1 hiro
1448 1 hiro
        while (fgets(buf, sizeof(buf), fp) != NULL) {
1449 1 hiro
                p = strchr(buf, '#');
1450 1 hiro
                if (p) *p = '\0';
1451 1 hiro
                g_strstrip(buf);
1452 1 hiro
1453 1 hiro
                p = buf;
1454 457 hiro
                while (*p && !g_ascii_isspace(*p)) p++;
1455 1 hiro
                if (*p) {
1456 1 hiro
                        *p = '\0';
1457 1 hiro
                        p++;
1458 1 hiro
                }
1459 1 hiro
                delim = strchr(buf, '/');
1460 1 hiro
                if (delim == NULL) continue;
1461 1 hiro
                *delim = '\0';
1462 1 hiro
1463 1 hiro
                mime_type = g_new(MimeType, 1);
1464 1 hiro
                mime_type->type = g_strdup(buf);
1465 1 hiro
                mime_type->sub_type = g_strdup(delim + 1);
1466 1 hiro
1467 457 hiro
                while (*p && g_ascii_isspace(*p)) p++;
1468 1 hiro
                if (*p)
1469 1 hiro
                        mime_type->extension = g_strdup(p);
1470 1 hiro
                else
1471 1 hiro
                        mime_type->extension = NULL;
1472 1 hiro
1473 1 hiro
                list = g_list_append(list, mime_type);
1474 1 hiro
        }
1475 1 hiro
1476 1 hiro
        fclose(fp);
1477 1 hiro
1478 1 hiro
        if (!list)
1479 1 hiro
                g_warning("Can't read mime.types\n");
1480 1 hiro
1481 1 hiro
        return list;
1482 1 hiro
}
1483 1 hiro
1484 1032 hiro
static GList *mailcap_list = NULL;
1485 1032 hiro
1486 1032 hiro
static GList *procmime_parse_mailcap(const gchar *file)
1487 1032 hiro
{
1488 1032 hiro
        GList *list = NULL;
1489 1032 hiro
        FILE *fp;
1490 1032 hiro
        gchar buf[BUFFSIZE];
1491 1032 hiro
        MailCap *mailcap;
1492 1032 hiro
1493 1032 hiro
        if ((fp = g_fopen(file, "rb")) == NULL) return NULL;
1494 1032 hiro
1495 1032 hiro
        while (fgets(buf, sizeof(buf), fp) != NULL) {
1496 1032 hiro
                gint i;
1497 1032 hiro
                gchar *p;
1498 1032 hiro
                gchar **strv;
1499 1032 hiro
1500 1032 hiro
                p = strchr(buf, '#');
1501 1032 hiro
                if (p) *p = '\0';
1502 1032 hiro
                g_strstrip(buf);
1503 1032 hiro
1504 1032 hiro
                strv = strsplit_with_quote(buf, ";", 0);
1505 1032 hiro
                if (!strv)
1506 1032 hiro
                        continue;
1507 1032 hiro
1508 1032 hiro
                for (i = 0; strv[i] != NULL; ++i)
1509 1032 hiro
                        g_strstrip(strv[i]);
1510 1032 hiro
1511 1032 hiro
                if (!strv[0] || *strv[0] == '\0' ||
1512 1032 hiro
                    !strv[1] || *strv[1] == '\0') {
1513 1032 hiro
                        g_strfreev(strv);
1514 1032 hiro
                        continue;
1515 1032 hiro
                }
1516 1032 hiro
1517 1032 hiro
                mailcap = g_new(MailCap, 1);
1518 1032 hiro
                mailcap->mime_type = g_strdup(strv[0]);
1519 1032 hiro
                mailcap->cmdline_fmt = g_strdup(strv[1]);
1520 1032 hiro
                mailcap->needs_terminal = FALSE;
1521 1032 hiro
1522 1032 hiro
                for (i = 0; strv[i] != NULL; ++i) {
1523 1032 hiro
                        if (strcmp(strv[i], "needsterminal") == 0)
1524 1032 hiro
                                mailcap->needs_terminal = TRUE;
1525 1032 hiro
                }
1526 1032 hiro
1527 1032 hiro
                g_strfreev(strv);
1528 1032 hiro
1529 1032 hiro
                list = g_list_append(list, mailcap);
1530 1032 hiro
        }
1531 1032 hiro
1532 1032 hiro
        return list;
1533 1032 hiro
}
1534 1032 hiro
1535 1032 hiro
gint procmime_execute_open_file(const gchar *file, const gchar *mime_type)
1536 1032 hiro
{
1537 1032 hiro
        gchar *mime_type_ = NULL;
1538 1032 hiro
        GList *cur;
1539 1032 hiro
        MailCap *mailcap;
1540 1035 hiro
        gchar *cmdline;
1541 1032 hiro
        gint ret = -1;
1542 1033 hiro
        static gboolean mailcap_list_init = FALSE;
1543 1032 hiro
1544 1032 hiro
        g_return_val_if_fail(file != NULL, -1);
1545 1032 hiro
1546 1032 hiro
        if (!mime_type ||
1547 1032 hiro
            g_ascii_strcasecmp(mime_type, "application/octet-stream") == 0) {
1548 1032 hiro
                gchar *tmp;
1549 1032 hiro
                tmp = procmime_get_mime_type(file);
1550 1032 hiro
                if (!tmp)
1551 1032 hiro
                        return -1;
1552 1032 hiro
                mime_type_ = g_ascii_strdown(tmp, -1);
1553 1032 hiro
                g_free(tmp);
1554 1032 hiro
        } else
1555 1032 hiro
                mime_type_ = g_ascii_strdown(mime_type, -1);
1556 1032 hiro
1557 1033 hiro
        if (!mailcap_list_init && !mailcap_list) {
1558 1033 hiro
                GList *list;
1559 1033 hiro
                gchar *path;
1560 1032 hiro
1561 1033 hiro
                path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "mailcap",
1562 1033 hiro
                                  NULL);
1563 1033 hiro
                mailcap_list = procmime_parse_mailcap(path);
1564 1033 hiro
                g_free(path);
1565 1033 hiro
#ifdef G_OS_WIN32
1566 1033 hiro
                path = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S "etc"
1567 1033 hiro
                                   G_DIR_SEPARATOR_S "mailcap", NULL);
1568 1033 hiro
                list = procmime_parse_mailcap(path);
1569 1033 hiro
                g_free(path);
1570 1033 hiro
#else
1571 1037 hiro
                if (!mailcap_list) {
1572 1037 hiro
                        path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1573 1037 hiro
                                           ".mailcap", NULL);
1574 1037 hiro
                        mailcap_list = procmime_parse_mailcap(path);
1575 1037 hiro
                        g_free(path);
1576 1037 hiro
                }
1577 1033 hiro
                list = procmime_parse_mailcap(SYSCONFDIR "/mailcap");
1578 1033 hiro
                if (!list)
1579 1033 hiro
                        list = procmime_parse_mailcap("/etc/mailcap");
1580 1033 hiro
#endif
1581 1033 hiro
                mailcap_list = g_list_concat(mailcap_list, list);
1582 1033 hiro
1583 1033 hiro
                mailcap_list_init = TRUE;
1584 1033 hiro
        }
1585 1033 hiro
1586 1032 hiro
        for (cur = mailcap_list; cur != NULL; cur = cur->next) {
1587 1032 hiro
                mailcap = (MailCap *)cur->data;
1588 1032 hiro
1589 1032 hiro
                if (!g_pattern_match_simple(mailcap->mime_type, mime_type_))
1590 1032 hiro
                        continue;
1591 1032 hiro
                if (mailcap->needs_terminal)
1592 1032 hiro
                        continue;
1593 1032 hiro
1594 1035 hiro
                if (str_find_format_times(mailcap->cmdline_fmt, 's') == 1)
1595 1032 hiro
                        cmdline = g_strdup_printf(mailcap->cmdline_fmt, file);
1596 1032 hiro
                else
1597 1032 hiro
                        cmdline = g_strconcat(mailcap->cmdline_fmt, " \"", file,
1598 1032 hiro
                                              "\"", NULL);
1599 1032 hiro
                ret = execute_command_line(cmdline, TRUE);
1600 1032 hiro
                g_free(cmdline);
1601 1032 hiro
                break;
1602 1032 hiro
        }
1603 1032 hiro
1604 1032 hiro
        g_free(mime_type_);
1605 1032 hiro
1606 1032 hiro
        return ret;
1607 1032 hiro
}
1608 1032 hiro
1609 1 hiro
EncodingType procmime_get_encoding_for_charset(const gchar *charset)
1610 1 hiro
{
1611 1 hiro
        if (!charset)
1612 1 hiro
                return ENC_8BIT;
1613 333 hiro
        else if (!g_ascii_strncasecmp(charset, "ISO-2022-", 9) ||
1614 333 hiro
                 !g_ascii_strcasecmp(charset, "US-ASCII"))
1615 1 hiro
                return ENC_7BIT;
1616 333 hiro
        else if (!g_ascii_strcasecmp(charset, "ISO-8859-5") ||
1617 333 hiro
                 !g_ascii_strncasecmp(charset, "KOI8-", 5) ||
1618 333 hiro
                 !g_ascii_strcasecmp(charset, "Windows-1251"))
1619 1 hiro
                return ENC_8BIT;
1620 333 hiro
        else if (!g_ascii_strncasecmp(charset, "ISO-8859-", 9))
1621 1 hiro
                return ENC_QUOTED_PRINTABLE;
1622 1 hiro
        else
1623 1 hiro
                return ENC_8BIT;
1624 1 hiro
}
1625 1 hiro
1626 1 hiro
EncodingType procmime_get_encoding_for_text_file(const gchar *file)
1627 1 hiro
{
1628 1 hiro
        FILE *fp;
1629 1 hiro
        guchar buf[BUFFSIZE];
1630 1 hiro
        size_t len;
1631 1 hiro
        size_t octet_chars = 0;
1632 1 hiro
        size_t total_len = 0;
1633 1 hiro
        gfloat octet_percentage;
1634 1 hiro
1635 478 hiro
        if ((fp = g_fopen(file, "rb")) == NULL) {
1636 1 hiro
                FILE_OP_ERROR(file, "fopen");
1637 1 hiro
                return ENC_UNKNOWN;
1638 1 hiro
        }
1639 1 hiro
1640 1 hiro
        while ((len = fread(buf, sizeof(guchar), sizeof(buf), fp)) > 0) {
1641 1 hiro
                guchar *p;
1642 1 hiro
                gint i;
1643 1 hiro
1644 1 hiro
                for (p = buf, i = 0; i < len; ++p, ++i) {
1645 1 hiro
                        if (*p & 0x80)
1646 1 hiro
                                ++octet_chars;
1647 1 hiro
                }
1648 1 hiro
                total_len += len;
1649 1 hiro
        }
1650 1 hiro
1651 1 hiro
        fclose(fp);
1652 1 hiro
1653 1 hiro
        if (total_len > 0)
1654 1 hiro
                octet_percentage = (gfloat)octet_chars / (gfloat)total_len;
1655 1 hiro
        else
1656 1 hiro
                octet_percentage = 0.0;
1657 1 hiro
1658 1 hiro
        debug_print("procmime_get_encoding_for_text_file(): "
1659 1 hiro
                    "8bit chars: %d / %d (%f%%)\n", octet_chars, total_len,
1660 1 hiro
                    100.0 * octet_percentage);
1661 1 hiro
1662 1 hiro
        if (octet_percentage > 0.20) {
1663 1 hiro
                debug_print("using BASE64\n");
1664 1 hiro
                return ENC_BASE64;
1665 1 hiro
        } else if (octet_chars > 0) {
1666 1 hiro
                debug_print("using quoted-printable\n");
1667 1 hiro
                return ENC_QUOTED_PRINTABLE;
1668 1 hiro
        } else {
1669 1 hiro
                debug_print("using 7bit\n");
1670 1 hiro
                return ENC_7BIT;
1671 1 hiro
        }
1672 1 hiro
}
1673 1 hiro
1674 1693 hiro
EncodingType procmime_get_encoding_for_str(const gchar *str)
1675 1693 hiro
{
1676 1693 hiro
        const guchar *p;
1677 1693 hiro
        size_t octet_chars = 0;
1678 1693 hiro
        size_t total_len = 0;
1679 1693 hiro
        gfloat octet_percentage;
1680 1693 hiro
1681 1693 hiro
        total_len = strlen(str);
1682 1693 hiro
1683 1910 hiro
        for (p = (const guchar *)str; *p != '\0'; ++p) {
1684 1693 hiro
                if (*p & 0x80)
1685 1693 hiro
                        ++octet_chars;
1686 1693 hiro
        }
1687 1693 hiro
1688 1693 hiro
        if (total_len > 0)
1689 1693 hiro
                octet_percentage = (gfloat)octet_chars / (gfloat)total_len;
1690 1693 hiro
        else
1691 1693 hiro
                octet_percentage = 0.0;
1692 1693 hiro
1693 1693 hiro
        debug_print("procmime_get_encoding_for_str(): "
1694 1693 hiro
                    "8bit chars: %d / %d (%f%%)\n", octet_chars, total_len,
1695 1693 hiro
                    100.0 * octet_percentage);
1696 1693 hiro
1697 1693 hiro
        if (octet_percentage > 0.20) {
1698 1693 hiro
                debug_print("using BASE64\n");
1699 1693 hiro
                return ENC_BASE64;
1700 1693 hiro
        } else if (octet_chars > 0) {
1701 1693 hiro
                debug_print("using quoted-printable\n");
1702 1693 hiro
                return ENC_QUOTED_PRINTABLE;
1703 1693 hiro
        } else {
1704 1693 hiro
                debug_print("using 7bit\n");
1705 1693 hiro
                return ENC_7BIT;
1706 1693 hiro
        }
1707 1693 hiro
}
1708 1693 hiro
1709 1 hiro
const gchar *procmime_get_encoding_str(EncodingType encoding)
1710 1 hiro
{
1711 1 hiro
        static const gchar *encoding_str[] = {
1712 1 hiro
                "7bit", "8bit", "quoted-printable", "base64", "x-uuencode",
1713 1 hiro
                NULL
1714 1 hiro
        };
1715 1 hiro
1716 1 hiro
        if (encoding >= ENC_7BIT && encoding <= ENC_UNKNOWN)
1717 1 hiro
                return encoding_str[encoding];
1718 1 hiro
        else
1719 1 hiro
                return NULL;
1720 1 hiro
}