0.9.7claws7
[claws.git] / src / procmime.c
index aed3ff7ace32fcdd61c385666ec6ab8ac7069153..c2814d699b0e1de84401a2bce76b7bc7b6f923de 100644 (file)
@@ -56,9 +56,11 @@ MimeInfo *procmime_mimeinfo_new(void)
        mimeinfo = g_new0(MimeInfo, 1);
        mimeinfo->type          = MIMETYPE_UNKNOWN;
        mimeinfo->encoding_type = ENC_UNKNOWN;
+       mimeinfo->disposition   = DISPOSITIONTYPE_UNKNOWN;
 
        mimeinfo->parameters = g_hash_table_new(g_str_hash, g_str_equal);
-
+       mimeinfo->node       = g_node_new(mimeinfo);
+       
        return mimeinfo;
 }
 
@@ -70,21 +72,14 @@ static gboolean procmime_mimeinfo_parameters_destroy(gpointer key, gpointer valu
        return TRUE;
 }
 
-void procmime_mimeinfo_free_all(MimeInfo *mimeinfo)
+static gboolean free_func(GNode *node, gpointer data)
 {
-       MimeInfo *next;
-
-       g_return_if_fail(mimeinfo);
+       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)
                unlink(mimeinfo->filename);
        g_free(mimeinfo->filename);
 
-       procmime_mimeinfo_free_all(mimeinfo->children);
        g_free(mimeinfo->subtype);
        g_free(mimeinfo->description);
        g_free(mimeinfo->id);
@@ -92,11 +87,27 @@ void procmime_mimeinfo_free_all(MimeInfo *mimeinfo)
        g_hash_table_foreach_remove(mimeinfo->parameters, procmime_mimeinfo_parameters_destroy, NULL);
        g_hash_table_destroy(mimeinfo->parameters);
 
-       next = mimeinfo->next;
+       if (mimeinfo->privacy)
+               privacy_free_privacydata(mimeinfo->privacy);
+
        g_free(mimeinfo);
-       mimeinfo = next;
+
+       return FALSE;
+}
+
+void procmime_mimeinfo_free_all(MimeInfo *mimeinfo)
+{
+       GNode *node;
+
+       g_return_if_fail(mimeinfo);
+
+       node = mimeinfo->node;
+       g_node_traverse(node, G_IN_ORDER, G_TRAVERSE_ALL, -1, free_func, NULL);
+
+       g_node_destroy(node);
 }
 
+#if 0 /* UNUSED */
 MimeInfo *procmime_mimeinfo_insert(MimeInfo *parent, MimeInfo *mimeinfo)
 {
        MimeInfo *child = parent->children;
@@ -141,31 +152,34 @@ void procmime_mimeinfo_replace(MimeInfo *old, MimeInfo *new)
                child = new;
        }
 }
+#endif
+
+MimeInfo *procmime_mimeinfo_parent(MimeInfo *mimeinfo)
+{
+       g_return_val_if_fail(mimeinfo != NULL, NULL);
+
+       if (mimeinfo->node->parent == NULL)
+               return NULL;
+       return (MimeInfo *) mimeinfo->node->parent->data;
+}
 
 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->children)
-               return mimeinfo->children;
-       if (mimeinfo->next)
-               return mimeinfo->next;
+       if (mimeinfo->node->children)
+               return (MimeInfo *) mimeinfo->node->children->data;
+       if (mimeinfo->node->next)
+               return (MimeInfo *) mimeinfo->node->next->data;
 
-       if (mimeinfo->main) {
-               mimeinfo = mimeinfo->main;
-               if (mimeinfo->next)
-                       return mimeinfo->next;
-       }
+       if (mimeinfo->node->parent == NULL)
+               return NULL;
 
-       for (mimeinfo = mimeinfo->parent; mimeinfo != NULL;
-            mimeinfo = mimeinfo->parent) {
-               if (mimeinfo->next)
-                       return mimeinfo->next;
-               if (mimeinfo->main) {
-                       mimeinfo = mimeinfo->main;
-                       if (mimeinfo->next)
-                               return mimeinfo->next;
-               }
+       while (mimeinfo->node->parent != NULL) {
+               mimeinfo = (MimeInfo *) mimeinfo->node->parent->data;
+               if (mimeinfo->node->next)
+                       return (MimeInfo *) mimeinfo->node->next->data;
        }
 
        return NULL;
@@ -179,7 +193,8 @@ MimeInfo *procmime_scan_message(MsgInfo *msginfo)
        filename = procmsg_get_message_file(msginfo);
        if(!filename)
                return NULL;
-       if (msginfo->folder->stype != F_QUEUE)
+       if (msginfo->folder->stype != F_QUEUE && 
+           msginfo->folder->stype != F_DRAFT)
                mimeinfo = procmime_scan_file(filename);
        else
                mimeinfo = procmime_scan_queue_file(filename);
@@ -197,6 +212,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];
@@ -427,57 +450,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;
@@ -499,18 +527,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;
 
