2006-02-22 Marcus Brinkmann <marcus@g10code.de>

* rungpg.c (read_colon_line): Invoke colon preprocess handler if
	it is set.
	(colon_preprocessor_t): New type.
	(struct engine_gpg): New member colon.preprocess_fnc.
	(gpg_keylist_preprocess): New function.
	* keylist.c (keylist_colon_handler): Allow short key IDs.
This commit is contained in:
Marcus Brinkmann 2006-02-22 11:02:50 +00:00
parent 9829cffc3c
commit 2f4b385332
4 changed files with 141 additions and 13 deletions

5
TODO
View File

@ -5,9 +5,6 @@ Hey Emacs, this is -*- outline -*- mode!
The test is currently disabled there and in gpg/t-import. The test is currently disabled there and in gpg/t-import.
** When gpg supports it, write binary subpackets directly, ** When gpg supports it, write binary subpackets directly,
and parse SUBPACKET status lines. and parse SUBPACKET status lines.
** External key listing for OpenPGP.
This probably requires changes at gpg.
* ABI's to break: * ABI's to break:
** gpgme_edit_cb_t: Add "processed" return argument ** gpgme_edit_cb_t: Add "processed" return argument
@ -81,7 +78,7 @@ Hey Emacs, this is -*- outline -*- mode!
release everything properly at a reset and at an error. Think hard release everything properly at a reset and at an error. Think hard
about where to guarantee what (ie, what happens if start fails, are about where to guarantee what (ie, what happens if start fails, are
the fds unregistered immediately - i think so?) the fds unregistered immediately - i think so?)
** Optimize the case where a data object has an underlying fd we can pass ** Optimize the case where a data object has 0an underlying fd we can pass
directly to the engine. This will be automatic with socket I/O and directly to the engine. This will be automatic with socket I/O and
descriptor passing. descriptor passing.
** Move code common to all engines up from gpg to engine. ** Move code common to all engines up from gpg to engine.

View File

@ -1,3 +1,12 @@
2006-02-22 Marcus Brinkmann <marcus@g10code.de>
* rungpg.c (read_colon_line): Invoke colon preprocess handler if
it is set.
(colon_preprocessor_t): New type.
(struct engine_gpg): New member colon.preprocess_fnc.
(gpg_keylist_preprocess): New function.
* keylist.c (keylist_colon_handler): Allow short key IDs.
2006-02-15 Marcus Brinkmann <marcus@g10code.de> 2006-02-15 Marcus Brinkmann <marcus@g10code.de>
* w32-io.c (create_writer): Make C->have_data a manually resetted * w32-io.c (create_writer): Make C->have_data a manually resetted

View File

@ -176,7 +176,8 @@ set_mainkey_trust_info (gpgme_key_t key, const char *src)
case 'd': case 'd':
/* Note that gpg 1.3 won't print that anymore but only uses /* Note that gpg 1.3 won't print that anymore but only uses
the capabilities field. */ the capabilities field. However, it is still used for
external key listings. */
key->disabled = 1; key->disabled = 1;
break; break;
@ -493,8 +494,9 @@ keylist_colon_handler (void *priv, char *line)
subkey->pubkey_algo = i; subkey->pubkey_algo = i;
} }
/* Field 5 has the long keyid. */ /* Field 5 has the long keyid. Allow short key IDs for the
if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1) output of an external keyserver listing. */
if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1)
strcpy (subkey->_keyid, field[4]); strcpy (subkey->_keyid, field[4]);
/* Field 6 has the timestamp (seconds). */ /* Field 6 has the timestamp (seconds). */

View File

