/[gpgoe]/trunk/src/OECrypto.c
ViewVC logotype

Contents of /trunk/src/OECrypto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (show annotations)
Sun Jun 4 10:12:47 2006 UTC (18 years, 11 months ago) by twoaday
File MIME type: text/plain
File size: 18392 byte(s)
Prepare new release.


1 /* OECrypto.c - OE crypto functions
2 * Copyright (C) 2001, 2002, 2003, 2006 Timo Schulz
3 *
4 * This file is part of GPGOE.
5 *
6 * GPGOE is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
10 *
11 * GPGOE is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with GPGOE; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <windows.h>
25 #include <assert.h>
26 #include <commctrl.h>
27
28 #include "resource.h"
29 #include "gpgme.h"
30 #include "GPGOE.h"
31
32
33 /* Valid OpenPGP message types. */
34 enum {
35 PGP_MESSAGE = 1,
36 PGP_CLEARSIG = 2,
37 PGP_SIG = 4,
38 PGP_KEY = 8,
39 };
40
41
42 /* Move the keyboard focus to the message window
43 to copy the text to the clipboard. */
44 static void
45 set_focus (HWND main)
46 {
47 HWND doc, mime, msg;
48
49 doc = FindWindowEx (main, NULL, "ME_DocHost", NULL );
50 mime = FindWindowEx (doc, NULL, "##MimeEdit_Server", NULL);
51 msg = FindWindowEx (mime, NULL, "Internet Explorer_Server", NULL);
52
53 AttachThreadInput (GetCurrentThreadId (),
54 GetWindowThreadProcessId (main, NULL),
55 TRUE);
56
57 SetFocus (doc);
58 SetFocus (mime);
59 SetFocus (msg);
60
61 AttachThreadInput (GetCurrentThreadId (),
62 GetWindowThreadProcessId (main, NULL),
63 FALSE);
64 }
65
66
67 /* Copy the message to the clipboard and then return the clipboard
68 data (which is the message). */
69 static char*
70 window_get_message (HWND main_hwnd)
71 {
72 set_focus (main_hwnd);
73 SetForegroundWindow (main_hwnd);
74 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE_SELECTALL, 0), 0);
75 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE_COPY, 0), 0);
76
77 /* even so SendMessage() should wait, we wait for safety reasons. */
78 Sleep (200);
79 return get_clip_text (NULL);
80 }
81
82
83 /* Paste the message given in @msg into the window @main_hwnd.
84 To make sure all existing text is overwritten, "select all"
85 is send to the window first. */
86 static void
87 window_set_message (HWND main_hwnd, const char *msg)
88 {
89 set_clip_text (NULL, msg, strlen (msg));
90 set_focus (main_hwnd);
91 SetForegroundWindow (main_hwnd);
92 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE_SELECTALL, 0), 0);
93 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE_PASTE, 0), 0);
94 }
95
96
97 /* Try to find the given recipient by key @key and
98 return it (NULL in case of error). */
99 static recip_list_t
100 find_recipient (recip_list_t rset, gpgme_key_t key)
101 {
102 recip_list_t n;
103 gpgme_user_id_t u;
104
105 for (n = rset; n; n = n->next) {
106 for (u = key->uids; u; u = u->next) {
107 if (u->email && strstr (u->email, n->addr))
108 return n;
109 }
110 }
111 return NULL;
112 }
113
114
115 /* Add recipient with address @addr and key @key to @rset. */
116 void
117 add_recipient (recip_list_t *rset, const char *addr, gpgme_key_t key)
118 {
119 recip_list_t r, n;
120
121 r = xcalloc (1, sizeof *r);
122 r->addr = xstrdup (addr);
123 r->key = key;
124 if (!*rset)
125 *rset = r;
126 else {
127 for (n=*rset; n->next; n=n->next)
128 ;
129 n->next = r;
130 }
131 }
132
133
134 /* Release recipient list @rset. */
135 static void
136 release_recipient (recip_list_t rset)
137 {
138 recip_list_t n;
139
140 while (rset != NULL) {
141 n = rset->next;
142 if (rset->key)
143 gpgme_key_release (rset->key);
144 free_if_alloc (rset->addr);
145 free_if_alloc (rset);
146 rset = n;
147 }
148 }
149
150
151 /* This functions converts the OE recipient fields to GPG compatible fields.
152 Currently the function support the following 'From' styles:
153 John Hacker <[email protected]>; [email protected]
154 or Foo Bar <[email protected]>, [email protected].
155 only the part between '<' '>' are added.
156 */
157 static int
158 parse_recipients (plugin_ctx_t ctx, recip_list_t *rset, char *recpt)
159 {
160 char *token, *p;
161 int count = 0;
162 char *p1, *p2;
163 int n1, n2;
164
165 assert (recpt && rset);
166
167 token = strtok (recpt, ",;");
168 while (token != NULL ) {
169 if ((p1=strchr (token, '<')) && (p2=strchr (token, '>'))
170 && strchr (token, '@')) {
171 n1 = p1 - token + 1 ;
172 n2 = p2 - token + 1;
173
174 p = xcalloc (1, strlen (token) + 1);
175 memcpy (p, token+n1, n2-n1-1);
176 add_recipient (rset, p, NULL);
177 count++;
178 free_if_alloc (p);
179 }
180 else if (strchr (token, '@') && !strchr (token, ' ')) {
181 p = xcalloc (1, strlen (token) + 1);
182 memcpy (p, token, strlen (token));
183 add_recipient (rset, p, NULL);
184 count++;
185 free_if_alloc (p);
186 }
187 token = strtok (NULL, ",;");
188 }
189 return count;
190 }
191
192
193 /* Fill in the key part of the recipient list @addrs if possible. */
194 static int
195 get_keys_from_addresses (recip_list_t addrs)
196 {
197 gpgme_ctx_t ctx;
198 gpgme_error_t err;
199 gpgme_key_t pk;
200 recip_list_t n, fnd;
201 char *p;
202 int nkeys=0;
203 DWORD len=0;
204
205 for (n = addrs; n; n = n->next)
206 len += strlen (n->addr) + 3;
207 p = xcalloc (1, len + 1);
208 for (n = addrs; n; n = n->next) {
209 strcat (p, n->addr);
210 strcat (p, " ");
211 }
212
213 err = gpgme_new (&ctx);
214 if (!err)
215 err = gpgme_op_keylist_start (ctx, p, 0);
216 while (!err) {
217 err = gpgme_op_keylist_next (ctx, &pk);
218 if (err)
219 break;
220 /* do not add invalid keys. */
221 if (pk->disabled || pk->expired || pk->revoked)
222 continue;
223 fnd = find_recipient (addrs, pk);
224 if (fnd != NULL && pk->can_encrypt) {
225 fnd->key = pk;
226 nkeys++;
227 }
228 }
229
230 gpgme_release (ctx);
231 free_if_alloc (p);
232 return nkeys;
233 }
234
235
236 /* Create gpgme input data object. If @encode is 1, use UTF8 conversion. */
237 gpgme_error_t
238 create_in_data (gpgme_data_t *in, const char *buf, int encode)
239 {
240 gpgme_error_t err;
241 char *enc_buf;
242
243 enc_buf = encode? native_to_utf8 (buf) : xstrdup (buf);
244 err = gpgme_data_new_from_mem (in, enc_buf, strlen (enc_buf), 1);
245 free_if_alloc (enc_buf);
246 return err;
247 }
248
249
250 /* Map gpgme data object to a string. */
251 void
252 map_gpgme_data (gpgme_data_t out, char **r_msg)
253 {
254 size_t len = 0;
255 char *p;
256
257 p = gpgme_data_release_and_get_mem (out, &len);
258 free_if_alloc (*r_msg);
259 *r_msg = xcalloc (1, len+1);
260 memcpy (*r_msg, p, len);
261 gpgme_free (p);
262 }
263
264
265 /* Try to extract the needed key information and retrieve
266 the keys if possible. */
267 static gpgme_error_t
268 get_keys (plugin_ctx_t ctx, recip_list_t *r_list, gpgme_key_t **r_keys)
269 {
270 gpgme_key_t *keys;
271 recip_list_t addrs = NULL, n;
272 int rcount = 0, nkeys = 0;
273 int i;
274
275 if (ctx->to && strlen (ctx->to) >= 3)
276 rcount += parse_recipients (ctx, &addrs, ctx->to);
277 if (ctx->cc && strlen (ctx->cc) >= 3)
278 rcount += parse_recipients (ctx, &addrs, ctx->cc);
279 if (ctx->bcc && strlen (ctx->bcc) >= 3)
280 rcount += parse_recipients (ctx, &addrs, ctx->bcc);
281
282 nkeys = get_keys_from_addresses (addrs);
283 /* at least some keys were not found, so we offer to select them. */
284 if (nkeys != rcount) {
285 ctx->rset = addrs;
286 rcount = DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_ENCRYPT,
287 ctx->main_wnd, encrypt_dlg_proc, (LPARAM)ctx);
288 if (rcount == 0)
289 return gpg_error (GPG_ERR_NO_PUBKEY);
290 nkeys += rcount;
291 }
292
293 keys = xcalloc (nkeys+1, sizeof *keys);
294 for (n = addrs, i=0; n; n = n->next) {
295 if (n->key != NULL)
296 keys[i++] = n->key;
297 }
298 *r_list = addrs;
299 *r_keys = keys;
300 return 0;
301 }
302
303
304 /* Encrypt the given message @r_msg with the recipients from the
305 To, Cc, Bcc fields. In case that a recipient was not found
306 use the recipient dialog so the user can select the missing keys. */
307 static gpgme_error_t
308 encrypt_msg (plugin_ctx_t ctx, char **r_msg)
309 {
310 gpgme_error_t err;
311 gpgme_key_t *keys = NULL;
312 gpgme_ctx_t gctx = NULL;
313 gpgme_data_t in = NULL, out = NULL;
314 recip_list_t list = NULL;
315 char *msg = *r_msg;
316
317 assert (ctx);
318
319 err = get_keys (ctx, &list, &keys);
320 if (err)
321 return err;
322
323 err = gpgme_new (&gctx);
324 if (!err)
325 err = create_in_data (&in, msg, ctx->use_utf8);
326 if (!err)
327 err = gpgme_data_new (&out);
328 if (!err) {
329 gpgme_set_armor (gctx, 1);
330 gpgme_set_textmode (gctx, 1);
331 err = gpgme_op_encrypt (gctx, keys,
332 GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
333 }
334
335 gpgme_release (gctx);
336 gpgme_data_release (in);
337 release_recipient (list);
338 free_if_alloc (keys);
339
340 if (err)
341 gpgme_data_release (out);
342 else
343 map_gpgme_data (out, r_msg);
344 return err;
345 }
346
347
348 /* Sign the message given in @r_msg with the GPG default key. */
349 static gpgme_error_t
350 sign_msg (plugin_ctx_t ctx, char **r_msg)
351 {
352 gpgme_error_t err;
353 gpgme_ctx_t gctx;
354 gpgme_data_t in, out;
355 pass_cb_t cb_val;
356 int cancel;
357
358 cb_val = new_pass_cb (ctx->main_wnd);
359
360 err = gpgme_new (&gctx);
361 if (!err)
362 err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
363 if (!err)
364 err = gpgme_data_new (&out);
365 if (!err) {
366 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
367 err = gpgme_op_sign (gctx, in, out, GPGME_SIG_MODE_CLEAR);
368 }
369
370 cancel = pass_cb_cancelled (cb_val);
371
372 gpgme_release (gctx);
373 gpgme_data_release (in);
374 free_pass_cb (cb_val);
375
376 if (err || cancel)
377 gpgme_data_release (out);
378 else
379 map_gpgme_data (out, r_msg);
380
381 return cancel? 0 : err;
382 }
383
384
385 static void
386 start_verify_dialog (HWND main_wnd, gpgme_signature_t sig, gpgme_data_t text)
387 {
388 struct verify_ctx_s ctx;
389
390 if (!sig)
391 return;
392 memset (&ctx, 0, sizeof (ctx));
393 ctx.sig = sig;
394 ctx.text = text;
395 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, main_wnd,
396 verify_dlg_proc, (LPARAM)&ctx);
397 }
398
399
400 /* Sign and encrypt the message @r_msg. */
401 static gpgme_error_t
402 sign_encrypt_msg (plugin_ctx_t ctx, char **r_msg)
403 {
404 gpgme_ctx_t gctx;
405 gpgme_data_t in, out;
406 gpgme_error_t err;
407 gpgme_key_t *keys;
408 pass_cb_t cb_val;
409 recip_list_t list = NULL;
410 int cancel;
411
412 err = get_keys (ctx, &list, &keys);
413 if (err)
414 return err;
415
416 cb_val = new_pass_cb (ctx->main_wnd);
417
418 err = gpgme_new (&gctx);
419 if (!err)
420 err = create_in_data (&in, *r_msg, ctx->use_utf8);
421 if (!err)
422 err = gpgme_data_new (&out);
423 if (!err) {
424 gpgme_set_armor (gctx, 1);
425 gpgme_set_textmode (gctx, 1);
426 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
427 err = gpgme_op_encrypt_sign (gctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,
428 in, out);
429 }
430
431 cancel = pass_cb_cancelled (cb_val);
432
433 gpgme_release (gctx);
434 gpgme_data_release (in);
435 release_recipient (list);
436 free_if_alloc (keys);
437 free_pass_cb (cb_val);
438
439 if (err || cancel)
440 gpgme_data_release (out);
441 else
442 map_gpgme_data (out, r_msg);
443 return cancel? 0 : err;
444 }
445
446
447 static gpgme_error_t
448 verify_msg (plugin_ctx_t ctx, char **r_msg)
449 {
450 gpgme_error_t err;
451 gpgme_ctx_t gctx;
452 gpgme_data_t out = NULL;
453 gpgme_data_t sig = NULL;
454 gpgme_verify_result_t res;
455
456 err = gpgme_new (&gctx);
457 if (!err)
458 err = gpgme_data_new_from_mem (&sig, *r_msg, strlen (*r_msg), 1);
459 if (!err)
460 err = gpgme_data_new (&out);
461 if (!err)
462 err = gpgme_op_verify (gctx, sig, NULL, out);
463 if (!err) {
464 res = gpgme_op_verify_result (gctx);
465 if (res && res->signatures)
466 start_verify_dialog (ctx->main_wnd, res->signatures, out);
467 }
468
469 gpgme_release (gctx);
470 gpgme_data_release (sig);
471
472 if (!err)
473 map_gpgme_data (out, r_msg);
474 else
475 gpgme_data_release (out);
476 return err;
477 }
478
479
480 /* Detailed error message when the decryption failed. */
481 static void
482 store_decrypt_info (char *buf, size_t buflen,
483 gpgme_decrypt_result_t res)
484 {
485 gpgme_key_t key = NULL;
486 gpgme_ctx_t ctx;
487 int algo;
488
489 if (!res->recipients)
490 return;
491
492 if (!gpgme_new (&ctx)) {
493 gpgme_get_key (ctx, res->recipients->keyid, &key, 0);
494 gpgme_release (ctx);
495 }
496
497 algo = res->recipients->pubkey_algo;
498 if (!key)
499 _snprintf (buf, buflen, _("encrypted with %s key, ID %s\n"
500 "decryption failed: secret key not available"),
501 algo == 1? "RSA" : algo==16? "ELG": "???",
502 res->recipients->keyid+8);
503 else {
504 char *uid = utf8_to_native (key->uids->uid);
505 _snprintf (buf, buflen, _("encrypted with %d-bit %s key, ID %s\n"
506 "\t\"%s\"\n"
507 "decryption failed: secret key not available"),
508 key->subkeys->length,
509 algo == 1? "RSA" : algo==16? "ELG": "???",
510 key->subkeys->keyid+8, uid);
511 free_if_alloc (uid);
512 }
513 if (key)
514 gpgme_key_release (key);
515 }
516
517
518 /* Decrypt the message given in @r_msg.
519 The old message will be freed and replaced with the plaintext. */
520 gpgme_error_t
521 oe_decrypt_msg (HWND main_wnd, char **r_msg)
522 {
523 gpgme_ctx_t gctx = NULL;
524 gpgme_data_t in = NULL, out = NULL;
525 gpgme_error_t err;
526 pass_cb_t cb_val;
527 int cancel;
528 char *msg = *r_msg;
529
530 cb_val = new_pass_cb (main_wnd);
531 err = gpgme_new (&gctx);
532 if (!err)
533 err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
534 if (!err)
535 err = gpgme_data_new (&out);
536 if (!err) {
537 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
538 err = gpgme_op_decrypt (gctx, in, out);
539 }
540
541 cancel = pass_cb_cancelled (cb_val);
542
543 gpgme_release (gctx);
544 gpgme_data_release (in);
545 free_pass_cb (cb_val);
546
547 if (err || cancel)
548 gpgme_data_release (out);
549 else
550 map_gpgme_data (out, r_msg);
551
552 return cancel? 0 : err;
553 }
554
555
556 /* Decrypt the message @r_msg. If the type @type is actually a signature,
557 the verify function is called instead of decryption. */
558 static gpgme_error_t
559 decrypt_msg (plugin_ctx_t ctx, char **r_msg, int *type, int *r_cancel)
560 {
561 gpgme_ctx_t gctx = NULL;
562 gpgme_data_t in = NULL, out = NULL;
563 gpgme_error_t err;
564 gpgme_verify_result_t res;
565 pass_cb_t cb_val;
566 char *msg = *r_msg;
567
568 if ((*type & PGP_SIG) || (*type & PGP_CLEARSIG))
569 return verify_msg (ctx, r_msg);
570
571 cb_val = new_pass_cb (ctx->main_wnd);
572
573 err = gpgme_new (&gctx);
574 if (!err)
575 err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
576 if (!err)
577 err = gpgme_data_new (&out);
578 if (!err) {
579 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
580 err = gpgme_op_decrypt_verify (gctx, in, out);
581 res = gpgme_op_verify_result (gctx);
582 if (res && res->signatures) {
583 start_verify_dialog (ctx->main_wnd, res->signatures, out);
584 *type |= PGP_SIG;
585 }
586 }
587 *r_cancel = pass_cb_cancelled (cb_val);
588
589 if (!*r_cancel && err) {
590 gpgme_decrypt_result_t r = gpgme_op_decrypt_result (gctx);
591 store_decrypt_info (ctx->errbuf, sizeof (ctx->errbuf)-1, r);
592 }
593
594 gpgme_release (gctx);
595 gpgme_data_release (in);
596 free_pass_cb (cb_val);
597
598 if (err || *r_cancel)
599 gpgme_data_release (out);
600 else
601 map_gpgme_data (out, r_msg);
602
603 return *r_cancel? 0 : err;
604 }
605
606
607 /* Return what kind of OpenPGP message @msg is. */
608 static int
609 parse_pgp_id (const char *msg)
610 {
611 int id = 0;
612
613 if (strstr (msg, "BEGIN PGP MESSAGE"))
614 id |= PGP_MESSAGE;
615 if (strstr (msg, "BEGIN PGP PUBLIC KEY") ||
616 strstr (msg, "BEGIN PGP SECRET KEY") ||
617 strstr (msg, "BEGIN PGP PRIVATE KEY"))
618 id |= PGP_KEY;
619 if (strstr (msg, "BEGIN PGP SIGNED MESSAGE"))
620 id |= PGP_CLEARSIG;
621 return id;
622 }
623
624
625 static int
626 winpt_key_import (void)
627 {
628 HWND winpt;
629
630 winpt = FindWindow ("WinPT", "WinPT");
631 if (winpt != NULL) {
632 PostMessage (winpt, WM_COMMAND, 40014, 0);
633 return 0;
634 }
635 return -1;
636 }
637
638
639 /* Try to decrypt a PGP/MIME message. */
640 static gpgme_error_t
641 oe_handle_pgp_mime_mail (plugin_ctx_t ctx)
642 {
643 SetEvent (plugin_active);
644
645 /* Select attachment number 0. */
646 AttachThreadInput (GetCurrentThreadId (),
647 GetWindowThreadProcessId (ctx->main_wnd, NULL),
648 TRUE);
649
650 SetFocus (ctx->addr_wnd);
651 SetFocus (ctx->attach);
652 ListView_SetItemState (ctx->attach, 0, LVIS_SELECTED|LVIS_FOCUSED,
653 LVIS_FOCUSED|LVIS_SELECTED);
654
655 AttachThreadInput (GetCurrentThreadId (),
656 GetWindowThreadProcessId (ctx->main_wnd, NULL),
657 FALSE);
658
659 SendMessage (ctx->addr_wnd, WM_COMMAND, ID_OE_SAVE_ATT, 0);
660
661 ResetEvent (plugin_active);
662
663 return 0;
664 }
665
666
667 /* This function can be use for all kind of OE messages.
668 It automatically choose the right procedure to handle the data. */
669 gpgme_error_t
670 oe_handle_mail (plugin_ctx_t ctx)
671 {
672 gpgme_error_t rc = 0;
673 char *msg;
674 int msg_type = 0;
675 int cancel;
676
677 assert (ctx);
678
679 msg = window_get_message (ctx->main_wnd);
680 #if 0
681 if ((!msg || strlen (msg)) < 2 &&
682 ctx->attach && ListView_GetItemCount (ctx->attach) == 2) {
683 free_if_alloc (msg);
684 return oe_handle_pgp_mime_mail (ctx);
685 }
686 #endif
687 if (!msg || strlen (msg) == 2) {
688 free_if_alloc (msg);
689 return 0;
690 }
691
692 if (strstr (msg, "-----BEGIN PGP") &&
693 strstr (msg, "-----END PGP"))
694 msg_type = parse_pgp_id (msg);
695
696 if (msg_type & PGP_KEY) {
697 if (winpt_key_import ())
698 MessageBox (ctx->main_wnd,
699 _("This mail contains one or more public or secret keys.\n\n"
700 "Please save the mail text in a file to use WinPT to import them."),
701 _("GPG Plug-in Info"), MB_ICONINFORMATION|MB_OK);
702 }
703 else if (msg_type) {
704 rc = decrypt_msg (ctx, &msg, &msg_type, &cancel);
705 SendMessage (ctx->msg_wnd, WM_CLEAR, 0, 0);
706 SendMessage (ctx->msg_wnd, WM_UNDO, 0, 0);
707 if (!cancel && !rc && (msg_type & PGP_MESSAGE) && !(msg_type & PGP_SIG)
708 && msg && strlen (msg) > 0) {
709 struct viewer_ctx_s viewer;
710 viewer.msg = msg;
711 viewer.main_wnd = ctx->main_wnd;
712 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VIEWER, ctx->main_wnd,
713 viewer_dlg_proc, (LPARAM)&viewer);
714 }
715 }
716 else if (ctx->sign || ctx->encrypt) {
717 if (!ctx->to && !ctx->cc && !ctx->bcc) {
718 free_if_alloc (msg);
719 return gpg_error (GPG_ERR_NO_DATA);
720 }
721 if (ctx->sign && ctx->encrypt)
722 rc = sign_encrypt_msg (ctx, &msg);
723 else if (ctx->sign)
724 rc = sign_msg (ctx, &msg);
725 else if (ctx->encrypt)
726 rc = encrypt_msg (ctx, &msg);
727 window_set_message (ctx->main_wnd, msg);
728 }
729
730 free_if_alloc (msg);
731 return rc;
732 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26