(prepare_new_sig, _gpgme_verify_status_handler): Remove
[gpgme.git] / gpgme / verify.c
index a63a564..c695b9e 100644 (file)
@@ -38,6 +38,7 @@ typedef struct
 
   gpgme_signature_t current_sig;
   int did_prepare_new_sig;
+  int only_newsig_seen;
 } *op_data_t;
 
 
@@ -151,16 +152,29 @@ static gpgme_error_t
 prepare_new_sig (op_data_t opd)
 {
   gpgme_signature_t sig;
-  
-  sig = calloc (1, sizeof (*sig));
-  if (!sig)
-    return gpg_error_from_errno (errno);
-  if (!opd->result.signatures)
-    opd->result.signatures = sig;
-  if (opd->current_sig)
-    opd->current_sig->next = sig;
-  opd->current_sig = sig;
+
+  if (opd->only_newsig_seen && opd->current_sig)
+    {
+      /* We have only seen the NEWSIG status and nothing else - we
+         better skip this signature therefore and reuse it for the
+         next possible signature. */
+      sig = opd->current_sig;
+      memset (sig, 0, sizeof *sig);
+      assert (opd->result.signatures == sig);
+    }
+  else
+    {
+      sig = calloc (1, sizeof (*sig));
+      if (!sig)
+        return gpg_error_from_errno (errno);
+      if (!opd->result.signatures)
+        opd->result.signatures = sig;
+      if (opd->current_sig)
+        opd->current_sig->next = sig;
+      opd->current_sig = sig;
+    }
   opd->did_prepare_new_sig = 1;
+  opd->only_newsig_seen = 0;
   return 0;
 }
 
@@ -508,7 +522,9 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_NEWSIG:
       if (sig)
         calc_sig_summary (sig);
-      return prepare_new_sig (opd);
+      err = prepare_new_sig (opd);
+      opd->only_newsig_seen = 1;
+      return err;
 
     case GPGME_STATUS_GOODSIG:
     case GPGME_STATUS_EXPSIG:
@@ -517,19 +533,23 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_ERRSIG:
       if (sig && !opd->did_prepare_new_sig)
        calc_sig_summary (sig);
+      opd->only_newsig_seen = 0;
       return parse_new_sig (opd, code, args);
 
     case GPGME_STATUS_VALIDSIG:
+      opd->only_newsig_seen = 0;
       return sig ? parse_valid_sig (sig, args)
        : gpg_error (GPG_ERR_INV_ENGINE);
 
     case GPGME_STATUS_NODATA:
+      opd->only_newsig_seen = 0;
       if (!sig)
        return gpg_error (GPG_ERR_NO_DATA);
       sig->status = gpg_error (GPG_ERR_NO_DATA);
       break;
 
     case GPGME_STATUS_UNEXPECTED:
+      opd->only_newsig_seen = 0;
       if (!sig)
        return gpg_error (GPG_ERR_GENERAL);
       sig->status = gpg_error (GPG_ERR_NO_DATA);
@@ -538,6 +558,7 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_NOTATION_NAME:
     case GPGME_STATUS_NOTATION_DATA:
     case GPGME_STATUS_POLICY_URL:
+      opd->only_newsig_seen = 0;
       return sig ? parse_notation (sig, code, args)
        : gpg_error (GPG_ERR_INV_ENGINE);
 
@@ -546,10 +567,12 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_TRUST_MARGINAL:
     case GPGME_STATUS_TRUST_FULLY:
     case GPGME_STATUS_TRUST_ULTIMATE:
+      opd->only_newsig_seen = 0;
       return sig ? parse_trust (sig, code, args)
        : gpg_error (GPG_ERR_INV_ENGINE);
 
     case GPGME_STATUS_ERROR:
+      opd->only_newsig_seen = 0;
       /* The error status is informational, so we don't return an
          error code if we are not ready to process this status. */
       return sig ? parse_error (sig, args) : 0;
@@ -557,6 +580,29 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_EOF:
       if (sig && !opd->did_prepare_new_sig)
        calc_sig_summary (sig);
+      if (opd->only_newsig_seen && sig)
+        {
+          gpgme_signature_t sig2;
+          /* The last signature has no valid information - remove it
+             from the list. */
+          assert (!sig->next);
+          if (sig == opd->result.signatures)
+            opd->result.signatures = NULL;
+          else
+            {
+              for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
+                if (sig2->next == sig)
+                  {
+                    sig2->next = NULL;
+                    break;
+                  }
+            }
+          /* Note that there is no need to release the members of SIG
+             because we won't be here if they have been set. */
+          free (sig);
+          opd->current_sig = NULL;
+        }
+      opd->only_newsig_seen = 0;
       break;
 
     default: