2002-02-26  Marcus Brinkmann  <marcus@g10code.de>

	* gpgme.texi (Encrypting a Plaintext): Document
	gpgme_op_encrypt_sign and gpgme_op_encrypt_sign_start.

gpgme/
2002-02-25  Marcus Brinkmann  <marcus@g10code.de>

	* engine.c (_gpgme_engine_op_encrypt_sign): New function.
	* engine.h (_gpgme_engine_op_encrypt_sign): New prototype.
	* rungpg.c (_gpgme_append_gpg_args_from_signers): New function.
	(_gpgme_gpg_op_sign): Use that new function.
	(_gpgme_gpg_op_encrypt_sign): New function.
	* rungpg.h (_gpgme_gpg_op_encrypt_sign): New prototype.
	* gpgme.h (gpgme_op_encrypt_sign_start): New prototype.
	(gpgme_op_encrypt_sign): Likewise.
	* Makefile.am (libgpgme_la_SOURCES): Add encrypt-sign.c.
	* ops.h (_gpgme_encrypt_status_handler): Add prototype.
	(_gpgme_sign_status_handler): Add prototype.
	* sign.c (sign_status_handler): Rename to ...
	(_gpgme_sign_status_handler): ... this and make non-static.
	* encrypt.c (encrypt_status_handler): Rename to ...
	(_gpgme_encrypt_status_handler): ... this and make non-static.
	* encrypt.c (gpgme_op_encrypt_start): Use new status handler name.
	* sign.c (gpgme_op_sign_start): Likewise.

tests/
2002-02-26  Marcus Brinkmann  <marcus@g10code.de>

	* gpg/t-encrypt-sign.c: New file.
	* gpg/Makefile.am (TESTS): Add t-encrypt-sign.
This commit is contained in:
Marcus Brinkmann 2002-02-26 00:08:09 +00:00
parent d75d6fb262
commit c22974f99f
17 changed files with 475 additions and 24 deletions

5
NEWS
View File

@ -3,10 +3,15 @@
to set and get the number of certifications to include in S/MIME
signed messages.
* New interfaces gpgme_op_encrypt_sign and gpgme_op_encrypt_sign_start
to encrypt and sign a message in a combined operation.
* Interface changes relative to the 0.3.3 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_set_include_certs NEW
gpgme_get_include_certs NEW
gpgme_op_encrypt_sign NEW
gpgme_op_encrypt_sign_start NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.3.3 (2002-02-12)

View File

@ -1,3 +1,8 @@
2002-02-26 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Encrypting a Plaintext): Document
gpgme_op_encrypt_sign and gpgme_op_encrypt_sign_start.
2002-02-25 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Creating a Signature): Add a note about

View File

@ -2201,7 +2201,7 @@ The function @code{gpgme_recipients_enum_close} releases the iterator
@subsubsection Encrypting a Plaintext
@deftypefun GpgmeError gpgme_op_encrypt (@w{GpgmeCtx @var{ctx}}, @w{GpgmeRecipients @var{rset}}, @w{GpgmeData @var{plain}}, @w{GpgmeData @var{cipher}})
The function @code{gpgme_op_crypt} encrypts the plaintext in the data
The function @code{gpgme_op_encrypt} encrypts the plaintext in the data
object @var{plain} for the recipients @var{rset} and stores the
ciphertext in the data object @var{cipher}. The type of the
ciphertext created is determined by the @acronym{ASCII} armor and text
@ -2232,6 +2232,30 @@ recipients.
@end deftypefun
@deftypefun GpgmeError gpgme_op_encrypt_sign (@w{GpgmeCtx @var{ctx}}, @w{GpgmeRecipients @var{rset}}, @w{GpgmeData @var{plain}}, @w{GpgmeData @var{cipher}})
The function @code{gpgme_op_encrypt_sign} does a combined encrypt and
sign operation. It is used like @code{gpgme_op_encrypt}, but the
ciphertext also contains signatures for the signers listed in
@var{ctx}.
The combined encrypt and sign operation is currently only available
for the OpenPGP crypto engine.
@end deftypefun
@deftypefun GpgmeError gpgme_op_encrypt_sign_start (@w{GpgmeCtx @var{ctx}}, @w{GpgmeRecipients @var{rset}}, @w{GpgmeData @var{plain}}, @w{GpgmeData @var{cipher}})
The function @code{gpgme_op_encrypt_sign_start} initiates a
@code{gpgme_op_encrypt_sign} operation. It can be completed by
calling @code{gpgme_wait} on the context. @xref{Waiting For
Completion}.
The function returns @code{GPGME_No_Error} if the operation could be
started successfully, @code{GPGME_Invalid_Value} if @var{ctx},
@var{rset}, @var{plain} or @var{cipher} is not a valid pointer, and
@code{GPGME_No_Recipient} if @var{rset} does not contain any valid
recipients.
@end deftypefun
@node Detailed Results
@subsection Detailed Results
@cindex cryptographic operation, detailed results

