From ce1d166ef700a188dcaf1b616f39f6c5750e4e9d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 8 Dec 2010 09:55:00 +0000 Subject: [PATCH] Allow multiple patterns for KEYLIST. --- src/ChangeLog | 6 +++++ src/gpgme-tool.c | 65 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index f718502a..f891d980 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2010-12-08 Werner Koch + + * gpgme-tool.c (strcpy_escaped_plus): New. + (DIM, xtoi_1, xtoi_2): New. + (cmd_keylist): Allow for multiple patterns. + 2010-11-23 Marcus Brinkmann * w32-io.c (create_reader, create_writer): Use small stack size on diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index 068681f6..e424c381 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -52,6 +52,10 @@ # define GT_GCC_A_PRINTF(f, a) #endif +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) @@ -506,6 +510,28 @@ log_error (int status, gpg_error_t errnum, const char *fmt, ...) } +/* Note that it is sufficient to allocate the target string D as long + as the source string S, i.e.: strlen(s)+1;. D == S is allowed. */ +static void +strcpy_escaped_plus (char *d, const char *s) +{ + while (*s) + { + if (*s == '%' && s[1] && s[2]) + { + s++; + *d++ = xtoi_2 (s); + s += 2; + } + else if (*s == '+') + *d++ = ' ', s++; + else + *d++ = *s++; + } + *d = 0; +} + + /* Check whether the option NAME appears in LINE. */ static int has_option (const char *line, const char *name) @@ -2671,14 +2697,22 @@ cmd_delete (assuan_context_t ctx, char *line) } +static const char hlp_keylist[] = + "KEYLIST [--secret-only] []\n" + "\n" + "List all certificates or only those specified by PATTERNS. Each\n" + "pattern shall be a percent-plus escaped certificate specification."; static gpg_error_t cmd_keylist (assuan_context_t ctx, char *line) { +#define MAX_CMD_KEYLIST_PATTERN 20 struct server *server = assuan_get_pointer (ctx); gpg_error_t err; int secret_only = 0; - const char *pattern[2]; + int idx; + const char *pattern[MAX_CMD_KEYLIST_PATTERN+1]; const char optstr[] = "--secret-only"; + char *p; if (!strncasecmp (line, optstr, strlen (optstr))) { @@ -2687,8 +2721,23 @@ cmd_keylist (assuan_context_t ctx, char *line) while (*line && !spacep (line)) line++; } - pattern[0] = line; - pattern[1] = NULL; + + idx = 0; + for (p=line; *p; line = p) + { + while (*p && *p != ' ') + p++; + if (*p) + *p++ = 0; + if (*line) + { + if (idx+1 == DIM (pattern)) + return gpg_error (GPG_ERR_TOO_MANY); + strcpy_escaped_plus (line, line); + pattern[idx++] = line; + } + } + pattern[idx] = NULL; err = gt_keylist_start (server->gt, pattern, secret_only); while (! err) @@ -2706,7 +2755,11 @@ cmd_keylist (assuan_context_t ctx, char *line) char buf[100]; /* FIXME: More data. */ snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr); - assuan_send_data (ctx, buf, strlen (buf)); + /* Write data and flush so that we see one D line for each + key. This does not change the semantics but is easier to + read by organic eyes. */ + if (!assuan_send_data (ctx, buf, strlen (buf))) + assuan_send_data (ctx, NULL, 0); gpgme_key_unref (key); } } @@ -2895,8 +2948,8 @@ register_commands (assuan_context_t ctx) { "GENKEY", cmd_genkey }, { "DELETE", cmd_delete }, /* TODO: EDIT, CARD_EDIT (with INQUIRE) */ - { "KEYLIST", cmd_keylist }, - { "LISTKEYS", cmd_keylist }, + { "KEYLIST", cmd_keylist, hlp_keylist }, + { "LISTKEYS", cmd_keylist, hlp_keylist }, /* TODO: TRUSTLIST, TRUSTLIST_EXT */ { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog }, /* TODO: ASSUAN */