~ubuntu-branches/ubuntu/dapper/gnupg2/dapper

« back to all changes in this revision

Viewing changes to tools/gpgparsemail.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

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