aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog23
-rw-r--r--src/assuan-defs.h23
-rw-r--r--src/assuan-handler.c216
-rw-r--r--src/assuan-inquire.c151
-rw-r--r--src/assuan-pipe-server.c1
-rw-r--r--src/assuan.h9
-rwxr-xr-xsrc/mkerrors9
7 files changed, 356 insertions, 76 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index ad04bb9..68905b6 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,26 @@
+2007-08-09 Marcus Brinkmann <[email protected]>
+
+ * assuan.h (assuan_process_done, assuan_inquire_ext): New
+ prototypes.
+ * assuan-defs.h (struct assuan_context_s): New members
+ in_process_next, in_command, inquire_cb, inquire_cb_data,
+ inquire_r_buffer, inquire_r_buffer_len, inquire_membuf.
+ (_assuan_inquire_ext_cb, _assuan_inquire_release): New prototypes.
+ * assuan-handler.c (PROCESS_DONE): New macro.
+ (dummy_handler, std_handler_nop, std_handler_cancel)
+ (std_handler_option, std_handler_bye, std_handler_auth)
+ (std_handler_reset, std_handler_end): Use PROCESS_DONE to
+ optionally call assuan_process_done if CTX->in_process_next is
+ true.
+ (assuan_process_done, process_next): New functions.
+ (assuan_process_next): Rewritten to support external event
+ handling.
+ * mkerrors: Do not clear high bits of -1 for old style EOF.
+ * assuan-inquire.c (_assuan_inquire_release)
+ (_assuan_inquire_ext_cb, assuan_inquire_ext): New functions.
+ * assuan-pipe-server.c (_assuan_release_context): Call
+ _assuan_inquire_release.
+
2007-07-12 Werner Koch <[email protected]>
* assuan.h (assuan_fd_t): New.
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index d1037c8..52b0d8b 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -103,6 +103,16 @@ struct assuan_context_s
int confidential;
int is_server; /* Set if this is context belongs to a server */
int in_inquire;
+ int in_process_next;
+ int in_command;
+
+ /* The following members are used by assuan_inquire_ext. */
+ int (*inquire_cb) (void *cb_data, int rc);
+ void *inquire_cb_data;
+ unsigned char **inquire_r_buffer;
+ size_t *inquire_r_buffer_len;
+ void *inquire_membuf;
+
char *hello_line;
char *okay_line; /* See assuan_set_okay_line() */
@@ -229,17 +239,20 @@ assuan_error_t _assuan_read_from_server (assuan_context_t ctx,
/*-- assuan-error.c --*/
+/*-- assuan-inquire.c --*/
+int _assuan_inquire_ext_cb (assuan_context_t ctx);
+void _assuan_inquire_release (assuan_context_t ctx);
-/* Map error codes as used in this implementaion to the libgpg-error
+/* Map error codes as used in this implementation to the libgpg-error
codes. */
assuan_error_t _assuan_error (int oldcode);
-/* Extrac the erro code from A. This works for both the old and the
- new style error codes. This needs to be whenever an error code is
- compared. */
+/* Extract the error code from A. This works for both the old and the
+ new style error codes. This needs to be used whenever an error
+ code is compared. */
#define err_code(a) ((a) & 0x00ffffff)
-/* Check whether A is the erro code for EOF. We allow forold and new
+/* Check whether A is the erro code for EOF. We allow for old and new
style EOF error codes here. */
#define err_is_eof(a) ((a) == (-1) || err_code (a) == 16383)
diff --git a/src/assuan-handler.c b/src/assuan-handler.c
index c940c36..1cb514a 100644
--- a/src/assuan-handler.c
+++ b/src/assuan-handler.c
@@ -33,18 +33,21 @@
static int my_strcasecmp (const char *a, const char *b);
+#define PROCESS_DONE(ctx, rc) \
+ ((ctx)->in_process_next ? assuan_process_done ((ctx), (rc)) : (rc))
static int
dummy_handler (assuan_context_t ctx, char *line)
{
- return set_error (ctx, Server_Fault, "no handler registered");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Server_Fault, "no handler registered"));
}
static int
std_handler_nop (assuan_context_t ctx, char *line)
{
- return 0; /* okay */
+ return PROCESS_DONE (ctx, 0); /* okay */
}
static int
@@ -52,7 +55,7 @@ std_handler_cancel (assuan_context_t ctx, char *line)
{
if (ctx->cancel_notify_fnc)
ctx->cancel_notify_fnc (ctx);
- return set_error (ctx, Not_Implemented, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
}
static int
@@ -63,9 +66,12 @@ std_handler_option (assuan_context_t ctx, char *line)
for (key=line; spacep (key); key++)
;
if (!*key)
- return set_error (ctx, Syntax_Error, "argument required");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Syntax_Error, "argument required"));
if (*key == '=')
- return set_error (ctx, Syntax_Error, "no option name given");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Syntax_Error,
+ "no option name given"));
for (value=key; *value && !spacep (value) && *value != '='; value++)
;
if (*value)
@@ -80,7 +86,9 @@ std_handler_option (assuan_context_t ctx, char *line)
for (; spacep (value); value++)
;
if (!*value)
- return set_error (ctx, Syntax_Error, "option argument expected");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Syntax_Error,
+ "option argument expected"));
}
if (*value)
{
@@ -94,12 +102,13 @@ std_handler_option (assuan_context_t ctx, char *line)
if (*key == '-' && key[1] == '-' && key[2])
key += 2; /* the double dashes are optional */
if (*key == '-')
- return set_error (ctx, Syntax_Error,
- "option should not begin with one dash");
+ return PROCESS_DONE (ctx,
+ set_error (ctx, Syntax_Error,
+ "option should not begin with one dash"));
if (ctx->option_handler_fnc)
- return ctx->option_handler_fnc (ctx, key, value);
- return 0;
+ return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value));
+ return PROCESS_DONE (ctx, 0);
}
static int
@@ -109,13 +118,13 @@ std_handler_bye (assuan_context_t ctx, char *line)
ctx->bye_notify_fnc (ctx);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
- return -1; /* pretty simple :-) */
+ return PROCESS_DONE (ctx, _assuan_error (-1)); /* pretty simple :-) */
}
static int
std_handler_auth (assuan_context_t ctx, char *line)
{
- return set_error (ctx, Not_Implemented, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
}
static int
@@ -126,13 +135,13 @@ std_handler_reset (assuan_context_t ctx, char *line)
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
_assuan_uds_close_fds (ctx);
- return 0;
+ return PROCESS_DONE (ctx, 0);
}
static int
std_handler_end (assuan_context_t ctx, char *line)
{
- return set_error (ctx, Not_Implemented, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
}
@@ -181,11 +190,11 @@ std_handler_input (assuan_context_t ctx, char *line)
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
- return rc;
+ return PROCESS_DONE (ctx, rc);
ctx->input_fd = fd;
if (ctx->input_notify_fnc)
ctx->input_notify_fnc (ctx, line);
- return 0;
+ return PROCESS_DONE (ctx, 0);
}
/* Format is OUTPUT FD=<n> */
@@ -197,11 +206,11 @@ std_handler_output (assuan_context_t ctx, char *line)
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
- return rc;
+ return PROCESS_DONE (ctx, rc);
ctx->output_fd = fd;
if (ctx->output_notify_fnc)
ctx->output_notify_fnc (ctx, line);
- return 0;
+ return PROCESS_DONE (ctx, 0);
}
@@ -414,9 +423,10 @@ my_strcasecmp (const char *a, const char *b)
return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
}
+
/* Parse the line, break out the command, find it in the command
table, remove leading and white spaces from the arguments, call the
- handler with the argument line and return the error */
+ handler with the argument line and return the error. */
static int
dispatch_command (assuan_context_t ctx, char *line, int linelen)
{
@@ -461,42 +471,34 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen)
return ctx->cmdtbl[i].handler (ctx, line);
}
-
-
-static int
-process_request (assuan_context_t ctx)
+/* Call this to acknowledge the current command. */
+int
+assuan_process_done (assuan_context_t ctx, int rc)
{
- int rc;
+ if (!ctx->in_command)
+ return _assuan_error (ASSUAN_General_Error);
- if (ctx->in_inquire)
- return _assuan_error (ASSUAN_Nested_Commands);
-
- rc = _assuan_read_line (ctx);
- if (rc)
- return rc;
- if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
- return 0; /* comment line - ignore */
+ ctx->in_command = 0;
- ctx->outbound.data.error = 0;
- ctx->outbound.data.linelen = 0;
- /* dispatch command and return reply */
- rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
- /* check from data write errors */
+ /* Check for data write errors. */
if (ctx->outbound.data.fp)
- { /* Flush the data lines */
+ {
+ /* Flush the data lines. */
fclose (ctx->outbound.data.fp);
ctx->outbound.data.fp = NULL;
if (!rc && ctx->outbound.data.error)
- rc = ctx->outbound.data.error;
+ rc = ctx->outbound.data.error;
}
- else /* flush any data send w/o using the data fp */
+ else
{
+ /* Flush any data send without using the data FP. */
assuan_send_data (ctx, NULL, 0);
if (!rc && ctx->outbound.data.error)
- rc = ctx->outbound.data.error;
+ rc = ctx->outbound.data.error;
}
- /* Error handling */
+
+ /* Error handling. */
if (!rc)
{
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
@@ -509,26 +511,26 @@ process_request (assuan_context_t ctx)
else
{
char errline[300];
-
+
if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
_assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc));
else
{
const char *text = ctx->err_no == rc? ctx->err_str:NULL;
-
+
#if defined(HAVE_W32_SYSTEM)
unsigned int source, code;
char ebuf[50];
const char *esrc;
-
+
source = ((rc >> 24) & 0xff);
code = (rc & 0x00ffffff);
if (source
&& !_assuan_gpg_strerror_r (rc, ebuf, sizeof ebuf)
&& (esrc=_assuan_gpg_strsource (rc)))
{
- /* Assume this is an libgpg-error. */
+ /* Assume this is an libgpg-error. */
sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
rc, ebuf, esrc,
text? " - ":"", text?text:"");
@@ -562,7 +564,7 @@ process_request (assuan_context_t ctx)
{
/* Assume this is an libgpg-error. */
char ebuf[50];
-
+
gpg_strerror_r (rc, ebuf, sizeof ebuf );
sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
rc,
@@ -577,19 +579,117 @@ process_request (assuan_context_t ctx)
}
rc = assuan_write_line (ctx, errline);
}
-
+
if (ctx->post_cmd_notify_fnc)
ctx->post_cmd_notify_fnc (ctx, rc);
-
+
ctx->confidential = 0;
if (ctx->okay_line)
{
xfree (ctx->okay_line);
ctx->okay_line = NULL;
}
+
+ return rc;
+}
+
+
+static int
+process_next (assuan_context_t ctx)
+{
+ int rc;
+
+ /* What the next thing to do is depends on the current state.
+ However, we will always first read the next line. The client is
+ required to write full lines without blocking long after starting
+ a partial line. */
+ rc = _assuan_read_line (ctx);
+ if (rc)
+ return rc;
+ if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
+ /* Comment lines are ignored. */
+ return 0;
+
+ /* Now we have a line that really means something. It could be one
+ of the following things: First, if we are not in a command
+ already, it is the next command to dispatch. Second, if we are
+ in a command, it can only be the response to an INQUIRE
+ reply. */
+
+ if (!ctx->in_command)
+ {
+ ctx->in_command = 1;
+
+ ctx->outbound.data.error = 0;
+ ctx->outbound.data.linelen = 0;
+ /* Dispatch command and return reply. */
+ ctx->in_process_next = 1;
+ rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
+ ctx->in_process_next = 0;
+ }
+ else if (ctx->in_inquire)
+ {
+ /* FIXME: Pick up the continuation. */
+ rc = _assuan_inquire_ext_cb (ctx);
+ }
+ else
+ {
+ /* Should not happen. The client is sending data while we are
+ in a command and not waiting for an inquire. We log an error
+ and discard it. */
+ _assuan_log_printf ("unexpected client data\n");
+ rc = 0;
+ }
+
return rc;
}
+
+/* This function should be invoked when the assuan connected FD is
+ ready for reading. If the equivalent to EWOULDBLOCK is returned
+ (this should be done by the command handler), assuan_process_next
+ should be invoked the next time the connected FD is readable.
+ Eventually, the caller will finish by invoking
+ assuan_process_done. */
+int
+assuan_process_next (assuan_context_t ctx)
+{
+ int rc;
+
+ do
+ {
+ rc = process_next (ctx);
+ }
+ while (!rc && assuan_pending_line (ctx));
+
+ return rc;
+}
+
+
+
+static int
+process_request (assuan_context_t ctx)
+{
+ int rc;
+
+ if (ctx->in_inquire)
+ return _assuan_error (ASSUAN_Nested_Commands);
+
+ rc = _assuan_read_line (ctx);
+ if (rc)
+ return rc;
+ if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
+ return 0; /* comment line - ignore */
+
+ ctx->in_command = 1;
+ ctx->outbound.data.error = 0;
+ ctx->outbound.data.linelen = 0;
+ /* dispatch command and return reply */
+ rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
+
+ return assuan_process_done (ctx, rc);
+}
+
/**
* assuan_process:
* @ctx: assuan context
@@ -618,24 +718,6 @@ assuan_process (assuan_context_t ctx)
/**
- * assuan_process_next:
- * @ctx: Assuan context
- *
- * Same as assuan_process() but the user has to provide the outer
- * loop. He should loop as long as the return code is zero and stop
- * otherwise; -1 is regular end.
- *
- * See also: assuan_get_active_fds()
- * Return value: -1 for end of server, 0 on success or an error code
- **/
-int
-assuan_process_next (assuan_context_t ctx)
-{
- return process_request (ctx);
-}
-
-
-/**
* assuan_get_active_fds:
* @ctx: Assuan context
* @what: 0 for read fds, 1 for write fds
diff --git a/src/assuan-inquire.c b/src/assuan-inquire.c
index e81ecb3..080f4ef 100644
--- a/src/assuan-inquire.c
+++ b/src/assuan-inquire.c
@@ -42,7 +42,7 @@ struct membuf
-/* A simple implemnation of a dynamic buffer. Use init_membuf() to
+/* A simple implementation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
@@ -232,8 +232,157 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
return rc;
}
+
+void
+_assuan_inquire_release (assuan_context_t ctx)
+{
+ if (ctx->in_inquire)
+ {
+ if (ctx->inquire_membuf)
+ {
+ free_membuf (ctx->inquire_membuf);
+ free (ctx->inquire_membuf);
+ }
+ ctx->in_inquire = 0;
+ }
+}
+
+
+int
+_assuan_inquire_ext_cb (assuan_context_t ctx)
+{
+ int rc;
+ unsigned char *line;
+ int linelen;
+ struct membuf *mb;
+ unsigned char *p;
+ line = (unsigned char *) ctx->inbound.line;
+ linelen = ctx->inbound.linelen;
+ mb = ctx->inquire_membuf;
+ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
+ {
+ rc = _assuan_error (ASSUAN_Canceled);
+ goto leave;
+ }
+ if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+ && (!line[3] || line[3] == ' '))
+ {
+ rc = 0;
+ goto leave;
+ }
+
+ if (line[0] != 'D' || line[1] != ' ' || mb == NULL)
+ {
+ rc = _assuan_error (ASSUAN_Unexpected_Command);
+ goto leave;
+ }
+
+ if (linelen < 3)
+ return 0;
+ line += 2;
+ linelen -= 2;
+
+ p = line;
+ while (linelen)
+ {
+ for (;linelen && *p != '%'; linelen--, p++)
+ ;
+ put_membuf (mb, line, p-line);
+ if (linelen > 2)
+ { /* handle escaping */
+ unsigned char tmp[1];
+ p++;
+ *tmp = xtoi_2 (p);
+ p += 2;
+ linelen -= 3;
+ put_membuf (mb, tmp, 1);
+ }
+ line = p;
+ }
+ if (mb->too_large)
+ {
+ rc = _assuan_error (ASSUAN_Too_Much_Data);
+ goto leave;
+ }
+ return 0;
+ leave:
+ if (mb)
+ {
+ *(ctx->inquire_r_buffer) = get_membuf (mb, ctx->inquire_r_buffer_len);
+ if (!*(ctx->inquire_r_buffer))
+ rc = _assuan_error (ASSUAN_Out_Of_Core);
+ free_membuf (mb);
+ free (mb);
+ }
+ (ctx->inquire_cb) (ctx->inquire_cb_data, rc);
+ return rc;
+}
+/**
+ * assuan_inquire_ext:
+ * @ctx: An assuan context
+ * @keyword: The keyword used for the inquire
+ * @r_buffer: Returns an allocated buffer
+ * @r_length: Returns the length of this buffer
+ * @maxlen: If not 0, the size limit of the inquired data.
+ * @cb: A callback handler which is invoked after the operation completed.
+ * @cb_data: A user-provided value passed to the callback handler.
+ *
+ * A Server may use this to Send an inquire. r_buffer, r_length and
+ * maxlen may all be NULL/0 to indicate that no real data is expected.
+ * When this function returns,
+ *
+ * Return value: 0 on success or an ASSUAN error code
+ **/
+assuan_error_t
+assuan_inquire_ext (assuan_context_t ctx, const char *keyword,
+ unsigned char **r_buffer, size_t *r_length, size_t maxlen,
+ int (*cb) (void *cb_data, int rc), void *cb_data)
+{
+ assuan_error_t rc;
+ struct membuf *mb = NULL;
+ char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
+ int nodataexpected;
+
+ if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
+ return _assuan_error (ASSUAN_Invalid_Value);
+ nodataexpected = !r_buffer && !r_length && !maxlen;
+ if (!nodataexpected && (!r_buffer || !r_length))
+ return _assuan_error (ASSUAN_Invalid_Value);
+ if (!ctx->is_server)
+ return _assuan_error (ASSUAN_Not_A_Server);
+ if (ctx->in_inquire)
+ return _assuan_error (ASSUAN_Nested_Commands);
+
+ if (!nodataexpected)
+ {
+ mb = malloc (sizeof (struct membuf));
+ if (!mb)
+ return _assuan_error (ASSUAN_Out_Of_Core);
+ init_membuf (mb, maxlen ? maxlen : 1024, maxlen);
+ }
+
+ strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
+ rc = assuan_write_line (ctx, cmdbuf);
+ if (rc)
+ {
+ free_membuf (mb);
+ free (mb);
+ return rc;
+ }
+
+ ctx->in_inquire = 1;
+
+ /* Set up the continuation. */
+ ctx->inquire_cb = cb;
+ ctx->inquire_cb_data = cb_data;
+ ctx->inquire_membuf = mb;
+ ctx->inquire_r_buffer = r_buffer;
+ ctx->inquire_r_buffer_len = r_length;
+
+ return 0;
+}
diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c
index 96bdfcc..e5dc15f 100644
--- a/src/assuan-pipe-server.c
+++ b/src/assuan-pipe-server.c
@@ -167,6 +167,7 @@ _assuan_release_context (assuan_context_t ctx)
{
if (ctx)
{
+ _assuan_inquire_release (ctx);
xfree (ctx->hello_line);
xfree (ctx->okay_line);
xfree (ctx->cmdtbl);
diff --git a/src/assuan.h b/src/assuan.h
index 5acf08c..3105602 100644
--- a/src/assuan.h
+++ b/src/assuan.h
@@ -75,6 +75,7 @@
_ASSUAN_PREFIX(assuan_register_option_handler)
#define assuan_process _ASSUAN_PREFIX(assuan_process)
#define assuan_process_next _ASSUAN_PREFIX(assuan_process_next)
+#define assuan_process_done _ASSUAN_PREFIX(assuan_process_done)
#define assuan_get_active_fds _ASSUAN_PREFIX(assuan_get_active_fds)
#define assuan_get_data_fp _ASSUAN_PREFIX(assuan_get_data_fp)
#define assuan_set_okay_line _ASSUAN_PREFIX(assuan_set_okay_line)
@@ -102,6 +103,7 @@
#define assuan_get_peercred _ASSUAN_PREFIX(assuan_get_peercred)
#define assuan_transact _ASSUAN_PREFIX(assuan_transact)
#define assuan_inquire _ASSUAN_PREFIX(assuan_inquire)
+#define assuan_inquire_ext _ASSUAN_PREFIX(assuan_inquire_ext)
#define assuan_read_line _ASSUAN_PREFIX(assuan_read_line)
#define assuan_pending_line _ASSUAN_PREFIX(assuan_pending_line)
#define assuan_write_line _ASSUAN_PREFIX(assuan_write_line)
@@ -372,6 +374,7 @@ int assuan_register_option_handler (assuan_context_t ctx,
int assuan_process (assuan_context_t ctx);
int assuan_process_next (assuan_context_t ctx);
+int assuan_process_done (assuan_context_t ctx, int rc);
int assuan_get_active_fds (assuan_context_t ctx, int what,
assuan_fd_t *fdarray, int fdarraysize);
@@ -462,7 +465,11 @@ assuan_transact (assuan_context_t ctx,
assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword,
unsigned char **r_buffer, size_t *r_length,
size_t maxlen);
-
+assuan_error_t assuan_inquire_ext (assuan_context_t ctx, const char *keyword,
+ unsigned char **r_buffer, size_t *r_length,
+ size_t maxlen,
+ int (*cb) (void *cb_data, int rc),
+ void *cb_data);
/*-- assuan-buffer.c --*/
assuan_error_t assuan_read_line (assuan_context_t ctx,
char **line, size_t *linelen);
diff --git a/src/mkerrors b/src/mkerrors
index 4f37e06..7087fdb 100755
--- a/src/mkerrors
+++ b/src/mkerrors
@@ -56,8 +56,13 @@ _assuan_error (int oldcode)
unsigned int n;
if (!err_source)
- return (oldcode & 0x00ffffff); /* Make sure that the gpg-error
- source part is cleared. */
+ {
+ if (oldcode == -1)
+ return -1;
+ else
+ return (oldcode & 0x00ffffff); /* Make sure that the gpg-error
+ source part is cleared. */
+ }
switch (oldcode)
{