View File

@ -1,3 +1,23 @@
2002-02-25 Marcus Brinkmann <marcus@g10code.de>
* engine.c (_gpgme_engine_op_encrypt_sign): New function.
* engine.h (_gpgme_engine_op_encrypt_sign): New prototype.
* rungpg.c (_gpgme_append_gpg_args_from_signers): New function.
(_gpgme_gpg_op_sign): Use that new function.
(_gpgme_gpg_op_encrypt_sign): New function.
* rungpg.h (_gpgme_gpg_op_encrypt_sign): New prototype.
* gpgme.h (gpgme_op_encrypt_sign_start): New prototype.
(gpgme_op_encrypt_sign): Likewise.
* Makefile.am (libgpgme_la_SOURCES): Add encrypt-sign.c.
* ops.h (_gpgme_encrypt_status_handler): Add prototype.
(_gpgme_sign_status_handler): Add prototype.
* sign.c (sign_status_handler): Rename to ...
(_gpgme_sign_status_handler): ... this and make non-static.
* encrypt.c (encrypt_status_handler): Rename to ...
(_gpgme_encrypt_status_handler): ... this and make non-static.
* encrypt.c (gpgme_op_encrypt_start): Use new status handler name.
* sign.c (gpgme_op_sign_start): Likewise.
2002-02-25 Marcus Brinkmann <marcus@g10code.de>
* verify.c (_gpgme_verify_status_handler): Parse the args line to

View File

@ -42,6 +42,7 @@ libgpgme_la_SOURCES = \
data.c recipient.c signers.c \
wait.c wait.h \
encrypt.c \
encrypt-sign.c \
decrypt.c \
decrypt-verify.c \
verify.c \

150
gpgme/encrypt-sign.c Normal file
View File

@ -0,0 +1,150 @@
/* encrypt-sign.c - encrypt and verify functions
* Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "context.h"
#include "ops.h"
static void
encrypt_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
{
char *encrypt_info = 0;
int encrypt_info_len;
_gpgme_encrypt_status_handler (ctx, code, args);
if (code == STATUS_EOF)
{
encrypt_info = gpgme_data_release_and_get_mem (ctx->op_info,
&encrypt_info_len);
ctx->op_info = NULL;
}
_gpgme_sign_status_handler (ctx, code, args);
if (code == STATUS_EOF && encrypt_info)
_gpgme_data_append (ctx->op_info, encrypt_info, encrypt_info_len);
}
GpgmeError
gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher)
{
int err = 0;
fail_on_pending_request (ctx);
ctx->pending = 1;
_gpgme_release_result (ctx);
/* Do some checks. */
if (!gpgme_recipients_count (recp))
{
/* FIXME: In this case we should do symmetric encryption. */
err = mk_error (No_Recipients);
goto leave;
}
/* Create an engine object. */
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
: GPGME_PROTOCOL_OpenPGP, &ctx->engine);
if (err)
goto leave;
err = _gpgme_passphrase_start (ctx);
if (err)
goto leave;
_gpgme_engine_set_status_handler (ctx->engine,
encrypt_sign_status_handler, ctx);
_gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
/* Check the supplied data */
if (gpgme_data_get_type (plain) == GPGME_DATA_TYPE_NONE)
{
err = mk_error (No_Data);
goto leave;
}
_gpgme_data_set_mode (plain, GPGME_DATA_MODE_OUT);
if (!cipher || gpgme_data_get_type (cipher) != GPGME_DATA_TYPE_NONE)
{
err = mk_error (Invalid_Value);
goto leave;
}
_gpgme_data_set_mode (cipher, GPGME_DATA_MODE_IN);
err = _gpgme_engine_op_encrypt_sign (ctx->engine, recp, plain, cipher,
ctx->use_armor, ctx /* FIXME */);
if (!err) /* And kick off the process. */
err = _gpgme_engine_start (ctx->engine, ctx);
leave:
if (err)
{
ctx->pending = 0;
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
return err;
}
/**
* gpgme_op_encrypt_sign:
* @ctx: The context
* @recp: The set of recipients
* @plain: plaintext input
* @cipher: signed ciphertext
*
* This function encrypts @plain for all recipients in recp, signs it,
* and returns the ciphertext in @out. The function does wait for the
* result.
*
* Return value: 0 on success or an errorcode.
**/
GpgmeError
gpgme_op_encrypt_sign (GpgmeCtx ctx, GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher)
{
GpgmeError err = gpgme_op_encrypt_sign_start (ctx, recp, plain, cipher);
if (!err)
{
gpgme_wait (ctx, &err, 1);
/* Old gpg versions don't return status info for invalid
recipients, so we simply check whether we got any output at
all, and if not we assume that we don't have valid
recipients. */
if (!ctx->error && gpgme_data_get_type (cipher) == GPGME_DATA_TYPE_NONE)
ctx->error = mk_error (No_Recipients);
err = ctx->error;
}
return err;
}

