]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch-show.c
gmime-cleanup: use GMime 3.0 function names
[notmuch] / notmuch-show.c
index 7afd39478b0e3aa5665d94b5e2acb6234c6793c0..c897591c2e3ca9626983179710188f7a88554a9f 100644 (file)
@@ -272,23 +272,48 @@ show_text_part_content (GMimeObject *part, GMimeStream *stream_out,
     GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
     GMimeStream *stream_filter = NULL;
     GMimeFilter *crlf_filter = NULL;
+    GMimeFilter *windows_filter = NULL;
     GMimeDataWrapper *wrapper;
     const char *charset;
 
     if (! g_mime_content_type_is_type (content_type, "text", "*"))
        INTERNAL_ERROR ("Illegal request to format non-text part (%s) as text.",
-                       g_mime_content_type_to_string (content_type));
+                       g_mime_content_type_get_mime_type (content_type));
 
     if (stream_out == NULL)
        return;
 
+    charset = g_mime_object_get_content_type_parameter (part, "charset");
+    charset = charset ? g_mime_charset_canon_name (charset) : NULL;
+    wrapper = g_mime_part_get_content (GMIME_PART (part));
+    if (wrapper && charset && !g_ascii_strncasecmp (charset, "iso-8859-", 9)) {
+       GMimeStream *null_stream = NULL;
+       GMimeStream *null_stream_filter = NULL;
+
+       /* Check for mislabeled Windows encoding */
+       null_stream = g_mime_stream_null_new ();
+       null_stream_filter = g_mime_stream_filter_new (null_stream);
+       windows_filter = g_mime_filter_windows_new (charset);
+       g_mime_stream_filter_add(GMIME_STREAM_FILTER (null_stream_filter),
+                                windows_filter);
+       g_mime_data_wrapper_write_to_stream (wrapper, null_stream_filter);
+       charset = g_mime_filter_windows_real_charset(
+           (GMimeFilterWindows *) windows_filter);
+
+       if (null_stream_filter)
+           g_object_unref (null_stream_filter);
+       if (null_stream)
+           g_object_unref (null_stream);
+       /* Keep a reference to windows_filter in order to prevent the
+        * charset string from deallocation. */
+    }
+
     stream_filter = g_mime_stream_filter_new (stream_out);
-    crlf_filter = g_mime_filter_crlf_new (false, false);
+    crlf_filter = g_mime_filter_dos2unix_new (false);
     g_mime_stream_filter_add(GMIME_STREAM_FILTER (stream_filter),
                             crlf_filter);
     g_object_unref (crlf_filter);
 
-    charset = g_mime_object_get_content_type_parameter (part, "charset");
     if (charset) {
        GMimeFilter *charset_filter;
        charset_filter = g_mime_filter_charset_new (charset, "UTF-8");
@@ -313,11 +338,12 @@ show_text_part_content (GMimeObject *part, GMimeStream *stream_out,
        }
     }
 
-    wrapper = g_mime_part_get_content_object (GMIME_PART (part));
     if (wrapper && stream_filter)
        g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);
     if (stream_filter)
        g_object_unref(stream_filter);
+    if (windows_filter)
+       g_object_unref (windows_filter);
 }
 
 static const char*