@@ -521,7 +538,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;
 
@@ -532,6 +549,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)
@@ -539,19 +567,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);
@@ -559,55 +585,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;
+       FILE *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;
@@ -627,15 +628,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;
@@ -650,9 +647,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;
@@ -665,7 +660,6 @@ gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str,
        g_free(filename);
 
        return found;
-#endif
 }
 
 gchar *procmime_get_tmp_file_name(MimeInfo *mimeinfo)
@@ -682,9 +676,14 @@ gchar *procmime_get_tmp_file_name(MimeInfo *mimeinfo)
        if ((mimeinfo->type == MIMETYPE_TEXT) && !g_strcasecmp(mimeinfo->subtype, "html"))
                base = "mimetmp.html";
        else {
-               base = mimeinfo->filename ? mimeinfo->filename
-                       : mimeinfo->name ? mimeinfo->name : "mimetmp";
-               base = g_basename(base);
+               const gchar *basetmp;
+
+               basetmp = procmime_mimeinfo_get_parameter(mimeinfo, "filename");
+               if (basetmp == NULL)
+                       basetmp = procmime_mimeinfo_get_parameter(mimeinfo, "name");
+               if (basetmp == NULL)
+                       basetmp = "mimetmp";
+               base = g_basename(basetmp);
                if (*base == '\0') base = "mimetmp";
                Xstrdup_a(base, base, return NULL);
                subst_for_filename(base);
@@ -942,17 +941,17 @@ const gchar *procmime_get_type_str(MimeMediaType type)
        return NULL;
 }
 