View File

@ -97,8 +97,8 @@ append_xml_encinfo (GpgmeData *rdh, char *args)
}
static void
encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
void
_gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
{
if (ctx->error)
return;
@ -158,7 +158,8 @@ gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
if (err)
goto leave;
_gpgme_engine_set_status_handler (ctx->engine, encrypt_status_handler, ctx);
_gpgme_engine_set_status_handler (ctx->engine, _gpgme_encrypt_status_handler,
ctx);
_gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
/* Check the supplied data */

View File

@ -333,6 +333,7 @@ _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret)
return 0;
}
GpgmeError
_gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph, int use_armor)
@ -354,6 +355,29 @@ _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
return 0;
}
GpgmeError
_gpgme_engine_op_encrypt_sign (EngineObject engine, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph, int use_armor,
GpgmeCtx ctx /* FIXME */)
{
if (!engine)
return mk_error (Invalid_Value);
switch (engine->protocol)
{
case GPGME_PROTOCOL_OpenPGP:
return _gpgme_gpg_op_encrypt_sign (engine->engine.gpg, recp, plain, ciph,
use_armor, ctx);
case GPGME_PROTOCOL_CMS:
return mk_error (Not_Implemented);
default:
break;
}
return 0;
}
GpgmeError
_gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
GpgmeData keydata, int use_armor)

View File

@ -46,6 +46,11 @@ GpgmeError _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key,
GpgmeError _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph,
int use_armor);
GpgmeError _gpgme_engine_op_encrypt_sign (EngineObject engine,
GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph,
int use_armor,
GpgmeCtx ctx /* FIXME */);
GpgmeError _gpgme_engine_op_export (EngineObject engine, GpgmeRecipients recp,
GpgmeData keydata, int use_armor);
GpgmeError _gpgme_engine_op_genkey (EngineObject engine, GpgmeData help_data,

View File

@ -427,6 +427,16 @@ GpgmeError gpgme_op_encrypt (GpgmeCtx ctx,
GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher);
/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
store the resulting ciphertext in CIPHER. Also sign the ciphertext
with the signers in CTX. */
GpgmeError gpgme_op_encrypt_sign_start (GpgmeCtx ctx,
GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher);
GpgmeError gpgme_op_encrypt_sign (GpgmeCtx ctx,
GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher);
/* Decrypt ciphertext CIPHER within CTX and store the resulting
plaintext in PLAIN. */
GpgmeError gpgme_op_decrypt_start (GpgmeCtx ctx,

View File

@ -101,9 +101,13 @@ GpgmeError _gpgme_decrypt_result (GpgmeCtx ctx);
/*-- sign.c --*/
void _gpgme_release_sign_result ( SignResult res );
void _gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code,
char *args);
/*-- encrypt.c --*/
void _gpgme_release_encrypt_result ( EncryptResult res );
void _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code,
char *args);
/*-- passphrase.c --*/
void _gpgme_release_passphrase_result (PassphraseResult result);