@@ -337,13 +363,13 @@ signature_status_to_string (GMimeSignatureStatus status)
 
 /* Print signature flags */
 struct key_map_struct {
-    GMimeSignatureError bit;
+    GMimeSignatureStatus bit;
     const char * string;
 };
 
 static void
 do_format_signature_errors (sprinter_t *sp, struct key_map_struct *key_map,
-                           unsigned int array_map_len, GMimeSignatureError errors) {
+                           unsigned int array_map_len, GMimeSignatureStatus errors) {
     sp->map_key (sp, "errors");
     sp->begin_map (sp);
 
@@ -357,30 +383,10 @@ do_format_signature_errors (sprinter_t *sp, struct key_map_struct *key_map,
     sp->end (sp);
 }
 
-#if (GMIME_MAJOR_VERSION < 3)
 static void
 format_signature_errors (sprinter_t *sp, GMimeSignature *signature)
 {
-    GMimeSignatureError errors = g_mime_signature_get_errors (signature);
-
-    if (errors == GMIME_SIGNATURE_ERROR_NONE)
-       return;
-
-    struct key_map_struct key_map[] = {
-       { GMIME_SIGNATURE_ERROR_EXPSIG, "sig-expired" },
-       { GMIME_SIGNATURE_ERROR_NO_PUBKEY, "key-missing"},
-       { GMIME_SIGNATURE_ERROR_EXPKEYSIG, "key-expired"},
-       { GMIME_SIGNATURE_ERROR_REVKEYSIG, "key-revoked"},
-       { GMIME_SIGNATURE_ERROR_UNSUPP_ALGO, "alg-unsupported"},
-    };
-
-    do_format_signature_errors (sp, key_map, ARRAY_SIZE(key_map), errors);
-}
-#else
-static void
-format_signature_errors (sprinter_t *sp, GMimeSignature *signature)
-{
-    GMimeSignatureError errors = g_mime_signature_get_errors (signature);
+    GMimeSignatureStatus errors = g_mime_signature_get_status (signature);
 
     if (!(errors & GMIME_SIGNATURE_STATUS_ERROR_MASK))
        return;
@@ -399,17 +405,14 @@ format_signature_errors (sprinter_t *sp, GMimeSignature *signature)
 
     do_format_signature_errors (sp, key_map, ARRAY_SIZE(key_map), errors);
 }
-#endif
 
-/* Signature status sprinter (GMime 2.6) */
+/* Signature status sprinter */
 static void
-format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node)
+format_part_sigstatus_sprinter (sprinter_t *sp, GMimeSignatureList *siglist)
 {
     /* Any changes to the JSON or S-Expression format should be
      * reflected in the file devel/schemata. */
 
-    GMimeSignatureList *siglist = node->sig_list;
-
     sp->begin_list (sp);
 
     if (!siglist) {
@@ -446,15 +449,11 @@ format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node)
                sp->map_key (sp, "expires");
                sp->integer (sp, expires);
            }
-           /* output user id only if validity is FULL or ULTIMATE. */
-           /* note that gmime is using the term "trust" here, which
-            * is WRONG.  It's actually user id "validity". */
            if (certificate) {
-               const char *name = g_mime_certificate_get_uid (certificate);
-               GMimeCertificateTrust trust = g_mime_certificate_get_trust (certificate);
-               if (name && (trust == GMIME_CERTIFICATE_TRUST_FULLY || trust == GMIME_CERTIFICATE_TRUST_ULTIMATE)) {
+               const char *uid = g_mime_certificate_get_valid_userid (certificate);
+               if (uid) {
                    sp->map_key (sp, "userid");
-                   sp->string (sp, name);
+                   sp->string (sp, uid);
                }
            }
        } else if (certificate) {
@@ -466,7 +465,7 @@ format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node)
        }
 
        if (notmuch_format_version <= 3) {
-           GMimeSignatureError errors = g_mime_signature_get_errors (signature);
+           GMimeSignatureStatus errors = g_mime_signature_get_status (signature);
            if (g_mime_signature_status_error (errors)) {
                sp->map_key (sp, "errors");
                sp->integer (sp, errors);
@@ -525,7 +524,7 @@ format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node,
        if (cid)
            g_mime_stream_printf (stream, ", Content-id: %s", cid);
 
-       content_string = g_mime_content_type_to_string (content_type);
+       content_string = g_mime_content_type_get_mime_type (content_type);
        g_mime_stream_printf (stream, ", Content-type: %s\n", content_string);
        g_free (content_string);
     }
@@ -552,16 +551,22 @@ format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node,
        g_mime_stream_printf (stream, "Date: %s\n", date_string);
        g_mime_stream_printf (stream, "\fheader}\n");
 
+       if (!params->output_body)
+       {
+           g_mime_stream_printf (stream, "\f%s}\n", part_type);
+           return NOTMUCH_STATUS_SUCCESS;
+       }
        g_mime_stream_printf (stream, "\fbody{\n");
     }
 
     if (leaf) {
        if (g_mime_content_type_is_type (content_type, "text", "*") &&
-           !g_mime_content_type_is_type (content_type, "text", "html"))
+           (params->include_html ||
+            ! g_mime_content_type_is_type (content_type, "text", "html")))
        {
            show_text_part_content (node->part, stream, 0);
        } else {
-           char *content_string = g_mime_content_type_to_string (content_type);
+           char *content_string = g_mime_content_type_get_mime_type (content_type);
            g_mime_stream_printf (stream, "Non-text part: %s\n", content_string);
            g_free (content_string);
        }