@ -65,6 +65,8 @@ struct fd_data_map_s
}; };
typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
struct engine_gpg struct engine_gpg
{ {
char *file_name; char *file_name;
@ -95,6 +97,7 @@ struct engine_gpg
engine_colon_line_handler_t fnc; /* this indicate use of this structrue */ engine_colon_line_handler_t fnc; /* this indicate use of this structrue */
void *fnc_value; void *fnc_value;
void *tag; void *tag;
colon_preprocessor_t preprocess_fnc;
} colon; } colon;
char **argv; char **argv;
@ -1013,14 +1016,27 @@ read_colon_line (engine_gpg_t gpg)
{ {
/* (we require that the last line is terminated by a LF) /* (we require that the last line is terminated by a LF)
and we skip empty lines. Note: we use UTF8 encoding and we skip empty lines. Note: we use UTF8 encoding
and escaping of special characters We require at and escaping of special characters. We require at
least one colon to cope with some other printed least one colon to cope with some other printed
information. */ information. */
*p = 0; *p = 0;
if (*buffer && strchr (buffer, ':')) if (*buffer && strchr (buffer, ':'))
{ {
char *line = NULL;
if (gpg->colon.preprocess_fnc)
{
gpgme_error_t err;
err = gpg->colon.preprocess_fnc (buffer, &line);
if (err)
return err;
}
assert (gpg->colon.fnc); assert (gpg->colon.fnc);
gpg->colon.fnc (gpg->colon.fnc_value, buffer); gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer);
if (line)
free (line);
} }
/* To reuse the buffer for the next line we have to /* To reuse the buffer for the next line we have to
@ -1613,6 +1629,93 @@ gpg_import (void *engine, gpgme_data_t keydata)
} }
/* The output for external keylistings in GnuPG is different from all
the other key listings. We catch this here with a special
preprocessor that reformats the colon handler lines. */
static gpgme_error_t
gpg_keylist_preprocess (char *line, char **r_line)
{
enum
{
RT_NONE, RT_INFO, RT_PUB, RT_UID
}
rectype = RT_NONE;
#define NR_FIELDS 16
char *field[NR_FIELDS];
int fields = 0;
*r_line = NULL;
while (line && fields < NR_FIELDS)
{
field[fields++] = line;
line = strchr (line, ':');
if (line)
*(line++) = '\0';
}
if (!strcmp (field[0], "info"))
rectype = RT_INFO;
else if (!strcmp (field[0], "pub"))
rectype = RT_PUB;
else if (!strcmp (field[0], "uid"))
rectype = RT_UID;
else
rectype = RT_NONE;
switch (rectype)
{
case RT_INFO:
/* FIXME: Eventually, check the version number at least. */
return 0;
case RT_PUB:
if (fields < 7)
return 0;
/* The format is:
pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
as defined in 5.2. Machine Readable Indexes of the OpenPGP
HTTP Keyserver Protocol (draft).
We want:
pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
*/
if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::",
field[6], field[3], field[2], field[1],
field[4], field[5]) < 0)
return gpg_error_from_errno (errno);
return 0;
case RT_UID:
/* The format is:
uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
as defined in 5.2. Machine Readable Indexes of the OpenPGP
HTTP Keyserver Protocol (draft).
We want:
uid:o<flags>::::<creatdate>:<expdate>:::<uid>:
*/
if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
field[4], field[2], field[3], field[1]) < 0)
return gpg_error_from_errno (errno);
return 0;
case RT_NONE:
/* Unknown record. */
break;
}
return 0;
}
static gpgme_error_t static gpgme_error_t
gpg_keylist (void *engine, const char *pattern, int secret_only, gpg_keylist (void *engine, const char *pattern, int secret_only,
gpgme_keylist_mode_t mode) gpgme_keylist_mode_t mode)
@ -1620,6 +1723,13 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
engine_gpg_t gpg = engine; engine_gpg_t gpg = engine;
gpgme_error_t err; gpgme_error_t err;
if (mode & GPGME_KEYLIST_MODE_EXTERN)
{
if ((mode & GPGME_KEYLIST_MODE_LOCAL)
|| secret_only)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
err = add_arg (gpg, "--with-colons"); err = add_arg (gpg, "--with-colons");
if (!err) if (!err)
err = add_arg (gpg, "--fixed-list-mode"); err = add_arg (gpg, "--fixed-list-mode");
@ -1635,9 +1745,19 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
err = add_arg (gpg, "show-sig-subpackets=\"20,26\""); err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
} }
if (!err) if (!err)
{
if (mode & GPGME_KEYLIST_MODE_EXTERN)
{
err = add_arg (gpg, "--search-keys");
gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
}
else
{
err = add_arg (gpg, secret_only ? "--list-secret-keys" err = add_arg (gpg, secret_only ? "--list-secret-keys"
: ((mode & GPGME_KEYLIST_MODE_SIGS) : ((mode & GPGME_KEYLIST_MODE_SIGS)
? "--check-sigs" : "--list-keys")); ? "--check-sigs" : "--list-keys"));
}
}
/* Tell the gpg object about the data. */ /* Tell the gpg object about the data. */
if (!err) if (!err)