LCOV - code coverage report
Current view: top level - tools - gpgparsemail.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 347 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 13 0.0 %

          Line data    Source code
       1             : /* gpgparsemail.c - Standalone crypto mail parser
       2             :  *      Copyright (C) 2004, 2007 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : 
      21             : /* This utility prints an RFC822, possible MIME structured, message
      22             :    in an annotated format with the first column having an indicator
      23             :    for the content of the line.  Several options are available to
      24             :    scrutinize the message.  S/MIME and OpenPGP support is included. */
      25             : 
      26             : #ifdef HAVE_CONFIG_H
      27             : #include <config.h>
      28             : #endif
      29             : 
      30             : #include <stdio.h>
      31             : #include <stdlib.h>
      32             : #include <stddef.h>
      33             : #include <string.h>
      34             : #include <errno.h>
      35             : #include <stdarg.h>
      36             : #include <assert.h>
      37             : #include <time.h>
      38             : #include <signal.h>
      39             : #include <unistd.h>
      40             : #include <fcntl.h>
      41             : #include <sys/wait.h>
      42             : 
      43             : #include "rfc822parse.h"
      44             : 
      45             : 
      46             : #define PGM "gpgparsemail"
      47             : 
      48             : /* Option flags. */
      49             : static int verbose;
      50             : static int debug;
      51             : static int opt_crypto;    /* Decrypt or verify messages. */
      52             : static int opt_no_header; /* Don't output the header lines. */
      53             : 
      54             : /* Structure used to communicate with the parser callback. */
      55             : struct parse_info_s {
      56             :   int show_header;             /* Show the header lines. */
      57             :   int show_data;               /* Show the data lines. */
      58             :   unsigned int skip_show;      /* Temporary disable above for these
      59             :                                    number of lines. */
      60             :   int show_data_as_note;       /* The next data line should be shown
      61             :                                   as a note. */
      62             :   int show_boundary;
      63             :   int nesting_level;
      64             : 
      65             :   int is_pkcs7;                /* Old style S/MIME message. */
      66             : 
      67             :   int smfm_state;              /* State of PGP/MIME or S/MIME parsing.  */
      68             :   int is_smime;                /* This is S/MIME and not PGP/MIME. */
      69             : 
      70             :   char *signing_protocol;
      71             :   int hashing_level;           /* The nesting level we are hashing. */
      72             :   int hashing;
      73             :   FILE *hash_file;
      74             : 
      75             :   FILE *sig_file;              /* Signature part with MIME or full
      76             :                                   pkcs7 data if IS_PCKS7 is set. */
      77             :   int  verify_now;             /* Flag set when all signature data is
      78             :                                   available. */
      79             : };
      80             : 
      81             : 
      82             : /* Print diagnostic message and exit with failure. */
      83             : static void
      84           0 : die (const char *format, ...)
      85             : {
      86             :   va_list arg_ptr;
      87             : 
      88           0 :   fflush (stdout);
      89           0 :   fprintf (stderr, "%s: ", PGM);
      90             : 
      91           0 :   va_start (arg_ptr, format);
      92           0 :   vfprintf (stderr, format, arg_ptr);
      93           0 :   va_end (arg_ptr);
      94           0 :   putc ('\n', stderr);
      95             : 
      96           0 :   exit (1);
      97             : }
      98             : 
      99             : 
     100             : /* Print diagnostic message. */
     101             : static void
     102           0 : err (const char *format, ...)
     103             : {
     104             :   va_list arg_ptr;
     105             : 
     106           0 :   fflush (stdout);
     107           0 :   fprintf (stderr, "%s: ", PGM);
     108             : 
     109           0 :   va_start (arg_ptr, format);
     110           0 :   vfprintf (stderr, format, arg_ptr);
     111           0 :   va_end (arg_ptr);
     112           0 :   putc ('\n', stderr);
     113           0 : }
     114             : 
     115             : static void *
     116           0 : xmalloc (size_t n)
     117             : {
     118           0 :   void *p = malloc (n);
     119           0 :   if (!p)
     120           0 :     die ("out of core: %s", strerror (errno));
     121           0 :   return p;
     122             : }
     123             : 
     124             : /* static void * */
     125             : /* xcalloc (size_t n, size_t m) */
     126             : /* { */
     127             : /*   void *p = calloc (n, m); */
     128             : /*   if (!p) */
     129             : /*     die ("out of core: %s", strerror (errno)); */
     130             : /*   return p; */
     131             : /* } */
     132             : 
     133             : /* static void * */
     134             : /* xrealloc (void *old, size_t n) */
     135             : /* { */
     136             : /*   void *p = realloc (old, n); */
     137             : /*   if (!p) */
     138             : /*     die ("out of core: %s", strerror (errno)); */
     139             : /*   return p; */
     140             : /* } */
     141             : 
     142             : static char *
     143           0 : xstrdup (const char *string)
     144             : {
     145           0 :   void *p = malloc (strlen (string)+1);
     146           0 :   if (!p)
     147           0 :     die ("out of core: %s", strerror (errno));
     148           0 :   strcpy (p, string);
     149           0 :   return p;
     150             : }
     151             : 
     152             : #ifndef HAVE_STPCPY
     153             : static char *
     154             : stpcpy (char *a,const char *b)
     155             : {
     156             :   while (*b)
     157             :     *a++ = *b++;
     158             :   *a = 0;
     159             : 
     160             :   return (char*)a;
     161             : }
     162             : #endif
     163             : 
     164             : static int
     165           0 : run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
     166             : {
     167             :   int rp[2];
     168             :   pid_t pid;
     169             :   int i, c, is_status;
     170             :   unsigned int pos;
     171             :   char status_buf[10];
     172             :   FILE *fp;
     173             : 
     174           0 :   if (pipe (rp) == -1)
     175           0 :     die ("error creating a pipe: %s", strerror (errno));
     176             : 
     177           0 :   pid = fork ();
     178           0 :   if (pid == -1)
     179           0 :     die ("error forking process: %s", strerror (errno));
     180             : 
     181           0 :   if (!pid)
     182             :     { /* Child. */
     183             :       char data_fd_buf[50];
     184             :       int fd;
     185             : 
     186             :       /* Connect our signature fd to stdin. */
     187           0 :       if (sig_fd != 0)
     188             :         {
     189           0 :           if (dup2 (sig_fd, 0) == -1)
     190           0 :             die ("dup2 stdin failed: %s", strerror (errno));
     191             :         }
     192             : 
     193             :       /* Keep our data fd and format it for gpg/gpgsm use. */
     194           0 :       if (data_fd == -1)
     195           0 :         *data_fd_buf = 0;
     196             :       else
     197           0 :         sprintf (data_fd_buf, "-&%d", data_fd);
     198             : 
     199             :       /* Send stdout to the bit bucket. */
     200           0 :       fd = open ("/dev/null", O_WRONLY);
     201           0 :       if (fd == -1)
     202           0 :         die ("can't open '/dev/null': %s", strerror (errno));
     203           0 :       if (fd != 1)
     204             :         {
     205           0 :           if (dup2 (fd, 1) == -1)
     206           0 :             die ("dup2 stderr failed: %s", strerror (errno));
     207             :         }
     208             : 
     209             :       /* Connect stderr to our pipe. */
     210           0 :       if (rp[1] != 2)
     211             :         {
     212           0 :           if (dup2 (rp[1], 2) == -1)
     213           0 :             die ("dup2 stderr failed: %s", strerror (errno));
     214             :         }
     215             : 
     216             :       /* Close other files. */
     217           0 :       for (i=0; (fd=close_list[i]) != -1; i++)
     218           0 :         if (fd > 2 && fd != data_fd)
     219           0 :           close (fd);
     220           0 :       errno = 0;
     221             : 
     222           0 :       if (smime)
     223           0 :         execlp ("gpgsm", "gpgsm",
     224             :                 "--enable-special-filenames",
     225             :                 "--status-fd", "2",
     226             :                 "--assume-base64",
     227             :                 "--verify",
     228             :                 "--",
     229             :                 "-", data_fd == -1? NULL : data_fd_buf,
     230             :                 NULL);
     231             :       else
     232           0 :         execlp ("gpg", "gpg",
     233             :                 "--enable-special-filenames",
     234             :                 "--status-fd", "2",
     235             :                 "--verify",
     236             :                 "--debug=512",
     237             :                 "--",
     238             :                 "-", data_fd == -1? NULL : data_fd_buf,
     239             :                 NULL);
     240             : 
     241           0 :       die ("failed to exec the crypto command: %s", strerror (errno));
     242             :     }
     243             : 
     244             :   /* Parent. */
     245           0 :   close (rp[1]);
     246             : 
     247           0 :   fp = fdopen (rp[0], "r");
     248           0 :   if (!fp)
     249           0 :     die ("can't fdopen pipe for reading: %s", strerror (errno));
     250             : 
     251           0 :   pos = 0;
     252           0 :   is_status = 0;
     253             :   assert (sizeof status_buf > 9);
     254           0 :   while ((c=getc (fp)) != EOF)
     255             :     {
     256           0 :       if (pos < 9)
     257           0 :         status_buf[pos] = c;
     258             :       else
     259             :         {
     260           0 :           if (pos == 9)
     261             :             {
     262           0 :               is_status = !memcmp (status_buf, "[GNUPG:] ", 9);
     263           0 :               if (is_status)
     264           0 :                 fputs ( "c ", stdout);
     265           0 :               else if (verbose)
     266           0 :                 fputs ( "# ", stdout);
     267           0 :               fwrite (status_buf, 9, 1, stdout);
     268             :             }
     269           0 :           putchar (c);
     270             :         }
     271           0 :       if (c == '\n')
     272             :         {
     273           0 :           if (verbose && pos < 9)
     274             :             {
     275           0 :               fputs ( "# ", stdout);
     276           0 :               fwrite (status_buf, pos+1, 1, stdout);
     277             :             }
     278           0 :           pos = 0;
     279             :         }
     280             :       else
     281           0 :         pos++;
     282             :     }
     283           0 :   if (pos)
     284             :     {
     285           0 :       if (verbose && pos < 9)
     286             :         {
     287           0 :           fputs ( "# ", stdout);
     288           0 :           fwrite (status_buf, pos+1, 1, stdout);
     289             :         }
     290           0 :       putchar ('\n');
     291             :     }
     292           0 :   fclose (fp);
     293             : 
     294           0 :   while ( (i=waitpid (pid, NULL, 0)) == -1 && errno == EINTR)
     295             :     ;
     296           0 :   if (i == -1)
     297           0 :     die ("waiting for child failed: %s", strerror (errno));
     298             : 
     299           0 :   return 0;
     300             : }
     301             : 
     302             : 
     303             : 
     304             : 
     305             : /* Verify the signature in the current temp files. */
     306             : static void
     307           0 : verify_signature (struct parse_info_s *info)
     308             : {
     309             :   int close_list[10];
     310             : 
     311           0 :   if (info->is_pkcs7)
     312             :     {
     313           0 :       assert (!info->hash_file);
     314           0 :       assert (info->sig_file);
     315           0 :       rewind (info->sig_file);
     316             :     }
     317             :   else
     318             :     {
     319           0 :       assert (info->hash_file);
     320           0 :       assert (info->sig_file);
     321           0 :       rewind (info->hash_file);
     322           0 :       rewind (info->sig_file);
     323             :     }
     324             : 
     325             : /*   printf ("# Begin hashed data\n"); */
     326             : /*   while ( (c=getc (info->hash_file)) != EOF) */
     327             : /*     putchar (c); */
     328             : /*   printf ("# End hashed data signature\n"); */
     329             : /*   printf ("# Begin signature\n"); */
     330             : /*   while ( (c=getc (info->sig_file)) != EOF) */
     331             : /*     putchar (c); */
     332             : /*   printf ("# End signature\n"); */
     333             : /*   rewind (info->hash_file); */
     334             : /*   rewind (info->sig_file); */
     335             : 
     336           0 :   close_list[0] = -1;
     337           0 :   run_gnupg (info->is_smime, fileno (info->sig_file),
     338           0 :              info->hash_file ? fileno (info->hash_file) : -1, close_list);
     339           0 : }
     340             : 
     341             : 
     342             : 
     343             : 
     344             : 
     345             : /* Prepare for a multipart/signed.
     346             :    FIELD_CTX is the parsed context of the content-type header.*/
     347             : static void
     348           0 : mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg,
     349             :                    rfc822parse_field_t field_ctx)
     350             : {
     351             :   const char *s;
     352             : 
     353             :   (void)msg;
     354             : 
     355           0 :   s = rfc822parse_query_parameter (field_ctx, "protocol", 1);
     356           0 :   if (s)
     357             :     {
     358           0 :       printf ("h signed.protocol: %s\n", s);
     359           0 :       if (!strcmp (s, "application/pgp-signature"))
     360             :         {
     361           0 :           if (info->smfm_state)
     362           0 :             err ("note: ignoring nested PGP/MIME or S/MIME signature");
     363             :           else
     364             :             {
     365           0 :               info->smfm_state = 1;
     366           0 :               info->is_smime = 0;
     367           0 :               free (info->signing_protocol);
     368           0 :               info->signing_protocol = xstrdup (s);
     369             :             }
     370             :         }
     371           0 :       else if (!strcmp (s, "application/pkcs7-signature")
     372           0 :                || !strcmp (s, "application/x-pkcs7-signature"))
     373             :         {
     374           0 :           if (info->smfm_state)
     375           0 :             err ("note: ignoring nested PGP/MIME or S/MIME signature");
     376             :           else
     377             :             {
     378           0 :               info->smfm_state = 1;
     379           0 :               info->is_smime = 1;
     380           0 :               free (info->signing_protocol);
     381           0 :               info->signing_protocol = xstrdup (s);
     382             :             }
     383             :         }
     384           0 :       else if (verbose)
     385           0 :         printf ("# this protocol is not supported\n");
     386             :     }
     387           0 : }
     388             : 
     389             : 
     390             : /* Prepare for a multipart/encrypted.
     391             :    FIELD_CTX is the parsed context of the content-type header.*/
     392             : static void
     393           0 : mime_encrypted_begin (struct parse_info_s *info, rfc822parse_t msg,
     394             :                       rfc822parse_field_t field_ctx)
     395             : {
     396             :   const char *s;
     397             : 
     398             :   (void)info;
     399             :   (void)msg;
     400             : 
     401           0 :   s = rfc822parse_query_parameter (field_ctx, "protocol", 0);
     402           0 :   if (s)
     403           0 :     printf ("h encrypted.protocol: %s\n", s);
     404           0 : }
     405             : 
     406             : 
     407             : /* Prepare for old-style pkcs7 messages. */
     408             : static void
     409           0 : pkcs7_begin (struct parse_info_s *info, rfc822parse_t msg,
     410             :              rfc822parse_field_t field_ctx)
     411             : {
     412             :   const char *s;
     413             : 
     414             :   (void)msg;
     415             : 
     416           0 :   s = rfc822parse_query_parameter (field_ctx, "name", 0);
     417           0 :   if (s)
     418           0 :     printf ("h pkcs7.name: %s\n", s);
     419           0 :   if (info->is_pkcs7)
     420           0 :     err ("note: ignoring nested pkcs7 data");
     421             :   else
     422             :     {
     423           0 :       info->is_pkcs7 = 1;
     424           0 :       if (opt_crypto)
     425             :         {
     426           0 :           assert (!info->sig_file);
     427           0 :           info->sig_file = tmpfile ();
     428           0 :           if (!info->sig_file)
     429           0 :             die ("error creating temp file: %s", strerror (errno));
     430             :         }
     431             :     }
     432           0 : }
     433             : 
     434             : 
     435             : /* Print the event received by the parser for debugging as comment
     436             :    line. */
     437             : static void
     438           0 : show_event (rfc822parse_event_t event)
     439             : {
     440             :   const char *s;
     441             : 
     442           0 :   switch (event)
     443             :     {
     444           0 :     case RFC822PARSE_OPEN: s= "Open"; break;
     445           0 :     case RFC822PARSE_CLOSE: s= "Close"; break;
     446           0 :     case RFC822PARSE_CANCEL: s= "Cancel"; break;
     447           0 :     case RFC822PARSE_T2BODY: s= "T2Body"; break;
     448           0 :     case RFC822PARSE_FINISH: s= "Finish"; break;
     449           0 :     case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break;
     450           0 :     case RFC822PARSE_LEVEL_DOWN: s= "Level_Down"; break;
     451           0 :     case RFC822PARSE_LEVEL_UP: s= "Level_Up"; break;
     452           0 :     case RFC822PARSE_BOUNDARY: s= "Boundary"; break;
     453           0 :     case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break;
     454           0 :     case RFC822PARSE_BEGIN_HEADER: s= "Begin_Header"; break;
     455           0 :     case RFC822PARSE_PREAMBLE: s= "Preamble"; break;
     456           0 :     case RFC822PARSE_EPILOGUE: s= "Epilogue"; break;
     457           0 :     default: s= "[unknown event]"; break;
     458             :     }
     459           0 :   printf ("# *** got RFC822 event %s\n", s);
     460           0 : }
     461             : 
     462             : /* This function is called by the parser to communicate events.  This
     463             :    callback comminucates with the main program using a structure
     464             :    passed in OPAQUE. Should retrun 0 or set errno and return -1. */
     465             : static int
     466           0 : message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
     467             : {
     468           0 :   struct parse_info_s *info = opaque;
     469             : 
     470           0 :   if (debug)
     471           0 :     show_event (event);
     472             : 
     473           0 :   if (event == RFC822PARSE_BEGIN_HEADER || event == RFC822PARSE_T2BODY)
     474             :     {
     475             :       /* We need to check here whether to start collecting signed data
     476             :          because attachments might come without header lines and thus
     477             :          we won't see the BEGIN_HEADER event.  */
     478           0 :       if (info->smfm_state == 1)
     479             :         {
     480           0 :           printf ("c begin_hash\n");
     481           0 :           info->hashing = 1;
     482           0 :           info->hashing_level = info->nesting_level;
     483           0 :           info->smfm_state++;
     484             : 
     485           0 :           if (opt_crypto)
     486             :             {
     487           0 :               assert (!info->hash_file);
     488           0 :               info->hash_file = tmpfile ();
     489           0 :               if (!info->hash_file)
     490           0 :                 die ("failed to create temporary file: %s", strerror (errno));
     491             :             }
     492             :         }
     493             :     }
     494             : 
     495             : 
     496           0 :   if (event == RFC822PARSE_OPEN)
     497             :     {
     498             :       /* Initialize for a new message. */
     499           0 :       info->show_header = 1;
     500             :     }
     501           0 :   else if (event == RFC822PARSE_T2BODY)
     502             :     {
     503             :       rfc822parse_field_t ctx;
     504             : 
     505           0 :       ctx = rfc822parse_parse_field (msg, "Content-Type", -1);
     506           0 :       if (ctx)
     507             :         {
     508             :           const char *s1, *s2;
     509           0 :           s1 = rfc822parse_query_media_type (ctx, &s2);
     510           0 :           if (s1)
     511             :             {
     512           0 :               printf ("h media: %*s%s %s\n",
     513           0 :                       info->nesting_level*2, "", s1, s2);
     514           0 :               if (info->smfm_state == 3)
     515             :                 {
     516           0 :                   char *buf = xmalloc (strlen (s1) + strlen (s2) + 2);
     517           0 :                   strcpy (stpcpy (stpcpy (buf, s1), "/"), s2);
     518           0 :                   assert (info->signing_protocol);
     519           0 :                   if (strcmp (buf, info->signing_protocol))
     520           0 :                     err ("invalid %s structure; expected '%s', found '%s'",
     521           0 :                          info->is_smime? "S/MIME":"PGP/MIME",
     522             :                          info->signing_protocol, buf);
     523             :                   else
     524             :                     {
     525           0 :                       printf ("c begin_signature\n");
     526           0 :                       info->smfm_state++;
     527           0 :                       if (opt_crypto)
     528             :                         {
     529           0 :                           assert (!info->sig_file);
     530           0 :                           info->sig_file = tmpfile ();
     531           0 :                           if (!info->sig_file)
     532           0 :                             die ("error creating temp file: %s",
     533           0 :                                  strerror (errno));
     534             :                         }
     535             :                     }
     536           0 :                   free (buf);
     537             :                 }
     538           0 :               else if (!strcmp (s1, "multipart"))
     539             :                 {
     540           0 :                   if (!strcmp (s2, "signed"))
     541           0 :                     mime_signed_begin (info, msg, ctx);
     542           0 :                   else if (!strcmp (s2, "encrypted"))
     543           0 :                     mime_encrypted_begin (info, msg, ctx);
     544             :                 }
     545           0 :               else if (!strcmp (s1, "application")
     546           0 :                        && (!strcmp (s2, "pkcs7-mime")
     547           0 :                            || !strcmp (s2, "x-pkcs7-mime")))
     548           0 :                 pkcs7_begin (info, msg, ctx);
     549             :             }
     550             :           else
     551           0 :             printf ("h media: %*s none\n", info->nesting_level*2, "");
     552             : 
     553           0 :           rfc822parse_release_field (ctx);
     554             :         }
     555             :       else
     556           0 :         printf ("h media: %*stext plain [assumed]\n",
     557           0 :                 info->nesting_level*2, "");
     558             : 
     559             : 
     560           0 :       info->show_header = 0;
     561           0 :       info->show_data = 1;
     562           0 :       info->skip_show = 1;
     563             :     }
     564           0 :   else if (event == RFC822PARSE_PREAMBLE)
     565           0 :     info->show_data_as_note = 1;
     566           0 :   else if (event == RFC822PARSE_LEVEL_DOWN)
     567             :     {
     568           0 :       printf ("b down\n");
     569           0 :       info->nesting_level++;
     570             :     }
     571           0 :   else if (event == RFC822PARSE_LEVEL_UP)
     572             :     {
     573           0 :       printf ("b up\n");
     574           0 :       if (info->nesting_level)
     575           0 :         info->nesting_level--;
     576             :       else
     577           0 :         err ("invalid structure (bad nesting level)");
     578             :     }
     579           0 :   else if (event == RFC822PARSE_BOUNDARY || event == RFC822PARSE_LAST_BOUNDARY)
     580             :     {
     581           0 :       info->show_data = 0;
     582           0 :       info->show_boundary = 1;
     583           0 :       if (event == RFC822PARSE_BOUNDARY)
     584             :         {
     585           0 :           info->show_header = 1;
     586           0 :           info->skip_show = 1;
     587           0 :           printf ("b part\n");
     588             :         }
     589             :       else
     590           0 :         printf ("b last\n");
     591             : 
     592           0 :       if (info->smfm_state == 2 && info->nesting_level == info->hashing_level)
     593             :         {
     594           0 :           printf ("c end_hash\n");
     595           0 :           info->smfm_state++;
     596           0 :           info->hashing = 0;
     597             :         }
     598           0 :       else if (info->smfm_state == 4)
     599             :         {
     600           0 :           printf ("c end_signature\n");
     601           0 :           info->verify_now = 1;
     602             :         }
     603             :     }
     604             : 
     605           0 :   return 0;
     606             : }
     607             : 
     608             : 
     609             : /* Read a message from FP and process it according to the global
     610             :    options. */
     611             : static void
     612           0 : parse_message (FILE *fp)
     613             : {
     614             :   char line[5000];
     615             :   size_t length;
     616             :   rfc822parse_t msg;
     617           0 :   unsigned int lineno = 0;
     618           0 :   int no_cr_reported = 0;
     619             :   struct parse_info_s info;
     620             : 
     621           0 :   memset (&info, 0, sizeof info);
     622             : 
     623           0 :   msg = rfc822parse_open (message_cb, &info);
     624           0 :   if (!msg)
     625           0 :     die ("can't open parser: %s", strerror (errno));
     626             : 
     627             :   /* Fixme: We should not use fgets becuase it can't cope with
     628             :      embedded nul characters. */
     629           0 :   while (fgets (line, sizeof (line), fp))
     630             :     {
     631           0 :       lineno++;
     632           0 :       if (lineno == 1 && !strncmp (line, "From ", 5))
     633           0 :         continue;  /* We better ignore a leading From line. */
     634             : 
     635           0 :       length = strlen (line);
     636           0 :       if (length && line[length - 1] == '\n')
     637           0 :         line[--length] = 0;
     638             :       else
     639           0 :         err ("line number %u too long or last line not terminated", lineno);
     640           0 :       if (length && line[length - 1] == '\r')
     641           0 :         line[--length] = 0;
     642           0 :       else if (verbose && !no_cr_reported)
     643             :         {
     644           0 :           err ("non canonical ended line detected (line %u)", lineno);
     645           0 :           no_cr_reported = 1;
     646             :         }
     647             : 
     648             : 
     649           0 :       if (rfc822parse_insert (msg, line, length))
     650           0 :         die ("parser failed: %s", strerror (errno));
     651             : 
     652           0 :       if (info.hashing)
     653             :         {
     654             :           /* Delay hashing of the CR/LF because the last line ending
     655             :              belongs to the next boundary. */
     656           0 :           if (debug)
     657           0 :             printf ("# hashing %s'%s'\n", info.hashing==2?"CR,LF+":"", line);
     658           0 :           if (opt_crypto)
     659             :             {
     660           0 :               if (info.hashing == 2)
     661           0 :                 fputs ("\r\n", info.hash_file);
     662           0 :               fputs (line, info.hash_file);
     663           0 :               if (ferror (info.hash_file))
     664           0 :                 die ("error writing to temporary file: %s", strerror (errno));
     665             :             }
     666             : 
     667           0 :           info.hashing = 2;
     668             :         }
     669             : 
     670           0 :       if (info.sig_file && opt_crypto)
     671             :         {
     672           0 :           if (info.verify_now)
     673             :             {
     674           0 :               verify_signature (&info);
     675           0 :               if (info.hash_file)
     676           0 :                 fclose (info.hash_file);
     677           0 :               info.hash_file = NULL;
     678           0 :               fclose (info.sig_file);
     679           0 :               info.sig_file = NULL;
     680           0 :               info.smfm_state = 0;
     681           0 :               info.is_smime = 0;
     682           0 :               info.is_pkcs7 = 0;
     683             :             }
     684             :           else
     685             :             {
     686           0 :               fputs (line, info.sig_file);
     687           0 :               fputs ("\r\n", info.sig_file);
     688           0 :               if (ferror (info.sig_file))
     689           0 :                 die ("error writing to temporary file: %s", strerror (errno));
     690             :             }
     691             :         }
     692             : 
     693           0 :       if (info.show_boundary)
     694             :         {
     695           0 :           if (!opt_no_header)
     696           0 :             printf (":%s\n", line);
     697           0 :           info.show_boundary = 0;
     698             :         }
     699             : 
     700           0 :       if (info.skip_show)
     701           0 :         info.skip_show--;
     702           0 :       else if (info.show_data)
     703             :         {
     704           0 :           if (info.show_data_as_note)
     705             :             {
     706           0 :               if (verbose)
     707           0 :                 printf ("# DATA: %s\n", line);
     708           0 :               info.show_data_as_note = 0;
     709             :             }
     710             :           else
     711           0 :             printf (" %s\n", line);
     712             :         }
     713           0 :       else if (info.show_header && !opt_no_header)
     714           0 :         printf (".%s\n", line);
     715             : 
     716             :     }
     717             : 
     718           0 :   if (info.sig_file && opt_crypto && info.is_pkcs7)
     719             :     {
     720           0 :       verify_signature (&info);
     721           0 :       fclose (info.sig_file);
     722           0 :       info.sig_file = NULL;
     723           0 :       info.is_pkcs7 = 0;
     724             :     }
     725             : 
     726           0 :   rfc822parse_close (msg);
     727           0 : }
     728             : 
     729             : 
     730             : int
     731           0 : main (int argc, char **argv)
     732             : {
     733           0 :   int last_argc = -1;
     734             : 
     735           0 :   if (argc)
     736             :     {
     737           0 :       argc--; argv++;
     738             :     }
     739           0 :   while (argc && last_argc != argc )
     740             :     {
     741           0 :       last_argc = argc;
     742           0 :       if (!strcmp (*argv, "--"))
     743             :         {
     744           0 :           argc--; argv++;
     745           0 :           break;
     746             :         }
     747           0 :       else if (!strcmp (*argv, "--help"))
     748             :         {
     749           0 :           puts (
     750             :                 "Usage: " PGM " [OPTION] [FILE]\n"
     751             :                 "Parse a mail message into an annotated format.\n\n"
     752             :                 "  --crypto    decrypt or verify messages\n"
     753             :                 "  --no-header don't output the header lines\n"
     754             :                 "  --verbose   enable extra informational output\n"
     755             :                 "  --debug     enable additional debug output\n"
     756             :                 "  --help      display this help and exit\n\n"
     757             :                 "With no FILE, or when FILE is -, read standard input.\n\n"
     758             :                 "WARNING: This tool is under development.\n"
     759             :                 "         The semantics may change without notice\n\n"
     760             :                 "Report bugs to <bug-gnupg@gnu.org>.");
     761           0 :           exit (0);
     762             :         }
     763           0 :       else if (!strcmp (*argv, "--verbose"))
     764             :         {
     765           0 :           verbose = 1;
     766           0 :           argc--; argv++;
     767             :         }
     768           0 :       else if (!strcmp (*argv, "--debug"))
     769             :         {
     770           0 :           verbose = debug = 1;
     771           0 :           argc--; argv++;
     772             :         }
     773           0 :       else if (!strcmp (*argv, "--crypto"))
     774             :         {
     775           0 :           opt_crypto = 1;
     776           0 :           argc--; argv++;
     777             :         }
     778           0 :       else if (!strcmp (*argv, "--no-header"))
     779             :         {
     780           0 :           opt_no_header = 1;
     781           0 :           argc--; argv++;
     782             :         }
     783             :     }
     784             : 
     785           0 :   if (argc > 1)
     786           0 :     die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
     787             : 
     788           0 :   signal (SIGPIPE, SIG_IGN);
     789             : 
     790           0 :   if (argc && strcmp (*argv, "-"))
     791           0 :     {
     792           0 :       FILE *fp = fopen (*argv, "rb");
     793           0 :       if (!fp)
     794           0 :         die ("can't open '%s': %s", *argv, strerror (errno));
     795           0 :       parse_message (fp);
     796           0 :       fclose (fp);
     797             :     }
     798             :   else
     799           0 :     parse_message (stdin);
     800             : 
     801           0 :   return 0;
     802             : }
     803             : 
     804             : 
     805             : /*
     806             : Local Variables:
     807             : compile-command: "gcc -Wall -Wno-pointer-sign -g -o gpgparsemail rfc822parse.c gpgparsemail.c"
     808             : End:
     809             : */

Generated by: LCOV version 1.11