gpg: Auto-migrate existing secring.gpg.
[gnupg.git] / tools / gpgparsemail.c
index 30759f9..a8b3dc7 100644 (file)
@@ -1,11 +1,11 @@
 /* gpgparsemail.c - Standalone crypto mail parser
- *     Copyright (C) 2004 Free Software Foundation, Inc.
+ *     Copyright (C) 2004, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,9 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 
@@ -66,7 +64,9 @@ struct parse_info_s {
 
   int is_pkcs7;                /* Old style S/MIME message. */
 
-  int gpgsm_mime;              /* gpgsm shall be used from S/MIME. */
+  int moss_state;              /* State of PGP/MIME or S/MIME parsing.  */
+  int is_smime;                /* This is S/MIME and not PGP/MIME. */
+
   char *signing_protocol;
   int hashing_level;           /* The nesting level we are hashing. */
   int hashing;                 
@@ -169,7 +169,6 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
   int i, c, is_status;
   unsigned int pos;
   char status_buf[10];
-  const char *cmd = smime? "gpgsm":"gpg";
   FILE *fp;
 
   if (pipe (rp) == -1)
@@ -200,7 +199,7 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
       /* Send stdout to the bit bucket. */
       fd = open ("/dev/null", O_WRONLY);
       if (fd == -1)
-        die ("can't open `/dev/null': %s", strerror (errno));
+        die ("can't open '/dev/null': %s", strerror (errno));
       if (fd != 1)
        {
           if (dup2 (fd, 1) == -1)
@@ -220,15 +219,25 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
           close (fd);
       errno = 0;
 
-      execlp (cmd, cmd,
-              "--enable-special-filenames",
-              "--status-fd", "2",
-              "--assume-base64",
-              "--verify",
-              "--",
-              "-", data_fd == -1? NULL : data_fd_buf,
-              NULL);
-
+      if (smime)
+        execlp ("gpgsm", "gpgsm",
+                "--enable-special-filenames",
+                "--status-fd", "2",
+                "--assume-base64",
+                "--verify",
+                "--",
+                "-", data_fd == -1? NULL : data_fd_buf,
+                NULL);
+      else
+        execlp ("gpg", "gpg",
+                "--enable-special-filenames",
+                "--status-fd", "2",
+                "--verify",
+                "--debug=512",
+                "--",
+                "-", data_fd == -1? NULL : data_fd_buf,
+                NULL);
+      
       die ("failed to exec the crypto command: %s", strerror (errno));
     }
 
@@ -325,7 +334,7 @@ verify_signature (struct parse_info_s *info)
 /*   rewind (info->sig_file); */
 
   close_list[0] = -1;
-  run_gnupg (1, fileno (info->sig_file),
+  run_gnupg (info->is_smime, fileno (info->sig_file),
              info->hash_file ? fileno (info->hash_file) : -1, close_list);
 }
 
