2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2021 Colin Leroy and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "claws-features.h"
28 #include <glib/gi18n.h>
31 #include <file-utils.h>
36 #include "pgpinline.h"
37 #include <plugins/pgpcore/sgpgme.h>
38 #include <plugins/pgpcore/prefs_gpg.h>
39 #include <plugins/pgpcore/passphrase.h>
40 #include <plugins/pgpcore/pgp_utils.h>
41 #include "quoted-printable.h"
45 extern struct GPGConfig prefs_gpg
;
47 typedef struct _PrivacyDataPGP PrivacyDataPGP
;
49 struct _PrivacyDataPGP
53 gboolean done_sigtest
;
57 typedef struct _PGPInlineTaskData
63 static PrivacySystem pgpinline_system
;
65 static PrivacyDataPGP
*pgpinline_new_privacydata()
69 data
= g_new0(PrivacyDataPGP
, 1);
70 data
->data
.system
= &pgpinline_system
;
75 static void pgpinline_free_privacydata(PrivacyData
*data
)
80 static gboolean
pgpinline_is_signed(MimeInfo
*mimeinfo
)
82 PrivacyDataPGP
*data
= NULL
;
83 const gchar
*sig_indicator
= "-----BEGIN PGP SIGNED MESSAGE-----";
84 gchar
*textdata
, *sigpos
;
86 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
88 if (procmime_mimeinfo_parent(mimeinfo
) == NULL
)
89 return FALSE
; /* not parent */
91 if (mimeinfo
->type
!= MIMETYPE_TEXT
&&
92 (mimeinfo
->type
!= MIMETYPE_APPLICATION
||
93 g_ascii_strcasecmp(mimeinfo
->subtype
, "pgp")))
96 /* Seal the deal. This has to be text/plain through and through. */
97 if (mimeinfo
->type
== MIMETYPE_APPLICATION
)
99 mimeinfo
->type
= MIMETYPE_TEXT
;
100 g_free(mimeinfo
->subtype
);
101 mimeinfo
->subtype
= g_strdup("plain");
104 if (mimeinfo
->privacy
!= NULL
) {
105 data
= (PrivacyDataPGP
*) mimeinfo
->privacy
;
106 if (data
->done_sigtest
)
107 return data
->is_signed
;
110 textdata
= procmime_get_part_as_string(mimeinfo
, TRUE
);
114 if ((sigpos
= strstr(textdata
, sig_indicator
)) == NULL
) {
119 if (!(sigpos
== textdata
) && !(sigpos
[-1] == '\n')) {
127 data
= pgpinline_new_privacydata();
128 mimeinfo
->privacy
= (PrivacyData
*) data
;
131 data
->done_sigtest
= TRUE
;
132 data
->is_signed
= TRUE
;
138 static void pgpinline_free_task_data(gpointer data
)
140 PGPInlineTaskData
*task_data
= (PGPInlineTaskData
*)data
;
142 g_free(task_data
->rawtext
);
143 g_free(task_data
->charset
);
147 static gchar
*get_sig_data(gchar
*rawtext
, gchar
*charset
)
151 conv
= conv_codeset_strdup(rawtext
, CS_UTF_8
, charset
);
153 conv
= conv_codeset_strdup(rawtext
, CS_UTF_8
, conv_get_locale_charset_str_no_utf8());
156 g_warning("can't convert charset to anything sane");
157 conv
= conv_codeset_strdup(rawtext
, CS_UTF_8
, CS_US_ASCII
);
163 static void pgpinline_check_sig_task(GTask
*task
,
164 gpointer source_object
,
165 gpointer g_task_data
,
166 GCancellable
*cancellable
)
168 PGPInlineTaskData
*task_data
= (PGPInlineTaskData
*)g_task_data
;
172 gpgme_data_t sigdata
= NULL
;
173 gpgme_data_t plain
= NULL
;
174 gpgme_verify_result_t gpgme_res
;
175 gboolean return_err
= TRUE
;
176 gboolean cancelled
= FALSE
;
177 SigCheckTaskResult
*task_result
= NULL
;
179 char err_str
[GPGERR_BUFSIZE
] = "";
181 domain
= g_quark_from_static_string("claws_pgpinline");
183 err
= gpgme_new(&ctx
);
184 if (err
!= GPG_ERR_NO_ERROR
) {
185 gpgme_strerror_r(err
, err_str
, GPGERR_BUFSIZE
);
186 g_warning("couldn't initialize GPG context: %s", err_str
);
190 gpgme_set_textmode(ctx
, 1);
191 gpgme_set_armor(ctx
, 1);
193 textstr
= get_sig_data(task_data
->rawtext
, task_data
->charset
);
195 err
= GPG_ERR_GENERAL
;
196 g_snprintf(err_str
, GPGERR_BUFSIZE
, "Couldn't convert text data to any sane charset.");
200 err
= gpgme_data_new_from_mem(&sigdata
, textstr
, strlen(textstr
), 1);
201 if (err
!= GPG_ERR_NO_ERROR
) {
202 gpgme_strerror_r(err
, err_str
, GPGERR_BUFSIZE
);
203 g_warning("gpgme_data_new_from_mem failed: %s", err_str
);
207 err
= gpgme_data_new(&plain
);
208 if (err
!= GPG_ERR_NO_ERROR
) {
209 gpgme_strerror_r(err
, err_str
, GPGERR_BUFSIZE
);
210 g_warning("gpgme_data_new failed: %s", err_str
);
214 if (g_task_return_error_if_cancelled(task
)) {
215 debug_print("task was cancelled, aborting task:%p\n", task
);
220 err
= gpgme_op_verify(ctx
, sigdata
, NULL
, plain
);
221 if (err
!= GPG_ERR_NO_ERROR
) {
222 gpgme_strerror_r(err
, err_str
, GPGERR_BUFSIZE
);
223 g_warning("gpgme_op_verify failed: %s\n", err_str
);
227 if (g_task_return_error_if_cancelled(task
)) {
228 debug_print("task was cancelled, aborting task:%p\n", task
);
233 gpgme_res
= gpgme_op_verify_result(ctx
);
234 if (gpgme_res
&& gpgme_res
->signatures
== NULL
) {
235 err
= GPG_ERR_SYSTEM_ERROR
;
236 g_warning("no signature found");
237 g_snprintf(err_str
, GPGERR_BUFSIZE
, "No signature found");
241 task_result
= g_new0(SigCheckTaskResult
, 1);
242 task_result
->sig_data
= g_new0(SignatureData
, 1);
244 task_result
->sig_data
->status
= sgpgme_sigstat_gpgme_to_privacy(ctx
, gpgme_res
);
245 task_result
->sig_data
->info_short
= sgpgme_sigstat_info_short(ctx
, gpgme_res
);
246 task_result
->sig_data
->info_full
= sgpgme_sigstat_info_full(ctx
, gpgme_res
);
251 gpgme_data_release(plain
);
253 gpgme_data_release(sigdata
);
263 g_task_return_new_error(task
, domain
, err
, "%s", err_str
);
265 g_task_return_pointer(task
, task_result
, privacy_free_sig_check_task_result
);
268 static gint
pgpinline_check_sig_async(MimeInfo
*mimeinfo
,
269 GCancellable
*cancellable
,
270 GAsyncReadyCallback callback
,
274 PGPInlineTaskData
*task_data
;
276 const gchar
*charset
;
278 if (procmime_mimeinfo_parent(mimeinfo
) == NULL
) {
279 g_warning("Checking signature on incorrect part");
283 if (mimeinfo
->type
!= MIMETYPE_TEXT
) {
284 g_warning("Checking signature on a non-text part");
288 rawtext
= procmime_get_part_as_string(mimeinfo
, TRUE
);
289 if (rawtext
== NULL
) {
290 g_warning("Failed to get part as string");
294 charset
= procmime_mimeinfo_get_parameter(mimeinfo
, "charset");
296 task_data
= g_new0(PGPInlineTaskData
, 1);
297 task_data
->rawtext
= rawtext
;
298 task_data
->charset
= g_strdup(charset
);
300 task
= g_task_new(NULL
, cancellable
, callback
, user_data
);
301 mimeinfo
->last_sig_check_task
= task
;
303 g_task_set_task_data(task
, task_data
, pgpinline_free_task_data
);
304 debug_print("creating check sig async task:%p task_data:%p\n", task
, task_data
);
305 g_task_set_return_on_cancel(task
, TRUE
);
306 g_task_run_in_thread(task
, pgpinline_check_sig_task
);
307 g_object_unref(task
);
312 static gboolean
pgpinline_is_encrypted(MimeInfo
*mimeinfo
)
314 const gchar
*begin_indicator
= "-----BEGIN PGP MESSAGE-----";
315 const gchar
*end_indicator
= "-----END PGP MESSAGE-----";
318 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
320 if (procmime_mimeinfo_parent(mimeinfo
) == NULL
)
321 return FALSE
; /* not parent */
323 if (mimeinfo
->type
!= MIMETYPE_TEXT
&&
324 (mimeinfo
->type
!= MIMETYPE_APPLICATION
||
325 g_ascii_strcasecmp(mimeinfo
->subtype
, "pgp")))
328 /* Seal the deal. This has to be text/plain through and through. */
329 if (mimeinfo
->type
== MIMETYPE_APPLICATION
)
331 mimeinfo
->type
= MIMETYPE_TEXT
;
332 g_free(mimeinfo
->subtype
);
333 mimeinfo
->subtype
= g_strdup("plain");
336 textdata
= procmime_get_part_as_string(mimeinfo
, TRUE
);
340 if (!pgp_locate_armor_header(textdata
, begin_indicator
)) {
344 if (!pgp_locate_armor_header(textdata
, end_indicator
)) {
354 static MimeInfo
*pgpinline_decrypt(MimeInfo
*mimeinfo
)
356 MimeInfo
*decinfo
, *parseinfo
;
357 gpgme_data_t cipher
, plain
;
360 gchar
*textdata
= NULL
;
362 const gchar
*src_codeset
= NULL
;
363 gpgme_verify_result_t sigstat
= 0;
364 PrivacyDataPGP
*data
= NULL
;
368 const gchar
*begin_indicator
= "-----BEGIN PGP MESSAGE-----";
369 const gchar
*end_indicator
= "-----END PGP MESSAGE-----";
371 SignatureData
*sig_data
= NULL
;
373 if (gpgme_new(&ctx
) != GPG_ERR_NO_ERROR
)
376 gpgme_set_textmode(ctx
, 1);
377 gpgme_set_armor(ctx
, 1);
379 cm_return_val_if_fail(mimeinfo
!= NULL
, NULL
);
380 cm_return_val_if_fail(pgpinline_is_encrypted(mimeinfo
), NULL
);
382 if (procmime_mimeinfo_parent(mimeinfo
) == NULL
||
383 mimeinfo
->type
!= MIMETYPE_TEXT
) {
385 privacy_set_error(_("Couldn't parse mime part."));
389 textdata
= procmime_get_part_as_string(mimeinfo
, TRUE
);
392 privacy_set_error(_("Couldn't get text data."));
396 debug_print("decrypting '%s'\n", textdata
);
397 gpgme_data_new_from_mem(&cipher
, textdata
, (size_t)strlen(textdata
), 1);
399 plain
= sgpgme_decrypt_verify(cipher
, &sigstat
, ctx
);
401 if (sigstat
!= NULL
&& sigstat
->signatures
!= NULL
) {
402 sig_data
= g_new0(SignatureData
, 1);
403 sig_data
->status
= sgpgme_sigstat_gpgme_to_privacy(ctx
, sigstat
);
404 sig_data
->info_short
= sgpgme_sigstat_info_short(ctx
, sigstat
);
405 sig_data
->info_full
= sgpgme_sigstat_info_full(ctx
, sigstat
);
409 gpgme_data_release(cipher
);
414 privacy_free_signature_data(sig_data
);
418 fname
= g_strdup_printf("%s%cplaintext.%08x",
419 get_mime_tmp_dir(), G_DIR_SEPARATOR
, ++id
);
421 if ((dstfp
= claws_fopen(fname
, "wb")) == NULL
) {
422 FILE_OP_ERROR(fname
, "claws_fopen");
423 privacy_set_error(_("Couldn't open decrypted file %s"), fname
);
425 privacy_free_signature_data(sig_data
);
428 gpgme_data_release(plain
);
432 src_codeset
= procmime_mimeinfo_get_parameter(mimeinfo
, "charset");
433 if (src_codeset
== NULL
)
434 src_codeset
= CS_ISO_8859_1
;
436 if (fprintf(dstfp
, "MIME-Version: 1.0\r\n"
437 "Content-Type: text/plain; charset=%s\r\n"
438 "Content-Transfer-Encoding: 8bit\r\n"
441 FILE_OP_ERROR(fname
, "fprintf");
442 privacy_set_error(_("Couldn't write to decrypted file %s"), fname
);
446 /* Store any part before encrypted text */
447 pos
= pgp_locate_armor_header(textdata
, begin_indicator
);
448 if (pos
!= NULL
&& (pos
- textdata
) > 0) {
449 if (claws_fwrite(textdata
, 1, pos
- textdata
, dstfp
) < pos
- textdata
) {
450 FILE_OP_ERROR(fname
, "claws_fwrite");
451 privacy_set_error(_("Couldn't write to decrypted file %s"), fname
);
456 if (claws_fwrite(_("\n--- Start of PGP/Inline encrypted data ---\n"), 1,
457 strlen(_("\n--- Start of PGP/Inline encrypted data ---\n")),
458 dstfp
) < strlen(_("\n--- Start of PGP/Inline encrypted data ---\n"))) {
459 FILE_OP_ERROR(fname
, "claws_fwrite");
460 privacy_set_error(_("Couldn't write to decrypted file %s"), fname
);
463 chars
= sgpgme_data_release_and_get_mem(plain
, &len
);
465 if (claws_fwrite(chars
, 1, len
, dstfp
) < len
) {
466 FILE_OP_ERROR(fname
, "claws_fwrite");
468 privacy_set_error(_("Couldn't write to decrypted file %s"), fname
);
473 /* Store any part after encrypted text */
474 if (claws_fwrite(_("--- End of PGP/Inline encrypted data ---\n"), 1,
475 strlen(_("--- End of PGP/Inline encrypted data ---\n")),
476 dstfp
) < strlen(_("--- End of PGP/Inline encrypted data ---\n"))) {
477 FILE_OP_ERROR(fname
, "claws_fwrite");
478 privacy_set_error(_("Couldn't write to decrypted file %s"), fname
);
482 pos
= pgp_locate_armor_header(pos
, end_indicator
);
483 if (pos
!= NULL
&& *pos
!= '\0') {
484 pos
+= strlen(end_indicator
);
485 if (claws_fwrite(pos
, 1, strlen(pos
), dstfp
) < strlen(pos
)) {
486 FILE_OP_ERROR(fname
, "claws_fwrite");
487 privacy_set_error(_("Couldn't write to decrypted file %s"), fname
);
495 if (claws_safe_fclose(dstfp
) == EOF
) {
496 FILE_OP_ERROR(fname
, "claws_fclose");
497 privacy_set_error(_("Couldn't close decrypted file %s"), fname
);
499 gpgme_data_release(plain
);
501 privacy_free_signature_data(sig_data
);
505 parseinfo
= procmime_scan_file(fname
);
508 if (parseinfo
== NULL
) {
509 privacy_set_error(_("Couldn't scan decrypted file."));
511 privacy_free_signature_data(sig_data
);
514 decinfo
= g_node_first_child(parseinfo
->node
) != NULL
?
515 g_node_first_child(parseinfo
->node
)->data
: NULL
;
517 if (decinfo
== NULL
) {
518 privacy_set_error(_("Couldn't scan decrypted file parts."));
520 privacy_free_signature_data(sig_data
);
524 g_node_unlink(decinfo
->node
);
525 procmime_mimeinfo_free_all(&parseinfo
);
529 if (sig_data
!= NULL
) {
530 if (decinfo
->privacy
!= NULL
) {
531 data
= (PrivacyDataPGP
*) decinfo
->privacy
;
533 data
= pgpinline_new_privacydata();
534 decinfo
->privacy
= (PrivacyData
*) data
;
537 data
->done_sigtest
= TRUE
;
538 data
->is_signed
= TRUE
;
539 decinfo
->sig_data
= sig_data
;
547 privacy_free_signature_data(sig_data
);
551 gpgme_data_release(plain
);
555 static gboolean
pgpinline_sign(MimeInfo
*mimeinfo
, PrefsAccount
*account
, const gchar
*from_addr
)
557 MimeInfo
*msgcontent
;
558 gchar
*textstr
, *tmp
;
562 gpgme_data_t gpgtext
, gpgsig
;
565 struct passphrase_cb_info_s info
;
566 gpgme_sign_result_t result
= NULL
;
568 memset (&info
, 0, sizeof info
);
570 /* get content node from message */
571 msgcontent
= (MimeInfo
*) mimeinfo
->node
->children
->data
;
572 if (msgcontent
->type
== MIMETYPE_MULTIPART
) {
573 if (!msgcontent
->node
->children
) {
574 debug_print("msgcontent->node->children NULL, bailing\n");
575 privacy_set_error(_("Malformed message"));
578 msgcontent
= (MimeInfo
*) msgcontent
->node
->children
->data
;
580 /* get rid of quoted-printable or anything */
581 procmime_decode_content(msgcontent
);
585 perror("my_tmpfile");
586 privacy_set_error(_("Couldn't create temporary file, %s"), g_strerror(errno
));
589 procmime_write_mimeinfo(msgcontent
, fp
);
592 /* read temporary file into memory */
593 textstr
= file_read_stream_to_str_no_recode(fp
);
597 gpgme_data_new_from_mem(&gpgtext
, textstr
, (size_t)strlen(textstr
), 0);
598 gpgme_data_new(&gpgsig
);
599 if ((err
= gpgme_new(&ctx
)) != GPG_ERR_NO_ERROR
) {
600 debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err
));
601 privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err
));
604 gpgme_set_textmode(ctx
, 1);
605 gpgme_set_armor(ctx
, 1);
607 if (!sgpgme_setup_signers(ctx
, account
, from_addr
)) {
612 prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent
);
613 if (!g_getenv("GPG_AGENT_INFO") || !prefs_gpg_get_config()->use_gpg_agent
) {
615 gpgme_set_passphrase_cb (ctx
, gpgmegtk_passphrase_cb
, &info
);
618 err
= gpgme_op_sign(ctx
, gpgtext
, gpgsig
, GPGME_SIG_MODE_CLEAR
);
619 if (err
!= GPG_ERR_NO_ERROR
) {
620 if (err
== GPG_ERR_CANCELED
) {
621 /* ignore cancelled signing */
622 privacy_reset_error();
623 debug_print("gpgme_op_sign cancelled\n");
625 privacy_set_error(_("Data signing failed, %s"), gpgme_strerror(err
));
626 debug_print("gpgme_op_sign error : %x\n", err
);
631 result
= gpgme_op_sign_result(ctx
);
632 if (result
&& result
->signatures
) {
633 gpgme_new_signature_t sig
= result
->signatures
;
635 debug_print("valid signature: %s\n", sig
->fpr
);
638 } else if (result
&& result
->invalid_signers
) {
639 gpgme_invalid_key_t invalid
= result
->invalid_signers
;
641 g_warning("invalid signer: %s (%s)", invalid
->fpr
,
642 gpgme_strerror(invalid
->reason
));
643 privacy_set_error(_("Data signing failed due to invalid signer: %s"),
644 gpgme_strerror(invalid
->reason
));
645 invalid
= invalid
->next
;
650 /* can't get result (maybe no signing key?) */
651 debug_print("gpgme_op_sign_result error\n");
652 privacy_set_error(_("Data signing failed, no results."));
658 sigcontent
= sgpgme_data_release_and_get_mem(gpgsig
, &len
);
660 if (sigcontent
== NULL
|| len
<= 0) {
661 g_warning("sgpgme_data_release_and_get_mem failed");
662 privacy_set_error(_("Data signing failed, no contents."));
663 gpgme_data_release(gpgtext
);
670 tmp
= g_malloc(len
+1);
671 memmove(tmp
, sigcontent
, len
+1);
673 gpgme_data_release(gpgtext
);
677 if (msgcontent
->content
== MIMECONTENT_FILE
&&
678 msgcontent
->data
.filename
!= NULL
) {
679 if (msgcontent
->tmp
== TRUE
)
680 claws_unlink(msgcontent
->data
.filename
);
681 g_free(msgcontent
->data
.filename
);
683 msgcontent
->data
.mem
= g_strdup(tmp
);
684 msgcontent
->content
= MIMECONTENT_MEM
;
687 /* avoid all sorts of clear-signing problems with non ascii
690 procmime_encode_content(msgcontent
, ENC_BASE64
);
696 static gchar
*pgpinline_get_encrypt_data(GSList
*recp_names
)
698 return sgpgme_get_encrypt_data(recp_names
, GPGME_PROTOCOL_OpenPGP
);
701 static const gchar
*pgpinline_get_encrypt_warning(void)
703 if (prefs_gpg_should_skip_encryption_warning(pgpinline_system
.id
))
706 return _("Please note that attachments are not encrypted by "
707 "the PGP/Inline system, nor are email headers, like Subject.");
710 static void pgpinline_inhibit_encrypt_warning(gboolean inhibit
)
713 prefs_gpg_add_skip_encryption_warning(pgpinline_system
.id
);
715 prefs_gpg_remove_skip_encryption_warning(pgpinline_system
.id
);
718 static gboolean
pgpinline_encrypt(MimeInfo
*mimeinfo
, const gchar
*encrypt_data
)
720 MimeInfo
*msgcontent
;
724 gchar
*textstr
, *tmp
;
725 gpgme_data_t gpgtext
, gpgenc
;
727 gpgme_key_t
*kset
= NULL
;
728 gchar
**fprs
= g_strsplit(encrypt_data
, " ", -1);
732 while (fprs
[i
] && strlen(fprs
[i
])) {
736 kset
= g_malloc(sizeof(gpgme_key_t
)*(i
+1));
737 memset(kset
, 0, sizeof(gpgme_key_t
)*(i
+1));
738 if ((err
= gpgme_new(&ctx
)) != GPG_ERR_NO_ERROR
) {
739 debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err
));
740 privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err
));
746 while (fprs
[i
] && strlen(fprs
[i
])) {
748 err
= gpgme_get_key(ctx
, fprs
[i
], &key
, 0);
750 debug_print("can't add key '%s'[%d] (%s)\n", fprs
[i
],i
, gpgme_strerror(err
));
751 privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs
[i
], gpgme_strerror(err
));
752 for (gint x
= 0; x
< i
; x
++)
753 gpgme_key_unref(kset
[x
]);
758 debug_print("found %s at %d\n", fprs
[i
], i
);
763 debug_print("Encrypting message content\n");
765 /* get content node from message */
766 msgcontent
= (MimeInfo
*) mimeinfo
->node
->children
->data
;
767 if (msgcontent
->type
== MIMETYPE_MULTIPART
) {
768 if (!msgcontent
->node
->children
) {
769 debug_print("msgcontent->node->children NULL, bailing\n");
770 privacy_set_error(_("Malformed message"));
771 for (gint x
= 0; x
< i
; x
++)
772 gpgme_key_unref(kset
[x
]);
777 msgcontent
= (MimeInfo
*) msgcontent
->node
->children
->data
;
779 /* get rid of quoted-printable or anything */
780 procmime_decode_content(msgcontent
);
784 privacy_set_error(_("Couldn't create temporary file, %s"), g_strerror(errno
));
785 perror("my_tmpfile");
786 for (gint x
= 0; x
< i
; x
++)
787 gpgme_key_unref(kset
[x
]);
792 procmime_write_mimeinfo(msgcontent
, fp
);
795 /* read temporary file into memory */
796 textstr
= file_read_stream_to_str_no_recode(fp
);
801 gpgme_data_new_from_mem(&gpgtext
, textstr
, (size_t)strlen(textstr
), 0);
802 gpgme_data_new(&gpgenc
);
803 if ((err
= gpgme_new(&ctx
)) != GPG_ERR_NO_ERROR
) {
804 debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err
));
805 privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err
));
806 for (gint x
= 0; x
< i
; x
++)
807 gpgme_key_unref(kset
[x
]);
812 gpgme_set_armor(ctx
, 1);
814 err
= gpgme_op_encrypt(ctx
, kset
, GPGME_ENCRYPT_ALWAYS_TRUST
, gpgtext
, gpgenc
);
816 enccontent
= sgpgme_data_release_and_get_mem(gpgenc
, &len
);
817 for (gint x
= 0; x
< i
; x
++)
818 gpgme_key_unref(kset
[x
]);
821 if (enccontent
== NULL
|| len
<= 0) {
822 g_warning("sgpgme_data_release_and_get_mem failed");
823 privacy_set_error(_("Encryption failed, %s"), gpgme_strerror(err
));
824 gpgme_data_release(gpgtext
);
832 tmp
= g_malloc(len
+1);
833 memmove(tmp
, enccontent
, len
+1);
837 gpgme_data_release(gpgtext
);
840 if (msgcontent
->content
== MIMECONTENT_FILE
&&
841 msgcontent
->data
.filename
!= NULL
) {
842 if (msgcontent
->tmp
== TRUE
)
843 claws_unlink(msgcontent
->data
.filename
);
844 g_free(msgcontent
->data
.filename
);
846 msgcontent
->data
.mem
= g_strdup(tmp
);
847 msgcontent
->content
= MIMECONTENT_MEM
;
856 static PrivacySystem pgpinline_system
= {
857 "pgpinline", /* id */
858 "PGP Inline", /* name */
860 pgpinline_free_privacydata
, /* free_privacydata */
862 pgpinline_is_signed
, /* is_signed(MimeInfo *) */
863 pgpinline_check_sig_async
,
865 pgpinline_is_encrypted
, /* is_encrypted(MimeInfo *) */
866 pgpinline_decrypt
, /* decrypt(MimeInfo *) */
872 pgpinline_get_encrypt_data
,
874 pgpinline_get_encrypt_warning
,
875 pgpinline_inhibit_encrypt_warning
,
876 prefs_gpg_auto_check_signatures
,
879 void pgpinline_init()
881 privacy_register_system(&pgpinline_system
);
884 void pgpinline_done()
886 privacy_unregister_system(&pgpinline_system
);
889 struct PluginFeature
*plugin_provides(void)
891 static struct PluginFeature features
[] =
892 { {PLUGIN_PRIVACY
, N_("PGP/Inline")},
893 {PLUGIN_NOTHING
, NULL
}};
896 #endif /* USE_GPGME */