0.9.6claws52
[claws.git] / src / procmime.c
index a322a019ebfc45a33c562b8e62f5afc4cca6d19d..7a22ac805b92a9f608d35e1160f08a963f39bf78 100644 (file)
@@ -76,7 +76,6 @@ static gboolean free_func(GNode *node, gpointer data)
        MimeInfo *mimeinfo = (MimeInfo *) node->data;
 
        g_free(mimeinfo->encoding);
-       g_free(mimeinfo->charset);
        g_free(mimeinfo->name);
        g_free(mimeinfo->content_disposition);
        if(mimeinfo->tmpfile)
@@ -168,15 +167,19 @@ MimeInfo *procmime_mimeinfo_parent(MimeInfo *mimeinfo)
 
 MimeInfo *procmime_mimeinfo_next(MimeInfo *mimeinfo)
 {
-       if (!mimeinfo) return NULL;
+       g_return_val_if_fail(mimeinfo != NULL, NULL);
+       g_return_val_if_fail(mimeinfo->node != NULL, NULL);
 
        if (mimeinfo->node->children)
                return (MimeInfo *) mimeinfo->node->children->data;
        if (mimeinfo->node->next)
                return (MimeInfo *) mimeinfo->node->next->data;
 
-       for (mimeinfo = (MimeInfo *) mimeinfo->node->parent->data; mimeinfo != NULL;
-            mimeinfo = (MimeInfo *) mimeinfo->node->parent->data) {
+       if (mimeinfo->node->parent == NULL)
+               return NULL;
+
+       while (mimeinfo->node->parent != NULL) {
+               mimeinfo = (MimeInfo *) mimeinfo->node->parent->data;
                if (mimeinfo->node->next)
                        return (MimeInfo *) mimeinfo->node->next->data;
        }
@@ -210,6 +213,14 @@ enum
        H_SUBJECT                   = 4
 };
 
+const gchar *procmime_mimeinfo_get_parameter(MimeInfo *mimeinfo, const gchar *name)
+{
+       g_return_val_if_fail(mimeinfo != NULL, NULL);
+       g_return_val_if_fail(name != NULL, NULL);
+       
+       return g_hash_table_lookup(mimeinfo->parameters, name);
+}
+
 gboolean procmime_decode_content(MimeInfo *mimeinfo)
 {
        gchar buf[BUFFSIZE];
@@ -440,57 +451,62 @@ void renderer_write_config(void)
        }
 }
 
-FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp)
+FILE *procmime_get_text_content(MimeInfo *mimeinfo)
 {
-       return NULL;
-
-#if 0  /* FIXME */
        FILE *tmpfp, *outfp;
-       gchar *src_codeset;
+       const gchar *src_codeset;
        gboolean conv_fail = FALSE;
        gchar buf[BUFFSIZE];
        gchar *str;
        struct ContentRenderer * renderer;
        GList * cur;
-
+       gchar *tmpfile, *content_type;
+    
        g_return_val_if_fail(mimeinfo != NULL, NULL);
-       g_return_val_if_fail(infp != NULL, NULL);
-       g_return_val_if_fail(mimeinfo->mime_type == MIME_TEXT ||
-                            mimeinfo->mime_type == MIME_TEXT_HTML ||
-                            mimeinfo->mime_type == MIME_TEXT_ENRICHED, NULL);
 
-       if (fseek(infp, mimeinfo->fpos, SEEK_SET) < 0) {
-               perror("fseek");
+       if (!procmime_decode_content(mimeinfo))
                return NULL;
-       }
 
-       while (fgets(buf, sizeof(buf), infp) != NULL)
-               if (buf[0] == '\r' || buf[0] == '\n') break;
+       tmpfile = procmime_get_tmp_file_name(mimeinfo);
+       if (tmpfile == NULL)
+               return NULL;
 
-       tmpfp = procmime_decode_content(NULL, infp, mimeinfo);
-       if (!tmpfp)
+       if (procmime_get_part(tmpfile, mimeinfo) < 0) {
+               g_free(tmpfile);
                return NULL;
+       }
+
+       tmpfp = fopen(tmpfile, "rb");
+       if (tmpfp == NULL) {
+               g_free(tmpfile);
+               return NULL;
+       }
 
        if ((outfp = my_tmpfile()) == NULL) {
                perror("tmpfile");
                fclose(tmpfp);
+               g_free(tmpfile);
                return NULL;
        }
 
        src_codeset = prefs_common.force_charset
-               ? prefs_common.force_charset : mimeinfo->charset;
+               ? prefs_common.force_charset : 
+               procmime_mimeinfo_get_parameter(mimeinfo, "charset");
 
        renderer = NULL;
 
+       content_type = g_strdup_printf("%s/%s", procmime_get_type_str(mimeinfo->type),
+               mimeinfo->subtype);
        for(cur = renderer_list ; cur != NULL ; cur = cur->next) {
                struct ContentRenderer * cr;
+
                cr = cur->data;
-               if (g_strcasecmp(cr->content_type,
-                                mimeinfo->content_type) == 0) {
+               if (g_strcasecmp(cr->content_type, content_type) == 0) {
                        renderer = cr;
                        break;
                }
        }
+       g_free(content_type);
 
        if (renderer != NULL) {
                FILE * p;
@@ -512,18 +528,7 @@ FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp)
                }
                
                dup2(oldout, 1);
-       } else if (mimeinfo->mime_type == MIME_TEXT) {
-               while (fgets(buf, sizeof(buf), tmpfp) != NULL) {
-                       str = conv_codeset_strdup(buf, src_codeset, NULL);
-                       if (str) {
-                               fputs(str, outfp);
-                               g_free(str);
-                       } else {
-                               conv_fail = TRUE;
-                               fputs(buf, outfp);
-                       }
-               }
-       } else if (mimeinfo->mime_type == MIME_TEXT_HTML) {
+       } else if (mimeinfo->type == MIMETYPE_TEXT && !g_strcasecmp(mimeinfo->subtype, "html")) {
                HTMLParser *parser;
                CodeConverter *conv;
 
@@ -534,7 +539,7 @@ FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp)
                }
                html_parser_destroy(parser);
                conv_code_converter_destroy(conv);
