* src/procmime.[ch]
[claws.git] / src / procmime.c
index bcc227492ff3d81ff4886b478640f6a1f5dcf4da..59224d3a1ae4f41d471778f3c233784b78f3a696 100644 (file)
@@ -59,7 +59,7 @@ MimeInfo *procmime_mimeinfo_new(void)
 
        mimeinfo->parameters = g_hash_table_new(g_str_hash, g_str_equal);
        mimeinfo->node       = g_node_new(mimeinfo);
-
+       
        return mimeinfo;
 }
 
@@ -77,7 +77,6 @@ static gboolean free_func(GNode *node, gpointer data)
 
        g_free(mimeinfo->encoding);
        g_free(mimeinfo->name);
-       g_free(mimeinfo->content_disposition);
        if(mimeinfo->tmpfile)
                unlink(mimeinfo->filename);
        g_free(mimeinfo->filename);
@@ -167,15 +166,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;
        }
@@ -191,7 +194,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);
@@ -597,26 +601,15 @@ FILE *procmime_get_first_text_content(MsgInfo *msginfo)
 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;
@@ -636,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;
@@ -659,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;
@@ -674,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)
@@ -691,8 +677,7 @@ 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 = mimeinfo->name ? mimeinfo->name : "mimetmp";
                base = g_basename(base);
                if (*base == '\0') base = "mimetmp";
                Xstrdup_a(base, base, return NULL);
@@ -956,6 +941,7 @@ void procmime_parse_mimepart(MimeInfo *parent,
                             gchar *content_encoding,
                             gchar *content_description,
                             gchar *content_id,
+                            gchar *content_disposition,
                             const gchar *filename,
                             guint offset,
                             guint length);
@@ -969,6 +955,8 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo)
                                                   NULL, TRUE},
                                {"Content-ID:",
                                                   NULL, TRUE},
+                               {"Content-Disposition:",
+                                                  NULL, TRUE},
                                {NULL,             NULL, FALSE}};
        guint content_start, i;
        FILE *fp;
@@ -987,9 +975,10 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo)
        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 < 4; i++) {
+       for (i = 0; i < (sizeof hentry / sizeof hentry[0]); i++) {
                g_free(hentry[i].body);
                hentry[i].body = NULL;
        }
@@ -1004,6 +993,8 @@ void procmime_parse_multipart(MimeInfo *mimeinfo)
                                                   NULL, TRUE},
                                {"Content-ID:",
                                                   NULL, TRUE},
+                               {"Content-Disposition:",
+                                                  NULL, TRUE},
                                {NULL,             NULL, FALSE}};
        gchar *p;
        gchar *boundary;
@@ -1012,13 +1003,13 @@ void procmime_parse_multipart(MimeInfo *mimeinfo)
        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)
+       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");
@@ -1028,10 +1019,11 @@ void procmime_parse_multipart(MimeInfo *mimeinfo)
                        break;
 
                if (IS_BOUNDARY(buf, boundary, boundary_len)) {
-                       if(lastoffset != -1) {
+                       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);
                        }
@@ -1040,7 +1032,7 @@ void procmime_parse_multipart(MimeInfo *mimeinfo)
                            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;
                        }
@@ -1048,9 +1040,41 @@ void procmime_parse_multipart(MimeInfo *mimeinfo)
                        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;
@@ -1058,6 +1082,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);
@@ -1068,6 +1095,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)] == '/') {
@@ -1078,25 +1109,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);
-               if ((parameters_parts[0] != NULL) && (parameters_parts[1] != NULL)) {
-                       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_strfreev(parameters_parts);
-       }
+       g_return_if_fail(content_disposition != NULL);
+       g_return_if_fail(mimeinfo != NULL);
 
-       g_strfreev(content_type_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;
+       }
+       if (!g_strcasecmp(str, "inline")) 
+               mimeinfo->disposition = DISPOSITIONTYPE_INLINE;
+       else if (!g_strcasecmp(str, "attachment"))
+               mimeinfo->disposition = DISPOSITIONTYPE_ATTACHMENT;
+       else
+               mimeinfo->disposition = DISPOSITIONTYPE_UNKNOWN;
+       
+       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;
@@ -1116,6 +1165,7 @@ void procmime_parse_mimepart(MimeInfo *parent,
                             gchar *content_encoding,
                             gchar *content_description,
                             gchar *content_id,
+                            gchar *content_disposition,
                             const gchar *filename,
                             guint offset,
                             guint length)
@@ -1154,6 +1204,11 @@ void procmime_parse_mimepart(MimeInfo *parent,
        else
                mimeinfo->id = NULL;
 
+       if (content_disposition != NULL) 
+               procmime_parse_content_disposition(content_disposition, mimeinfo);
+       else
+               mimeinfo->disposition = DISPOSITIONTYPE_INLINE;
+
        /* Call parser for mime type */
        switch (mimeinfo->type) {
                case MIMETYPE_MESSAGE:
@@ -1216,7 +1271,8 @@ static MimeInfo *procmime_scan_file_with_offset(const gchar *filename, int offse
        mimeinfo->length = buf.st_size - offset;
 
        procmime_parse_message_rfc822(mimeinfo);
-       output_mime_structure(mimeinfo, 0);
+       if (debug_get_mode())
+               output_mime_structure(mimeinfo, 0);
 
        return mimeinfo;
 }