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

Generated by: LCOV version 1.11