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

Contents of /trunk/MyGPGME/decrypt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File MIME type: text/plain
File size: 19747 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26