@@ -340,18 +349,34 @@ mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg,
                    rfc822parse_field_t field_ctx)
 {
   const char *s;
+
+  (void)msg;
+
   s = rfc822parse_query_parameter (field_ctx, "protocol", 1);
   if (s)
     {
       printf ("h signed.protocol: %s\n", s);
-      if (!strcmp (s, "application/pkcs7-signature")
-          || !strcmp (s, "application/x-pkcs7-signature"))
+      if (!strcmp (s, "application/pgp-signature"))
+        {
+          if (info->moss_state)
+            err ("note: ignoring nested PGP/MIME or S/MIME signature");
+          else
+            {
+              info->moss_state = 1;
+              info->is_smime = 0;
+              free (info->signing_protocol);
+              info->signing_protocol = xstrdup (s);
+            }
+        }
+      else if (!strcmp (s, "application/pkcs7-signature")
+               || !strcmp (s, "application/x-pkcs7-signature"))
         {
-          if (info->gpgsm_mime)
-            err ("note: ignoring nested pkcs7-signature");
+          if (info->moss_state)
+            err ("note: ignoring nested PGP/MIME or S/MIME signature");
           else
             {
-              info->gpgsm_mime = 1;
+              info->moss_state = 1;
+              info->is_smime = 1;
               free (info->signing_protocol);
               info->signing_protocol = xstrdup (s);
             }
@@ -369,6 +394,10 @@ mime_encrypted_begin (struct parse_info_s *info, rfc822parse_t msg,
                       rfc822parse_field_t field_ctx)
 {
   const char *s;
+
+  (void)info;
+  (void)msg;
+
   s = rfc822parse_query_parameter (field_ctx, "protocol", 0);
   if (s)
     printf ("h encrypted.protocol: %s\n", s);
@@ -381,6 +410,9 @@ pkcs7_begin (struct parse_info_s *info, rfc822parse_t msg,
              rfc822parse_field_t field_ctx)
 {
   const char *s;
+  
+  (void)msg;
+
   s = rfc822parse_query_parameter (field_ctx, "name", 0);
   if (s)
     printf ("h pkcs7.name: %s\n", s);
@@ -437,6 +469,30 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
 
   if (debug)
     show_event (event);
+
+  if (event == RFC822PARSE_BEGIN_HEADER || event == RFC822PARSE_T2BODY)
+    {
+      /* We need to check here whether to start collecting signed data
+         because attachments might come without header lines and thus
+         we won't see the BEGIN_HEADER event.  */
+      if (info->moss_state == 1)
+        {
+          printf ("c begin_hash\n");
+          info->hashing = 1;
+          info->hashing_level = info->nesting_level;
+          info->moss_state++;
+
+          if (opt_crypto)
+            {
+              assert (!info->hash_file);
+              info->hash_file = tmpfile ();
+              if (!info->hash_file)
+                die ("failed to create temporary file: %s", strerror (errno));
+            }
+        }
+    }
+
+
   if (event == RFC822PARSE_OPEN)
     {
       /* Initialize for a new message. */
@@ -455,18 +511,19 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
             {
               printf ("h media: %*s%s %s\n", 
                       info->nesting_level*2, "", s1, s2);
-              if (info->gpgsm_mime == 3)
+              if (info->moss_state == 3)
                 {
                   char *buf = xmalloc (strlen (s1) + strlen (s2) + 2);
                   strcpy (stpcpy (stpcpy (buf, s1), "/"), s2);
                   assert (info->signing_protocol);
                   if (strcmp (buf, info->signing_protocol))
-                    err ("invalid S/MIME structure; expected `%s', found `%s'",
+                    err ("invalid %s structure; expected '%s', found '%s'",
+                         info->is_smime? "S/MIME":"PGP/MIME",
                          info->signing_protocol, buf);
                   else
                     {
                       printf ("c begin_signature\n");
-                      info->gpgsm_mime++;
+                      info->moss_state++;
                       if (opt_crypto)
                         {
                           assert (!info->sig_file);
@@ -492,12 +549,14 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
             }
           else
             printf ("h media: %*s none\n", info->nesting_level*2, "");
-
+              
           rfc822parse_release_field (ctx);
         }
       else
         printf ("h media: %*stext plain [assumed]\n",
                 info->nesting_level*2, "");
+
+
       info->show_header = 0;
       info->show_data = 1;
       info->skip_show = 1;
@@ -530,36 +589,18 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
       else 
         printf ("b last\n");
 
-      if (info->gpgsm_mime == 2 && info->nesting_level == info->hashing_level)
+      if (info->moss_state == 2 && info->nesting_level == info->hashing_level)
         {
           printf ("c end_hash\n");
-          info->gpgsm_mime++;
+          info->moss_state++;
           info->hashing = 0;
         }
-      else if (info->gpgsm_mime == 4)
+      else if (info->moss_state == 4)
         {
           printf ("c end_signature\n");
           info->verify_now = 1;
         }
     }
-  else if (event == RFC822PARSE_BEGIN_HEADER)
-    {
-      if (info->gpgsm_mime == 1)
-        {
-          printf ("c begin_hash\n");
-          info->hashing = 1;
-          info->hashing_level = info->nesting_level;
-          info->gpgsm_mime++;
-
-          if (opt_crypto)
-            {
-              assert (!info->hash_file);
-              info->hash_file = tmpfile ();
-              if (!info->hash_file)
-                die ("failed to create temporary file: %s", strerror (errno));
-            }
-        }
-    }
 
   return 0;
 }
@@ -613,7 +654,7 @@ parse_message (FILE *fp)
           /* Delay hashing of the CR/LF because the last line ending
              belongs to the next boundary. */
           if (debug)
-            printf ("# hashing %s`%s'\n", info.hashing==2?"CR,LF+":"", line);
+            printf ("# hashing %s'%s'\n", info.hashing==2?"CR,LF+":"", line);
           if (opt_crypto)
             {
               if (info.hashing == 2)
@@ -636,7 +677,8 @@ parse_message (FILE *fp)
               info.hash_file = NULL;
               fclose (info.sig_file);
               info.sig_file = NULL;
-              info.gpgsm_mime = 0;
+              info.moss_state = 0;
+              info.is_smime = 0;
               info.is_pkcs7 = 0;
             }
           else
@@ -749,7 +791,7 @@ main (int argc, char **argv)
     {
       FILE *fp = fopen (*argv, "rb");
       if (!fp)
-        die ("can't open `%s': %s", *argv, strerror (errno));
+        die ("can't open '%s': %s", *argv, strerror (errno));
       parse_message (fp);
       fclose (fp);
     }
@@ -762,6 +804,6 @@ main (int argc, char **argv)
 
 /*
 Local Variables:
-compile-command: "gcc -Wall -g -o gpgparsemail rfc822parse.c gpgparsemail.c"
+compile-command: "gcc -Wall -Wno-pointer-sign -g -o gpgparsemail rfc822parse.c gpgparsemail.c"
 End:
 */