View File

@ -1256,6 +1256,7 @@ _gpgme_gpg_op_delete (GpgObject gpg, GpgmeKey key, int allow_secret)
return err;
}
static GpgmeError
_gpgme_append_gpg_args_from_recipients (GpgObject gpg,
const GpgmeRecipients rset)
@ -1275,6 +1276,33 @@ _gpgme_append_gpg_args_from_recipients (GpgObject gpg,
return err;
}
static GpgmeError
_gpgme_append_gpg_args_from_signers (GpgObject gpg,
GpgmeCtx ctx /* FIXME */)
{
GpgmeError err = 0;
int i;
GpgmeKey key;
for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
{
const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
NULL, 0);
if (s)
{
if (!err)
err = _gpgme_gpg_add_arg (gpg, "-u");
if (!err)
err = _gpgme_gpg_add_arg (gpg, s);
}
gpgme_key_unref (key);
if (err) break;
}
return err;
}
GpgmeError
_gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph, int use_armor)
@ -1308,6 +1336,45 @@ _gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp,
return err;
}
GpgmeError
_gpgme_gpg_op_encrypt_sign (GpgObject gpg, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph, int use_armor,
GpgmeCtx ctx /* FIXME */)
{
GpgmeError err;
err = _gpgme_gpg_add_arg (gpg, "--encrypt");
if (!err)
err = _gpgme_gpg_add_arg (gpg, "--sign");
if (!err && use_armor)
err = _gpgme_gpg_add_arg (gpg, "--armor");
/* If we know that all recipients are valid (full or ultimate trust)
* we can suppress further checks */
if (!err && _gpgme_recipients_all_valid (recp))
err = _gpgme_gpg_add_arg (gpg, "--always-trust");
if (!err)
err = _gpgme_append_gpg_args_from_recipients (gpg, recp);
if (!err)
err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
/* Tell the gpg object about the data. */
if (!err)
err = _gpgme_gpg_add_arg (gpg, "--output");
if (!err)
err = _gpgme_gpg_add_arg (gpg, "-");
if (!err)
err = _gpgme_gpg_add_data (gpg, ciph, 1);
if (!err)
err = _gpgme_gpg_add_arg (gpg, "--");
if (!err)
err = _gpgme_gpg_add_data (gpg, plain, 0);
return err;
}
GpgmeError
_gpgme_gpg_op_export (GpgObject gpg, GpgmeRecipients recp,
GpgmeData keydata, int use_armor)
@ -1404,8 +1471,6 @@ _gpgme_gpg_op_sign (GpgObject gpg, GpgmeData in, GpgmeData out,
int use_textmode, GpgmeCtx ctx /* FIXME */)
{
GpgmeError err;
GpgmeKey key;
int i;
if (mode == GPGME_SIG_MODE_CLEAR)
err = _gpgme_gpg_add_arg (gpg, "--clearsign");
@ -1419,20 +1484,9 @@ _gpgme_gpg_op_sign (GpgObject gpg, GpgmeData in, GpgmeData out,
if (!err && use_textmode)
_gpgme_gpg_add_arg (gpg, "--textmode");
}
for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
{
const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
NULL, 0);
if (s)
{
if (!err)
err = _gpgme_gpg_add_arg (gpg, "-u");
if (!err)
err = _gpgme_gpg_add_arg (gpg, s);
}
gpgme_key_unref (key);
if (err) break;
}
err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
/* Tell the gpg object about the data. */
if (!err)

View File

