Create expando %(<datefmt>) for the classic PGP and GPGME select key
menu in $pgp_entry_format.
Add "expires" to $pgp_sort_keys methods.
Refactor the datetime parser in gnupgparse.c and apply it to both the
creation and expiration dates in the output.
---
crypt-gpgme.c | 37 ++++++++++++++++++--
gnupgparse.c | 96 +++++++++++++++++++++++++++++----------------------
init.h | 3 ++
pgpkey.c | 27 +++++++++++++--
pgplib.h | 1 +
sort.h | 1 +
6 files changed, 118 insertions(+), 47 deletions(-)
diff --git a/crypt-gpgme.c b/crypt-gpgme.c
index f5ee87bd..6badab78 100644
--- a/crypt-gpgme.c
+++ b/crypt-gpgme.c
@@ -3287,12 +3287,14 @@ static const char *crypt_entry_fmt(char *dest,
switch (ascii_tolower(op))
{
case '[':
+ case '(':
{
const char *cp;
char buf2[SHORT_STRING], *p;
int do_locales;
struct tm *tm;
size_t len;
+ int expires = (op == '(');
p = dest;
@@ -3306,7 +3308,7 @@ static const char *crypt_entry_fmt(char *dest,
do_locales = 1;
len = destlen - 1;
- while (len > 0 && *cp != ']')
+ while (len > 0 && *cp != (expires ? ')' : ']'))
{
if (*cp == '%')
{
@@ -3332,7 +3334,9 @@ static const char *crypt_entry_fmt(char *dest,
{
time_t tt = 0;
- if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
+ if (expires && key->kobj->subkeys && (key->kobj->subkeys->expires >
0))
+ tt = key->kobj->subkeys->expires;
+ else if (!expires && key->kobj->subkeys &&
(key->kobj->subkeys->timestamp > 0))
tt = key->kobj->subkeys->timestamp;
tm = localtime(&tt);
@@ -3539,6 +3543,32 @@ static int crypt_compare_date(const void *a, const void
*b)
: _crypt_compare_date(a, b));
}
+/* Compare 2 creation dates and the addresses. For sorting. */
+static int _crypt_compare_expires(const void *a, const void *b)
+{
+ const crypt_key_t * const *s = (const crypt_key_t * const *) a;
+ const crypt_key_t * const *t = (const crypt_key_t * const *) b;
+ unsigned long ts = 0, tt = 0;
+
+ if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->expires > 0))
+ ts = (*s)->kobj->subkeys->expires;
+ if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->expires > 0))
+ tt = (*t)->kobj->subkeys->expires;
+
+ if (ts > tt)
+ return 1;
+ if (ts < tt)
+ return -1;
+
+ return mutt_strcasecmp((*s)->uid, (*t)->uid);
+}
+
+static int crypt_compare_expires(const void *a, const void *b)
+{
+ return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_expires(a, b)
+ : _crypt_compare_expires(a, b));
+}
+
/* Compare two trust values, the key length, the creation dates. the
addresses and the key IDs. For sorting. */
static int _crypt_compare_trust(const void *a, const void *b)
@@ -4539,6 +4569,9 @@ static crypt_key_t *crypt_select_key(crypt_key_t *keys,
case SORT_DATE:
f = crypt_compare_date;
break;
+ case SORT_EXPIRES:
+ f = crypt_compare_expires;
+ break;
case SORT_KEYID:
f = crypt_compare_keyid;
break;
diff --git a/gnupgparse.c b/gnupgparse.c
index 81b25503..f3c3d37c 100644
--- a/gnupgparse.c
+++ b/gnupgparse.c
@@ -116,6 +116,53 @@ static void fix_uid(char *uid)
}
}
+static int parse_timestamp(char *p, time_t *timestamp)
+{
+ if (strchr(p, '-')) /* gpg pre-2.0.10 used format (yyyy-mm-dd) */
+ {
+ char tstr[11];
+ struct tm time;
+
+ time.tm_sec = 0;
+ time.tm_min = 0;
+ time.tm_hour = 12;
+ strncpy(tstr, p, 11);
+ tstr[4] = '\0';
+ tstr[7] = '\0';
+ if (mutt_atoi(tstr, &time.tm_year, 0) < 0)
+ {
+ p = tstr;
+ goto bail;
+ }
+ time.tm_year -= 1900;
+ if (mutt_atoi(tstr+5, &time.tm_mon, 0) < 0)
+ {
+ p = tstr+5;
+ goto bail;
+ }
+ time.tm_mon -= 1;
+ if (mutt_atoi(tstr+8, &time.tm_mday, 0) < 0)
+ {
+ p = tstr+8;
+ goto bail;
+ }
+ *timestamp = mutt_mktime(&time, 0);
+ }
+ else /* gpg 2.0.10+ uses seconds since 1970-01-01 */
+ {
+ unsigned long long secs;
+
+ if (mutt_atoull(p, &secs, MUTT_ATOI_ALLOW_EMPTY) < 0)
+ goto bail;
+ *timestamp = (time_t)secs;
+ }
+
+ return 0;
+
+bail:
+ return -1;
+}
+
static pgp_key_t parse_pub_line(char *buf, int *is_subkey, pgp_key_t k)
{
pgp_uid_t *uid = NULL;
@@ -245,50 +292,15 @@ static pgp_key_t parse_pub_line(char *buf, int
*is_subkey, pgp_key_t k)
}
case 6: /* timestamp (1998-02-28) */
- {
muttdbg(2, "time stamp: %s", p);
-
- if (strchr(p, '-')) /* gpg pre-2.0.10 used format (yyyy-mm-dd) */
- {
- char tstr[11];
- struct tm time;
-
- time.tm_sec = 0;
- time.tm_min = 0;
- time.tm_hour = 12;
- strncpy(tstr, p, 11);
- tstr[4] = '\0';
- tstr[7] = '\0';
- if (mutt_atoi(tstr, &time.tm_year, 0) < 0)
- {
- p = tstr;
- goto bail;
- }
- time.tm_year -= 1900;
- if (mutt_atoi(tstr+5, &time.tm_mon, 0) < 0)
- {
- p = tstr+5;
- goto bail;
- }
- time.tm_mon -= 1;
- if (mutt_atoi(tstr+8, &time.tm_mday, 0) < 0)
- {
- p = tstr+8;
- goto bail;
- }
- tmp.gen_time = mutt_mktime(&time, 0);
- }
- else /* gpg 2.0.10+ uses seconds since 1970-01-01 */
- {
- unsigned long long secs;
-
- if (mutt_atoull(p, &secs, MUTT_ATOI_ALLOW_EMPTY) < 0)
- goto bail;
- tmp.gen_time = (time_t)secs;
- }
+ if (parse_timestamp(p, &tmp.gen_time))
+ goto bail;
break;
- }
- case 7: /* valid for n days */
+
+ case 7: /* expires timestamp */
+ muttdbg(2, "expires time stamp: %s", p);
+ if (parse_timestamp(p, &tmp.exp_time))
+ goto bail;
break;
case 8: /* Local id */
break;
diff --git a/init.h b/init.h
index af684866..087ebfa8 100644
--- a/init.h
+++ b/init.h
@@ -168,6 +168,7 @@ const struct mapping_t SortAliasMethods[] = { /*
DT_SORT_ALIAS */
const struct mapping_t SortKeyMethods[] = { /* DT_SORT_KEYS */
{ "address", SORT_ADDRESS },
{ "date", SORT_DATE },
+ { "expires", SORT_EXPIRES },
{ "keyid", SORT_KEYID },
{ "trust", SORT_TRUST },
{ NULL, 0 }
@@ -2641,6 +2642,7 @@ struct option_t MuttVars[] = {
** .dt %c .dd capabilities
** .dt %t .dd trust/validity of the key-uid association
** .dt %[<s>] .dd date of the key where <s> is an \fCstrftime(3)\fP
expression
+ ** .dt %(<s>) .dd expires date of the key where <s> is an \fCstrftime(3)\fP
expression
** .de
** .pp
** (PGP only)
@@ -2834,6 +2836,7 @@ struct option_t MuttVars[] = {
** .dt address .dd sort alphabetically by user id
** .dt keyid .dd sort alphabetically by key id
** .dt date .dd sort by key creation date
+ ** .dt expires .dd sort by key expiration date
** .dt trust .dd sort by the trust of the key
** .de
** .pp
diff --git a/pgpkey.c b/pgpkey.c
index a6532e4c..06789ea3 100644
--- a/pgpkey.c
+++ b/pgpkey.c
@@ -152,13 +152,14 @@ static const char *pgp_entry_fmt(char *dest,
switch (ascii_tolower(op))
{
case '[':
-
+ case '(':
{
const char *cp;
char buf2[SHORT_STRING], *p;
int do_locales;
struct tm *tm;
size_t len;
+ int expires = (op == '(');
p = dest;
@@ -172,7 +173,7 @@ static const char *pgp_entry_fmt(char *dest,
do_locales = 1;
len = destlen - 1;
- while (len > 0 && *cp != ']')
+ while (len > 0 && *cp != (expires ? ')' : ']'))
{
if (*cp == '%')
{
@@ -196,7 +197,7 @@ static const char *pgp_entry_fmt(char *dest,
*p = 0;
- tm = localtime(&key->gen_time);
+ tm = localtime(expires ? &key->exp_time : &key->gen_time);
if (!do_locales)
setlocale(LC_TIME, "C");
@@ -355,6 +356,23 @@ static int pgp_compare_date(const void *a, const void *b)
: _pgp_compare_date(a, b));
}
+static int _pgp_compare_expires(const void *a, const void *b)
+{
+ int r;
+ const pgp_uid_t * const *s = (const pgp_uid_t * const *) a;
+ const pgp_uid_t * const *t = (const pgp_uid_t * const *) b;
+
+ if ((r = mutt_numeric_cmp((*s)->parent->exp_time, (*t)->parent->exp_time)))
+ return r;
+ return (mutt_strcasecmp((*s)->addr, (*t)->addr));
+}
+
+static int pgp_compare_expires(const void *a, const void *b)
+{
+ return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_expires(a, b)
+ : _pgp_compare_expires(a, b));
+}
+
static int _pgp_compare_trust(const void *a, const void *b)
{
int r;
@@ -502,6 +520,9 @@ static pgp_key_t pgp_select_key(pgp_key_t keys,
case SORT_DATE:
f = pgp_compare_date;
break;
+ case SORT_EXPIRES:
+ f = pgp_compare_expires;
+ break;
case SORT_KEYID:
f = pgp_compare_keyid;
break;
diff --git a/pgplib.h b/pgplib.h
index 4a7fa94e..cccd8d9d 100644
--- a/pgplib.h
+++ b/pgplib.h
@@ -38,6 +38,7 @@ struct pgp_keyinfo
int flags;
short keylen;
time_t gen_time;
+ time_t exp_time;
int numalg;
const char *algorithm;
struct pgp_keyinfo *parent;
diff --git a/sort.h b/sort.h
index 863a6655..9fe1e557 100644
--- a/sort.h
+++ b/sort.h
@@ -37,6 +37,7 @@
#define SORT_LABEL 19
#define SORT_AUX 20 /* $sort_thread_groups delegation to $sort_aux */
#define SORT_UID 21 /* used internally by the IMAP code */
+#define SORT_EXPIRES 22
/* Sort and sort_aux are shorts, and are a composite of a
* constant sort operation number and a set of compounded
--
2.55.0