-       } else if (mimeinfo->mime_type == MIME_TEXT_ENRICHED) {
+       } else if (mimeinfo->type == MIMETYPE_TEXT && !g_strcasecmp(mimeinfo->subtype, "enriched")) {
                ERTFParser *parser;
                CodeConverter *conv;
 
@@ -545,6 +550,17 @@ FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp)
                }
                ertf_parser_destroy(parser);
                conv_code_converter_destroy(conv);
+       } else if (mimeinfo->type == MIMETYPE_TEXT) {
+               while (fgets(buf, sizeof(buf), tmpfp) != NULL) {
+                       str = conv_codeset_strdup(buf, src_codeset, NULL);
+                       if (str) {
+                               fputs(str, outfp);
+                               g_free(str);
+                       } else {
+                               conv_fail = TRUE;
+                               fputs(buf, outfp);
+                       }
+               }
        }
 
        if (conv_fail)
@@ -552,19 +568,17 @@ FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp)
 
        fclose(tmpfp);
        rewind(outfp);
+       unlink(tmpfile);
+       g_free(tmpfile);
 
        return outfp;
-#endif
 }
 
 /* search the first text part of (multipart) MIME message,
    decode, convert it and output to outfp. */
 FILE *procmime_get_first_text_content(MsgInfo *msginfo)
 {
-       return NULL;
-
-#if 0  /* FIXME */
-       FILE *infp, *outfp = NULL;
+       FILE *outfp = NULL;
        MimeInfo *mimeinfo, *partinfo;
 
        g_return_val_if_fail(msginfo != NULL, NULL);
@@ -572,55 +586,30 @@ FILE *procmime_get_first_text_content(MsgInfo *msginfo)
        mimeinfo = procmime_scan_message(msginfo);
        if (!mimeinfo) return NULL;
 
-       if ((infp = procmsg_open_message(msginfo)) == NULL) {
-               procmime_mimeinfo_free_all(mimeinfo);
-               return NULL;
-       }
-
        partinfo = mimeinfo;
-       while (partinfo && partinfo->mime_type != MIME_TEXT)
+       while (partinfo && partinfo->type != MIMETYPE_TEXT)
                partinfo = procmime_mimeinfo_next(partinfo);
-       if (!partinfo) {
-               partinfo = mimeinfo;
-               while (partinfo && partinfo->mime_type != MIME_TEXT_HTML &&
-                               partinfo->mime_type != MIME_TEXT_ENRICHED)
-                       partinfo = procmime_mimeinfo_next(partinfo);
-       }
-       
 
        if (partinfo)
-               outfp = procmime_get_text_content(partinfo, infp);
+               outfp = procmime_get_text_content(partinfo);
 
-       fclose(infp);
        procmime_mimeinfo_free_all(mimeinfo);
 
        return outfp;
-#endif
 }
 
 gboolean procmime_find_string_part(MimeInfo *mimeinfo, const gchar *filename,
                                   const gchar *str, gboolean case_sens)
 {
-       return FALSE;
-
-#if 0  /* FIXME */
        FILE *infp, *outfp;
        gchar buf[BUFFSIZE];
        gchar *(* StrFindFunc) (const gchar *haystack, const gchar *needle);
 
        g_return_val_if_fail(mimeinfo != NULL, FALSE);
-       g_return_val_if_fail(mimeinfo->mime_type == MIME_TEXT ||
-                            mimeinfo->mime_type == MIME_TEXT_HTML ||
-                            mimeinfo->mime_type == MIME_TEXT_ENRICHED, FALSE);
+       g_return_val_if_fail(mimeinfo->type == MIMETYPE_TEXT, FALSE);
        g_return_val_if_fail(str != NULL, FALSE);
 
-       if ((infp = fopen(filename, "rb")) == NULL) {
-               FILE_OP_ERROR(filename, "fopen");
-               return FALSE;
-       }
-
-       outfp = procmime_get_text_content(mimeinfo, infp);
-       fclose(infp);
+       outfp = procmime_get_text_content(mimeinfo);
 
        if (!outfp)
                return FALSE;
@@ -640,15 +629,11 @@ gboolean procmime_find_string_part(MimeInfo *mimeinfo, const gchar *filename,
        fclose(outfp);
 
        return FALSE;
-#endif
 }
 
 gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str,
                              gboolean case_sens)
 {
-       return FALSE;
-
-#if 0  /* FIXME */
        MimeInfo *mimeinfo;
        MimeInfo *partinfo;
        gchar *filename;
@@ -663,9 +648,7 @@ gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str,
 
        for (partinfo = mimeinfo; partinfo != NULL;
             partinfo = procmime_mimeinfo_next(partinfo)) {
-               if (partinfo->mime_type == MIME_TEXT ||
-                   partinfo->mime_type == MIME_TEXT_HTML ||
-                   partinfo->mime_type == MIME_TEXT_ENRICHED) {
+               if (partinfo->type == MIMETYPE_TEXT) {
                        if (procmime_find_string_part
                                (partinfo, filename, str, case_sens) == TRUE) {
                                found = TRUE;
@@ -678,7 +661,6 @@ gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str,
        g_free(filename);
 
        return found;
-#endif
 }
 
 gchar *procmime_get_tmp_file_name(MimeInfo *mimeinfo)
@@ -960,12 +942,11 @@ void procmime_parse_mimepart(MimeInfo *parent,
                             gchar *content_encoding,
                             gchar *content_description,
                             gchar *content_id,
-                            FILE *fp,
                             const gchar *filename,
                             guint offset,
                             guint length);
 
-void procmime_parse_message_rfc822(MimeInfo *mimeinfo, FILE *fp)
+void procmime_parse_message_rfc822(MimeInfo *mimeinfo)
 {
        HeaderEntry hentry[] = {{"Content-Type:",  NULL, TRUE},
                                {"Content-Transfer-Encoding:",
@@ -976,15 +957,23 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo, FILE *fp)
                                                   NULL, TRUE},
                                {NULL,             NULL, FALSE}};
        guint content_start, i;
+       FILE *fp;
 
+       if(mimeinfo->encoding_type != ENC_BINARY && 
+          mimeinfo->encoding_type != ENC_7BIT && 
+          mimeinfo->encoding_type != ENC_8BIT)
+               procmime_decode_content(mimeinfo);
+
+       fp = fopen(mimeinfo->filename, "rb");
        fseek(fp, mimeinfo->offset, SEEK_SET);
        procheader_get_header_fields(fp, hentry);
        content_start = ftell(fp);
+       fclose(fp);
 
        procmime_parse_mimepart(mimeinfo,
                                hentry[0].body, hentry[1].body,
                                hentry[2].body, hentry[3].body, 
-                               fp, mimeinfo->filename, content_start,
+                               mimeinfo->filename, content_start,
                                mimeinfo->length - (content_start - mimeinfo->offset));
        for (i = 0; i < 4; i++) {
                g_free(hentry[i].body);
@@ -992,7 +981,7 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo, FILE *fp)
        }
 }
 
-void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
+void procmime_parse_multipart(MimeInfo *mimeinfo)
 {
        HeaderEntry hentry[] = {{"Content-Type:",  NULL, TRUE},
                                {"Content-Transfer-Encoding:",
@@ -1006,12 +995,19 @@ void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
        gchar *boundary;
        gint boundary_len = 0, lastoffset = -1, i;
        gchar buf[BUFFSIZE];
+       FILE *fp;
 
        boundary = g_hash_table_lookup(mimeinfo->parameters, "boundary");
        if(!boundary)
                return;
        boundary_len = strlen(boundary);
 
+       if(mimeinfo->encoding_type != ENC_BINARY && 
+          mimeinfo->encoding_type != ENC_7BIT && 
+          mimeinfo->encoding_type != ENC_8BIT)
+               procmime_decode_content(mimeinfo);
+
+       fp = fopen(mimeinfo->filename, "rb");
        fseek(fp, mimeinfo->offset, SEEK_SET);
        while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
                if (ftell(fp) > (mimeinfo->offset + mimeinfo->length))
@@ -1022,7 +1018,7 @@ void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
                                procmime_parse_mimepart(mimeinfo,
                                                        hentry[0].body, hentry[1].body,
                                                        hentry[2].body, hentry[3].body, 
-                                                       fp, mimeinfo->filename, lastoffset,
+                                                       mimeinfo->filename, lastoffset,
                                                        (ftell(fp) - strlen(buf)) - lastoffset);
                        }
                        
@@ -1038,6 +1034,7 @@ void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
                        lastoffset = ftell(fp);
                }
        }
+       fclose(fp);
 }
 
 static void procmime_parse_content_type(const gchar *content_type, MimeInfo *mimeinfo)
@@ -1105,15 +1102,11 @@ void procmime_parse_mimepart(MimeInfo *parent,
                             gchar *content_encoding,
                             gchar *content_description,
                             gchar *content_id,
-                            FILE *fp,
                             const gchar *filename,
                             guint offset,
                             guint length)
 {
        MimeInfo *mimeinfo;
-       guint oldpos;
-
-       g_return_if_fail(fp != NULL);
 
        /* Create MimeInfo */
        mimeinfo = procmime_mimeinfo_new();
@@ -1147,23 +1140,21 @@ void procmime_parse_mimepart(MimeInfo *parent,
        else
                mimeinfo->id = NULL;
 
-       oldpos = ftell(fp);
        /* Call parser for mime type */
        switch (mimeinfo->type) {
                case MIMETYPE_MESSAGE:
                        if (g_strcasecmp(mimeinfo->subtype, "rfc822") == 0) {
-                               procmime_parse_message_rfc822(mimeinfo, fp);
+                               procmime_parse_message_rfc822(mimeinfo);
                        }
                        break;
                        
                case MIMETYPE_MULTIPART:
-                       procmime_parse_multipart(mimeinfo, fp);
+                       procmime_parse_multipart(mimeinfo);
                        break;
                        
                default:
                        break;
        }
-       fseek(fp, oldpos, SEEK_SET);
 }
 
 static gchar *typenames[] = {
@@ -1195,23 +1186,22 @@ static void output_mime_structure(MimeInfo *mimeinfo, int indent)
        g_node_traverse(mimeinfo->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, output_func, NULL);
 }
 
-MimeInfo *procmime_scan_fp(FILE *fp, const gchar *filename)
+static MimeInfo *procmime_scan_file_with_offset(const gchar *filename, int offset)
 {
        MimeInfo *mimeinfo;
-       gint offset;
-       struct stat stat;
+       struct stat buf;
 
-       fstat(fileno(fp), &stat);
-       offset = ftell(fp);
+       stat(filename, &buf);
 
        mimeinfo = procmime_mimeinfo_new();
+       mimeinfo->encoding_type = ENC_BINARY;
        mimeinfo->type = MIMETYPE_MESSAGE;
        mimeinfo->subtype = g_strdup("rfc822");
        mimeinfo->filename = g_strdup(filename);
        mimeinfo->offset = offset;
-       mimeinfo->length = stat.st_size - offset;
+       mimeinfo->length = buf.st_size - offset;
 
-       procmime_parse_message_rfc822(mimeinfo, fp);
+       procmime_parse_message_rfc822(mimeinfo);
        output_mime_structure(mimeinfo, 0);
 
        return mimeinfo;
@@ -1219,18 +1209,11 @@ MimeInfo *procmime_scan_fp(FILE *fp, const gchar *filename)
 
 MimeInfo *procmime_scan_file(gchar *filename)
 {
-       FILE *fp;
        MimeInfo *mimeinfo;
 
        g_return_val_if_fail(filename != NULL, NULL);
 
-       /* Open file */
-       if((fp = fopen(filename, "rb")) == NULL)
-               return NULL;
-
-       mimeinfo = procmime_scan_fp(fp, filename);
-
-       fclose(fp);
+       mimeinfo = procmime_scan_file_with_offset(filename, 0);
 
        return mimeinfo;
 }
@@ -1240,20 +1223,20 @@ MimeInfo *procmime_scan_queue_file(gchar *filename)
        FILE *fp;
        MimeInfo *mimeinfo;
        gchar buf[BUFFSIZE];
+       gint offset = 0;
 
        g_return_val_if_fail(filename != NULL, NULL);
 
        /* Open file */
        if((fp = fopen(filename, "rb")) == NULL)
                return NULL;
-
        /* Skip queue header */
        while (fgets(buf, sizeof(buf), fp) != NULL)
                if (buf[0] == '\r' || buf[0] == '\n') break;
-
-       mimeinfo = procmime_scan_fp(fp, filename);
-
+       offset = ftell(fp);
        fclose(fp);
 
+       mimeinfo = procmime_scan_file_with_offset(filename, offset);
+
        return mimeinfo;
 }