@ -126,6 +126,9 @@ GpgmeError _gpgme_gpg_op_delete (GpgObject gpg, GpgmeKey key, int allow_secret);
GpgmeError _gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph,
int use_armor);
GpgmeError _gpgme_gpg_op_encrypt_sign (GpgObject gpg, GpgmeRecipients recp,
GpgmeData plain, GpgmeData ciph,
int use_armor, GpgmeCtx ctx);
GpgmeError _gpgme_gpg_op_export (GpgObject gpg, GpgmeRecipients recp,
GpgmeData keydata, int use_armor);
GpgmeError _gpgme_gpg_op_genkey (GpgObject gpg, GpgmeData help_data,

View File

@ -135,8 +135,8 @@ append_xml_siginfo (GpgmeData *rdh, char *args)
_gpgme_data_append_string (dh, "</fpr>\n");
}
static void
sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
void
_gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
{
_gpgme_passphrase_status_handler (ctx, code, args);
@ -210,7 +210,8 @@ gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
if (err)
goto leave;
_gpgme_engine_set_status_handler (ctx->engine, sign_status_handler, ctx);
_gpgme_engine_set_status_handler (ctx->engine, _gpgme_sign_status_handler,
ctx);
_gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
_gpgme_engine_op_sign (ctx->engine, in, out, mode, ctx->use_armor,

View File

@ -1,3 +1,8 @@
2002-02-26 Marcus Brinkmann <marcus@g10code.de>
* gpg/t-encrypt-sign.c: New file.
* gpg/Makefile.am (TESTS): Add t-encrypt-sign.
2002-02-13 Werner Koch <wk@gnupg.org>
* gpgsm/Makefile.am (private-keys-v1.d): Don't

View File

@ -23,7 +23,7 @@ GPG = @GPG@
TESTS_ENVIRONMENT = GNUPGHOME=.
TESTS = t-encrypt t-sign t-signers t-decrypt t-verify \
TESTS = t-encrypt t-encrypt-sign t-sign t-signers t-decrypt t-verify \
t-decrypt-verify t-keylist t-export t-import t-trustlist
CLEANFILES = secring.gpg pubring.gpg trustdb.gpg random_seed

139
tests/gpg/t-encrypt-sign.c Normal file
View File

@ -0,0 +1,139 @@
/* t-encrypt-sign.c - regression test
* Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <gpgme.h>
#define fail_if_err(a) do { if(a) { \
fprintf (stderr, "%s:%d: GpgmeError %s\n", \
__FILE__, __LINE__, gpgme_strerror(a)); \
exit (1); } \
} while(0)
static void
print_op_info (GpgmeCtx c)
{
char *s = gpgme_get_op_info (c, 0);
if (!s)
puts ("<!-- no operation info available -->");
else {
puts (s);
free (s);
}
}
static void
print_data ( GpgmeData dh )
{
char buf[100];
size_t nread;
GpgmeError err;
err = gpgme_data_rewind ( dh );
fail_if_err (err);
while ( !(err = gpgme_data_read ( dh, buf, 100, &nread )) ) {
fwrite ( buf, nread, 1, stdout );
}
if (err != GPGME_EOF)
fail_if_err (err);
}
static const char *
passphrase_cb ( void *opaque, const char *desc, void **r_hd )
{
const char *pass;
if ( !desc ) {
/* cleanup by looking at *r_hd */
return NULL;
}
pass = "abc";
fprintf (stderr, "%% requesting passphrase for `%s': ", desc );
fprintf (stderr, "sending `%s'\n", pass );
return pass;
}
int
main (int argc, char **argv )
{
GpgmeCtx ctx;
GpgmeError err;
GpgmeData in, out;
GpgmeRecipients rset;
err = gpgme_check_engine ();
fail_if_err (err);
puts ( gpgme_get_engine_info() );
do {
err = gpgme_new (&ctx);
fail_if_err (err);
gpgme_set_armor (ctx, 1);
if (!getenv("GPG_AGENT_INFO"))
gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 );
fail_if_err (err);
err = gpgme_data_new ( &out );
fail_if_err (err);
err = gpgme_recipients_new (&rset);
fail_if_err (err);
err = gpgme_recipients_add_name_with_validity (rset, "Bob",
GPGME_VALIDITY_FULL);
fail_if_err (err);
err = gpgme_recipients_add_name_with_validity (rset, "Alpha",
GPGME_VALIDITY_FULL);
fail_if_err (err);
err = gpgme_op_encrypt_sign (ctx, rset, in, out);
print_op_info (ctx);
fail_if_err (err);
fflush (NULL);
fputs ("Begin Result:\n", stdout );
print_data (out);
fputs ("End Result.\n", stdout );
gpgme_recipients_release (rset);
gpgme_data_release (in);
gpgme_data_release (out);
gpgme_release (ctx);
} while ( argc > 1 && !strcmp( argv[1], "--loop" ) );
return 0;
}