gpgme/trunk/gpgme/trustlist.c
Marcus Brinkmann bfc95ce4e8 2002-02-02 Marcus Brinkmann <marcus@g10code.de>
This patch has gotten a bit large... mmh.  The main thing that
	happens here is that error values are now not determined in the
	operation function after gpgme_wait completed, but in the status
	handler when EOF is received.  It should always be the case that
	either an error is flagged or EOF is received, so that after a
	gpgme_wait you should never have the situation that no error is
	flagged and EOF is not received.  One problem is that the engine
	status handlers don't have access to the context, a horrible
	kludge works around this for now.  All errors that happen during a
	pending operation should be catched and reported in ctx->error,
	including out-of-core and cancellation.  This rounds up neatly a
	couple of loose ends, and makes it possible to pass up any errors
	in the communication with the backend as well.  As a bonus, there
	will be a function to access gpgme->wait, so that the operations
	can truly be implemented with their _start function.

	* engine-gpgsm.c (gpgsm_status_handler): Horrible kludge to report
	error back to the context.
	* rungpg.c (gpg_status_handler): Same horrible kludge applied here.

	* engine-gpgsm.c (gpgsm_assuan_simple_command): Add error checking.

	* wait.c (_gpgme_wait_on_condition): If canceled, set CTX->error
	to a value indication that.

	* verify.c (add_notation): Set error, not out_of_core.
	(finish_sig): Likewise.
	(gpgme_op_verify_start): Don't clear out_of_core.
	(_gpgme_verify_status_handler): At EOF, clean up the notation data.
	(gpgme_op_verify): And don't do it here.

	* trustlist.c (trustlist_status_handler): Check error, not out_of_core.
	(gpgme_op_trustlist_start): Don't clear out_of_core.
	(gpgme_op_trustlist_next): Check error, not out_of_core.
	(gpgme_op_trustlist_end): Likewise.

	* ops.h (test_and_allocate_result): New macro.
	(_gpgme_passphrase_result): Remove prototype.
	* delete.c (gpgme_op_delete): Return error from context.
	(delete_status_handler): Use macro test_and_allocate_result.
	Perform error checking at EOF.
	(gpgme_op_delete_start): Release result.
	* passphrase.c (_gpgme_passphrase_status_handler): Use macro
	test_and_allocate_result, and perform error checking here.
	(_gpgme_passphrase_result): Function removed.
	* sign.c (gpgme_op_sign_start): Do not set out_of_core to zero.
	(gpgme_op_sign): Just return the error value from the context.
	(sign_status_handler): Only progress if no error is set yet.  If
	we process an EOF, set the resulting error value (if any).
	* decrypt.c (_gpgme_decrypt_result): Function removed.
	(create_result_struct): Function removed.
	(_gpgme_decrypt_status_handler): Use macro test_and_allocate_result,
	caclulate error on EOF, do not progress with errors.
	(_gpgme_decrypt_start): Do not set out_of_core to zero.
	(gpgme_op_decrypt): Just return the error value from the context.
	* encrypt.c (encrypt_status_handler): Perform the error checking
	here.
	(gpgme_op_encrypt_start): Do not clear out_of_core.
	* export.c (export_status_handler): Return if error is set in context.
	(gpgme_op_export_start): Release result.
	(gpgme_op_export): Return error from context.
	* decrypt-verify.c (gpgme_op_decrypt_verify): Return the error in
	the context.
	* genkey.c (genkey_status_handler): Use macro
	test_and_allocate_result.  Perform error checking at EOF.
	(gpgme_op_genkey): Just return the error from context.
	* import.c (gpgme_op_import): Return the error from context.
	(import_status_handler): Use macro test_and_allocate_result.
	* keylist.c (gpgme_op_keylist_start): Do not clear out_of_core.
	(gpgme_op_keylist_next): Return error of context.
	(keylist_colon_handler): Set error instead out_of_code.
	(finish_key): Likewise.

	* context.h: Remove member out_of_core, add member error.
	* gpgme.c (_gpgme_release_result): Clear error flag.

	* engine.h (_gpgme_engine_get_error): New prototype.
	* engine.c (_gpgme_engine_get_error): New function.
	* engine-gpgsm.c (_gpgme_gpgsm_get_error): New function.

	* engine-gpgsm.c (map_assuan_error): New function.
	(gpgsm_assuan_simple_command): Change return type to GpgmeError,
	use the new function to map error values.
	(gpgsm_set_fd): Change return type tp GpgmeError.
	(_gpgme_gpgsm_op_decrypt): Change type of ERR to GpgmeError.
	(gpgsm_set_recipients): Likewise.  Change type of return value
	equivalently.  Adjust error values.
	(_gpgme_gpgsm_op_import): Likewise.
	(_gpgme_gpgsm_op_sign): Likewise.
	(struct gpgsm_object_s): New member error.
	(gpgsm_status_handler): Set error if error occurs.  Determine
	error number from ERR line received.  If assuan_read_line fails,
	terminate the connection.
2002-02-02 03:52:59 +00:00

334 lines
6.5 KiB
C

