/[winpt]/trunk/MyGPGME/decrypt.c
ViewVC logotype

Contents of /trunk/MyGPGME/decrypt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Mon Apr 4 07:01:43 2005 UTC (19 years, 10 months ago) by twoaday
File MIME type: text/plain
File size: 19065 byte(s)
2005-03-22  Timo Schulz  <twoaday@freakmail.de>
                                                                                
        * editcard.c: Support new status-fd entries SC_OP_SUCCESS
        and SC_OP_FAILURE.
        * editkey.c (cmd_addrev_handler): Check if context != NULL.
        * import.c (import_command_handler): Wrong function signature.
        Noted by Kurt Fitzner.
        * types.h: Fixed encrypt_result_s. Noted by Kurt.
        * gpgme.h (gpgme_editkey_addrev_set): Changed return type.
        Kudos to Kurt.
        * key.c: Removed some unreachable code. By Kurt.
                                                                                


1 /* decrypt.c - decrypt functions
2 * Copyright (C) 2000 Werner Koch (dd9jn)
3 * Copyright (C) 2001-2004 Timo Schulz
4 *
5 * This file is part of MyGPGME.
6 *
7 * MyGPGME is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * MyGPGME is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <windows.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32 struct decrypt_result_s {
33 gpgme_sig_t sig;
34 int no_data;
35 int no_seckey;
36 int no_passphrase;
37 int idea_cipher;
38 int okay;
39 int sig_okay;
40 int failed;
41 int bad_mdc;
42 int bad_armor;
43 int bad_passphrase;
44 int key_algo;
45 int file_start;
46 int file_done;
47 char keyid[16+1];
48 char cardno[32+1];
49 void * last_pw_handle;
50 char * userid_hint;
51 char * passphrase_info;
52 char * file_name;
53 };
54
55
56 void
57 gpgme_decrypt_get_sig_ctx (gpgme_ctx_t ctx, gpgme_sig_t * r_sig)
58 {
59 if (!ctx)
60 return;
61 if (r_sig)
62 *r_sig = NULL;
63 if (ctx && ctx->result.decrypt->sig) {
64 _gpgme_sig_ref (ctx->result.decrypt->sig);
65 if (r_sig)
66 *r_sig = ctx->result.decrypt->sig;
67 }
68 } /* gpgme_decrypt_get_sig_ctx */
69
70
71 void
72 gpgme_decrypt_get_status( gpgme_ctx_t ctx, char * keyid,
73 gpgme_op_flags_t * r_flags )
74 {
75 gpgme_op_flags_t flags = 0;
76 _decrypt_result_t res;
77
78 if( !keyid )
79 return;
80 if( ctx->result_type != RESULT_TYPE_DECRYPT )
81 return;
82 if( !ctx->result.decrypt->okay
83 && ctx->result.decrypt->no_seckey ) {
84 strcpy( keyid, ctx->result.decrypt->keyid );
85 flags |= GPGME_OPFLAG_NOSECKEY;
86 }
87 res = ctx->result.decrypt;
88 if (res->bad_armor)
89 flags |= GPGME_OPFLAG_BADARMOR;
90 if (res->bad_mdc)
91 flags |= GPGME_OPFLAG_BADMDC;
92 if (r_flags)
93 *r_flags = flags;
94 } /* gpgme_decrypt_get_status */
95
96
97 void
98 _gpgme_release_decrypt_result( _decrypt_result_t res )
99 {
100 if( res ) {
101 safe_free( res->passphrase_info );
102 safe_free( res->userid_hint );
103 gpgme_sig_release( res->sig );
104 safe_free( res );
105 }
106 } /* _gpgme_release_decrypt_result */
107
108
109 static gpgme_error_t
110 create_result_struct (gpgme_ctx_t ctx)
111 {
112 assert( !ctx->result.decrypt );
113 ctx->result.decrypt = calloc( 1, sizeof * ctx->result.decrypt );
114 if( !ctx->result.decrypt )
115 return mk_error( Out_Of_Core );
116 ctx->result_type = RESULT_TYPE_DECRYPT;
117 return 0;
118 } /* create_result_struct */
119
120
121 static void
122 list_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char * args )
123 {
124 char keyid[32] = {0};
125
126 if (ctx->out_of_core)
127 return;
128 if (code == STATUS_ENC_TO) {
129 keyid[0] = (char)atol (args+17);
130 strncpy (keyid+1, args, 16);
131 gpgme_recipients_add_name (ctx->enc_to, keyid);
132 }
133 } /* list_status_handler */
134
135
136 static gpgme_sig_t
137 add_signature( gpgme_ctx_t ctx )
138 {
139 gpgme_sig_t sig, s;
140 gpgme_error_t err;
141
142 err = gpgme_sig_new( &sig );
143 if( err ) {
144 ctx->out_of_core = 1;
145 return NULL;
146 }
147 if( ctx->result.decrypt->file_name ) {
148 sig->file_name = strdup( ctx->result.decrypt->file_name );
149 if( !sig->file_name ) {
150 ctx->out_of_core = 1;
151 safe_free( sig );
152 return NULL;
153 }
154 }
155 if( !ctx->result.decrypt->sig )
156 ctx->result.decrypt->sig = sig;
157 else {
158 for( s = ctx->result.decrypt->sig; s->next; s=s->next )
159 ;
160 s->next = sig;
161 }
162 return sig;
163 } /* add_signature */
164
165
166 static void
167 decrypt_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char *args )
168 {
169 static gpgme_sig_t sig = NULL;
170 static char keyid[16+1];
171 char *p = NULL, fpr[40+1];
172 int i = 0, j=0;
173 char ch = 0;
174
175 if (ctx->out_of_core)
176 return;
177
178 if (ctx->result_type == RESULT_TYPE_NONE) {
179 if (create_result_struct (ctx)) {
180 ctx->out_of_core = 1;
181 return;
182 }
183 }
184
185 assert (ctx->result_type == RESULT_TYPE_DECRYPT);
186
187 if (code == STATUS_GOODSIG || code == STATUS_REVKEYSIG
188 || code == STATUS_EXPKEYSIG || code == STATUS_BADSIG
189 || code == STATUS_ERRSIG) {
190 sig = add_signature (ctx);
191 if (!sig || ctx->out_of_core)
192 return;
193 }
194
195 _gpgme_nodata_status_handler (code, args, &ctx->result.decrypt->no_data);
196 _gpgme_pass_status_handler (code, args, &ctx->result.decrypt->bad_passphrase,
197 &ctx->result.decrypt->no_data,
198 &ctx->result.decrypt->passphrase_info);
199 if (sig)
200 _gpgme_sigtrust_status_handler (code, args, &sig->trust);
201
202 switch( code ) {
203 case STATUS_EOF:
204 break;
205
206 case STATUS_USERID_HINT:
207 safe_free( ctx->result.decrypt->userid_hint );
208 p = ctx->result.decrypt->userid_hint = strdup( args );
209 if (!p) {
210 ctx->out_of_core = 1;
211 return;
212 }
213 break;
214
215 case STATUS_DECRYPTION_OKAY:
216 ctx->result.decrypt->okay = 1;
217 break;
218
219 case STATUS_DECRYPTION_FAILED:
220 ctx->result.decrypt->failed = 1;
221 break;
222
223 case STATUS_RSA_OR_IDEA:
224 ctx->result.decrypt->idea_cipher = 1;
225 break;
226
227 case STATUS_SIG_ID:
228 DEBUG0( "Plaintext was signed!\n" );
229 break;
230
231 case STATUS_NO_SECKEY:
232 ctx->result.decrypt->no_seckey++;
233 strncpy( ctx->result.decrypt->keyid, args, 16 );
234 break;
235
236 case STATUS_NO_PUBKEY:
237 sig->sigstat = GPGME_SIG_STAT_NOKEY;
238 break;
239
240 case STATUS_VALIDSIG:
241 p = fpr;
242 for( i = 0; i < DIM(fpr) && args[i] && args[i] != ' ' ; i++ )
243 *p++ = args[i];
244 *p = 0;
245 /* skip the formatted date */
246 while ( args[i] && args[i] == ' ')
247 i++;
248 while ( args[i] && args[i] != ' ')
249 i++;
250 /* and get the timestamp */
251 sig->created = strtoul( args + i, NULL, 10 );
252 ctx->result.decrypt->sig_okay = 1;
253 break;
254
255 case STATUS_GOODSIG:
256 case STATUS_BADSIG:
257 if( code == STATUS_GOODSIG )
258 sig->sigstat = GPGME_SIG_STAT_GOOD;
259 else
260 sig->sigstat = GPGME_SIG_STAT_BAD;
261 strncpy( sig->id, args, 16 );
262 sig->user_id = p = calloc (1, strlen (args + 16) + 2);
263 if (!p)
264 {
265 ctx->out_of_core = 1;
266 return;
267 }
268 strcpy (p, args + 16);
269 break;
270
271 case STATUS_EXPKEYSIG:
272 case STATUS_REVKEYSIG:
273 if( code == STATUS_EXPKEYSIG )
274 sig->sigstat = GPGME_SIG_STAT_E_GOOD;
275 else if( code == STATUS_REVKEYSIG )
276 sig->sigstat = GPGME_SIG_STAT_R_GOOD;
277 for( i=0, p=sig->id; args[i] && args[i] != ' '; i++ )
278 *p++ = args[i];
279 *p = '\0';
280 p = sig->user_id = calloc( 1, strlen( args+i ) + 2 );
281 if( !p ) {
282 ctx->out_of_core = 1;
283 return;
284 }
285 j=0;
286 while( args[i] )
287 p[j++] = args[i++];
288 p[j++] = '\0';
289 break;
290
291 case STATUS_ERRSIG:
292 sig->sigstat = GPGME_SIG_STAT_ERROR;
293 break;
294
295 case STATUS_BADMDC:
296 ctx->result.decrypt->bad_mdc = 1;
297 break;
298
299 case STATUS_BADARMOR:
300 ctx->result.decrypt->bad_armor = 1;
301 break;
302
303 case STATUS_FILE_START:
304 if (*args == '3') {
305 safe_free (ctx->result.decrypt->file_name);
306 p = ctx->result.decrypt->file_name = strdup (args+2);
307 if( !p ) {
308 ctx->out_of_core = 1;
309 return;
310 }
311 }
312 ctx->result.decrypt->file_start++;
313 if (ctx->cb.interactiv)
314 ctx->cb.interactiv (ctx->cb.interactiv_value, code, NULL, args+2);
315 break;
316
317 case STATUS_FILE_DONE:
318 ctx->result.decrypt->file_done++;
319 if( ctx->cb.interactiv )
320 ctx->cb.interactiv( ctx->cb.interactiv_value, code, NULL, NULL );
321 break;
322
323 case STATUS_CARDCTRL:
324 ch = args[i++];
325 if (ch == '4') {
326 ctx->result.decrypt->no_seckey = -1;
327 break;
328 }
329 if (ch != '3')
330 break;
331 i++;
332 p = ctx->result.decrypt->cardno;
333 for (; i-1 < DIM (ctx->result.decrypt->cardno) && args[i]; i++)
334 *p++ = args[i];
335 *p = 0;
336 break;
337
338 default:
339 break; /* ignore all other codes */
340 }
341 } /* decrypt_status_handler */
342
343
344 static const char *
345 decrypt_command_handler (void * opaque, gpg_status_code_t code, const char * key)
346 {
347 gpgme_ctx_t c = opaque;
348
349 if (!code) {
350 /* We have been called for cleanup */
351 if (c->cb.passphrase) {
352 c->cb.passphrase (c->cb.passphrase_value, NULL,
353 &c->result.decrypt->last_pw_handle);
354 }
355 return NULL;
356 }
357
358 if (!key || !c->cb.passphrase)
359 return NULL;
360
361 if (c->result_type == RESULT_TYPE_NONE) {
362 if (create_result_struct (c)) {
363 c->out_of_core = 1;
364 return NULL;
365 }
366 }
367
368 if( code == STATUS_GET_HIDDEN
369 && (!strcmp( key, "passphrase.enter" )
370 || !strcmp( key, "passphrase.pin.ask" )) ) {
371 const char * userid_hint = c->result.decrypt->userid_hint;
372 const char * passphrase_info = c->result.decrypt->passphrase_info;
373 const char * cardno = c->result.decrypt->cardno;
374 int bad_passphrase = c->result.decrypt->bad_passphrase;
375 int is_card=0;
376 char * buf;
377 const char *s;
378
379 c->result.decrypt->bad_passphrase = 0;
380 is_card = !strcmp (key, "passphrase.pin.ask");
381 if (!userid_hint)
382 userid_hint = "[User ID hint missing]";
383 if (!passphrase_info)
384 passphrase_info = "[passphrase info missing]";
385 buf = malloc (20 + strlen (userid_hint)
386 + strlen (passphrase_info) + 3);
387 if( !buf ) {
388 c->out_of_core = 1;
389 return NULL;
390 }
391 sprintf (buf, "%s\n%s\n%s", bad_passphrase? "TRY_AGAIN":"ENTER_PASSPHRASE",
392 userid_hint, passphrase_info);
393 s = c->cb.passphrase (c->cb.passphrase_value, is_card? cardno : buf,
394 &c->result.decrypt->last_pw_handle);
395 safe_free (buf);
396 return s;
397 }
398 else if( (code == STATUS_GET_BOOL
399 && !strcmp( key, "openfile.overwrite.okay" ))
400 || (code == STATUS_GET_LINE && !strcmp( key, "openfile.askoutname" )) )
401 if (c->cb.interactiv)
402 return c->cb.interactiv( c->cb.interactiv_value, code, key, NULL );
403
404 return NULL;
405 } /* decrypt_command_handler */
406
407
408 static gpgme_error_t
409 list_keys_start( gpgme_ctx_t ctx, gpgme_data_t ciph, const char * file,
410 gpgme_recipients_t * r_keys )
411 {
412 gpgme_error_t rc;
413 gpgme_recipients_t keys;
414 FILE * fp;
415 const char * s;
416 char * p;
417
418 if (!r_keys)
419 return mk_error (Invalid_Value);
420 if (ciph && file || !ciph && !file)
421 return mk_error (Invalid_Mode);
422
423 *r_keys = NULL;
424 fail_on_pending_request( ctx );
425 ctx->pending = 1;
426
427 _gpgme_gpg_release( &ctx->gpg );
428 rc = _gpgme_gpg_new( &ctx->gpg );
429 if( rc )
430 return rc;
431
432 if( ciph ) {
433 p = _gpgme_data_get_as_string( ciph );
434 if( !p )
435 return mk_error( Out_Of_Core );
436
437 s = _gpgme_get_tmpfile( 0 );
438 fp = fopen( s, "wb" );
439 if( !fp ) {
440 safe_free( p );
441 return mk_error( File_Error );
442 }
443 fwrite (p, 1, strlen (p), fp);
444 fclose (fp);
445 safe_free (p);
446 }
447 else
448 s = file;
449
450 rc = gpgme_recipients_new( &keys );
451 if( rc )
452 return rc;
453 ctx->enc_to = keys;
454
455 _gpgme_gpg_set_status_handler( ctx->gpg, list_status_handler, ctx );
456 _gpgme_gpg_add_arg( ctx->gpg, "--list-only" );
457 _gpgme_gpg_add_arg( ctx->gpg, s );
458
459 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
460 if( rc ) {
461 ctx->pending = 0;
462 _gpgme_gpg_release( &ctx->gpg );
463 gpgme_recipients_release( keys ); keys = NULL;
464 }
465 *r_keys = keys;
466 return rc;
467 } /* list_keys_start */
468
469
470 /* It either works with a file or a data object but not with both! */
471 gpgme_error_t
472 gpgme_op_list_keys( gpgme_data_t ciph, const char * file,
473 gpgme_recipients_t * r_rset )
474 {
475 gpgme_ctx_t ctx = NULL;
476 gpgme_error_t err;
477
478 if( !r_rset )
479 return mk_error (Invalid_Value);
480 *r_rset = NULL;
481 err = gpgme_new( &ctx );
482 if( !err )
483 err = list_keys_start( ctx, ciph, file, r_rset );
484 if( !err ) {
485 gpgme_wait( ctx, 1 );
486 ctx->pending = 0;
487 }
488 gpgme_release( ctx );
489 return err;
490 } /* gpgme_op_list_keys */
491
492
493 static gpgme_error_t
494 file_decrypt_start( gpgme_ctx_t ctx, const char ** input, size_t nfiles,
495 const char * output )
496 {
497 gpgme_error_t rc;
498
499 if( !input )
500 return mk_error( Invalid_Value );
501
502 fail_on_pending_request( ctx );
503 ctx->pending = 1;
504
505 _gpgme_gpg_release( &ctx->gpg );
506 rc = _gpgme_gpg_new( &ctx->gpg );
507 if( rc )
508 return rc;
509
510 _gpgme_gpg_set_status_handler( ctx->gpg, decrypt_status_handler, ctx );
511 if( !ctx->use_pass_fd )
512 _gpgme_gpg_set_command_handler( ctx->gpg, decrypt_command_handler, ctx );
513 else {
514 rc = _gpgme_add_passphrase( ctx );
515 if( rc ) {
516 _gpgme_gpg_release( &ctx->gpg );
517 return rc;
518 }
519 }
520
521 if( !ctx->cb.interactiv )
522 _gpgme_gpg_add_arg( ctx->gpg, "--yes" );
523 if( nfiles > 1 || !output )
524 _gpgme_gpg_add_arg( ctx->gpg, "--no-mangle-dos-filenames" );
525 if( ctx->pipemode || nfiles > 1 )
526 _gpgme_gpg_add_arg( ctx->gpg, "--decrypt-files" );
527 else
528 _gpgme_gpg_add_arg( ctx->gpg, "--decrypt" );
529
530 /* cannot use --output with --decrypt-files */
531 if( nfiles == 1 && !ctx->pipemode && output ) {
532 _gpgme_gpg_add_arg( ctx->gpg, "--output" );
533 _gpgme_gpg_add_arg( ctx->gpg, output );
534 }
535
536 while( nfiles-- )
537 _gpgme_gpg_add_arg( ctx->gpg, *input++ );
538
539 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
540 if( rc ) {
541 ctx->pending = 0;
542 _gpgme_gpg_release( &ctx->gpg );
543 }
544
545 return rc;
546 } /* file_decrypt_start */
547
548
549 static gpgme_error_t
550 decrypt_start( gpgme_ctx_t ctx, gpgme_data_t ciph, gpgme_data_t plain )
551 {
552 int rc = 0;
553
554 fail_on_pending_request( ctx );
555 ctx->pending = 1;
556
557 _gpgme_release_result( ctx );
558 ctx->out_of_core = 0;
559
560 /* create a process object */
561 _gpgme_gpg_release( &ctx->gpg );
562 rc = _gpgme_gpg_new( &ctx->gpg );
563 if( rc )
564 goto leave;
565
566 _gpgme_gpg_set_status_handler( ctx->gpg, decrypt_status_handler, ctx );
567 if( ctx->use_logging )
568 _gpgme_gpg_set_logging_handler( ctx->gpg, ctx );
569 if( ctx->cb.passphrase ) {
570 rc = _gpgme_gpg_set_command_handler( ctx->gpg, decrypt_command_handler, ctx );
571 if ( rc )
572 goto leave;
573 }
574 else if( ctx->passphrase_value ) {
575 rc = _gpgme_add_passphrase( ctx );
576 if( rc )
577 goto leave;
578 }
579
580 /* build the commandline */
581 _gpgme_gpg_add_arg( ctx->gpg, "--decrypt" );
582 /* Check the supplied data */
583 if( !ciph || gpgme_data_get_type( ciph ) == GPGME_DATA_TYPE_NONE ) {
584 rc = mk_error( No_Data );
585 goto leave;
586 }
587 _gpgme_data_set_mode( ciph, GPGME_DATA_MODE_OUT );
588 if( gpgme_data_get_type( plain ) != GPGME_DATA_TYPE_NONE ) {
589 rc = mk_error( Invalid_Value );
590 goto leave;
591 }
592 _gpgme_data_set_mode( plain, GPGME_DATA_MODE_IN );
593
594 /* Tell the gpg object about the data */
595 _gpgme_gpg_add_arg ( ctx->gpg, "--output" );
596 _gpgme_gpg_add_arg ( ctx->gpg, "-" );
597 _gpgme_gpg_add_data( ctx->gpg, plain, 1 );
598 _gpgme_gpg_add_data( ctx->gpg, ciph, 0 );
599
600 /* and kick off the process */
601 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
602
603 leave:
604 if( rc ) {
605 ctx->pending = 0;
606 _gpgme_gpg_release( &ctx->gpg );
607 }
608 return rc;
609 } /* decrypt_start */
610
611
612 static gpgme_error_t
613 get_decrypt_result( gpgme_ctx_t ctx )
614 {
615 gpgme_error_t err;
616 struct decrypt_result_s * res;
617
618 assert( ctx->result.decrypt );
619 res = ctx->result.decrypt;
620 if( ctx->result_type != RESULT_TYPE_DECRYPT )
621 err = mk_error( General_Error );
622 else if (res->okay || res->sig_okay)
623 err = 0;
624 else if( ctx->out_of_core )
625 err = mk_error( Out_Of_Core );
626 else if( res->no_passphrase )
627 err = mk_error( No_Passphrase );
628 else if( res->bad_passphrase )
629 err = mk_error( Bad_Passphrase );
630 else if( res->no_seckey)
631 err = mk_error( No_Seckey );
632 else if( res->idea_cipher )
633 err = mk_error( Cipher_IDEA );
634 else if( res->failed || (res->file_start != res->file_done) )
635 err = mk_error( Decryption_Failed );
636 else if( !res->okay || !res->no_data )
637 err = mk_error( No_Data );
638 else if( gpgme_get_process_rc( ctx ) )
639 err = mk_error( Internal_GPG_Problem );
640 return err;
641 } /* get_decrypt_result */
642
643
644 /**
645 * gpgme_op_decrypt:
646 * @c: The context
647 * @ciph: ciphertext input
648 * @plain: plaintext output
649 *
650 * This function decrypts @in to @out.
651 * Other parameters are take from the context @c.
652 * The function does wait for the result.
653 *
654 * Return value: 0 on success or an errorcode.
655 **/
656 gpgme_error_t
657 gpgme_op_decrypt( gpgme_ctx_t ctx, gpgme_data_t ciph, gpgme_data_t plain )
658
659 {
660 gpgme_error_t err;
661
662 err = decrypt_start( ctx, ciph, plain );
663 if( !err ) {
664 gpgme_wait( ctx, 1 );
665 ctx->pending = 0;
666 err = get_decrypt_result( ctx );
667 }
668 return err;
669 } /* gpgme_op_decrypt */
670
671
672 gpgme_error_t
673 gpgme_op_file_decrypt( gpgme_ctx_t ctx, const char * ciph, const char * plain )
674 {
675 gpgme_error_t err;
676 const char * files[1];
677
678 files[0] = ciph;
679
680 err = file_decrypt_start( ctx, files, 1, plain );
681 if( !err ) {
682 gpgme_wait( ctx, 1 );
683 err = get_decrypt_result( ctx );
684 ctx->pending = 0;
685 }
686 return err;
687 } /* gpgme_op_file_decrypt */
688
689
690 gpgme_error_t
691 gpgme_op_files_decrypt( gpgme_ctx_t ctx, const char ** files, size_t nfiles )
692 {
693 gpgme_error_t err;
694
695 err = file_decrypt_start( ctx, files, nfiles, NULL );
696 if( !err ) {
697 gpgme_wait( ctx, 1 );
698 err = get_decrypt_result( ctx );
699 ctx->pending = 0;
700 }
701 return err;
702 }
703
704
705 gpgme_error_t
706 gpgme_op_clip_decrypt( gpgme_ctx_t ctx )
707 {
708 gpgme_error_t err;
709 gpgme_data_t ciph = NULL;
710 gpgme_data_t plain = NULL;
711
712 err = gpgme_data_new_from_clipboard (&ciph);
713 if( !err )
714 err = gpgme_data_new( &plain );
715 if( !err )
716 err = gpgme_op_decrypt( ctx, ciph, plain );
717
718 gpgme_data_release_and_set_clipboard( plain );
719 gpgme_data_release( ciph );
720
721 return err;
722 } /* gpgme_op_clip_decrypt */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26