@@ -583,7 +588,7 @@ format_omitted_part_meta_sprinter (sprinter_t *sp, GMimeObject *meta, GMimePart
 {
     const char *content_charset = g_mime_object_get_content_type_parameter (meta, "charset");
     const char *cte = g_mime_object_get_header (meta, "content-transfer-encoding");
-    GMimeDataWrapper *wrapper = g_mime_part_get_content_object (part);
+    GMimeDataWrapper *wrapper = g_mime_part_get_content (part);
     GMimeStream *stream = g_mime_data_wrapper_get_stream (wrapper);
     ssize_t content_length = g_mime_stream_length (stream);
 
@@ -656,11 +661,11 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node,
 
     if (node->verify_attempted) {
        sp->map_key (sp, "sigstatus");
-       format_part_sigstatus_sprinter (sp, node);
+       format_part_sigstatus_sprinter (sp, node->sig_list);
     }
 
     sp->map_key (sp, "content-type");
-    content_string = g_mime_content_type_to_string (content_type);
+    content_string = g_mime_content_type_get_mime_type (content_type);
     sp->string (sp, content_string);
     g_free (content_string);
 
@@ -846,7 +851,7 @@ format_part_raw (unused (const void *ctx), unused (sprinter_t *sp),
        /* For leaf parts, we emit only the transfer-decoded
         * body. */
        GMimeDataWrapper *wrapper;
-       wrapper = g_mime_part_get_content_object (GMIME_PART (node->part));
+       wrapper = g_mime_part_get_content (GMIME_PART (node->part));
 
        if (wrapper && stream_filter)
            g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);
@@ -877,6 +882,11 @@ show_message (void *ctx,
     void *local = talloc_new (ctx);
     mime_node_t *root, *part;
     notmuch_status_t status;
+    unsigned int session_keys = 0;
+    notmuch_status_t session_key_count_error = NOTMUCH_STATUS_SUCCESS;
+
+    if (params->crypto.decrypt == NOTMUCH_DECRYPT_TRUE)
+       session_key_count_error = notmuch_message_count_properties (message, "session-key", &session_keys);
 
     status = mime_node_open (local, message, &(params->crypto), &root);
     if (status)
@@ -884,6 +894,19 @@ show_message (void *ctx,
     part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
     if (part)
        status = format->part (local, sp, part, indent, params);
+    if (params->crypto.decrypt == NOTMUCH_DECRYPT_TRUE && session_key_count_error == NOTMUCH_STATUS_SUCCESS) {
+       unsigned int new_session_keys = 0;
+       if (notmuch_message_count_properties (message, "session-key", &new_session_keys) == NOTMUCH_STATUS_SUCCESS &&
+           new_session_keys > session_keys) {
+           /* try a quiet re-indexing */
+           notmuch_indexopts_t *indexopts = notmuch_database_get_default_indexopts (notmuch_message_get_database (message));
+           if (indexopts) {
+               notmuch_indexopts_set_decrypt_policy (indexopts, NOTMUCH_DECRYPT_AUTO);
+               print_status_message ("Error re-indexing message with --decrypt=stash",
+                                     message, notmuch_message_reindex (message, indexopts));
+           }
+       }
+    }
   DONE:
     talloc_free (local);
     return status;
@@ -1083,6 +1106,7 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
        .part = -1,
        .omit_excluded = true,
        .output_body = true,
+       .crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO },
     };
     int format = NOTMUCH_FORMAT_NOT_SPECIFIED;
     bool exclude = true;
@@ -1102,7 +1126,13 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
        { .opt_bool = &params.entire_thread, .name = "entire-thread",
          .present = &entire_thread_set },
        { .opt_int = &params.part, .name = "part" },
-       { .opt_bool = &params.crypto.decrypt, .name = "decrypt" },
+       { .opt_keyword = (int*)(&params.crypto.decrypt), .name = "decrypt",
+         .keyword_no_arg_value = "true", .keywords =
+         (notmuch_keyword_t []){ { "false", NOTMUCH_DECRYPT_FALSE },
+                                 { "auto", NOTMUCH_DECRYPT_AUTO },
+                                 { "true", NOTMUCH_DECRYPT_NOSTASH },
+                                 { "stash", NOTMUCH_DECRYPT_TRUE },
+                                 { 0, 0 } } },
        { .opt_bool = &params.crypto.verify, .name = "verify" },
        { .opt_bool = &params.output_body, .name = "body" },
        { .opt_bool = &params.include_html, .name = "include-html" },
@@ -1116,8 +1146,9 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
 
     notmuch_process_shared_options (argv[0]);
 
-    /* decryption implies verification */
-    if (params.crypto.decrypt)
+    /* explicit decryption implies verification */
+    if (params.crypto.decrypt == NOTMUCH_DECRYPT_NOSTASH ||
+       params.crypto.decrypt == NOTMUCH_DECRYPT_TRUE)
        params.crypto.verify = true;
 
     /* specifying a part implies single message display */
@@ -1154,15 +1185,19 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
            fprintf (stderr, "Warning: --body=false is incompatible with --part > 0. Disabling.\n");
            params.output_body = true;
        } else {
-           if (format != NOTMUCH_FORMAT_JSON && format != NOTMUCH_FORMAT_SEXP)
+           if (format != NOTMUCH_FORMAT_TEXT &&
+               format != NOTMUCH_FORMAT_JSON &&
+               format != NOTMUCH_FORMAT_SEXP)
                fprintf (stderr,
-                        "Warning: --body=false only implemented for format=json and format=sexp\n");
+                        "Warning: --body=false only implemented for format=text, format=json and format=sexp\n");
        }
     }
 
     if (params.include_html &&
-        (format != NOTMUCH_FORMAT_JSON && format != NOTMUCH_FORMAT_SEXP)) {
-       fprintf (stderr, "Warning: --include-html only implemented for format=json and format=sexp\n");
+        (format != NOTMUCH_FORMAT_TEXT &&
+        format != NOTMUCH_FORMAT_JSON &&
+        format != NOTMUCH_FORMAT_SEXP)) {
+       fprintf (stderr, "Warning: --include-html only implemented for format=text, format=json and format=sexp\n");
     }
 
     query_string = query_string_from_args (config, argc-opt_index, argv+opt_index);
@@ -1176,12 +1211,11 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
        return EXIT_FAILURE;
     }
 
-#if (GMIME_MAJOR_VERSION < 3)
-    params.crypto.gpgpath = notmuch_config_get_crypto_gpg_path (config);
-#endif
-
+    notmuch_database_mode_t mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
+    if (params.crypto.decrypt == NOTMUCH_DECRYPT_TRUE)
+       mode = NOTMUCH_DATABASE_MODE_READ_WRITE;
     if (notmuch_database_open (notmuch_config_get_database_path (config),
-                              NOTMUCH_DATABASE_MODE_READ_ONLY, &notmuch))
+                              mode, &notmuch))
        return EXIT_FAILURE;
 
     notmuch_exit_if_unmatched_db_uuid (notmuch);