-MimeInfo *procmime_parse_mimepart(MimeInfo *parent,
-                                 gchar *content_type,
-                                 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_mimepart(MimeInfo *parent,
+                            gchar *content_type,
+                            gchar *content_encoding,
+                            gchar *content_description,
+                            gchar *content_id,
+                            gchar *content_disposition,
+                            const gchar *filename,
+                            guint offset,
+                            guint length);
+
+void procmime_parse_message_rfc822(MimeInfo *mimeinfo)
 {
        HeaderEntry hentry[] = {{"Content-Type:",  NULL, TRUE},
                                {"Content-Transfer-Encoding:",
@@ -961,25 +960,36 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo, FILE *fp)
                                                   NULL, TRUE},
                                {"Content-ID:",
                                                   NULL, TRUE},
+                               {"Content-Disposition:",
+                                                  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);
 
-       mimeinfo->children = procmime_parse_mimepart(mimeinfo,
-                                                    hentry[0].body, hentry[1].body,
-                                                    hentry[2].body, hentry[3].body, 
-                                                    fp, mimeinfo->filename, content_start,
-                                                    mimeinfo->length - (content_start - mimeinfo->offset));
-       for (i = 0; i < 4; i++) {
+       procmime_parse_mimepart(mimeinfo,
+                               hentry[0].body, hentry[1].body,
+                               hentry[2].body, hentry[3].body, 
+                               hentry[4].body, 
+                               mimeinfo->filename, content_start,
+                               mimeinfo->length - (content_start - mimeinfo->offset));
+       for (i = 0; i < (sizeof hentry / sizeof hentry[0]); i++) {
                g_free(hentry[i].body);
                hentry[i].body = NULL;
        }
 }
 
-void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
+void procmime_parse_multipart(MimeInfo *mimeinfo)
 {
        HeaderEntry hentry[] = {{"Content-Type:",  NULL, TRUE},
                                {"Content-Transfer-Encoding:",
@@ -988,45 +998,46 @@ void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
                                                   NULL, TRUE},
                                {"Content-ID:",
                                                   NULL, TRUE},
+                               {"Content-Disposition:",
+                                                  NULL, TRUE},
                                {NULL,             NULL, FALSE}};
        gchar *p;
        gchar *boundary;
        gint boundary_len = 0, lastoffset = -1, i;
        gchar buf[BUFFSIZE];
-       MimeInfo *lastmimeinfo = NULL;
+       FILE *fp;
 
        boundary = g_hash_table_lookup(mimeinfo->parameters, "boundary");
-       if(!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))
                        break;
 
                if (IS_BOUNDARY(buf, boundary, boundary_len)) {
-                       if(lastoffset != -1) {
-                               MimeInfo *newmimeinfo = NULL;
-
-                               newmimeinfo = procmime_parse_mimepart(mimeinfo,
-                                                                     hentry[0].body, hentry[1].body,
-                                                                     hentry[2].body, hentry[3].body, 
-                                                                     fp, mimeinfo->filename, lastoffset,
-                                                                     (ftell(fp) - strlen(buf)) - lastoffset);
-                                                                     
-                               if (lastmimeinfo == NULL)
-                                       mimeinfo->children = newmimeinfo;
-                               else
-                                       lastmimeinfo->next = newmimeinfo;
-                               lastmimeinfo = newmimeinfo;
+                       if (lastoffset != -1) {
+                               procmime_parse_mimepart(mimeinfo,
+                                                       hentry[0].body, hentry[1].body,
+                                                       hentry[2].body, hentry[3].body, 
+                                                       hentry[4].body, 
+                                                       mimeinfo->filename, lastoffset,
+                                                       (ftell(fp) - strlen(buf)) - lastoffset);
                        }
                        
                        if (buf[2 + boundary_len]     == '-' &&
                            buf[2 + boundary_len + 1] == '-')
                                break;
 
-                       for (i = 0; i < 4; i++) {
+                       for (i = 0; i < (sizeof hentry / sizeof hentry[0]) ; i++) {
                                g_free(hentry[i].body);
                                hentry[i].body = NULL;
                        }
@@ -1034,8 +1045,41 @@ void procmime_parse_multipart(MimeInfo *mimeinfo, FILE *fp)
                        lastoffset = ftell(fp);
                }
        }
+       for (i = 0; i < (sizeof hentry / sizeof hentry[0]); i++) {
+               g_free(hentry[i].body);
+               hentry[i].body = NULL;
+       }
+       fclose(fp);
 }
 
+static void add_to_mimeinfo_parameters(gchar **parts, MimeInfo *mimeinfo)
+{
+       gchar **strarray;
+
+       for (strarray = parts; *strarray != NULL; strarray++) {
+               gchar **parameters_parts;
+
+               parameters_parts = g_strsplit(*strarray, "=", 1);
+               if ((parameters_parts[0] != NULL) && (parameters_parts[1] != NULL)) {
+                       gchar *firstspace;
+
+                       g_strstrip(parameters_parts[0]);
+                       g_strstrip(parameters_parts[1]);
+                       g_strdown(parameters_parts[0]);
+                       if(parameters_parts[1][0] == '"')
+                               extract_quote(parameters_parts[1], '"');
+                       else if ((firstspace = strchr(parameters_parts[1], ' ')) != NULL)
+                               *firstspace = '\0';
+                       if(g_hash_table_lookup(mimeinfo->parameters,
+                                              parameters_parts[0]) == NULL)
+                               g_hash_table_insert(mimeinfo->parameters,
+                                                   g_strdup(parameters_parts[0]),
+                                                   g_strdup(parameters_parts[1]));
+               }
+               g_strfreev(parameters_parts);
+       }
+}      
+
 static void procmime_parse_content_type(const gchar *content_type, MimeInfo *mimeinfo)
 {
        gchar **content_type_parts;
@@ -1043,6 +1087,9 @@ static void procmime_parse_content_type(const gchar *content_type, MimeInfo *mim
        gchar *str;
        struct TypeTable *typetablearray;
        
+       g_return_if_fail(content_type != NULL);
+       g_return_if_fail(mimeinfo != NULL);
+       
        /* Split content type into parts and remove trailing
           and leading whitespaces from all strings */
        content_type_parts = g_strsplit(content_type, ";", 0);
@@ -1053,6 +1100,10 @@ static void procmime_parse_content_type(const gchar *content_type, MimeInfo *mim
        /* Get mimeinfo->type and mimeinfo->subtype */
        mimeinfo->type = MIMETYPE_UNKNOWN;
        str = content_type_parts[0];
+       if (str == NULL) {
+               g_strfreev(content_type_parts);
+               return;
+       }
        for (typetablearray = mime_type_table; typetablearray->str != NULL; typetablearray++) {
                if (g_strncasecmp(str, typetablearray->str, strlen(typetablearray->str)) == 0 &&
                    str[strlen(typetablearray->str)] == '/') {
@@ -1063,24 +1114,43 @@ static void procmime_parse_content_type(const gchar *content_type, MimeInfo *mim
        }
 
        /* Get mimeinfo->parmeters */
-       for (strarray = &content_type_parts[1]; *strarray != NULL; strarray++) {
-               gchar **parameters_parts;
+       add_to_mimeinfo_parameters(&content_type_parts[1], mimeinfo);
+       g_strfreev(content_type_parts);
+}
 
-               parameters_parts = g_strsplit(*strarray, "=", 1);
-               g_strdown(parameters_parts[0]);
-               if(parameters_parts[1][0] == '"')
-                       extract_quote(parameters_parts[1], '"');
+static void procmime_parse_content_disposition(const gchar *content_disposition, MimeInfo *mimeinfo)
+{
+       gchar **content_disp_parts;
+       gchar **strarray;
+       gchar *str;
 
-               g_hash_table_insert(mimeinfo->parameters,
-                                   g_strdup(parameters_parts[0]),
-                                   g_strdup(parameters_parts[1]));
+       g_return_if_fail(content_disposition != NULL);
+       g_return_if_fail(mimeinfo != NULL);
 
-               g_strfreev(parameters_parts);
+       /* Split into parts and remove trailing
+          and leading whitespaces from all strings */
+       content_disp_parts = g_strsplit(content_disposition, ";", 0);
+       for (strarray = content_disp_parts; *strarray != NULL; strarray++) {
+               g_strstrip(*strarray);
+       }
+       /* Get mimeinfo->disposition */
+       str = content_disp_parts[0];
+       if (str == NULL) {
+               g_strfreev(content_disp_parts);
+               return;
        }
-
-       g_strfreev(content_type_parts);
+       if (!g_strcasecmp(str, "inline")) 
+               mimeinfo->disposition = DISPOSITIONTYPE_INLINE;
+       else if (!g_strcasecmp(str, "attachment"))
+               mimeinfo->disposition = DISPOSITIONTYPE_ATTACHMENT;
+       else
+               mimeinfo->disposition = DISPOSITIONTYPE_ATTACHMENT;
+       
+       add_to_mimeinfo_parameters(&content_disp_parts[1], mimeinfo);
+       g_strfreev(content_disp_parts);
 }
 
+
 static void procmime_parse_content_encoding(const gchar *content_encoding, MimeInfo *mimeinfo)
 {
        struct EncodingTable *enc_table;
@@ -1095,24 +1165,22 @@ static void procmime_parse_content_encoding(const gchar *content_encoding, MimeI
        return;
 }
 
-MimeInfo *procmime_parse_mimepart(MimeInfo *parent,
-                                 gchar *content_type,
-                                 gchar *content_encoding,
-                                 gchar *content_description,
-                                 gchar *content_id,
-                                 FILE *fp,
-                                 const gchar *filename,
-                                 guint offset,
-                                 guint length)
+void procmime_parse_mimepart(MimeInfo *parent,
+                            gchar *content_type,
+                            gchar *content_encoding,
+                            gchar *content_description,
+                            gchar *content_id,
+                            gchar *content_disposition,
+                            const gchar *filename,
+                            guint offset,
+                            guint length)
 {
        MimeInfo *mimeinfo;
-       guint oldpos;
-
-       g_return_val_if_fail(fp != NULL, NULL);
 
        /* Create MimeInfo */
        mimeinfo = procmime_mimeinfo_new();
-       mimeinfo->parent = parent;
+       if (parent != NULL)
+               g_node_append(parent->node, mimeinfo->node);
        mimeinfo->filename = g_strdup(filename);
        mimeinfo->offset = offset;
        mimeinfo->length = length;
@@ -1141,25 +1209,26 @@ MimeInfo *procmime_parse_mimepart(MimeInfo *parent,
        else
                mimeinfo->id = NULL;
 
-       oldpos = ftell(fp);
+       if (content_disposition != NULL) 
+               procmime_parse_content_disposition(content_disposition, mimeinfo);
+       else
+               mimeinfo->disposition = DISPOSITIONTYPE_UNKNOWN;
+
        /* 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);
-
-       return mimeinfo;
 }
 
 static gchar *typenames[] = {
@@ -1173,49 +1242,53 @@ static gchar *typenames[] = {
     "unknown",
 };
 
-static void output_mime_structure(MimeInfo *mimeinfo, int indent)
+static gboolean output_func(GNode *node, gpointer data)
 {
-       int i;
-       
-       for(i = 0; i < indent; i++)
-               printf(" ");
+       guint i, depth;
+       MimeInfo *mimeinfo = (MimeInfo *) node->data;
+
+       depth = g_node_depth(node);
+       for(i = 0; i < depth; i++)
+               printf("    ");
        printf("%s/%s (offset:%d length:%d encoding: %d)\n", typenames[mimeinfo->type], mimeinfo->subtype, mimeinfo->offset, mimeinfo->length, mimeinfo->encoding_type);
 
-       if(mimeinfo->children)
-               output_mime_structure(mimeinfo->children, indent + 4);
-       if(mimeinfo->next)
-               output_mime_structure(mimeinfo->next, indent);
+       return FALSE;
+}
+
+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 = buf.st_size - offset;
 
-       mimeinfo = procmime_parse_mimepart(NULL, "message/rfc822", "binary", NULL, NULL, fp, filename, offset, stat.st_size - offset);
-       output_mime_structure(mimeinfo, 0);
+       procmime_parse_message_rfc822(mimeinfo);
+       if (debug_get_mode())
+               output_mime_structure(mimeinfo, 0);
 
        return mimeinfo;
 }
 
 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;
 }
@@ -1225,20 +1298,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;
 }