static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo) { MimeInfo *decinfo, *parseinfo; gpgme_data_t cipher, plain; FILE *dstfp; gchar *fname; gchar *textdata = NULL; static gint id = 0; const gchar *src_codeset = NULL; gpgme_verify_result_t sigstat = 0; PrivacyDataPGP *data = NULL; gpgme_ctx_t ctx; gchar *chars; size_t len; const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----"; const gchar *end_indicator = "-----END PGP MESSAGE-----"; gchar *pos; if (gpgme_new(&ctx) != GPG_ERR_NO_ERROR) return NULL; gpgme_set_textmode(ctx, 1); gpgme_set_armor(ctx, 1); cm_return_val_if_fail(mimeinfo != NULL, NULL); cm_return_val_if_fail(pgpinline_is_encrypted(mimeinfo), NULL); if (procmime_mimeinfo_parent(mimeinfo) == NULL || mimeinfo->type != MIMETYPE_TEXT) { gpgme_release(ctx); privacy_set_error(_("Couldn't parse mime part.")); return NULL; } textdata = get_part_as_string(mimeinfo); if (!textdata) { gpgme_release(ctx); privacy_set_error(_("Couldn't get text data.")); return NULL; } debug_print("decrypting '%s'\n", textdata); gpgme_data_new_from_mem(&cipher, textdata, (size_t)strlen(textdata), 1); plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx); if (sigstat && !sigstat->signatures) sigstat = NULL; gpgme_data_release(cipher); if (plain == NULL) { gpgme_release(ctx); return NULL; } fname = g_strdup_printf("%s%cplaintext.%08x", get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id); if ((dstfp = g_fopen(fname, "wb")) == NULL) { FILE_OP_ERROR(fname, "fopen"); privacy_set_error(_("Couldn't open decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; } src_codeset = procmime_mimeinfo_get_parameter(mimeinfo, "charset"); if (src_codeset == NULL) src_codeset = CS_ISO_8859_1; if (fprintf(dstfp, "MIME-Version: 1.0\r\n" "Content-Type: text/plain; charset=%s\r\n" "Content-Transfer-Encoding: 8bit\r\n" "\r\n", src_codeset) < 0) { FILE_OP_ERROR(fname, "fprintf"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } /* Store any part before encrypted text */ pos = pgp_locate_armor_header(textdata, begin_indicator); if (pos != NULL && (pos - textdata) > 0) { if (fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } if (fwrite(_("\n--- Start of PGP/Inline encrypted data ---\n"), 1, strlen(_("\n--- Start of PGP/Inline encrypted data ---\n")), dstfp) < strlen(_("\n--- Start of PGP/Inline encrypted data ---\n"))) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } chars = sgpgme_data_release_and_get_mem(plain, &len); if (len > 0) { if (fwrite(chars, 1, len, dstfp) < len) { FILE_OP_ERROR(fname, "fwrite"); g_free(chars); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } g_free(chars); /* Store any part after encrypted text */ if (fwrite(_("--- End of PGP/Inline encrypted data ---\n"), 1, strlen(_("--- End of PGP/Inline encrypted data ---\n")), dstfp) < strlen(_("--- End of PGP/Inline encrypted data ---\n"))) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } if (pos != NULL) { pos = pgp_locate_armor_header(pos, end_indicator); if (pos != NULL && *pos != '\0') { pos += strlen(end_indicator); if (fwrite(pos, 1, strlen(pos), dstfp) < strlen(pos)) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } } if (fclose(dstfp) == EOF) { FILE_OP_ERROR(fname, "fclose"); privacy_set_error(_("Couldn't close decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; } parseinfo = procmime_scan_file(fname); g_free(fname); if (parseinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't scan decrypted file.")); return NULL; } decinfo = g_node_first_child(parseinfo->node) != NULL ? g_node_first_child(parseinfo->node)->data : NULL; if (decinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't scan decrypted file parts.")); return NULL; } g_node_unlink(decinfo->node); procmime_mimeinfo_free_all(parseinfo); decinfo->tmp = TRUE; if (sigstat != GPGME_SIG_STAT_NONE) { if (decinfo->privacy != NULL) { data = (PrivacyDataPGP *) decinfo->privacy; } else { data = pgpinline_new_privacydata(); decinfo->privacy = (PrivacyData *) data; } if (data != NULL) { data->done_sigtest = TRUE; data->is_signed = TRUE; data->sigstatus = sigstat; if (data->ctx) gpgme_release(data->ctx); data->ctx = ctx; } } else gpgme_release(ctx); return decinfo; FILE_ERROR: fclose(dstfp); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; }
static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo) { MimeInfo *encinfo, *decinfo, *parseinfo; gpgme_data_t cipher = NULL, plain = NULL; static gint id = 0; FILE *dstfp; gchar *fname; gpgme_verify_result_t sigstat = NULL; PrivacyDataPGP *data = NULL; gpgme_ctx_t ctx; gchar *chars; size_t len; gpgme_error_t err; if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); return NULL; } cm_return_val_if_fail(pgpmime_is_encrypted(mimeinfo), NULL); encinfo = (MimeInfo *) g_node_nth_child(mimeinfo->node, 1)->data; cipher = sgpgme_data_from_mimeinfo(encinfo); plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx); gpgme_data_release(cipher); if (plain == NULL) { debug_print("plain is null!\n"); gpgme_release(ctx); return NULL; } fname = g_strdup_printf("%s%cplaintext.%08x", get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id); if ((dstfp = claws_fopen(fname, "wb")) == NULL) { FILE_OP_ERROR(fname, "claws_fopen"); privacy_set_error(_("Couldn't open decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); debug_print("can't open!\n"); return NULL; } if (fprintf(dstfp, "MIME-Version: 1.0\n") < 0) { FILE_OP_ERROR(fname, "fprintf"); claws_fclose(dstfp); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); debug_print("can't open!\n"); return NULL; } chars = sgpgme_data_release_and_get_mem(plain, &len); if (len > 0) { if (claws_fwrite(chars, 1, len, dstfp) < len) { FILE_OP_ERROR(fname, "claws_fwrite"); g_free(chars); claws_fclose(dstfp); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); debug_print("can't open!\n"); return NULL; } } g_free(chars); if (claws_safe_fclose(dstfp) == EOF) { FILE_OP_ERROR(fname, "claws_fclose"); privacy_set_error(_("Couldn't close decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); debug_print("can't open!\n"); return NULL; } parseinfo = procmime_scan_file(fname); g_free(fname); if (parseinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't parse decrypted file.")); return NULL; } decinfo = g_node_first_child(parseinfo->node) != NULL ? g_node_first_child(parseinfo->node)->data : NULL; if (decinfo == NULL) { privacy_set_error(_("Couldn't parse decrypted file parts.")); gpgme_release(ctx); return NULL; } g_node_unlink(decinfo->node); procmime_mimeinfo_free_all(&parseinfo); decinfo->tmp = TRUE; if (sigstat != NULL && sigstat->signatures != NULL) { if (decinfo->privacy != NULL) { data = (PrivacyDataPGP *) decinfo->privacy; } else { data = pgpmime_new_privacydata(); decinfo->privacy = (PrivacyData *) data; } if (data != NULL) { data->done_sigtest = TRUE; data->is_signed = TRUE; data->sigstatus = sigstat; if (data->ctx) gpgme_release(data->ctx); data->ctx = ctx; } } else gpgme_release(ctx); return decinfo; }