w32: Remove all support for WindowsCE
[gpgme.git] / src / keylist.c
index 8a0c5a3..6fe256c 100644 (file)
@@ -16,7 +16,7 @@
    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/>.
+   License along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #if HAVE_CONFIG_H
@@ -54,6 +54,9 @@ typedef struct
 {
   struct _gpgme_op_keylist_result result;
 
+  /* The error code from ERROR keydb_search. */
+  gpgme_error_t keydb_search_err;
+
   gpgme_key_t tmp_key;
 
   /* This points to the last uid in tmp_key.  */
@@ -135,10 +138,17 @@ keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
       opd->result.truncated = 1;
       break;
 
+    case GPGME_STATUS_ERROR:
+      err = _gpgme_parse_failure (args);
+      if (!opd->keydb_search_err && !strcmp (args, "keydb_search"))
+        opd->keydb_search_err = err;
+      err = 0;
+      break;
+
     default:
       break;
     }
-  return 0;
+  return err;
 }
 
 \f
@@ -366,6 +376,25 @@ set_ownertrust (gpgme_key_t key, const char *src)
 }
 
 
+static gpgme_keyorg_t
+parse_keyorg (const char *string)
+{
+  switch (atoi (string))
+    {
+    case 0: return GPGME_KEYORG_UNKNOWN;
+    case 1:
+    case 2:
+      return GPGME_KEYORG_KS;
+    case 3: return GPGME_KEYORG_DANE;
+    case 4: return GPGME_KEYORG_WKD;
+    case 5: return GPGME_KEYORG_URL;
+    case 6: return GPGME_KEYORG_FILE;
+    case 7: return GPGME_KEYORG_SELF;
+    default: return GPGME_KEYORG_OTHER;
+    }
+}
+
+
 /* Parse field 15 of a secret key or subkey.  This fields holds a
    reference to smartcards.  FIELD is the content of the field and we
    are allowed to modify it.  */
@@ -525,7 +554,7 @@ keylist_colon_handler (void *priv, char *line)
       RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
     }
   rectype = RT_NONE;
-#define NR_FIELDS 17
+#define NR_FIELDS 20
   char *field[NR_FIELDS];
   int fields = 0;
   void *hook;
@@ -702,6 +731,16 @@ keylist_colon_handler (void *priv, char *line)
             return gpg_error_from_syserror ();
         }
 
+      /* Field 18 has the compliance flags.  */
+      if (fields >= 17 && *field[17])
+        PARSE_COMPLIANCE_FLAGS (field[17], subkey);
+
+      if (fields >= 20)
+        {
+          key->last_update = _gpgme_parse_timestamp_ul (field[18]);
+          key->origin = parse_keyorg (field[19]);
+        }
+
       break;
 
     case RT_SUB:
@@ -775,6 +814,10 @@ keylist_colon_handler (void *priv, char *line)
             return gpg_error_from_syserror ();
         }
 
+      /* Field 18 has the compliance flags.  */
+      if (fields >= 17 && *field[17])
+        PARSE_COMPLIANCE_FLAGS (field[17], subkey);
+
       break;
 
     case RT_UID:
@@ -783,12 +826,15 @@ keylist_colon_handler (void *priv, char *line)
        {
          if (_gpgme_key_append_name (key, field[9], 1))
            return gpg_error (GPG_ERR_ENOMEM);  /* FIXME */
-         else
-           {
-             if (field[1])
-               set_userid_flags (key, field[1]);
-             opd->tmp_uid = key->_last_uid;
-           }
+
+          if (field[1])
+            set_userid_flags (key, field[1]);
+          opd->tmp_uid = key->_last_uid;
+          if (fields >= 20)
+            {
+              opd->tmp_uid->last_update = _gpgme_parse_timestamp_ul (field[18]);
+              opd->tmp_uid->origin = parse_keyorg (field[19]);
+            }
        }
       break;
 
@@ -1107,6 +1153,42 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
 }
 
 
+/* Start a keylist operation within CTX to show keys contained
+ * in DATA.  */
+gpgme_error_t
+gpgme_op_keylist_from_data_start (gpgme_ctx_t ctx, gpgme_data_t data,
+                                  int reserved)
+{
+  gpgme_error_t err;
+  void *hook;
+  op_data_t opd;
+
+  TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_from_data_start", ctx);
+
+  if (!ctx || !data || reserved)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = _gpgme_op_reset (ctx, 2);
+  if (err)
+    return TRACE_ERR (err);
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
+                               sizeof (*opd), release_op_data);
+  opd = hook;
+  if (err)
+    return TRACE_ERR (err);
+
+  _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
+  err = _gpgme_engine_set_colon_line_handler (ctx->engine,
+                                              keylist_colon_handler, ctx);
+  if (err)
+    return TRACE_ERR (err);
+
+  err = _gpgme_engine_op_keylist_data (ctx->engine, data);
+  return TRACE_ERR (err);
+}
+
+
 /* Return the next key from the keylist in R_KEY.  */
 gpgme_error_t
 gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
@@ -1138,7 +1220,8 @@ gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
        return TRACE_ERR (err);
 
       if (!opd->key_cond)
-       return TRACE_ERR (gpg_error (GPG_ERR_EOF));
+       return TRACE_ERR (opd->keydb_search_err? opd->keydb_search_err
+                          /**/                 : gpg_error (GPG_ERR_EOF));
 
       opd->key_cond = 0;
       assert (opd->key_queue);
@@ -1178,11 +1261,14 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
 {
   gpgme_ctx_t listctx;
   gpgme_error_t err;
-  gpgme_key_t key;
+  gpgme_key_t result, key;
 
   TRACE_BEG2 (DEBUG_CTX, "gpgme_get_key", ctx,
              "fpr=%s, secret=%i", fpr, secret);
 
+  if (r_key)
+    *r_key = NULL;
+
   if (!ctx || !r_key || !fpr)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
@@ -1212,7 +1298,7 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
 
   err = gpgme_op_keylist_start (listctx, fpr, secret);
   if (!err)
-    err = gpgme_op_keylist_next (listctx, r_key);
+    err = gpgme_op_keylist_next (listctx, &result);
   if (!err)
     {
     try_next_key:
@@ -1222,9 +1308,9 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
       else
        {
           if (!err
-              && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
+              && result && result->subkeys && result->subkeys->fpr
               && key && key->subkeys && key->subkeys->fpr
-              && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
+              && !strcmp (result->subkeys->fpr, key->subkeys->fpr))
             {
               /* The fingerprint is identical.  We assume that this is
                  the same key and don't mark it as an ambiguous.  This
@@ -1240,12 +1326,14 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
              gpgme_key_unref (key);
              err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
            }
-         gpgme_key_unref (*r_key);
+         gpgme_key_unref (result);
+          result = NULL;
        }
     }
   gpgme_release (listctx);
   if (! err)
     {
+      *r_key = result;
       TRACE_LOG2 ("key=%p (%s)", *r_key,
                  ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
                  (*r_key)->subkeys->fpr : "invalid");