/* trustlist.c - key listing
* 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 <time.h>
#include <assert.h>
#include "util.h"
#include "context.h"
#include "ops.h"
struct gpgme_trust_item_s
{
int level;
char keyid[16+1];
int type;
char ot[2];
char val[2];
char *name;
};
static GpgmeTrustItem
trust_item_new (void)
{
GpgmeTrustItem item;
item = xtrycalloc (1, sizeof *item);
return item;
}
static void
trustlist_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
{
if (ctx->error)
return;
switch (code)
{
case STATUS_EOF:
break;
default:
break;
}
}
/*
* This handler is used to parse the output of --list-trust-path:
* Format:
* level:keyid:type:recno:ot:val:mc:cc:name:
* With TYPE = U for a user ID
* K for a key
* The RECNO is either the one of the dir record or the one of the uid record.
* OT is the the usual trust letter and only availabel on K lines.
* VAL is the calcualted validity
* MC is the marginal trust counter and only available on U lines
* CC is the same for the complete count
* NAME ist the username and only printed on U lines
*/
static void
trustlist_colon_handler (GpgmeCtx ctx, char *line)
{
char *p, *pend;
int field = 0;
GpgmeTrustItem item = NULL;
struct trust_queue_item_s *q, *q2;
if (ctx->error)
return;
if (!line)
return; /* EOF */
for (p = line; p; p = pend)
{
field++;
pend = strchr (p, ':');
if (pend)
*pend++ = 0;
switch (field)
{
case 1: /* level */
q = xtrymalloc (sizeof *q);
if (!q)
{
ctx->error = mk_error (Out_Of_Core);
return;
}
q->next = NULL;
q->item = item = trust_item_new ();
if (!q->item)
{
xfree (q);
ctx->error = mk_error (Out_Of_Core);
return;
}
/* fixme: lock queue, keep a tail pointer */
q2 = ctx->trust_queue;
if (!q2)
ctx->trust_queue = q;
else
{
while (q2->next)
q2 = q2->next;
q2->next = q;
}
/* fixme: unlock queue */
item->level = atoi (p);
break;
case 2: /* long keyid */
if (strlen (p) == DIM(item->keyid) - 1)
strcpy (item->keyid, p);
break;
case 3: /* type */
item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0;
break;
case 5: /* owner trust */
item->ot[0] = *p;
item->ot[1] = 0;
break;
case 6: /* validity */
item->val[0] = *p;
item->val[1] = 0;
break;
case 9: /* user ID */
item->name = xtrystrdup (p);
if (!item->name)
ctx->error = mk_error (Out_Of_Core);
break;
}
}
if (field)
ctx->key_cond = 1;
}
GpgmeError
gpgme_op_trustlist_start (GpgmeCtx ctx, const char *pattern, int max_level)
{
GpgmeError err = 0;
fail_on_pending_request (ctx);
if (!pattern || !*pattern)
return mk_error (Invalid_Value);
ctx->pending = 1;
if (ctx->engine)
{
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
_gpgme_release_result (ctx);
err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
: GPGME_PROTOCOL_OpenPGP, &ctx->engine);
if (err)
goto leave;
_gpgme_engine_set_status_handler (ctx->engine, trustlist_status_handler, ctx);
err = _gpgme_engine_set_colon_line_handler (ctx->engine,
trustlist_colon_handler, ctx);
if (err)
goto leave;
err =_gpgme_engine_op_trustlist (ctx->engine, pattern);
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;
}
GpgmeError
gpgme_op_trustlist_next (GpgmeCtx ctx, GpgmeTrustItem *r_item)
{
struct trust_queue_item_s *q;
if (!r_item)
return mk_error (Invalid_Value);
*r_item = NULL;
if (!ctx)
return mk_error (Invalid_Value);
if (!ctx->pending)
return mk_error (No_Request);
if (ctx->error)
return ctx->error;
if (!ctx->trust_queue)
{
_gpgme_wait_on_condition (ctx, 1, &ctx->key_cond);
if (ctx->error)
return ctx->error;
if (!ctx->key_cond)
return mk_error (EOF);
ctx->key_cond = 0;
assert (ctx->trust_queue);
}
q = ctx->trust_queue;
ctx->trust_queue = q->next;
*r_item = q->item;
xfree (q);
return 0;
}
/**
* gpgme_op_trustlist_end:
* @c: Context
*
* Ends the trustlist operation and allows to use the context for some
* other operation next.
**/
GpgmeError
gpgme_op_trustlist_end (GpgmeCtx ctx)
{
if (!ctx)
return mk_error (Invalid_Value);
if (!ctx->pending)
return mk_error (No_Request);
if (ctx->error)
return ctx->error;
ctx->pending = 0;
return 0;
}
void
gpgme_trust_item_release (GpgmeTrustItem item)
{
if (!item)
return;
xfree (item->name);
xfree (item);
}
const char *
gpgme_trust_item_get_string_attr (GpgmeTrustItem item, GpgmeAttr what,
const void *reserved, int idx)
{
const char *val = NULL;
if (!item)
return NULL;
if (reserved)
return NULL;
if (idx)
return NULL;
switch (what)
{
case GPGME_ATTR_KEYID:
val = item->keyid;
break;
case GPGME_ATTR_OTRUST:
val = item->ot;
break;
case GPGME_ATTR_VALIDITY:
val = item->val;
break;
case GPGME_ATTR_USERID:
val = item->name;
break;
default:
break;
}
return val;
}
int
gpgme_trust_item_get_int_attr (GpgmeTrustItem item, GpgmeAttr what,
const void *reserved, int idx)
{
int val = 0;
if (!item)
return 0;
if (reserved)
return 0;
if (idx)
return 0;
switch (what)
{
case GPGME_ATTR_LEVEL:
val = item->level;
break;
case GPGME_ATTR_TYPE:
val = item->type;
break;
default:
break;
}
return val;
}