gpgme_op_export_ext EXTENDED: Arg RESERVED is now a MODE flag.
gpgme_op_export_keys_start NEW.
gpgme_op_export_keys NEW.
+ GPGME_DATA_ENCODING_URL NEW.
+ GPGME_DATA_ENCODING_URL0 NEW.
+ GPGME_DATA_ENCODING_URLESC NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* gpgme.texi (Exporting Keys): Document gpgme_op_export_keys.
(Importing Keys): Document gpgme_op_import_keys.
+ (Data Buffer Meta-Data): Document URL encodings.
2009-05-28 Marcus Brinkmann <marcus@g10code.de>
@item GPGME_DATA_ENCODING_ARMOR
This specifies that the data is encoded in an armored form as used by
OpenPGP and PEM.
+
+@item GPGME_DATA_ENCODING_URL
+The data is a list of linefeed delimited URLs. This is only useful with
+@code{gpgme_op_import}.
+
+@item GPGME_DATA_ENCODING_URL0
+The data is a list of binary zero delimited URLs. This is only useful
+with @code{gpgme_op_import}.
+
+@item GPGME_DATA_ENCODING_URLESC
+The data is a list of linefeed delimited URLs with all control and space
+characters percent escaped. This mode is is not yet implemented.
+
@end table
@end deftp
2009-06-16 Werner Koch <wk@g10code.com>
+ * version.c: Include stdlib.h.
+
+ * gpgme.h.in (gpgme_data_encoding_t): Add GPGME_DATA_ENCODING_URL,
+ GPGME_DATA_ENCODING_URLESC, GPGME_DATA_ENCODING_URL0.
+ * data.c (gpgme_data_set_encoding): Adjust for new values.
+ * engine-gpg.c (string_from_data): New.
+ (gpg_import): Implement --fetch-key feature.
+
* gpgme.h.in (gpgme_op_export_keys_start, gpgme_op_export_keys): New.
* gpgme.def, libgpgme.vers: Add them.
* export.c (gpgme_op_export_keys_start, gpgme_op_export_keys): New.
"encoding=%i", enc);
if (!dh)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
+ if (enc < 0 || enc > GPGME_DATA_ENCODING_URL0)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
dh->encoding = enc;
return TRACE_ERR (0);
return err;
}
+/* Return the next DELIM delimited string from DATA as a C-string.
+ The caller needs to provide the address of a pointer variable which
+ he has to set to NULL before the first call. After the last call
+ to this function, this function needs to be called once more with
+ DATA set to NULL so that the function can release its internal
+ state. After that the pointer variable is free for use again.
+ Note that we use a delimiter and thus a trailing delimiter is not
+ required. DELIM may not be changed after the first call. */
+static const char *
+string_from_data (gpgme_data_t data, int delim,
+ void **helpptr, gpgme_error_t *r_err)
+{
+#define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that. */
+ struct {
+ int eof_seen;
+ int nbytes; /* Length of the last returned string including
+ the delimiter. */
+ int buflen; /* Valid length of BUF. */
+ char buf[MYBUFLEN+1]; /* Buffer with one byte extra space. */
+ } *self;
+ char *p;
+ int nread;
+
+ *r_err = 0;
+ if (!data)
+ {
+ if (*helpptr)
+ {
+ free (*helpptr);
+ *helpptr = NULL;
+ }
+ return NULL;
+ }
+
+ if (*helpptr)
+ self = *helpptr;
+ else
+ {
+ self = malloc (sizeof *self);
+ if (!self)
+ {
+ *r_err = gpg_error_from_syserror ();
+ return NULL;
+ }
+ *helpptr = self;
+ self->eof_seen = 0;
+ self->nbytes = 0;
+ self->buflen = 0;
+ }
+
+ if (self->eof_seen)
+ return NULL;
+
+ assert (self->nbytes <= self->buflen);
+ memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
+ self->buflen -= self->nbytes;
+ self->nbytes = 0;
+
+ do
+ {
+ /* Fixme: This is fairly infective scanning because we may scan
+ the buffer several times. */
+ p = memchr (self->buf, delim, self->buflen);
+ if (p)
+ {
+ *p = 0;
+ self->nbytes = p - self->buf + 1;
+ return self->buf;
+ }
+
+ if ( !(MYBUFLEN - self->buflen) )
+ {
+ /* Not enough space - URL too long. */
+ *r_err = gpg_error (GPG_ERR_TOO_LARGE);
+ return NULL;
+ }
+
+ nread = gpgme_data_read (data, self->buf + self->buflen,
+ MYBUFLEN - self->buflen);
+ if (nread < 0)
+ {
+ *r_err = gpg_error_from_syserror ();
+ return NULL;
+ }
+ self->buflen += nread;
+ }
+ while (nread);
+
+ /* EOF reached. If we have anything in the buffer, append a Nul and
+ return it. */
+ self->eof_seen = 1;
+ if (self->buflen)
+ {
+ self->buf[self->buflen] = 0; /* (we allocated one extra byte) */
+ return self->buf;
+ }
+ return NULL;
+#undef MYBUFLEN
+}
+
+
static gpgme_error_t
gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
engine_gpg_t gpg = engine;
gpgme_error_t err;
int idx;
+ gpgme_data_encoding_t dataenc;
if (keydata && keyarray)
gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
+ dataenc = gpgme_data_get_encoding (keydata);
+
if (keyarray)
{
err = add_arg (gpg, "--recv-keys");
err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
}
}
+ else if (dataenc == GPGME_DATA_ENCODING_URL
+ || dataenc == GPGME_DATA_ENCODING_URL0)
+ {
+ void *helpptr;
+ const char *string;
+ gpgme_error_t xerr;
+ int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
+
+ /* FIXME: --fetch-keys is probably not correct because it can't
+ grok all kinds of URLs. On Unix it should just work but on
+ Windows we will build the command line and that may fail for
+ some embedded control characters. It is anyway limited to
+ the maximum size of the command line. We need another
+ command which can take its input from a file. Maybe we
+ should use an option to gpg to modify such commands (ala
+ --multifile). */
+ err = add_arg (gpg, "--fetch-keys");
+ if (!err)
+ err = add_arg (gpg, "--");
+ helpptr = NULL;
+ while (!err
+ && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
+ err = add_arg (gpg, string);
+ if (!err)
+ err = xerr;
+ string_from_data (NULL, delim, &helpptr, &xerr);
+ }
+ else if (dataenc == GPGME_DATA_ENCODING_URLESC)
+ {
+ /* Already escaped URLs are not yet supported. */
+ err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ }
else
{
err = add_arg (gpg, "--import");
GPGME_DATA_ENCODING_NONE = 0, /* Not specified. */
GPGME_DATA_ENCODING_BINARY = 1,
GPGME_DATA_ENCODING_BASE64 = 2,
- GPGME_DATA_ENCODING_ARMOR = 3 /* Either PEM or OpenPGP Armor. */
+ GPGME_DATA_ENCODING_ARMOR = 3, /* Either PEM or OpenPGP Armor. */
+ GPGME_DATA_ENCODING_URL = 4, /* LF delimited URL list. */
+ GPGME_DATA_ENCODING_URLESC = 5, /* Ditto, but percent escaped. */
+ GPGME_DATA_ENCODING_URL0 = 6 /* Nul delimited URL list. */
}
gpgme_data_encoding_t;
#if HAVE_CONFIG_H
#include <config.h>
#endif
+#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
2009-06-16 Werner Koch <wk@g10code.com>
+ * gpg/pgp-import.c: New.
+ * gpg/t-support.h (print_import_result, nonnull): Factored out
+ from other tools.
+
* gpg/pgp-export.c, gpg/pgp-keylist.c: New.
2009-06-09 Werner Koch <wk@g10code.com>
# We don't run t-genkey in the test suite, because it takes too long
# The other programs are used for debugging.
-noinst_PROGRAMS = $(TESTS) t-genkey pgp-keylist pgp-export
+noinst_PROGRAMS = $(TESTS) t-genkey pgp-keylist pgp-export pgp-import
mkdemodirs: mkdemodirs.in Makefile
sed -e 's,[@]GPG[@],$(GPG),g' < $(srcdir)/mkdemodirs.in > mkdemodirs
static int verbose;
-static const char *
-nonnull (const char *s)
-{
- return s? s :"[none]";
-}
-
-
static int
show_usage (int ex)
{
--- /dev/null
+/* pgp-import.c - Helper to run an import command
+ Copyright (C) 2008, 2009 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 Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* We need to include config.h so that we know whether we are building
+ with large file system (LFS) support. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#define PGM "pgp-import"
+
+#include "t-support.h"
+
+
+static int verbose;
+
+
+static int
+show_usage (int ex)
+{
+ fputs ("usage: " PGM " [options] FILENAMEs\n\n"
+ "Options:\n"
+ " --verbose run in verbose mode\n"
+ " --url import from given URLs\n"
+ " -0 URLs are delimited by a nul\n"
+ , stderr);
+ exit (ex);
+}
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ gpgme_error_t err;
+ gpgme_ctx_t ctx;
+ int url_mode = 0;
+ int nul_mode = 0;
+ gpgme_import_result_t impres;
+ gpgme_data_t data;
+
+ if (argc)
+ { argc--; argv++; }
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ show_usage (0);
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--url"))
+ {
+ url_mode = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "-0"))
+ {
+ nul_mode = 1;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ show_usage (1);
+
+ }
+
+ if (!argc)
+ show_usage (1);
+
+ init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+ err = gpgme_new (&ctx);
+ fail_if_err (err);
+ gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+
+ for (; argc; argc--, argv++)
+ {
+ printf ("reading file `%s'\n", *argv);
+ err = gpgme_data_new_from_file (&data, *argv, 1);
+ fail_if_err (err);
+
+ if (url_mode)
+ gpgme_data_set_encoding (data, (nul_mode? GPGME_DATA_ENCODING_URL0
+ : GPGME_DATA_ENCODING_URL));
+
+ err = gpgme_op_import (ctx, data);
+ fail_if_err (err);
+ impres = gpgme_op_import_result (ctx);
+ if (!impres)
+ {
+ fprintf (stderr, PGM ": no import result returned\n");
+ exit (1);
+ }
+ print_import_result (impres);
+
+ gpgme_data_release (data);
+ }
+
+ gpgme_release (ctx);
+ return 0;
+}
static int verbose;
-static const char *
-nonnull (const char *s)
-{
- return s? s :"[none]";
-}
-
-
-static void
-print_import_result (gpgme_import_result_t r)
-{
- gpgme_import_status_t st;
-
- printf ("key import results:\n"
- " considered: %d\n"
- " no user id: %d\n"
- " imported: %d\n"
- " imported_rsa: %d\n"
- " unchanged: %d\n"
- " new user ids: %d\n"
- " new subkeys: %d\n"
- " new signatures: %d\n"
- " new revocations: %d\n"
- " secret read: %d\n"
- " secret imported: %d\n"
- " secret unchanged: %d\n"
- " skipped new keys: %d\n"
- " not imported: %d\n",
- r->considered,
- r->no_user_id,
- r->imported,
- r->imported_rsa,
- r->unchanged,
- r->new_user_ids,
- r->new_sub_keys,
- r->new_signatures,
- r->new_revocations,
- r->secret_read,
- r->secret_imported,
- r->secret_unchanged,
- r->skipped_new_keys,
- r->not_imported);
-
- for (st=r->imports; st; st = st->next)
- {
- printf (" fpr: %s err: %d (%s) status:", nonnull (st->fpr),
- st->result, gpg_strerror (st->result));
- if (st->status & GPGME_IMPORT_NEW)
- fputs (" new", stdout);
- if (st->status & GPGME_IMPORT_UID)
- fputs (" uid", stdout);
- if (st->status & GPGME_IMPORT_SIG)
- fputs (" sig", stdout);
- if (st->status & GPGME_IMPORT_SUBKEY)
- fputs (" subkey", stdout);
- if (st->status & GPGME_IMPORT_SECRET)
- fputs (" secret", stdout);
- putchar ('\n');
- }
-}
-
-
static int
show_usage (int ex)
{
while (0)
+static const char *
+nonnull (const char *s)
+{
+ return s? s :"[none]";
+}
+
+
void
print_data (gpgme_data_t dh)
{
err = gpgme_engine_check_version (proto);
fail_if_err (err);
}
+
+
+void
+print_import_result (gpgme_import_result_t r)
+{
+ gpgme_import_status_t st;
+
+ for (st=r->imports; st; st = st->next)
+ {
+ printf (" fpr: %s err: %d (%s) status:", nonnull (st->fpr),
+ st->result, gpg_strerror (st->result));
+ if (st->status & GPGME_IMPORT_NEW)
+ fputs (" new", stdout);
+ if (st->status & GPGME_IMPORT_UID)
+ fputs (" uid", stdout);
+ if (st->status & GPGME_IMPORT_SIG)
+ fputs (" sig", stdout);
+ if (st->status & GPGME_IMPORT_SUBKEY)
+ fputs (" subkey", stdout);
+ if (st->status & GPGME_IMPORT_SECRET)
+ fputs (" secret", stdout);
+ putchar ('\n');
+ }
+ printf ("key import summary:\n"
+ " considered: %d\n"
+ " no user id: %d\n"
+ " imported: %d\n"
+ " imported_rsa: %d\n"
+ " unchanged: %d\n"
+ " new user ids: %d\n"
+ " new subkeys: %d\n"
+ " new signatures: %d\n"
+ " new revocations: %d\n"
+ " secret read: %d\n"
+ " secret imported: %d\n"
+ " secret unchanged: %d\n"
+ " skipped new keys: %d\n"
+ " not imported: %d\n",
+ r->considered,
+ r->no_user_id,
+ r->imported,
+ r->imported_rsa,
+ r->unchanged,
+ r->new_user_ids,
+ r->new_sub_keys,
+ r->new_signatures,
+ r->new_revocations,
+ r->secret_read,
+ r->secret_imported,
+ r->secret_unchanged,
+ r->skipped_new_keys,
+ r->not_imported);
+}
+