* convert-from-106, lspgpot: Check for gpg binary before proceeding.
[gnupg.git] / tools / gpgsplit.c
1 /* gpgsplit.c - An OpenPGP packet splitting tool
2  * Copyright (C) 2001, 2002, 2003 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  * TODO: Add an option to uncompress packets.  This should come quite handy.
23  */
24
25 #include <config.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include <assert.h>
33 #ifdef HAVE_DOSISH_SYSTEM
34 # include <fcntl.h> /* for setmode() */
35 #endif
36 #include <zlib.h>
37 #ifdef HAVE_BZIP2
38 #include <bzlib.h>
39 #endif /* HAVE_BZIP2 */
40 #if defined(__riscos__) && defined(USE_ZLIBRISCOS)
41 # include "zlib-riscos.h"
42 #endif
43
44 #define INCLUDED_BY_MAIN_MODULE 1
45 #include "../g10/packet.h"
46 #include "util.h"
47
48 static int opt_verbose;
49 static const char *opt_prefix = "";
50 static int opt_uncompress;
51 static int opt_secret_to_public;
52 static int opt_no_split;
53
54 static void g10_exit( int rc );
55 static void split_packets (const char *fname);
56
57
58 enum cmd_and_opt_values {
59   aNull = 0,
60   oVerbose        = 'v',
61   oPrefix       = 'p',                          
62   oUncompress   = 500,                      
63   oSecretToPublic,                      
64   oNoSplit,
65
66   aTest
67 };
68
69
70 static ARGPARSE_OPTS opts[] = {
71
72     { 301, NULL, 0, "@Options:\n " },
73
74     { oVerbose, "verbose",   0, "verbose" },
75     { oPrefix,  "prefix",    2, "|STRING|Prepend filenames with STRING" },
76     { oUncompress, "uncompress", 0, "uncompress a packet"},
77     { oSecretToPublic, "secret-to-public", 0, "convert secret keys to public keys"},
78     { oNoSplit, "no-split", 0, "write to stdout and don't actually split"},
79 {0} };
80
81
82 const char *
83 strusage( int level )
84 {
85   const char *p;
86   switch (level)
87     {
88     case 11: p = "gpgsplit (GnuPG)";
89       break;
90     case 13: p = VERSION; break;
91     case 17: p = PRINTABLE_OS_NAME; break;
92     case 19: p =
93                "Please report bugs to <bug-gnupg@gnu.org>.\n";
94     break;
95     case 1:
96     case 40:    p =
97                   "Usage: gpgsplit [options] [files] (-h for help)";
98     break;
99     case 41:    p =
100                   "Syntax: gpgsplit [options] [files]\n"
101                   "Split an OpenPGP message into packets\n";
102     break;
103     
104     default:    p = default_strusage(level);
105     }
106   return p;
107 }
108
109
110
111 int
112 main( int argc, char **argv )
113 {
114   ARGPARSE_ARGS pargs;
115
116 #ifdef HAVE_DOSISH_SYSTEM
117   setmode( fileno(stdin), O_BINARY );
118   setmode( fileno(stdout), O_BINARY );
119 #endif
120   log_set_name("gpgsplit");
121   
122   pargs.argc = &argc;
123   pargs.argv = &argv;
124   pargs.flags=  1;  /* do not remove the args */
125   while (optfile_parse( NULL, NULL, NULL, &pargs, opts))
126     {
127       switch (pargs.r_opt)
128         {
129         case oVerbose: opt_verbose = 1; break;
130         case oPrefix: opt_prefix = pargs.r.ret_str; break;
131         case oUncompress: opt_uncompress = 1; break;
132         case oSecretToPublic: opt_secret_to_public = 1; break;
133         case oNoSplit: opt_no_split = 1; break;
134         default : pargs.err = 2; break;
135         }
136     }
137   
138   if (log_get_errorcount(0))
139     g10_exit (2);
140
141   if (!argc)
142     split_packets (NULL);
143   else
144     {
145       for ( ;argc; argc--, argv++) 
146         split_packets (*argv);
147     }
148   
149   g10_exit (0);
150   return 0; 
151 }
152
153
154 static void
155 g10_exit (int rc)
156 {
157   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
158   exit(rc );
159 }
160
161 static const char *
162 pkttype_to_string (int pkttype)
163 {
164   const char *s;
165
166   switch (pkttype)
167     {
168     case PKT_PUBKEY_ENC    : s = "pk_enc"; break;
169     case PKT_SIGNATURE     : s = "sig"; break;
170     case PKT_SYMKEY_ENC    : s = "sym_enc"; break;
171     case PKT_ONEPASS_SIG   : s = "onepass_sig"; break;
172     case PKT_SECRET_KEY    : s = "secret_key"; break;
173     case PKT_PUBLIC_KEY    : s = "public_key"; break;
174     case PKT_SECRET_SUBKEY : s = "secret_subkey"; break;
175     case PKT_COMPRESSED    : 
176       s = opt_uncompress? "uncompressed":"compressed";
177       break;
178     case PKT_ENCRYPTED     : s = "encrypted"; break;
179     case PKT_MARKER            : s = "marker"; break;
180     case PKT_PLAINTEXT     : s = "plaintext"; break;
181     case PKT_RING_TRUST    : s = "ring_trust"; break;
182     case PKT_USER_ID       : s = "user_id"; break;
183     case PKT_PUBLIC_SUBKEY : s = "public_subkey"; break;
184     case PKT_OLD_COMMENT   : s = "old_comment"; break;
185     case PKT_ATTRIBUTE     : s = "attribute"; break;
186     case PKT_ENCRYPTED_MDC : s = "encrypted_mdc"; break;
187     case PKT_MDC               : s = "mdc"; break;
188     case PKT_COMMENT       : s = "comment"; break;
189     case PKT_GPG_CONTROL   : s = "gpg_control"; break;
190     default: s = "unknown"; break;
191     }
192   return s;
193 }
194
195
196 /*
197  * Create a new filename and a return a pointer to a statically
198  * allocated buffer 
199  */
200 static char *
201 create_filename (int pkttype)
202 {
203   static unsigned int partno = 0;
204   static char *name;
205   
206   if (!name) 
207     name = m_alloc (strlen (opt_prefix) + 100 );
208   
209   assert (pkttype < 1000 && pkttype >= 0 );
210   partno++;
211   sprintf (name, "%s%06u-%03d" EXTSEP_S "%.40s",
212            opt_prefix, partno, pkttype, pkttype_to_string (pkttype));
213   return name;
214 }
215
216 static int
217 read_u16 (FILE *fp, size_t *rn)
218 {
219   int c;
220
221   if ( (c = getc (fp)) == EOF )
222     return -1;
223   *rn = c << 8;
224   if ( (c = getc (fp)) == EOF )
225     return -1;
226   *rn |= c;
227   return 0;
228 }
229
230 static int
231 read_u32 (FILE *fp, unsigned long *rn)
232 {
233   size_t tmp;
234   
235   if (read_u16 (fp, &tmp))
236     return -1;
237   *rn = tmp << 16;
238   if (read_u16 (fp, &tmp))
239     return -1;
240   *rn |= tmp;
241   return 0;
242 }
243
244 static int
245 write_old_header (FILE *fp, int pkttype, unsigned int len)
246 {     
247   int ctb = (0x80 | ((pkttype & 15)<<2));
248   
249   if (len < 256)
250     ;
251   else if (len < 65536)
252     ctb |= 1;
253   else
254     ctb |= 2;
255
256   if ( putc ( ctb, fp) == EOF )
257     return -1;
258
259   if ( (ctb & 2) )
260     {
261       if (putc ((len>>24), fp) == EOF)
262         return -1;
263       if (putc ((len>>16), fp) == EOF)
264         return -1;
265     }
266   if ( (ctb & 3) )
267     {
268       if (putc ((len>>8), fp) == EOF)
269         return -1;
270     }
271   if (putc ((len&0xff), fp) == EOF)
272     return -1;
273   return 0;
274 }
275
276 static int
277 write_new_header (FILE *fp, int pkttype, unsigned int len)
278 {     
279   if ( putc ((0xc0 | (pkttype & 0x3f)), fp) == EOF )
280     return -1;
281
282   if (len < 192)
283     {
284       if (putc (len, fp) == EOF)
285         return -1;
286     }
287   else if (len < 8384)
288     {
289       len -= 192;
290       if (putc ((len/256)+192, fp) == EOF)
291         return -1;
292       if (putc ((len%256), fp) == EOF)
293         return -1;
294     }
295   else
296     {
297       if (putc ( 0xff, fp) == EOF)
298         return -1;
299       if (putc ( (len >> 24), fp) == EOF)
300         return -1;
301       if (putc ( (len >> 16), fp) == EOF)
302         return -1;
303       if (putc ( (len >> 8), fp) == EOF)
304         return -1;
305       if (putc ( (len & 0xff), fp) == EOF)
306         return -1;
307     }
308   return 0;
309 }
310
311 /* Return the length of the public key given BUF of BUFLEN with a
312    secret key. */
313 static int
314 public_key_length (const unsigned char *buf, size_t buflen)
315 {
316   const unsigned char *s;
317   int nmpis;
318
319   /*   byte version number (3 or 4)
320        u32  creation time 
321        [u16  valid days (version 3 only)]
322        byte algorithm 
323        n    MPIs (n and e) */
324   if (!buflen)
325     return 0;
326   if (buf[0] < 2 || buf[0] > 4)
327     return 0; /* wrong version number */
328   if (buflen < (buf[0] == 4? 6:8))
329     return 0;
330   s = buf + (buf[0] == 4? 6:8);
331   buflen -= (buf[0] == 4? 6:8);
332   switch (s[-1])
333     {
334     case 1:
335     case 2:
336     case 3:
337       nmpis = 2;
338       break;
339     case 16:
340     case 20:
341       nmpis = 3;
342       break;
343     case 17:
344       nmpis = 4;
345       break;
346     default:
347       return 0;
348     }
349
350   for (; nmpis; nmpis--)
351     {
352       unsigned int nbits, nbytes;
353
354       if (buflen < 2)
355         return 0;
356       nbits = (s[0] << 8) | s[1];
357       s += 2; buflen -= 2;
358       nbytes = (nbits+7) / 8;
359       if (buflen < nbytes)
360         return 0;
361       s += nbytes; buflen -= nbytes;
362     }
363
364   return s - buf;
365 }
366
367 static int
368 handle_zlib(int algo,FILE *fpin,FILE *fpout)
369 {
370   z_stream zs;
371   byte *inbuf, *outbuf;
372   unsigned int inbufsize, outbufsize;
373   int c,zinit_done, zrc, nread, count;
374   size_t n;
375               
376   memset (&zs, 0, sizeof zs);
377   inbufsize = 2048;
378   inbuf = m_alloc (inbufsize);
379   outbufsize = 8192;
380   outbuf = m_alloc (outbufsize);
381   zs.avail_in = 0;
382   zinit_done = 0;
383               
384   do
385     {
386       if (zs.avail_in < inbufsize)
387         {
388           n = zs.avail_in;
389           if (!n)
390             zs.next_in = (Bytef *) inbuf;
391           count = inbufsize - n;
392           for (nread=0;
393                nread < count && (c=getc (fpin)) != EOF;
394                nread++) 
395             inbuf[n+nread] = c;
396                       
397           n += nread;
398           if (nread < count && algo == 1) 
399             {
400               inbuf[n] = 0xFF; /* chew dummy byte */
401               n++;
402             }
403           zs.avail_in = n;
404         }
405       zs.next_out = (Bytef *) outbuf;
406       zs.avail_out = outbufsize;
407                     
408       if (!zinit_done) 
409         {
410           zrc = (algo == 1? inflateInit2 ( &zs, -13)
411                  : inflateInit ( &zs ));
412           if (zrc != Z_OK) 
413             {
414               log_fatal ("zlib problem: %s\n", zs.msg? zs.msg :
415                          zrc == Z_MEM_ERROR ? "out of core" :
416                          zrc == Z_VERSION_ERROR ?
417                          "invalid lib version" :
418                          "unknown error" );
419             }
420           zinit_done = 1;
421         }
422       else
423         {
424 #ifdef Z_SYNC_FLUSH
425           zrc = inflate (&zs, Z_SYNC_FLUSH);
426 #else
427           zrc = inflate (&zs, Z_PARTIAL_FLUSH);
428 #endif
429           if (zrc == Z_STREAM_END)
430             ; /* eof */
431           else if (zrc != Z_OK && zrc != Z_BUF_ERROR)
432             {
433               if (zs.msg)
434                 log_fatal ("zlib inflate problem: %s\n", zs.msg );
435               else
436                 log_fatal ("zlib inflate problem: rc=%d\n", zrc );
437             }
438           for (n=0; n < outbufsize - zs.avail_out; n++) 
439             {
440               if (putc (outbuf[n], fpout) == EOF )
441                 return 1;
442             }
443         }
444     } 
445   while (zrc != Z_STREAM_END && zrc != Z_BUF_ERROR);
446   inflateEnd (&zs);
447
448   return 0;
449 }
450
451 #ifdef HAVE_BZIP2
452 static int
453 handle_bzip2(int algo,FILE *fpin,FILE *fpout)
454 {
455   bz_stream bzs;
456   byte *inbuf, *outbuf;
457   unsigned int inbufsize, outbufsize;
458   int c,zinit_done, zrc, nread, count;
459   size_t n;
460               
461   memset (&bzs, 0, sizeof bzs);
462   inbufsize = 2048;
463   inbuf = m_alloc (inbufsize);
464   outbufsize = 8192;
465   outbuf = m_alloc (outbufsize);
466   bzs.avail_in = 0;
467   zinit_done = 0;
468               
469   do
470     {
471       if (bzs.avail_in < inbufsize)
472         {
473           n = bzs.avail_in;
474           if (!n)
475             bzs.next_in = inbuf;
476           count = inbufsize - n;
477           for (nread=0;
478                nread < count && (c=getc (fpin)) != EOF;
479                nread++) 
480             inbuf[n+nread] = c;
481                       
482           n += nread;
483           if (nread < count && algo == 1) 
484             {
485               inbuf[n] = 0xFF; /* chew dummy byte */
486               n++;
487             }
488           bzs.avail_in = n;
489         }
490       bzs.next_out = outbuf;
491       bzs.avail_out = outbufsize;
492                     
493       if (!zinit_done) 
494         {
495           zrc = BZ2_bzDecompressInit(&bzs,0,0);
496           if (zrc != BZ_OK) 
497             log_fatal ("bz2lib problem: %d\n",zrc);
498           zinit_done = 1;
499         }
500       else
501         {
502           zrc = BZ2_bzDecompress(&bzs);
503           if (zrc == BZ_STREAM_END)
504             ; /* eof */
505           else if (zrc != BZ_OK && zrc != BZ_PARAM_ERROR)
506             log_fatal ("bz2lib inflate problem: %d\n", zrc );
507           for (n=0; n < outbufsize - bzs.avail_out; n++) 
508             {
509               if (putc (outbuf[n], fpout) == EOF )
510                 return 1;
511             }
512         }
513     } 
514   while (zrc != BZ_STREAM_END && zrc != BZ_PARAM_ERROR);
515   BZ2_bzDecompressEnd(&bzs);
516
517   return 0;
518 }
519 #endif /* HAVE_BZIP2 */
520
521 /* hdr must point to a buffer large enough to hold all header bytes */
522 static int
523 write_part ( const char *fname, FILE *fpin, unsigned long pktlen,
524              int pkttype, int partial, unsigned char *hdr, size_t hdrlen)
525 {
526   FILE *fpout;
527   int c, first;
528   unsigned char *p;
529   const char *outname = create_filename (pkttype);
530   
531 #if defined(__riscos__) && defined(USE_ZLIBRISCOS)
532   static int initialized = 0;
533
534   if (!initialized)
535       initialized = riscos_load_module("ZLib", zlib_path, 1);
536 #endif
537   if (opt_no_split)
538     fpout = stdout;
539   else
540     {
541       if (opt_verbose)
542         log_info ("writing `%s'\n", outname);
543       fpout = fopen (outname, "wb");
544       if (!fpout) 
545         {
546           log_error ("error creating `%s': %s\n", outname, strerror(errno));
547           /* stop right now, otherwise we would mess up the sequence
548              of the part numbers */
549           g10_exit (1);
550         }
551     }
552
553   if (opt_secret_to_public
554       && (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY))
555     {
556       unsigned char *blob = m_alloc (pktlen);
557       int i, len;
558
559       pkttype = pkttype == PKT_SECRET_KEY? PKT_PUBLIC_KEY:PKT_PUBLIC_SUBKEY;
560
561       for (i=0; i < pktlen; i++) 
562         {
563           c = getc (fpin);
564           if (c == EOF) 
565             goto read_error;
566           blob[i] = c;
567         }
568       len = public_key_length (blob, pktlen);
569       if (!len)
570         {
571           log_error ("error calcualting public key length\n");
572           g10_exit (1);
573         }
574       if ( (hdr[0] & 0x40) )
575         { 
576           if (write_new_header (fpout, pkttype, len))
577             goto write_error;
578         }
579       else
580         { 
581           if (write_old_header (fpout, pkttype, len))
582             goto write_error;
583         }
584
585       for (i=0; i < len; i++) 
586         {
587           if ( putc (blob[i], fpout) == EOF )
588             goto write_error;
589         }
590
591       goto ready;
592     }
593
594
595   if (!opt_uncompress)
596     {
597       for (p=hdr; hdrlen; p++, hdrlen--)
598         {
599           if ( putc (*p, fpout) == EOF )
600             goto write_error;
601         }
602     }
603   
604   first = 1;
605   while (partial)
606     {
607       size_t partlen;
608       
609       if (partial == 1)
610         { /* openpgp */
611           if (first )
612             {
613               c = pktlen;
614               assert( c >= 224 && c < 255 );
615               first = 0;
616             }
617           else if ((c = getc (fpin)) == EOF ) 
618             goto read_error;
619           else
620             hdr[hdrlen++] = c;
621             
622           if (c < 192)
623             {
624               pktlen = c;
625               partial = 0; /* (last segment may follow) */
626             }
627           else if (c < 224 )
628             {
629               pktlen = (c - 192) * 256;
630               if ((c = getc (fpin)) == EOF) 
631                 goto read_error;
632               hdr[hdrlen++] = c;
633               pktlen += c + 192;
634               partial = 0;
635             }
636           else if (c == 255)
637             {
638               if (read_u32 (fpin, &pktlen))
639                 goto read_error;
640               hdr[hdrlen++] = pktlen >> 24;
641               hdr[hdrlen++] = pktlen >> 16;
642               hdr[hdrlen++] = pktlen >> 8;
643               hdr[hdrlen++] = pktlen;
644               partial = 0;
645             }
646           else
647             { /* next partial body length */
648               for (p=hdr; hdrlen; p++, hdrlen--)
649                 {
650                   if ( putc (*p, fpout) == EOF )
651                     goto write_error;
652                 }
653               partlen = 1 << (c & 0x1f);
654               for (; partlen; partlen--) 
655                 {
656                   if ((c = getc (fpin)) == EOF) 
657                     goto read_error;
658                   if ( putc (c, fpout) == EOF )
659                     goto write_error;
660                 }
661             }
662         }
663       else if (partial == 2)
664         { /* old gnupg */
665           assert (!pktlen);
666           if ( read_u16 (fpin, &partlen) )
667             goto read_error;
668           hdr[hdrlen++] = partlen >> 8;
669           hdr[hdrlen++] = partlen;
670           for (p=hdr; hdrlen; p++, hdrlen--) 
671             {
672               if ( putc (*p, fpout) == EOF )
673                 goto write_error;
674             }
675           if (!partlen)
676             partial = 0; /* end of packet */
677           for (; partlen; partlen--) 
678             {
679               c = getc (fpin);
680               if (c == EOF) 
681                 goto read_error;
682               if ( putc (c, fpout) == EOF )
683                 goto write_error;
684             }
685         }
686       else
687         { /* compressed: read to end */
688           pktlen = 0;
689           partial = 0;
690           hdrlen = 0;
691           if (opt_uncompress) 
692             {
693               if ((c = getc (fpin)) == EOF)
694                 goto read_error;
695
696               if(c==1 || c==2)
697                 {
698                   if(handle_zlib(c,fpin,fpout))
699                     goto write_error;
700                 }
701 #ifdef HAVE_BZIP2
702               else if(c==3)
703                 {
704                   if(handle_bzip2(c,fpin,fpout))
705                     goto write_error;
706                 }
707 #endif /* HAVE_BZIP2 */
708               else
709                 {
710                   log_error("invalid compression algorithm (%d)\n",c);
711                   goto read_error;
712                 }
713             }
714           else
715             {
716               while ( (c=getc (fpin)) != EOF ) 
717                 {
718                   if ( putc (c, fpout) == EOF )
719                     goto write_error;
720                 }
721             }
722           if (!feof (fpin))
723             goto read_error;
724         }
725     }
726
727   for (p=hdr; hdrlen; p++, hdrlen--) 
728     {
729       if ( putc (*p, fpout) == EOF )
730         goto write_error;
731     }
732   
733   /* standard packet or last segment of partial length encoded packet */
734   for (; pktlen; pktlen--) 
735     {
736       c = getc (fpin);
737       if (c == EOF) 
738         goto read_error;
739       if ( putc (c, fpout) == EOF )
740         goto write_error;
741     }
742   
743  ready:
744   if ( !opt_no_split && fclose (fpout) )
745     log_error ("error closing `%s': %s\n", outname, strerror (errno));
746   return 0;
747   
748  write_error:    
749   log_error ("error writing `%s': %s\n", outname, strerror (errno));
750   if (!opt_no_split)
751     fclose (fpout);
752   return 2;
753   
754  read_error:
755   if (!opt_no_split)
756     {
757       int save = errno;
758       fclose (fpout);
759       errno = save;
760     }
761   return -1;
762 }
763
764
765
766 static int
767 do_split (const char *fname, FILE *fp)
768 {
769   int c, ctb, pkttype;
770   unsigned long pktlen = 0;
771   int partial = 0;
772   unsigned char header[20];
773   int header_idx = 0;
774   
775   ctb = getc (fp);
776   if (ctb == EOF)
777     return 3; /* ready */
778   header[header_idx++] = ctb;
779   
780   if (!(ctb & 0x80))
781     {
782       log_error("invalid CTB %02x\n", ctb );
783       return 1;
784     }
785   if ( (ctb & 0x40) )
786     { /* new CTB */
787       pkttype =  (ctb & 0x3f);
788       if( (c = getc (fp)) == EOF )
789         return -1;
790       header[header_idx++] = c;
791
792       if ( c < 192 )
793         pktlen = c;
794       else if ( c < 224 )
795         {
796           pktlen = (c - 192) * 256;
797           if( (c = getc (fp)) == EOF ) 
798             return -1;
799           header[header_idx++] = c;
800           pktlen += c + 192;
801         }
802       else if ( c == 255 ) 
803         {
804           if (read_u32 (fp, &pktlen))
805             return -1;
806           header[header_idx++] = pktlen >> 24;
807           header[header_idx++] = pktlen >> 16;
808           header[header_idx++] = pktlen >> 8;
809           header[header_idx++] = pktlen; 
810         }
811       else
812         { /* partial body length */
813           pktlen = c;
814           partial = 1;
815         }
816     }
817   else
818     {
819       int lenbytes;
820       
821       pkttype = (ctb>>2)&0xf;
822       lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
823       if (!lenbytes )
824         {
825           pktlen = 0; /* don't know the value */
826           if( pkttype == PKT_COMPRESSED )
827             partial = 3;
828           else
829             partial = 2; /* the old GnuPG partial length encoding */
830         }
831       else
832         {
833           for ( ; lenbytes; lenbytes-- ) 
834             {
835               pktlen <<= 8;
836               if( (c = getc (fp)) == EOF ) 
837                 return -1;
838               header[header_idx++] = c;
839               
840               pktlen |= c;
841             }
842         }
843     }
844
845   return write_part (fname, fp, pktlen, pkttype, partial,
846                      header, header_idx);
847 }
848
849
850 static void
851 split_packets (const char *fname)
852 {
853   FILE *fp;
854   int rc;
855   
856   if (!fname || !strcmp (fname, "-"))
857     {
858       fp = stdin;
859       fname = "-";
860     }
861   else if ( !(fp = fopen (fname,"rb")) ) 
862     {
863       log_error ("can't open `%s': %s\n", fname, strerror (errno));
864       return;
865     }
866   
867   while ( !(rc = do_split (fname, fp)) )
868     ;
869   if ( rc > 0 )
870     ; /* error already handled */
871   else if ( ferror (fp) )
872     log_error ("error reading `%s': %s\n", fname, strerror (errno));
873   else
874     log_error ("premature EOF while reading `%s'\n", fname );
875   
876   if ( fp != stdin )
877     fclose (fp);
878 }