Page MenuHome GnuPG

No OneTemporary

diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am
index b47169cb..547dcd44 100644
--- a/gpgme/Makefile.am
+++ b/gpgme/Makefile.am
@@ -1,34 +1,36 @@
# Process this file with automake to produce Makefile.in
EXTRA_DIST = gpgme-config.in gpgme.m4 mkerrors mkstatus
BUILT_SOURCES = errors.c status-table.h
bin_SCRIPTS = gpgme-config
m4datadir = $(datadir)/aclocal
m4data_DATA = gpgme.m4
include_HEADERS = gpgme.h
lib_LTLIBRARIES = libgpgme.la
libgpgme_la_LDFLAGS = -version-info \
@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
libgpgme_la_INCLUDES = -I$(top_srcdir)/lib
libgpgme_la_SOURCES = \
gpgme.h types.h util.h util.c \
context.h ops.h \
data.c recipient.c \
wait.c wait.h \
encrypt.c \
verify.c \
+ key.c key.h \
+ keylist.c \
rungpg.c rungpg.h status-table.h \
gpgme.c errors.c
errors.c : gpgme.h
$(srcdir)/mkerrors < $(srcdir)/gpgme.h > errors.c
status-table.h : rungpg.h
$(srcdir)/mkstatus < $(srcdir)/rungpg.h > status-table.h
diff --git a/gpgme/context.h b/gpgme/context.h
index c45d1bf6..ab5a2d3d 100644
--- a/gpgme/context.h
+++ b/gpgme/context.h
@@ -1,99 +1,101 @@
/* context.h
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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
*/
#ifndef CONTEXT_H
#define CONTEXT_H
#include "gpgme.h"
#include "types.h"
#include "rungpg.h" /* for GpgObject */
typedef enum {
RESULT_TYPE_NONE = 0,
RESULT_TYPE_VERIFY,
} ResultType;
/* Currently we need it at several places, so we put the definition
* into this header file */
struct gpgme_context_s {
int initialized;
int pending; /* a gpg request is still pending */
/* at some points we need to allocate memory but we are not
* able to handle a malloc problem at that point, so we set this
* flag to indicate this condition */
int out_of_core;
GpgObject gpg; /* the running gpg process */
int verbosity; /* level of verbosity to use */
int use_armor; /* use armoring */
ResultType result_type;
union {
VerifyResult verify;
} result;
+
+ GpgmeKey tmp_key; /* used by keylist.c */
};
struct gpgme_data_s {
size_t len;
const char *data;
GpgmeDataType type;
GpgmeDataMode mode;
size_t readpos;
size_t writepos;
size_t private_len;
char *private_buffer;
};
struct recipient_s {
struct recipient_s *next;
char name[1];
};
struct gpgme_recipient_set_s {
struct recipient_s *list;
int checked; /* wether the recipients are all valid */
};
#define fail_on_pending_request(c) \
do { \
if (!(c)) return GPGME_Invalid_Value; \
if ((c)->pending) return GPGME_Busy; \
} while (0)
#define wait_on_request_or_fail(c) \
do { \
if (!(c)) return GPGME_Invalid_Value;\
if (!(c)->pending) return GPGME_No_Request; \
gpgme_wait ((c), 1); \
} while (0)
#endif /* CONTEXT_H */
diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c
index 10df5080..8a8cbb27 100644
--- a/gpgme/gpgme.c
+++ b/gpgme/gpgme.c
@@ -1,108 +1,110 @@
/* gpgme.c - GnuPG Made Easy
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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 "util.h"
#include "context.h"
#include "ops.h"
/**
* gpgme_new_context:
* @r_ctx: Returns the new context
*
* Create a new context to be used with most of the other GPGME
* functions. Use gpgme_release_contect() to release all resources
*
* Return value: An error code
**/
GpgmeError
gpgme_new_context (GpgmeCtx *r_ctx)
{
GpgmeCtx c;
c = xtrycalloc ( 1, sizeof *c );
if (!c)
return mk_error (Out_Of_Core);
c->verbosity = 1;
c->use_armor = 1;
*r_ctx = c;
return 0;
}
/**
* gpgme_release_contect:
* @c: Context to be released.
*
* Release all resources associated with the given context.
**/
void
gpgme_release_context ( GpgmeCtx c )
{
_gpgme_gpg_release_object ( c->gpg );
_gpgme_release_result ( c );
+ _gpgme_key_release ( c->tmp_key );
xfree ( c );
}
void
_gpgme_release_result ( GpgmeCtx c )
{
switch (c->result_type) {
case RESULT_TYPE_NONE:
break;
case RESULT_TYPE_VERIFY:
_gpgme_release_verify_result ( c->result.verify );
break;
}
+
c->result.verify = NULL;
c->result_type = RESULT_TYPE_NONE;
}
diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h
index 88a84348..32a925fc 100644
--- a/gpgme/gpgme.h
+++ b/gpgme/gpgme.h
@@ -1,124 +1,126 @@
/* gpgme.h - GnuPG Made Easy
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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
*/
#ifndef GPGME_H
#define GPGME_H
#ifdef __cplusplus
extern "C" {
#if 0 /* just to make Emacs auto-indent happy */
}
#endif
#endif
struct gpgme_context_s;
typedef struct gpgme_context_s *GpgmeCtx;
struct gpgme_data_s;
typedef struct gpgme_data_s *GpgmeData;
struct gpgme_recipient_set_s;
typedef struct gpgme_recipient_set_s *GpgmeRecipientSet;
typedef enum {
GPGME_EOF = -1,
GPGME_No_Error = 0,
GPGME_General_Error = 1,
GPGME_Out_Of_Core = 2,
GPGME_Invalid_Value = 3,
GPGME_Busy = 4,
GPGME_No_Request = 5,
GPGME_Exec_Error = 6,
GPGME_Too_Many_Procs = 7,
GPGME_Pipe_Error = 8,
GPGME_No_Recipients = 9,
GPGME_No_Data = 10,
GPGME_Conflict = 11,
GPGME_Not_Implemented = 12,
GPGME_Read_Error = 13,
GPGME_Write_Error = 14,
GPGME_Invalid_Type = 15,
GPGME_Invalid_Mode = 16,
} GpgmeError;
typedef enum {
GPGME_DATA_TYPE_NONE = 0,
GPGME_DATA_TYPE_MEM = 1,
GPGME_DATA_TYPE_FD = 2,
GPGME_DATA_TYPE_FILE = 3
} GpgmeDataType;
/* Context management */
GpgmeError gpgme_new_context (GpgmeCtx *r_ctx);
void gpgme_release_context ( GpgmeCtx c );
GpgmeCtx gpgme_wait ( GpgmeCtx c, int hang );
/* Functions to handle recipients */
GpgmeError gpgme_new_recipient_set (GpgmeRecipientSet *r_rset);
void gpgme_release_recipient_set ( GpgmeRecipientSet rset);
GpgmeError gpgme_add_recipient (GpgmeRecipientSet rset, const char *name);
unsigned int gpgme_count_recipients ( const GpgmeRecipientSet rset );
/* Functions to handle data sources */
GpgmeError gpgme_new_data ( GpgmeData *r_dh,
const char *buffer, size_t size, int copy );
void gpgme_release_data ( GpgmeData dh );
GpgmeDataType gpgme_query_data_type ( GpgmeData dh );
GpgmeError gpgme_rewind_data ( GpgmeData dh );
GpgmeError gpgme_read_data ( GpgmeData dh,
char *buffer, size_t length, size_t *nread );
/* Basic GnuPG functions */
GpgmeError gpgme_start_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
GpgmeData in, GpgmeData out );
GpgmeError gpgme_start_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text );
/* Key management functions */
+GpgmeError gpgme_keylist_start ( GpgmeCtx c,
+ const char *pattern, int secret_only );
/* Convenience functions for syncronous usage */
GpgmeError gpgme_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
GpgmeData in, GpgmeData out );
GpgmeError gpgme_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text );
/* miscellaneous functions */
const char *gpgme_strerror (GpgmeError err);
#ifdef __cplusplus
}
#endif
#endif /* GPGME_H */
diff --git a/gpgme/key.c b/gpgme/key.c
new file mode 100644
index 00000000..92bb5972
--- /dev/null
+++ b/gpgme/key.c
@@ -0,0 +1,135 @@
+/* key.c - Key and keyList objects
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * 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 <assert.h>
+
+#include "util.h"
+#include "ops.h"
+#include "key.h"
+
+#define ALLOC_CHUNK 1024
+#define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
+
+
+GpgmeError
+_gpgme_key_new( GpgmeKey *r_key )
+{
+ GpgmeKey key;
+
+ *r_key = NULL;
+ key = xtrycalloc ( 1, sizeof *key );
+ if (!key)
+ return mk_error (Out_Of_Core);
+
+ *r_key = key;
+ return 0;
+}
+
+void
+_gpgme_key_release ( GpgmeKey key )
+{
+ struct user_id_s *u, *u2;
+
+ if (!key)
+ return;
+
+ xfree (key->fingerprint);
+ for ( u = key->uids; u; u = u2 ) {
+ u2 = u->next;
+ xfree (u);
+ }
+ xfree (key);
+}
+
+/*
+ * Take a name from the --with-colon listing, remove certain escape sequences
+ * sequences and put it into the list of UIDs
+ */
+GpgmeError
+_gpgme_key_append_name ( GpgmeKey key, const char *s )
+{
+ struct user_id_s *uid;
+ char *d;
+
+ assert (key);
+ /* we can malloc a buffer of the same length, because the converted
+ * string will never be larger */
+ uid = xtrymalloc ( sizeof *uid + strlen (s) );
+ if ( !uid )
+ return mk_error (Out_Of_Core);
+ uid->validity = 0;
+ d = uid->name;
+
+ while ( *s ) {
+ if ( *s != '\\' )
+ *d++ = *s++;
+ else if ( s[1] == '\\' ) {
+ s++;
+ *d++ = *s++;
+ }
+ else if ( s[1] == 'n' ) {
+ s += 2;
+ *d++ = '\n';
+ }
+ else if ( s[1] == 'r' ) {
+ s += 2;
+ *d++ = '\r';
+ }
+ else if ( s[1] == 'v' ) {
+ s += 2;
+ *d++ = '\v';
+ }
+ else if ( s[1] == 'b' ) {
+ s += 2;
+ *d++ = '\b';
+ }
+ else if ( s[1] == '0' ) {
+ /* Hmmm: no way to express this */
+ s += 2;
+ *d++ = '\\';
+ *d++ = '\0';
+ }
+ else if ( s[1] == 'x' && my_isdigit (s[2]) && my_isdigit (s[3]) ) {
+ unsigned int val = (s[2]-'0')*16 + (s[3]-'0');
+ if ( !val ) {
+ *d++ = '\\';
+ *d++ = '\0';
+ }
+ else
+ *(byte*)d++ = val;
+ s += 3;
+ }
+ else { /* should not happen */
+ s++;
+ *d++ = '\\';
+ *d++ = *s++;
+ }
+ }
+
+ uid->next = key->uids;
+ key->uids = uid;
+ return 0;
+}
+
+
+
diff --git a/gpgme/ops.h b/gpgme/key.h
similarity index 54%
copy from gpgme/ops.h
copy to gpgme/key.h
index 59efeffc..bd32c4b7 100644
--- a/gpgme/ops.h
+++ b/gpgme/key.h
@@ -1,51 +1,59 @@
-/* ops.h - internal operations stuff
+/* key.h
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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
*/
-#ifndef OPS_H
-#define OPS_H
+#ifndef KEY_H
+#define KEY_H
+#include <time.h>
#include "types.h"
-/*-- gpgme.c --*/
-void _gpgme_release_result ( GpgmeCtx c );
+struct user_id_s {
+ struct user_id_s *next;
+ int validity; /* 0 = undefined, 1 = not, 2 = marginal,
+ 3 = full, 4 = ultimate */
+ char name[1];
+};
+struct gpgme_key_s {
+ struct {
+ unsigned int revoked:1 ;
+ unsigned int expired:1 ;
+ unsigned int disabled:1 ;
+ } flags;
+ unsigned int key_algo;
+ unsigned int key_len;
+ char keyid[16+1];
+ char *fingerprint; /* malloced hex digits */
+ time_t timestamp; /* -1 for invalid, 0 for not available */
+ struct user_id_s *uids;
+
+};
-/*-- recipient.c --*/
-void _gpgme_append_gpg_args_from_recipients (
- const GpgmeRecipientSet rset,
- GpgObject gpg );
+GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s );
-/*-- data.c --*/
-GpgmeDataMode _gpgme_query_data_mode ( GpgmeData dh );
-void _gpgme_set_data_mode ( GpgmeData dh, GpgmeDataMode mode );
-GpgmeError _gpgme_append_data ( GpgmeData dh,
- const char *buffer, size_t length );
-/*-- verify.c --*/
-void _gpgme_release_verify_result ( VerifyResult res );
-
-#endif /* OPS_H */
+#endif /* KEY_H */
diff --git a/gpgme/keylist.c b/gpgme/keylist.c
new file mode 100644
index 00000000..1e7d5b12
--- /dev/null
+++ b/gpgme/keylist.c
@@ -0,0 +1,334 @@
+/* keylist.c - key listing
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * 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"
+#include "key.h"
+
+#define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
+
+static void finish_key ( GpgmeCtx ctx );
+
+
+static void
+keylist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
+{
+ if ( ctx->out_of_core )
+ return;
+
+ switch (code) {
+ case STATUS_EOF:
+ if (ctx->tmp_key)
+ finish_key (ctx);
+ break;
+
+ default:
+ /* ignore all other codes */
+ fprintf (stderr, "keylist_status: code=%d not handled\n", code );
+ break;
+ }
+}
+
+
+static time_t
+parse_timestamp ( char *p )
+{
+ struct tm tm;
+ int i;
+
+ if (!*p )
+ return 0;
+
+ if (strlen(p) < 10 || p[4] != '-' || p[7] != '-' )
+ return (time_t)-1;
+ p[4] = 0;
+ p[7] = 0;
+ p[10] = 0; /* just in case the time part follows */
+ memset (&tm, 0, sizeof tm);
+
+ i = atoi (p);
+ if ( i < 1900 )
+ return (time_t)-1;
+ tm.tm_year = i - 1900;
+
+ i = atoi (p+5);
+ if ( i < 1 || i > 12 )
+ return (time_t)-1;
+ tm.tm_mon = i-1;
+
+ i = atoi (p+8);
+ if ( i < 1 || i > 31 )
+ return (time_t)-1;
+ tm.tm_mday = i;
+
+ return mktime (&tm);
+}
+
+
+static void
+set_trust_info ( GpgmeKey key, const char *s )
+{
+ /* look at letters and stop at the first digit */
+ for (; *s && !my_isdigit (*s); s++ ) {
+ switch (*s) {
+ case 'e': key->flags.expired = 1; break;
+ case 'r': key->flags.revoked = 1; break;
+ case 'd': key->flags.disabled = 1; break;
+ case 'n': key->uids->validity = 1; break;
+ case 'm': key->uids->validity = 2; break;
+ case 'f': key->uids->validity = 3; break;
+ case 'u': key->uids->validity = 4; break;
+ }
+ }
+}
+
+
+/* Note: we are allowed to modify line */
+static void
+keylist_colon_handler ( GpgmeCtx ctx, char *line )
+{
+ char *p, *pend;
+ int field = 0;
+ enum {
+ RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC
+ } rectype = RT_NONE;
+ GpgmeKey key = ctx->tmp_key;
+ int i;
+ const char *trust_info = NULL;
+
+
+ if ( ctx->out_of_core )
+ return;
+ if (!line)
+ return; /* EOF */
+
+ fprintf (stderr, "line=`%s'\n", line );
+
+ for (p = line; p; p = pend) {
+ field++;
+ pend = strchr (p, ':');
+ if (pend)
+ *pend++ = 0;
+
+ if ( field == 1 ) {
+ if ( !strcmp ( p, "sig" ) )
+ rectype = RT_SIG;
+ else if ( !strcmp ( p, "uid" ) && key ) {
+ rectype = RT_UID;
+ key = ctx->tmp_key;
+ }
+ else if ( !strcmp ( p, "sub" ) )
+ rectype = RT_SUB;
+ else if ( !strcmp ( p, "pub" ) ) {
+ /* start a new keyblock */
+ if ( _gpgme_key_new ( &key ) ) {
+ ctx->out_of_core=1; /* the only kind of error we can get */
+ return;
+ }
+ rectype = RT_PUB;
+ if ( ctx->tmp_key )
+ finish_key ( ctx );
+ assert ( !ctx->tmp_key );
+ ctx->tmp_key = key;
+ }
+ else if ( !strcmp ( p, "fpr" ) && key )
+ rectype = RT_FPR;
+ else if ( !strcmp ( p, "ssb" ) )
+ rectype = RT_SSB;
+ else if ( !strcmp ( p, "sec" ) )
+ rectype = RT_SEC;
+ else
+ rectype = RT_NONE;
+
+ }
+ else if ( rectype == RT_PUB /*|| rectype == RT_SUB*/ ) {
+ switch (field) {
+ case 2: /* trust info */
+ if ( rectype == RT_PUB )
+ trust_info = p; /*save for later */
+ break;
+ case 3: /* key length */
+ i = atoi (p);
+ if ( i > 1 ) /* ignore invalid values */
+ key->key_len = i;
+ break;
+ case 4: /* pubkey algo */
+ i = atoi (p);
+ if ( i > 1 && i < 128 )
+ key->key_algo = i;
+ break;
+ case 5: /* long keyid */
+ if ( strlen (p) == DIM(key->keyid)-1 )
+ strcpy (key->keyid, p);
+ break;
+ case 6: /* timestamp (1998-02-28) */
+ key->timestamp = parse_timestamp (p);
+ break;
+ case 7: /* valid for n days */
+ break;
+ case 8: /* reserved (LID) */
+ break;
+ case 9: /* ownertrust */
+ break;
+ case 10: /* This is the first name listed */
+ if ( rectype == RT_PUB ) {
+ if ( _gpgme_key_append_name ( key, p) )
+ ctx->out_of_core = 1;
+ else {
+ if (trust_info)
+ set_trust_info (key, trust_info);
+ }
+ }
+ break;
+ case 11: /* signature class */
+ break;
+ case 12:
+ pend = NULL; /* we can stop here */
+ break;
+ }
+ }
+ else if ( rectype == RT_UID ) {
+ switch (field) {
+ case 2: /* trust info */
+ trust_info = p; /*save for later */
+ break;
+ case 10: /* the 2nd, 3rd,... user ID */
+ if ( _gpgme_key_append_name ( key, p) )
+ ctx->out_of_core = 1;
+ else {
+ if (trust_info)
+ set_trust_info (key, trust_info);
+ }
+ pend = NULL; /* we can stop here */
+ break;
+ }
+ }
+ else if ( rectype == RT_FPR ) {
+ switch (field) {
+ case 10: /* fingerprint (take only the first one)*/
+ if ( !key->fingerprint && *p ) {
+ key->fingerprint = xtrystrdup (p);
+ if ( !key->fingerprint )
+ ctx->out_of_core = 1;
+ }
+ pend = NULL; /* that is all we want */
+ break;
+ }
+ }
+ }
+
+}
+
+
+/*
+ * We have read an entire key into ctx->tmp_key and should now finish
+ * it. It is assumed that this releases ctx->tmp_key.
+ */
+static void
+finish_key ( GpgmeCtx ctx )
+{
+ GpgmeKey key = ctx->tmp_key;
+ struct user_id_s *u;
+
+ assert (key);
+ ctx->tmp_key = NULL;
+
+ fprintf (stderr, "finish_key: keyid=`%s'\n", key->keyid );
+ if ( key->fingerprint )
+ fprintf (stderr, "finish_key: fpr=`%s'\n", key->fingerprint );
+ for (u=key->uids; u; u = u->next )
+ fprintf (stderr, "finish_key: uid=`%s'\n", u->name );
+
+
+ /* fixme: call the callback or do something else with the key */
+
+ _gpgme_key_release (key);
+}
+
+
+
+
+GpgmeError
+gpgme_keylist_start ( GpgmeCtx c, const char *pattern, int secret_only )
+{
+ GpgmeError rc = 0;
+ int i;
+
+ fail_on_pending_request( c );
+ c->pending = 1;
+
+ _gpgme_release_result (c);
+ c->out_of_core = 0;
+
+ if ( c->gpg ) {
+ _gpgme_gpg_release_object ( c->gpg );
+ c->gpg = NULL;
+ }
+ _gpgme_key_release (c->tmp_key);
+ c->tmp_key = NULL;
+
+ rc = _gpgme_gpg_new_object ( &c->gpg );
+ if (rc)
+ goto leave;
+
+ _gpgme_gpg_set_status_handler ( c->gpg, keylist_status_handler, c );
+
+ rc = _gpgme_gpg_set_colon_line_handler ( c->gpg,
+ keylist_colon_handler, c );
+ if (rc)
+ goto leave;
+
+ /* build the commandline */
+ for ( i=0; i < c->verbosity; i++ )
+ _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
+ _gpgme_gpg_add_arg ( c->gpg, "--with-colons" );
+ _gpgme_gpg_add_arg ( c->gpg, "--with-fingerprint" );
+ _gpgme_gpg_add_arg ( c->gpg, secret_only?
+ "--list-secret-keys":"--list-keys" );
+
+ /* Tell the gpg object about the data */
+ _gpgme_gpg_add_arg ( c->gpg, "--" );
+ if (pattern && *pattern)
+ _gpgme_gpg_add_arg ( c->gpg, pattern );
+
+ /* and kick off the process */
+ rc = _gpgme_gpg_spawn ( c->gpg, c );
+
+ leave:
+ if (rc) {
+ c->pending = 0;
+ _gpgme_gpg_release_object ( c->gpg ); c->gpg = NULL;
+ }
+ return rc;
+}
+
+
+
+
+
+
diff --git a/gpgme/ops.h b/gpgme/ops.h
index 59efeffc..020f0fae 100644
--- a/gpgme/ops.h
+++ b/gpgme/ops.h
@@ -1,51 +1,56 @@
/* ops.h - internal operations stuff
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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
*/
#ifndef OPS_H
#define OPS_H
#include "types.h"
/*-- gpgme.c --*/
void _gpgme_release_result ( GpgmeCtx c );
/*-- recipient.c --*/
void _gpgme_append_gpg_args_from_recipients (
const GpgmeRecipientSet rset,
GpgObject gpg );
/*-- data.c --*/
GpgmeDataMode _gpgme_query_data_mode ( GpgmeData dh );
void _gpgme_set_data_mode ( GpgmeData dh, GpgmeDataMode mode );
GpgmeError _gpgme_append_data ( GpgmeData dh,
const char *buffer, size_t length );
+/*-- key.c --*/
+GpgmeError _gpgme_key_new( GpgmeKey *r_key );
+void _gpgme_key_release ( GpgmeKey key );
+
+
/*-- verify.c --*/
void _gpgme_release_verify_result ( VerifyResult res );
#endif /* OPS_H */
diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c
index ac6ba114..29263293 100644
--- a/gpgme/rungpg.c
+++ b/gpgme/rungpg.c
@@ -1,726 +1,893 @@
/* rungpg.c
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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 <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include "gpgme.h"
#include "util.h"
#include "ops.h"
#include "wait.h"
#include "rungpg.h"
#include "context.h" /*temp hack until we have GpmeData methods to do I/O */
#include "status-table.h"
/* This type is used to build a list of gpg arguments and
* data sources/sinks */
struct arg_and_data_s {
struct arg_and_data_s *next;
GpgmeData data; /* If this is not NULL .. */
int dup_to;
char arg[1]; /* .. this is used */
};
struct fd_data_map_s {
GpgmeData data;
int inbound; /* true if this is used for reading from gpg */
int dup_to;
int fd; /* the fd to use */
int peer_fd; /* the outher side of the pipe */
};
struct gpg_object_s {
struct arg_and_data_s *arglist;
struct arg_and_data_s **argtail;
int arg_error;
struct {
int fd[2];
size_t bufsize;
char *buffer;
size_t readpos;
int eof;
GpgStatusHandler fnc;
void *fnc_value;
} status;
+ /* This is a kludge - see the comment at gpg_colon_line_handler */
+ struct {
+ int fd[2];
+ size_t bufsize;
+ char *buffer;
+ size_t readpos;
+ int eof;
+ GpgColonLineHandler fnc; /* this indicate use of this structrue */
+ void *fnc_value;
+ } colon;
+
char **argv;
struct fd_data_map_s *fd_data_map;
pid_t pid;
int running;
int exit_status;
int exit_signal;
};
static void kill_gpg ( GpgObject gpg );
static void free_argv ( char **argv );
static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
-static int gpg_status_handler ( void *opaque, pid_t pid, int fd );
+
static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd );
static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd );
+static int gpg_status_handler ( void *opaque, pid_t pid, int fd );
static GpgmeError read_status ( GpgObject gpg );
+static int gpg_colon_line_handler ( void *opaque, pid_t pid, int fd );
+static GpgmeError read_colon_line ( GpgObject gpg );
+
GpgmeError
_gpgme_gpg_new_object ( GpgObject *r_gpg )
{
GpgObject gpg;
int rc = 0;
gpg = xtrycalloc ( 1, sizeof *gpg );
if ( !gpg ) {
rc = mk_error (Out_Of_Core);
goto leave;
}
gpg->argtail = &gpg->arglist;
gpg->status.fd[0] = -1;
gpg->status.fd[1] = -1;
+ gpg->colon.fd[0] = -1;
+ gpg->colon.fd[1] = -1;
/* allocate the read buffer for the status pipe */
gpg->status.bufsize = 1024;
gpg->status.readpos = 0;
gpg->status.buffer = xtrymalloc (gpg->status.bufsize);
if (!gpg->status.buffer) {
rc = mk_error (Out_Of_Core);
goto leave;
}
/* In any case we need a status pipe - create it right here and
* don't handle it with our generic GpgmeData mechanism */
if (pipe (gpg->status.fd) == -1) {
rc = mk_error (Pipe_Error);
goto leave;
}
gpg->status.eof = 0;
_gpgme_gpg_add_arg ( gpg, "--status-fd" );
{
char buf[25];
sprintf ( buf, "%d", gpg->status.fd[1]);
_gpgme_gpg_add_arg ( gpg, buf );
}
_gpgme_gpg_add_arg ( gpg, "--batch" );
_gpgme_gpg_add_arg ( gpg, "--no-tty" );
leave:
if (rc) {
_gpgme_gpg_release_object (gpg);
*r_gpg = NULL;
}
else
*r_gpg = gpg;
return rc;
}
void
_gpgme_gpg_release_object ( GpgObject gpg )
{
if ( !gpg )
return;
xfree (gpg->status.buffer);
+ xfree (gpg->colon.buffer);
if ( gpg->argv )
free_argv (gpg->argv);
if (gpg->status.fd[0] != -1 )
close (gpg->status.fd[0]);
if (gpg->status.fd[1] != -1 )
close (gpg->status.fd[1]);
+ if (gpg->colon.fd[0] != -1 )
+ close (gpg->colon.fd[0]);
+ if (gpg->colon.fd[1] != -1 )
+ close (gpg->colon.fd[1]);
free_fd_data_map (gpg->fd_data_map);
kill_gpg (gpg); /* fixme: should be done asyncronously */
xfree (gpg);
}
static void
kill_gpg ( GpgObject gpg )
{
#if 0
if ( gpg->running ) {
/* still running? Must send a killer */
kill ( gpg->pid, SIGTERM);
sleep (2);
if ( !waitpid (gpg->pid, NULL, WNOHANG) ) {
/* pay the murderer better and then forget about it */
kill (gpg->pid, SIGKILL);
}
gpg->running = 0;
}
#endif
}
GpgmeError
_gpgme_gpg_add_arg ( GpgObject gpg, const char *arg )
{
struct arg_and_data_s *a;
assert (gpg);
assert (arg);
a = xtrymalloc ( sizeof *a + strlen (arg) );
if ( !a ) {
gpg->arg_error = 1;
return mk_error(Out_Of_Core);
}
a->next = NULL;
a->data = NULL;
a->dup_to = -1;
strcpy ( a->arg, arg );
*gpg->argtail = a;
gpg->argtail = &a->next;
return 0;
}
GpgmeError
_gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to )
{
struct arg_and_data_s *a;
assert (gpg);
assert (data);
a = xtrymalloc ( sizeof *a - 1 );
if ( !a ) {
gpg->arg_error = 1;
return mk_error(Out_Of_Core);
}
a->next = NULL;
a->data = data;
a->dup_to = dup_to;
*gpg->argtail = a;
gpg->argtail = &a->next;
return 0;
}
/*
* Note, that the status_handler is allowed to modifiy the args value
*/
void
_gpgme_gpg_set_status_handler ( GpgObject gpg,
GpgStatusHandler fnc, void *fnc_value )
{
assert (gpg);
gpg->status.fnc = fnc;
gpg->status.fnc_value = fnc_value;
}
+/* Kludge to process --with-colon output */
+GpgmeError
+_gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
+ GpgColonLineHandler fnc, void *fnc_value )
+{
+ assert (gpg);
+
+ gpg->colon.bufsize = 1024;
+ gpg->colon.readpos = 0;
+ gpg->colon.buffer = xtrymalloc (gpg->colon.bufsize);
+ if (!gpg->colon.buffer) {
+ return mk_error (Out_Of_Core);
+ }
+ if (pipe (gpg->colon.fd) == -1) {
+ xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
+ return mk_error (Pipe_Error);
+ }
+ gpg->colon.eof = 0;
+ gpg->colon.fnc = fnc;
+ gpg->colon.fnc_value = fnc_value;
+ return 0;
+}
+
+
static void
free_argv ( char **argv )
{
int i;
for (i=0; argv[i]; i++ )
xfree (argv[i]);
xfree (argv);
}
static void
free_fd_data_map ( struct fd_data_map_s *fd_data_map )
{
int i;
for (i=0; fd_data_map[i].data; i++ ) {
if ( fd_data_map[i].fd != -1 )
close (fd_data_map[i].fd);
if ( fd_data_map[i].peer_fd != -1 )
close (fd_data_map[i].peer_fd);
/* don't realease data because this is only a reference */
}
xfree (fd_data_map);
}
static GpgmeError
build_argv ( GpgObject gpg )
{
struct arg_and_data_s *a;
struct fd_data_map_s *fd_data_map;
size_t datac=0, argc=0;
char **argv;
int need_special = 0;
if ( gpg->argv ) {
free_argv ( gpg->argv );
gpg->argv = NULL;
}
if (gpg->fd_data_map) {
free_fd_data_map (gpg->fd_data_map);
gpg->fd_data_map = NULL;
}
argc++; /* for argv[0] */
for ( a=gpg->arglist; a; a = a->next ) {
argc++;
if (a->data) {
/*fprintf (stderr, "build_argv: data\n" );*/
datac++;
if ( a->dup_to == -1 )
need_special = 1;
}
else {
/* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
}
}
if ( need_special )
argc++;
argv = xtrycalloc ( argc+1, sizeof *argv );
if (!argv)
return mk_error (Out_Of_Core);
fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map );
if (!fd_data_map) {
free_argv (argv);
return mk_error (Out_Of_Core);
}
argc = datac = 0;
argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */
if (!argv[argc]) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Out_Of_Core);
}
argc++;
if ( need_special ) {
argv[argc] = xtrystrdup ( "--enable-special-filenames" );
if (!argv[argc]) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Out_Of_Core);
}
argc++;
}
for ( a=gpg->arglist; a; a = a->next ) {
if ( a->data ) {
switch ( _gpgme_query_data_mode (a->data) ) {
case GPGME_DATA_MODE_NONE:
case GPGME_DATA_MODE_INOUT:
xfree (fd_data_map);
free_argv (argv);
return mk_error (Invalid_Mode);
case GPGME_DATA_MODE_IN:
/* create a pipe to read from gpg */
fd_data_map[datac].inbound = 1;
break;
case GPGME_DATA_MODE_OUT:
/* create a pipe to pass it down to gpg */
fd_data_map[datac].inbound = 0;
break;
}
switch ( gpgme_query_data_type (a->data) ) {
case GPGME_DATA_TYPE_NONE:
if ( fd_data_map[datac].inbound )
break; /* allowed */
xfree (fd_data_map);
free_argv (argv);
return mk_error (Invalid_Type);
case GPGME_DATA_TYPE_MEM:
break;
case GPGME_DATA_TYPE_FD:
case GPGME_DATA_TYPE_FILE:
xfree (fd_data_map);
free_argv (argv);
return mk_error (Not_Implemented);
}
/* create a pipe */
{
int fds[2];
if (pipe (fds) == -1) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Pipe_Error);
}
/* if the data_type is FD, we have to do a dup2 here */
if (fd_data_map[datac].inbound) {
fd_data_map[datac].fd = fds[0];
fd_data_map[datac].peer_fd = fds[1];
}
else {
fd_data_map[datac].fd = fds[1];
fd_data_map[datac].peer_fd = fds[0];
}
}
fd_data_map[datac].data = a->data;
fd_data_map[datac].dup_to = a->dup_to;
if ( a->dup_to == -1 ) {
argv[argc] = xtrymalloc ( 25 );
if (!argv[argc]) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Out_Of_Core);
}
sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd );
argc++;
}
datac++;
}
else {
argv[argc] = xtrystrdup ( a->arg );
if (!argv[argc]) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Out_Of_Core);
}
argc++;
}
}
gpg->argv = argv;
gpg->fd_data_map = fd_data_map;
return 0;
}
GpgmeError
_gpgme_gpg_spawn( GpgObject gpg, void *opaque )
{
int rc;
int i;
pid_t pid;
if ( !gpg )
return mk_error (Invalid_Value);
/* Kludge, so that we don't need to check the return code of
* all the gpgme_gpg_add_arg(). we bail out here instead */
if ( gpg->arg_error )
return mk_error (Out_Of_Core);
rc = build_argv ( gpg );
if ( rc )
return rc;
fflush (stderr);
pid = fork ();
if (pid == -1) {
return mk_error (Exec_Error);
}
if ( !pid ) { /* child */
int duped_stdin = 0;
int duped_stderr = 0;
close (gpg->status.fd[0]);
+
+ if (gpg->colon.fnc) {
+ /* dup it to stdout */
+ if ( dup2 ( gpg->colon.fd[1], 1 ) == -1 ) {
+ fprintf (stderr,"dup2(colon, 1) failed: %s\n",
+ strerror (errno) );
+ _exit (8);
+ }
+ close (gpg->colon.fd[0]);
+ close (gpg->colon.fd[1]);
+ }
for (i=0; gpg->fd_data_map[i].data; i++ ) {
close (gpg->fd_data_map[i].fd);
gpg->fd_data_map[i].fd = -1;
if ( gpg->fd_data_map[i].dup_to != -1 ) {
if ( dup2 (gpg->fd_data_map[i].peer_fd,
gpg->fd_data_map[i].dup_to ) == -1 ) {
fprintf (stderr, "dup2 failed in child: %s\n",
strerror (errno));
_exit (8);
}
if ( gpg->fd_data_map[i].dup_to == 0 )
duped_stdin=1;
if ( gpg->fd_data_map[i].dup_to == 2 )
duped_stderr=1;
close ( gpg->fd_data_map[i].peer_fd );
}
}
if( !duped_stdin || !duped_stderr ) {
int fd = open ( "/dev/null", O_RDONLY );
if ( fd == -1 ) {
fprintf (stderr,"can't open `/dev/null': %s\n",
strerror (errno) );
_exit (8);
}
/* Make sure that gpg has a connected stdin */
if ( !duped_stdin ) {
if ( dup2 ( fd, 0 ) == -1 ) {
fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n",
strerror (errno) );
_exit (8);
}
}
/* We normally don't want all the normal output */
if ( !duped_stderr ) {
if ( dup2 ( fd, 2 ) == -1 ) {
fprintf (stderr,"dup2(dev/null, 2) failed: %s\n",
strerror (errno) );
_exit (8);
}
}
close (fd);
}
execv ("./gpg", gpg->argv );
fprintf (stderr,"exec of gpg failed\n");
_exit (8);
}
/* parent */
gpg->pid = pid;
/*_gpgme_register_term_handler ( closure, closure_value, pid );*/
- if ( gpg->status.fd[1] != -1 )
+ if ( gpg->status.fd[1] != -1 ) {
close (gpg->status.fd[1]);
+ gpg->status.fd[1] = -1;
+ }
if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
gpg, pid, gpg->status.fd[0], 1 ) ) {
/* FIXME: kill the child */
return mk_error (General_Error);
}
+
+ if ( gpg->colon.fd[1] != -1 ) {
+ close (gpg->colon.fd[1]);
+ gpg->colon.fd[1] = -1;
+ assert ( gpg->colon.fd[0] != -1 );
+ if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
+ gpg, pid, gpg->colon.fd[0], 1 ) ) {
+ /* FIXME: kill the child */
+ return mk_error (General_Error);
+
+ }
+ }
+
for (i=0; gpg->fd_data_map[i].data; i++ ) {
close (gpg->fd_data_map[i].peer_fd);
gpg->fd_data_map[i].peer_fd = -1;
if ( _gpgme_register_pipe_handler (
opaque,
gpg->fd_data_map[i].inbound?
gpg_inbound_handler:gpg_outbound_handler,
gpg->fd_data_map[i].data,
pid, gpg->fd_data_map[i].fd,
gpg->fd_data_map[i].inbound )
) {
/* FIXME: kill the child */
return mk_error (General_Error);
}
}
/* fixme: check what data we can release here */
gpg->running = 1;
return 0;
}
static int
gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
{
GpgmeData dh = opaque;
GpgmeError err;
int nread;
char buf[200];
assert ( _gpgme_query_data_mode (dh) == GPGME_DATA_MODE_IN );
do {
nread = read (fd, buf, 200 );
} while ( nread == -1 && errno == EINTR);
fprintf(stderr, "inbound on fd %d: nread=%d\n", fd, nread );
if ( nread < 0 ) {
fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
fd, nread, strerror (errno) );
return 1;
}
else if (!nread)
return 1; /* eof */
/* We could improve this with a GpgmeData function which takes
* the read function or provides a memory area for writing to it.
*/
err = _gpgme_append_data ( dh, buf, nread );
if ( err ) {
fprintf (stderr, "_gpgme_append_data failed: %s\n",
gpgme_strerror(err));
/* Fixme: we should close the pipe or read it to /dev/null in
* this case. Returnin EOF is not sufficient */
return 1;
}
return 0;
}
static int
write_mem_data ( GpgmeData dh, int fd )
{
size_t nbytes;
int nwritten;
nbytes = dh->len - dh->readpos;
if ( !nbytes ) {
close (fd);
return 1;
}
do {
nwritten = write ( fd, dh->data+dh->readpos, nbytes );
} while ( nwritten == -1 && errno == EINTR );
if ( nwritten < 1 ) {
fprintf (stderr, "write_mem_data: write failed on fd %d (n=%d): %s\n",
fd, nwritten, strerror (errno) );
close (fd);
return 1;
}
dh->readpos += nwritten;
return 0;
}
static int
gpg_outbound_handler ( void *opaque, pid_t pid, int fd )
{
GpgmeData dh = opaque;
assert ( _gpgme_query_data_mode (dh) == GPGME_DATA_MODE_OUT );
switch ( gpgme_query_data_type (dh) ) {
case GPGME_DATA_TYPE_MEM:
if ( write_mem_data ( dh, fd ) )
return 1; /* ready */
break;
default:
assert (0);
}
return 0;
}
static int
gpg_status_handler ( void *opaque, pid_t pid, int fd )
{
GpgObject gpg = opaque;
int rc = 0;
assert ( fd == gpg->status.fd[0] );
rc = read_status ( gpg );
if ( rc ) {
fprintf (stderr, "gpg_handler: read_status problem %d\n - stop", rc);
return 1;
}
return gpg->status.eof;
}
static int
status_cmp (const void *ap, const void *bp)
{
const struct status_table_s *a = ap;
const struct status_table_s *b = bp;
return strcmp (a->name, b->name);
}
/*
* Handle the status output of GnuPG. This function does read entire
* lines and passes them as C strings to the callback function (we can
* use C Strings because the status output is always UTF-8 encoded).
* Of course we have to buffer the lines to cope with long lines
* e.g. with a large user ID. Note: We can optimize this to only cope
* with status line code we know about and skip all other stuff
* without buffering (i.e. without extending the buffer). */
static GpgmeError
read_status ( GpgObject gpg )
{
char *p;
int nread;
size_t bufsize = gpg->status.bufsize;
char *buffer = gpg->status.buffer;
size_t readpos = gpg->status.readpos;
assert (buffer);
if (bufsize - readpos < 256) {
/* need more room for the read */
bufsize += 1024;
buffer = xtryrealloc (buffer, bufsize);
if ( !buffer )
return mk_error (Out_Of_Core);
}
do {
nread = read ( gpg->status.fd[0], buffer+readpos, bufsize-readpos );
} while (nread == -1 && errno == EINTR);
if (nread == -1)
return mk_error(Read_Error);
if (!nread) {
gpg->status.eof = 1;
if (gpg->status.fnc)
gpg->status.fnc ( gpg->status.fnc_value, STATUS_EOF, "" );
return 0;
}
while (nread > 0) {
for (p = buffer + readpos; nread; nread--, p++) {
if ( *p == '\n' ) {
/* (we require that the last line is terminated by a LF) */
*p = 0;
fprintf (stderr, "read_status: `%s'\n", buffer);
if (!strncmp (buffer, "[GNUPG:] ", 9 )
&& buffer[9] >= 'A' && buffer[9] <= 'Z'
&& gpg->status.fnc ) {
struct status_table_s t, *r;
char *rest;
rest = strchr (buffer+9, ' ');
if ( !rest )
rest = p; /* set to an empty string */
else
*rest++ = 0;
t.name = buffer+9;
/* (the status table as one extra element) */
r = bsearch ( &t, status_table, DIM(status_table)-1,
sizeof t, status_cmp );
if ( r ) {
gpg->status.fnc ( gpg->status.fnc_value,
r->code, rest);
}
}
/* To reuse the buffer for the next line we have to
* shift the remaining data to the buffer start and
* restart the loop Hmmm: We can optimize this
* function by looking forward in the buffer to see
* whether a second complete line is available and in
* this case avoid the memmove for this line. */
nread--; p++;
if (nread)
memmove (buffer, p, nread);
readpos = 0;
break; /* the for loop */
}
else
readpos++;
}
}
/* Update the gpg object. */
gpg->status.bufsize = bufsize;
gpg->status.buffer = buffer;
gpg->status.readpos = readpos;
return 0;
}
+/*
+ * This colonline handler thing is not the clean way to do it.
+ * It might be better to enhance the GpgmeData object to act as
+ * a wrapper for a callback. Same goes for the status thing.
+ * For now we use this thing here becuase it is easier to implement.
+ */
+static int
+gpg_colon_line_handler ( void *opaque, pid_t pid, int fd )
+{
+ GpgObject gpg = opaque;
+ GpgmeError rc = 0;
+
+ assert ( fd == gpg->colon.fd[0] );
+ rc = read_colon_line ( gpg );
+ if ( rc ) {
+ fprintf (stderr, "gpg_colon_line_handler: "
+ "read problem %d\n - stop", rc);
+ return 1;
+ }
+
+ return gpg->status.eof;
+}
+
+static GpgmeError
+read_colon_line ( GpgObject gpg )
+{
+ char *p;
+ int nread;
+ size_t bufsize = gpg->colon.bufsize;
+ char *buffer = gpg->colon.buffer;
+ size_t readpos = gpg->colon.readpos;
+
+ assert (buffer);
+ if (bufsize - readpos < 256) {
+ /* need more room for the read */
+ bufsize += 1024;
+ buffer = xtryrealloc (buffer, bufsize);
+ if ( !buffer )
+ return mk_error (Out_Of_Core);
+ }
+
+
+ do {
+ nread = read ( gpg->colon.fd[0], buffer+readpos, bufsize-readpos );
+ } while (nread == -1 && errno == EINTR);
+
+ if (nread == -1)
+ return mk_error(Read_Error);
+
+ if (!nread) {
+ gpg->colon.eof = 1;
+ assert (gpg->colon.fnc);
+ gpg->colon.fnc ( gpg->colon.fnc_value, NULL );
+ return 0;
+ }
+
+ while (nread > 0) {
+ for (p = buffer + readpos; nread; nread--, p++) {
+ if ( *p == '\n' ) {
+ /* (we require that the last line is terminated by a
+ * LF) and we skip empty lines. Note: we use UTF8
+ * encoding and escaping of special characters
+ * We require at least one colon to cope with
+ * some other printed information.
+ */
+ *p = 0;
+ if ( *buffer && strchr (buffer, ':') ) {
+ assert (gpg->colon.fnc);
+ gpg->colon.fnc ( gpg->colon.fnc_value, buffer );
+ }
+
+ /* To reuse the buffer for the next line we have to
+ * shift the remaining data to the buffer start and
+ * restart the loop Hmmm: We can optimize this
+ * function by looking forward in the buffer to see
+ * whether a second complete line is available and in
+ * this case avoid the memmove for this line. */
+ nread--; p++;
+ if (nread)
+ memmove (buffer, p, nread);
+ readpos = 0;
+ break; /* the for loop */
+ }
+ else
+ readpos++;
+ }
+ }
+
+ /* Update the gpg object. */
+ gpg->colon.bufsize = bufsize;
+ gpg->colon.buffer = buffer;
+ gpg->colon.readpos = readpos;
+ return 0;
+}
+
diff --git a/gpgme/rungpg.h b/gpgme/rungpg.h
index 5a27ce96..fd29ca41 100644
--- a/gpgme/rungpg.h
+++ b/gpgme/rungpg.h
@@ -1,103 +1,108 @@
/* rungpg.h - gpg calling functions
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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
*/
#ifndef RUNGPG_H
#define RUNGPG_H
#include "types.h"
typedef enum {
STATUS_EOF ,
/* mkstatus starts here */
STATUS_ENTER ,
STATUS_LEAVE ,
STATUS_ABORT ,
STATUS_GOODSIG ,
STATUS_BADSIG ,
STATUS_ERRSIG ,
STATUS_BADARMOR ,
STATUS_RSA_OR_IDEA ,
STATUS_SIGEXPIRED ,
STATUS_KEYREVOKED ,
STATUS_TRUST_UNDEFINED ,
STATUS_TRUST_NEVER ,
STATUS_TRUST_MARGINAL ,
STATUS_TRUST_FULLY ,
STATUS_TRUST_ULTIMATE ,
STATUS_SHM_INFO ,
STATUS_SHM_GET ,
STATUS_SHM_GET_BOOL ,
STATUS_SHM_GET_HIDDEN ,
STATUS_NEED_PASSPHRASE ,
STATUS_VALIDSIG ,
STATUS_SIG_ID ,
STATUS_ENC_TO ,
STATUS_NODATA ,
STATUS_BAD_PASSPHRASE ,
STATUS_NO_PUBKEY ,
STATUS_NO_SECKEY ,
STATUS_NEED_PASSPHRASE_SYM,
STATUS_DECRYPTION_FAILED ,
STATUS_DECRYPTION_OKAY ,
STATUS_MISSING_PASSPHRASE ,
STATUS_GOOD_PASSPHRASE ,
STATUS_GOODMDC ,
STATUS_BADMDC ,
STATUS_ERRMDC ,
STATUS_IMPORTED ,
STATUS_IMPORT_RES ,
STATUS_FILE_START ,
STATUS_FILE_DONE ,
STATUS_FILE_ERROR ,
STATUS_BEGIN_DECRYPTION ,
STATUS_END_DECRYPTION ,
STATUS_BEGIN_ENCRYPTION ,
STATUS_END_ENCRYPTION ,
STATUS_DELETE_PROBLEM ,
STATUS_GET_BOOL ,
STATUS_GET_LINE ,
STATUS_GET_HIDDEN ,
STATUS_GOT_IT ,
STATUS_PROGRESS ,
STATUS_SIG_CREATED ,
STATUS_SESSION_KEY
} GpgStatusCode;
typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args );
+typedef void (*GpgColonLineHandler)( GpgmeCtx, char *line );
GpgmeError _gpgme_gpg_new_object ( GpgObject *r_gpg );
void _gpgme_gpg_release_object ( GpgObject gpg );
GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg );
GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to );
void _gpgme_gpg_set_status_handler ( GpgObject gpg,
GpgStatusHandler fnc,
void *fnc_value );
+GpgmeError _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
+ GpgColonLineHandler fnc,
+ void *fnc_value );
+
GpgmeError _gpgme_gpg_spawn ( GpgObject gpg, void *opaque );
#endif /* RUNGPG_H */
diff --git a/gpgme/types.h b/gpgme/types.h
index 82f6b79d..045fd7e4 100644
--- a/gpgme/types.h
+++ b/gpgme/types.h
@@ -1,57 +1,60 @@
/* types.h - Some type definitions
* Copyright (C) 2000 Werner Koch (dd9jn)
*
* 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
*/
#ifndef TYPES_H
#define TYPES_H
#include "gpgme.h" /* external objects and prototypes */
typedef unsigned char byte;
typedef enum {
GPGME_DATA_MODE_NONE = 0,
GPGME_DATA_MODE_IN = 1,
GPGME_DATA_MODE_OUT = 2,
GPGME_DATA_MODE_INOUT = 3
} GpgmeDataMode;
/*
* Declaration of internal objects
*/
/*-- rungpg.c --*/
struct gpg_object_s;
typedef struct gpg_object_s *GpgObject;
/*-- verify.c --*/
struct verify_result_s;
typedef struct verify_result_s *VerifyResult;
+/*-- key.c --*/
+struct gpgme_key_s;
+typedef struct gpgme_key_s *GpgmeKey;
#endif /* TYPES_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index aced4007..74709b11 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,12 +1,12 @@
## Process this file with automake to create Makefile.in
-TESTS = t-encrypt t-verify
+TESTS = t-encrypt t-verify t-keylist
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
INCLUDES =
LDADD = ../gpgme/libgpgme.la
noinst_PROGRAMS = $(TESTS)
diff --git a/tests/t-keylist.c b/tests/t-keylist.c
new file mode 100644
index 00000000..43ad3237
--- /dev/null
+++ b/tests/t-keylist.c
@@ -0,0 +1,74 @@
+/* t-keylist.c - regression test
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * 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/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
+doit ( GpgmeCtx ctx, const char *pattern )
+{
+ GpgmeError err;
+
+ err = gpgme_keylist_start (ctx, pattern, 0 );
+ fail_if_err (err);
+ gpgme_wait (ctx, 1);
+}
+
+
+int
+main (int argc, char **argv )
+{
+ GpgmeCtx ctx;
+ GpgmeError err;
+ int loop = 0;
+ const char *pattern;
+
+ if( argc ) {
+ argc--; argv++;
+ }
+
+ if (argc && !strcmp( *argv, "--loop" ) ) {
+ loop = 1;
+ argc--; argv++;
+ }
+ pattern = argc? *argv : NULL;
+
+ err = gpgme_new_context (&ctx);
+ fail_if_err (err);
+ do {
+ doit ( ctx, pattern );
+ } while ( loop );
+ gpgme_release_context (ctx);
+
+ return 0;
+}
+
+
+

File Metadata

Mime Type
text/x-diff
Expires
Mon, Feb 2, 8:15 AM (1 d, 10 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
01/2c/9d47c80d3657ccd5ccd5a0b949ec

Event Timeline