できた。ちょっとパッチ。テストするのが面倒だからなぁ、投稿するかどうかは不明。
Index: libsylph/procheader.c =================================================================== --- libsylph/procheader.c (revision 2362) +++ libsylph/procheader.c (working copy) @@ -690,7 +690,7 @@ MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME); } else if (!charset) { procmime_scan_content_type_str - (hp, NULL, &charset, NULL, NULL); + (hp, NULL, &charset, NULL, NULL, NULL); } break; case H_SEEN: Index: libsylph/procmime.c =================================================================== --- libsylph/procmime.c (revision 2362) +++ libsylph/procmime.c (working copy) @@ -69,6 +69,7 @@ g_free(mimeinfo->boundary); g_free(mimeinfo->content_disposition); g_free(mimeinfo->filename); + g_free(mimeinfo->smime_type); g_free(mimeinfo->sigstatus); g_free(mimeinfo->sigstatus_full); @@ -379,14 +380,17 @@ g_free(mimeinfo->charset); g_free(mimeinfo->name); g_free(mimeinfo->boundary); + g_free(mimeinfo->smime_type); mimeinfo->content_type = NULL; mimeinfo->charset = NULL; mimeinfo->name = NULL; mimeinfo->boundary = NULL; + mimeinfo->smime_type = NULL; procmime_scan_content_type_str(content_type, &mimeinfo->content_type, &mimeinfo->charset, &mimeinfo->name, - &mimeinfo->boundary); + &mimeinfo->boundary, + &mimeinfo->smime_type); mimeinfo->mime_type = procmime_scan_mime_type(mimeinfo->content_type); if (mimeinfo->mime_type == MIME_MULTIPART && !mimeinfo->boundary) @@ -706,7 +710,8 @@ void procmime_scan_content_type_str(const gchar *content_type, gchar **mime_type, gchar **charset, - gchar **name, gchar **boundary) + gchar **name, gchar **boundary, + gchar **smime_type) { MimeParams *mparams; GSList *cur; @@ -730,6 +735,10 @@ !g_ascii_strcasecmp(param->name, "boundary")) { *boundary = g_strdup(param->value); boundary = NULL; + } else if (smime_type && + !g_ascii_strcasecmp(param->name, "smime-type")) { + *smime_type = g_strdup(param->value); + smime_type = NULL; } } Index: libsylph/procmime.h =================================================================== --- libsylph/procmime.h (revision 2362) +++ libsylph/procmime.h (working copy) @@ -102,6 +102,7 @@ gchar *charset; gchar *name; gchar *boundary; + gchar *smime_type; gchar *content_disposition; gchar *filename; @@ -155,7 +156,8 @@ gchar **mime_type, gchar **charset, gchar **name, - gchar **boundary); + gchar **boundary, + gchar **smime_type); void procmime_scan_content_disposition (MimeInfo *mimeinfo, const gchar *content_disposition); MimeInfo *procmime_scan_mime_header (FILE *fp); Index: src/compose.c =================================================================== --- src/compose.c (revision 2362) +++ src/compose.c (working copy) @@ -1410,7 +1410,8 @@ if (hentry[H_CONTENT_TYPE].body != NULL) { procmime_scan_content_type_str(hentry[H_CONTENT_TYPE].body, - NULL, &charset, NULL, NULL); + NULL, &charset, NULL, NULL, + NULL); g_free(hentry[H_CONTENT_TYPE].body); hentry[H_CONTENT_TYPE].body = NULL; } Index: src/rfc2015.c =================================================================== --- src/rfc2015.c (revision 2362) +++ src/rfc2015.c (working copy) @@ -364,7 +364,8 @@ } #endif -static gpgme_data_t pgp_decrypt(MsgInfo *msginfo, MimeInfo *partinfo, FILE *fp) +static gpgme_data_t pgp_decrypt(MsgInfo *msginfo, MimeInfo *partinfo, FILE *fp, + gboolean pgp) { gpgme_ctx_t ctx = NULL; gpgme_error_t err; @@ -372,6 +373,7 @@ struct passphrase_cb_info_s info; gpgme_verify_result_t verifyresult = NULL; const gchar *result = NULL; + const gchar *filename; memset(&info, 0, sizeof info); @@ -380,13 +382,37 @@ debug_print("gpgme_new failed: %s\n", gpgme_strerror(err)); goto leave; } + if (!pgp) { + err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS); + if (err) { + debug_print("gpgme_set_protocol failed: %s\n", + gpgme_strerror(err)); + goto leave; + } + } - err = gpgme_data_new_from_filepart(&cipher, NULL, fp, - partinfo->fpos, partinfo->size); - if (err) { - debug_print("gpgme_data_new_from_filepart failed: %s\n", - gpgme_strerror(err)); - goto leave; + if (pgp) { + err = gpgme_data_new_from_filepart(&cipher, NULL, fp, + partinfo->fpos, partinfo->size); + if (err) { + debug_print("gpgme_data_new_from_filepart failed: %s\n", + gpgme_strerror(err)); + goto leave; + } + } else { + filename = procmime_get_tmp_file_name(partinfo); + if (procmime_get_part_fp(filename, fp, partinfo) < 0) { + g_warning("Can't get the S/MIME data file."); + g_free(filename); + goto leave; + } + err = gpgme_data_new_from_file(&cipher, filename, 1); + g_free(filename); + if (err) { + debug_print("gpgme_data_new_from_file failed: %s\n", + gpgme_strerror(err)); + goto leave; + } } err = gpgme_data_new(&plain); @@ -538,12 +564,23 @@ gint rfc2015_is_encrypted(MimeInfo *mimeinfo) { - if (!mimeinfo || mimeinfo->mime_type != MIME_MULTIPART) + if (!mimeinfo) return 0; - if (g_ascii_strcasecmp(mimeinfo->content_type, "multipart/encrypted")) - return 0; - /* fixme: we should check the protocol parameter */ - return 1; + + /* PGP */ + if (mimeinfo->mime_type == MIME_MULTIPART && + !g_ascii_strcasecmp(mimeinfo->content_type, "multipart/encrypted")) { + /* fixme: we should check the protocol parameter */ + return 1; + } + + /* S/MIME */ + if (!g_ascii_strcasecmp(mimeinfo->content_type, "application/pkcs7-mime") && + !g_ascii_strcasecmp(mimeinfo->smime_type, "enveloped-data")) { + return 1; + } + + return 0; } gboolean rfc2015_msg_is_encrypted(const gchar *file) @@ -625,47 +662,72 @@ gchar buf[BUFFSIZE]; gint in_cline; gpgme_error_t err; + gboolean multi = FALSE; g_return_if_fail(msginfo != NULL); g_return_if_fail(mimeinfo != NULL); g_return_if_fail(fp != NULL); - g_return_if_fail(mimeinfo->mime_type == MIME_MULTIPART); + multi = (mimeinfo->mime_type == MIME_MULTIPART); - debug_print("** decrypting multipart/encrypted message\n"); + debug_print("** decrypting multipart/encrypted or application/pkcs7-mime message\n"); /* skip headers */ if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0) perror("fseek"); tmpinfo = procmime_scan_mime_header(fp); - if (!tmpinfo || tmpinfo->mime_type != MIME_MULTIPART) { + if (!tmpinfo) { DECRYPTION_ABORT(); } - procmime_scan_multipart_message(tmpinfo, fp); + if (multi) { + if (tmpinfo->mime_type == MIME_MULTIPART) { + procmime_scan_multipart_message(tmpinfo, fp); + partinfo = tmpinfo->children; + } else { + DECRYPTION_ABORT(); + } + } else { + partinfo = tmpinfo; + } - /* check that we have the 2 parts */ - partinfo = tmpinfo->children; - if (!partinfo || !partinfo->next) { + if (!partinfo) { DECRYPTION_ABORT(); } - if (!g_ascii_strcasecmp(partinfo->content_type, + if (multi && !g_ascii_strcasecmp(partinfo->content_type, "application/pgp-encrypted")) { + /* check that we have the 2 parts */ + if (!partinfo->next) { + DECRYPTION_ABORT(); + } /* Fixme: check that the version is 1 */ ver_ok = 1; + + partinfo = partinfo->next; + if (ver_ok && + !g_ascii_strcasecmp(partinfo->content_type, + "application/octet-stream")) { + if (partinfo->next) { + g_warning("oops: pgp_encrypted with more than 2 parts"); + } + } else { + DECRYPTION_ABORT(); + } + + debug_print("** yep, it is pgp encrypted\n"); } - partinfo = partinfo->next; - if (ver_ok && - !g_ascii_strcasecmp(partinfo->content_type, - "application/octet-stream")) { - if (partinfo->next) - g_warning("oops: pgp_encrypted with more than 2 parts"); - } else { - DECRYPTION_ABORT(); + + if (!g_ascii_strcasecmp(partinfo->content_type, + "application/pkcs7-mime")) { + if (!g_ascii_strcasecmp(partinfo->smime_type, + "enveloped-data")) { + ver_ok = 1; /*???*/ + } else { + DECRYPTION_ABORT(); + } + debug_print("** yep, it is smime encrypted\n"); } - debug_print("** yep, it is pgp encrypted\n"); - - plain = pgp_decrypt(msginfo, partinfo, fp); + plain = pgp_decrypt(msginfo, partinfo, fp, multi); if (!plain) { DECRYPTION_ABORT(); }
RFC も何も見てないので、 偶然うちの (mutt から送った) S/MIME メッセージを見ることができただけかもしれないし、 セキュリティについても知らない。保証はしないよ。
とくに outlook とのやりとりなんかのバッドノウハウはまったく知らない。