Annotation of pgp/src/armor.c, revision 1.1.1.7

1.1.1.7 ! root        1: /*      armor.c  - ASCII/binary encoding/decoding based partly on PEM RFC1113.
        !             2:    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
1.1.1.6   root        3: 
1.1.1.7 ! root        4:    (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
        !             5:    The author assumes no liability for damages resulting from the use
        !             6:    of this software, even if the damage results from defects in this
        !             7:    software.  No warranty is expressed or implied.
        !             8: 
        !             9:    Note that while most PGP source modules bear Philip Zimmermann's
        !            10:    copyright notice, many of them have been revised or entirely written
        !            11:    by contributors who frequently failed to put their names in their
        !            12:    code.  Code that has been incorporated into PGP from other authors
        !            13:    was either originally published in the public domain or is used with
        !            14:    permission from the various authors.
        !            15: 
        !            16:    PGP is available for free to the public under certain restrictions.
        !            17:    See the PGP User's Guide (included in the release package) for
        !            18:    important information about licensing, patent restrictions on
        !            19:    certain algorithms, trademarks, copyrights, and export controls.
        !            20:  */
1.1.1.6   root       21: #include <ctype.h>
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24: #include "mpilib.h"
                     25: #include "fileio.h"
                     26: #include "mpiio.h"
                     27: #include "language.h"
                     28: #include "pgp.h"
                     29: #include "crypto.h"
                     30: #include "armor.h"
                     31: 
                     32: static int dpem_file(char *infile, char *outfile);
                     33: static crcword crchware(byte ch, crcword poly, crcword accum);
                     34: static int pem_file(char *infilename, char *outfilename, char *clearfilename);
1.1.1.7 ! root       35: static int pemdecode(FILE * in, FILE * out);
1.1.1.6   root       36: static void mk_crctbl(crcword poly);
                     37: static boolean is_pemfile(char *infile);
                     38: 
1.1.1.7 ! root       39: /*      Begin PEM routines.
        !            40:    This converts a binary file into printable ASCII characters, in a
        !            41:    radix-64 form mostly compatible with the PEM RFC1113 format.
        !            42:    This makes it easier to send encrypted files over a 7-bit channel.
        !            43:  */
1.1.1.6   root       44: 
                     45: /* Index this array by a 6 bit value to get the character corresponding
                     46:  * to that value.
                     47:  */
                     48: static
                     49: unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                     50: abcdefghijklmnopqrstuvwxyz0123456789+/";
                     51: 
                     52: /* Index this array by a 7 bit value to get the 6-bit binary field
                     53:  * corresponding to that value.  Any illegal characters return high bit set.
                     54:  */
                     55: static
1.1.1.7 ! root       56: unsigned char asctobin[] =
        !            57: {
        !            58:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            59:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            60:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            61:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            62:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            63:     0200, 0200, 0200, 0076, 0200, 0200, 0200, 0077,
        !            64:     0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073,
        !            65:     0074, 0075, 0200, 0200, 0200, 0200, 0200, 0200,
        !            66:     0200, 0000, 0001, 0002, 0003, 0004, 0005, 0006,
        !            67:     0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016,
        !            68:     0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026,
        !            69:     0027, 0030, 0031, 0200, 0200, 0200, 0200, 0200,
        !            70:     0200, 0032, 0033, 0034, 0035, 0036, 0037, 0040,
        !            71:     0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050,
        !            72:     0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060,
        !            73:     0061, 0062, 0063, 0200, 0200, 0200, 0200, 0200
1.1.1.6   root       74: };
1.1.1.7 ! root       75: 
        !            76: /* Current line number for mult decodes */
        !            77: static long infile_line;
1.1.1.6   root       78: 
                     79: /************************************************************************/
                     80: 
                     81: /* CRC Routines. */
1.1.1.7 ! root       82: /*      These CRC functions are derived from code in chapter 19 of the book 
        !            83:  *    "C Programmer's Guide to Serial Communications", by Joe Campbell.
        !            84:  *      Generalized to any CRC width by Philip Zimmermann.
        !            85:  */
1.1.1.6   root       86: 
                     87: #define byte unsigned char
                     88: 
1.1.1.7 ! root       89: #define CRCBITS 24             /* may be 16, 24, or 32 */
        !            90: /* #define maskcrc(crc) ((crcword)(crc)) *//* if CRCBITS is 16 or 32 */
1.1.1.6   root       91: #define maskcrc(crc) ((crc) & 0xffffffL)       /* if CRCBITS is 24 */
1.1.1.7 ! root       92: #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */
1.1.1.6   root       93: #define CRCSHIFTS (CRCBITS-8)
                     94: 
                     95: /*
                     96:  * Notes on making a good 24-bit CRC--
                     97:  * The primitive irreducible polynomial of degree 23 over GF(2),
                     98:  * 040435651 (octal), comes from Appendix C of "Error Correcting Codes,
                     99:  * 2nd edition" by Peterson and Weldon, page 490.  This polynomial was
                    100:  * chosen for its uniform density of ones and zeros, which has better
                    101:  * error detection properties than polynomials with a minimal number of
                    102:  * nonzero terms.  Multiplying this primitive degree-23 polynomial by
                    103:  * the polynomial x+1 yields the additional property of detecting any
                    104:  * odd number of bits in error, which means it adds parity.  This 
                    105:  * approach was recommended by Neal Glover.
                    106:  *
                    107:  * To multiply the polynomial 040435651 by x+1, shift it left 1 bit and
                    108:  * bitwise add (xor) the unshifted version back in.  Dropping the unused 
                    109:  * upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 
                    110:  * octal, or 0x864cfb hex.  
                    111:  *
                    112:  * You can detect spurious leading zeros or framing errors in the 
                    113:  * message by initializing the CRC accumulator to some agreed-upon 
                    114:  * nonzero "random-like" value, but this is a bit nonstandard.  
                    115:  */
                    116: 
1.1.1.7 ! root      117: #define CCITTCRC 0x1021                /* CCITT's 16-bit CRC generator polynomial */
        !           118: #define PRZCRC 0x864cfbL       /* PRZ's 24-bit CRC generator polynomial */
1.1.1.6   root      119: #define CRCINIT 0xB704CEL      /* Init value for CRC accumulator */
                    120: 
                    121: static
                    122: crcword crctable[256];         /* Table for speeding up CRC's */
                    123: 
                    124: /*
                    125:  * mk_crctbl derives a CRC lookup table from the CRC polynomial.
                    126:  * The table is used later by the crcbytes function given below.
                    127:  * mk_crctbl only needs to be called once at the dawn of time.
                    128:  *
                    129:  * The theory behind mk_crctbl is that table[i] is initialized
                    130:  * with the CRC of i, and this is related to the CRC of i>>1,
                    131:  * so the CRC of i>>1 (pointed to by p) can be used to derive
                    132:  * the CRC of i (pointed to by q).
                    133:  */
                    134: static
                    135: void mk_crctbl(crcword poly)
                    136: {
1.1.1.7 ! root      137:     int i;
        !           138:     crcword t, *p, *q;
        !           139:     p = q = crctable;
        !           140:     *q++ = 0;
        !           141:     *q++ = poly;
        !           142:     for (i = 1; i < 128; i++) {
        !           143:        t = *++p;
        !           144:        if (t & CRCHIBIT) {
        !           145:            t <<= 1;
        !           146:            *q++ = t ^ poly;
        !           147:            *q++ = t;
        !           148:        } else {
        !           149:            t <<= 1;
        !           150:            *q++ = t;
        !           151:            *q++ = t ^ poly;
1.1.1.6   root      152:        }
1.1.1.7 ! root      153:     }
1.1.1.6   root      154: }
                    155: 
                    156: /*
                    157:  * Accumulate a buffer's worth of bytes into a CRC accumulator,
                    158:  * returning the new CRC value.
                    159:  */
                    160: crcword
1.1.1.7 ! root      161: crcbytes(byte * buf, unsigned len, register crcword accum)
1.1.1.6   root      162: {
1.1.1.7 ! root      163:     do {
        !           164:        accum = accum << 8 ^ crctable[(byte) (accum >> CRCSHIFTS) ^ *buf++];
        !           165:     } while (--len);
        !           166:     return maskcrc(accum);
        !           167: }                              /* crcbytes */
1.1.1.6   root      168: 
                    169: /* Initialize the CRC table using our codes */
                    170: void init_crc(void)
                    171: {
1.1.1.7 ! root      172:     mk_crctbl(PRZCRC);
1.1.1.6   root      173: }
                    174: 
                    175: 
                    176: /************************************************************************/
                    177: 
                    178: 
                    179: /* ENC is the basic 1 character encoding function to make a char printing */
                    180: #define ENC(c) ((int)bintoasc[((c) & 077)])
                    181: #define PAD            '='
                    182: 
                    183: /*
                    184:  * output one group of up to 3 bytes, pointed at by p, on file f.
                    185:  * if fewer than 3 are present, the 1 or two extras must be zeros.
                    186:  */
1.1.1.7 ! root      187: static void outdec(char *p, FILE * f, int count)
1.1.1.6   root      188: {
1.1.1.7 ! root      189:     int c1, c2, c3, c4;
1.1.1.6   root      190: 
1.1.1.7 ! root      191:     c1 = *p >> 2;
        !           192:     c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
        !           193:     c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
        !           194:     c4 = p[2] & 077;
        !           195:     putc(ENC(c1), f);
        !           196:     putc(ENC(c2), f);
        !           197:     if (count == 1) {
        !           198:        putc(PAD, f);
        !           199:        putc(PAD, f);
        !           200:     } else {
        !           201:        putc(ENC(c3), f);
        !           202:        if (count == 2)
        !           203:            putc(PAD, f);
        !           204:        else
        !           205:            putc(ENC(c4), f);
        !           206:     }
        !           207: }                              /* outdec */
1.1.1.6   root      208: 
                    209: 
                    210: /* Output the CRC value, MSB first per normal CRC conventions */
1.1.1.7 ! root      211: static void outcrc(word32 crc, FILE * outFile)
1.1.1.6   root      212: {
1.1.1.7 ! root      213:     char crcbuf[4];
        !           214:     crcbuf[0] = (crc >> 16) & 0xff;
        !           215:     crcbuf[1] = (crc >> 8) & 0xff;
        !           216:     crcbuf[2] = (crc >> 0) & 0xff;
        !           217:     putc(PAD, outFile);
        !           218:     outdec(crcbuf, outFile, 3);
        !           219:     putc('\n', outFile);
        !           220: }                              /* outcrc */
1.1.1.6   root      221: 
                    222: /* Return filename for output (text mode), but replace last letter(s) of
                    223:  * filename with the ascii for num.  It will use the appropriate number
                    224:  * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit,
                    225:  * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits.  If its
                    226:  * >= 1000, then we have other problems to worry about, and this might do
                    227:  * weird things.
                    228:  */
1.1.1.7 ! root      229: static char *numFilename(char *fname, int num, int ofnum)
1.1.1.6   root      230: {
1.1.1.7 ! root      231:     static char fnamenum[MAX_PATH];
        !           232:     int len;
        !           233:     int offset = 1;
        !           234: 
        !           235:     strcpy(fnamenum, fname);
        !           236:     len = strlen(fnamenum);
        !           237:     do {
        !           238:        fnamenum[len - offset] = '0' + (num % 10);
        !           239:        num /= 10;
        !           240:        ofnum /= 10;
        !           241:        offset++;
        !           242:     } while (ofnum >= 1 && offset < 4);
        !           243:     return fnamenum;
1.1.1.6   root      244: }
                    245: 
                    246: /*
                    247:  * Reads and discards a line from the given file.  Returns -1 on error or
                    248:  * EOF, 0 if the line is blank, and 1 if the line is not blank.
                    249:  */
1.1.1.7 ! root      250: static int skipline(FILE * f)
1.1.1.6   root      251: {
1.1.1.7 ! root      252:     int state, flag, c;
1.1.1.6   root      253: 
1.1.1.7 ! root      254:     state = 0;
        !           255:     flag = 0;
        !           256:     for (;;) {
        !           257:        c = getc(f);
        !           258:        if (c == '\n')
        !           259:            return flag;
        !           260:        if (state) {
        !           261:            ungetc(c, f);
        !           262:            return flag;
        !           263:        }
        !           264:        if (c == EOF)
        !           265:            return -1;
        !           266:        if (c == '\r')
        !           267:            state = 1;
        !           268:        else if (c != ' ')
        !           269:            flag = 1;
        !           270:     }
        !           271: }                              /* skipline */
1.1.1.6   root      272: 
                    273: /*
                    274:  * Copies a line from the input file to the output.  Does NOT copy the
                    275:  * trailing newline.  Returns -1 on EOF or error, 0 if the line was terminated
                    276:  * by EOF, and 1 if the line was terminated with a newline sequence.
                    277:  */
1.1.1.7 ! root      278: static int copyline(FILE * in, FILE * out)
1.1.1.6   root      279: {
1.1.1.7 ! root      280:     int state, flag, c;
1.1.1.6   root      281: 
1.1.1.7 ! root      282:     state = 0;
        !           283:     for (;;) {
        !           284:        c = getc(in);
        !           285:        if (c == '\n')
        !           286:            return 1;
        !           287:        if (state) {
        !           288:            ungetc(c, in);
        !           289:            return 1;
        !           290:        }
        !           291:        if (c == EOF)
        !           292:            return 0;
        !           293:        if (c == '\r')
        !           294:            state = 1;
        !           295:        else
        !           296:            putc(c, out);
        !           297:     }
        !           298: }                              /* copyline */
1.1.1.6   root      299: 
                    300: /*
                    301:  * Reads a line from file f, up to the size of the buffer.  The line in the
                    302:  * buffer will NOT include line termination, although any of (CR, LF, CRLF)
                    303:  * is accepted on input.  The return value is -1 on error, 0 if the line
                    304:  * was terminated abnormally (EOF, error, or out of buffer space), and
                    305:  * 1 if the line was terminated normally.
                    306:  *
                    307:  * Passing in a buffer less than 2 characters long is not a terribly bright
                    308:  * idea.
                    309:  */
1.1.1.7 ! root      310: static int getline(char *buf, int n, FILE * f)
1.1.1.6   root      311: {
1.1.1.7 ! root      312:     int state;
        !           313:     char *p;
        !           314:     int c;
        !           315: 
        !           316:     state = 0;
        !           317:     p = buf;
        !           318:     for (;;) {
        !           319:        c = getc(f);
        !           320:        if (c == '\n') {
        !           321:            *p = 0;
        !           322:            return 1;           /* Line terminated with \n or \r\n */
        !           323:        }
        !           324:        if (state) {
        !           325:            ungetc(c, f);
        !           326:            *p = 0;
        !           327:            return 1;           /* Line terminated with \r */
        !           328:        }
        !           329:        if (c == EOF) {
        !           330:            *p = 0;
        !           331:            return (p == buf) ? -1 : 0;         /* Error */
        !           332:        }
        !           333:        if (c == '\r')
        !           334:            state = 1;
        !           335:        else if (--n > 0) {
        !           336:            *p++ = c;
        !           337:        } else {
        !           338:            ungetc(c, f);
        !           339:            *p = 0;
        !           340:            return 0;           /* Out of buffer space */
        !           341:        }
        !           342:     }                          /* for (;;) */
        !           343: }                              /* getline */
1.1.1.6   root      344: 
                    345: /*
                    346:  * Read a line from file f, buf must be able to hold at least 80 characters.
                    347:  * Strips trailing spaces and line terminator, can read LF, CRLF and CR
                    348:  * textfiles.  Anything after 80 characters is ignored.  It can't be ASCII
                    349:  * armor anyway.
                    350:  */
                    351: static char *
1.1.1.7 ! root      352:  get_armor_line(char *buf, FILE * f)
1.1.1.6   root      353: {
1.1.1.7 ! root      354:     int c, n = 79;
        !           355:     char *p = buf;
1.1.1.6   root      356: 
1.1.1.7 ! root      357:     do {
        !           358:        c = getc(f);
        !           359:        if (c == '\n' || c == '\r' || c == EOF)
        !           360:            break;
        !           361:        *p++ = c;
        !           362:     } while (--n > 0);
        !           363:     if (p == buf && c == EOF) {
        !           364:        *buf = '\0';
        !           365:        return NULL;
        !           366:     }
        !           367:     /* skip to end of line */
        !           368:     while (c != '\n' && c != '\r' && c != EOF)
        !           369:        c = getc(f);
        !           370:     if (c == '\r' && (c = getc(f)) != '\n')
        !           371:        ungetc(c, f);
        !           372:     while (--p >= buf && *p == ' ');
        !           373:     *++p = '\0';
        !           374:     return buf;
1.1.1.6   root      375: }
                    376: 
                    377: 
                    378: /*
                    379:  * Encode a file in sections.  64 ASCII bytes * 720 lines = 46K, 
                    380:  * recommended max.  Usenet message size is 50K so this leaves a nice 
                    381:  * margin for .signature.  In the interests of orthogonality and 
                    382:  * programmer laziness no check is made for a message containing only 
1.1.1.7 ! root      383:  * a few lines (or even just an 'end')  after a section break. 
1.1.1.6   root      384:  */
                    385: #define LINE_LEN       48L
                    386: int pem_lines = 720;
                    387: #define BYTES_PER_SECTION      (LINE_LEN * pem_lines)
                    388: 
                    389: #if 1
                    390: /* This limit is advisory only; longer lines are handled properly.
                    391:  * The only requirement is that this be at least as long as the longest
                    392:  * delimiter string used by PGP
                    393:  * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n")
                    394:  */
                    395: #define MAX_LINE_SIZE 80
                    396: #else
1.1.1.7 ! root      397: #ifdef MSDOS                   /* limited stack space */
1.1.1.6   root      398: #define MAX_LINE_SIZE  256
                    399: #else
                    400: #define MAX_LINE_SIZE  1024
                    401: #endif
                    402: #endif
                    403: 
                    404: #ifndef VMS
                    405: /* armored files are opened in binary mode so that CRLF/LF/CR files
                    406:    can be handled by all systems */
                    407: #define        FOPRPEM FOPRBIN
                    408: #else
                    409: #define        FOPRPEM FOPRTXT
                    410: #endif
                    411: 
1.1.1.7 ! root      412: extern boolean verbose;                /* Undocumented command mode in PGP.C */
1.1.1.6   root      413: extern boolean filter_mode;
                    414: 
                    415: /*
                    416:  * Copy from infilename to outfilename, PEM encoding as you go along,
                    417:  * and with breaks every
                    418:  * pem_lines lines.
                    419:  * If clearfilename is non-NULL, first output that file preceded by a
                    420:  * special header line.
                    421:  */
                    422: static
                    423: int pem_file(char *infilename, char *outfilename, char *clearfilename)
                    424: {
1.1.1.7 ! root      425:     char buffer[MAX_LINE_SIZE];
        !           426:     int i, rc, bytesRead, lines = 0;
        !           427:     int noSections, currentSection = 1;
        !           428:     long fileLen;
        !           429:     crcword crc;
        !           430:     FILE *inFile, *outFile, *clearFile;
        !           431:     char *blocktype = "MESSAGE";
        !           432: 
        !           433:     /* open input file as binary */
        !           434:     if ((inFile = fopen(infilename, FOPRBIN)) == NULL)
        !           435:        return 1;
        !           436: 
        !           437:     if (!outfilename || pem_lines == 0) {
        !           438:        noSections = 1;
        !           439:     } else {
        !           440:        /* Evaluate how many parts this file will comprise */
        !           441:        fseek(inFile, 0L, SEEK_END);
        !           442:        fileLen = ftell(inFile);
        !           443:        rewind(inFile);
        !           444:        noSections = (fileLen + BYTES_PER_SECTION - 1) /
        !           445:            BYTES_PER_SECTION;
        !           446:        if (noSections > 99) {
        !           447:            pem_lines = ((fileLen + LINE_LEN - 1) / LINE_LEN + 98) / 99;
        !           448:            noSections = (fileLen + BYTES_PER_SECTION - 1) /
        !           449:                BYTES_PER_SECTION;
        !           450:            fprintf(pgpout,
        !           451:            "value for \"armorlines\" is too low, using %d\n", pem_lines);
        !           452:        }
        !           453:     }
        !           454: 
        !           455:     if (outfilename == NULL) {
        !           456:        outFile = stdout;
        !           457:     } else {
        !           458:        if (noSections > 1) {
        !           459:            force_extension(outfilename, ASC_EXTENSION);
        !           460:            outFile =
        !           461:                fopen(numFilename(outfilename, 1, noSections),
        !           462:                      FOPWTXT);
1.1.1.6   root      463:        } else {
1.1.1.7 ! root      464:            outFile = fopen(outfilename, FOPWTXT);
1.1.1.6   root      465:        }
1.1.1.7 ! root      466:     }
1.1.1.6   root      467: 
1.1.1.7 ! root      468:     if (outFile == NULL) {
1.1.1.6   root      469:        fclose(inFile);
1.1.1.7 ! root      470:        return 1;
        !           471:     }
        !           472:     if (clearfilename) {
        !           473:        if ((clearFile = fopen(clearfilename, FOPRTXT)) == NULL) {
        !           474:            fclose(inFile);
        !           475:            if (outFile != stdout)
        !           476:                fclose(outFile);
        !           477:            return 1;
        !           478:        }
        !           479:        fprintf(outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
        !           480:        while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0) {
        !           481:            /* Quote lines beginning with '-' as per RFC1113;
        !           482:             * Also quote lines beginning with "From "; this is
        !           483:             * for Unix mailers which add ">" to such lines.
        !           484:             */
        !           485:            if (buffer[0] == '-' || strncmp(buffer, "From ", 5) == 0)
        !           486:                fputs("- ", outFile);
        !           487:            fputs(buffer, outFile);
        !           488:            /* If there is more on this line, copy it */
        !           489:            if (i == 0)
        !           490:                if (copyline(clearFile, outFile) <= 0)
        !           491:                    break;
        !           492:            fputc('\n', outFile);
        !           493:        }
        !           494:        fclose(clearFile);
        !           495:        putc('\n', outFile);
        !           496:        blocktype = "SIGNATURE";
        !           497:     }
        !           498:     if (noSections == 1) {
        !           499:        byte ctb = 0;
        !           500:        ctb = getc(inFile);
        !           501:        if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
        !           502:            blocktype = "PUBLIC KEY BLOCK";
        !           503:        fprintf(outFile, "-----BEGIN PGP %s-----\n", blocktype);
        !           504:        rewind(inFile);
        !           505:     } else {
        !           506:        fprintf(outFile,
        !           507:                "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           508:                1, noSections);
        !           509:     }
        !           510:     fprintf(outFile, "Version: %s\n", LANG(rel_version));
        !           511:     if (globalCommentString[0])
        !           512:        fprintf(outFile, "Comment: %s\n", globalCommentString);
        !           513:     fprintf(outFile, "\n");
        !           514: 
        !           515:     init_crc();
        !           516:     crc = CRCINIT;
        !           517: 
        !           518:     while ((bytesRead = fread(buffer, 1, LINE_LEN, inFile)) > 0) {
        !           519:        /* Munge up LINE_LEN characters */
        !           520:        if (bytesRead < LINE_LEN)
        !           521:            fill0(buffer + bytesRead, LINE_LEN - bytesRead);
        !           522: 
        !           523:        crc = crcbytes((byte *) buffer, bytesRead, crc);
        !           524:        for (i = 0; i < bytesRead - 3; i += 3)
        !           525:            outdec(buffer + i, outFile, 3);
        !           526:        outdec(buffer + i, outFile, bytesRead - i);
        !           527:        putc('\n', outFile);
        !           528: 
        !           529:        if (++lines == pem_lines && currentSection < noSections) {
        !           530:            lines = 0;
        !           531:            outcrc(crc, outFile);
        !           532:            fprintf(outFile,
        !           533:                    "-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
        !           534:                    currentSection, noSections);
        !           535:            if (write_error(outFile)) {
        !           536:                fclose(outFile);
1.1.1.6   root      537:                return -1;
1.1.1.7 ! root      538:            }
        !           539:            fclose(outFile);
        !           540:            outFile = fopen(numFilename(outfilename,
        !           541:                                        ++currentSection,
        !           542:                                        noSections), FOPWTXT);
        !           543:            if (outFile == NULL) {
        !           544:                fclose(inFile);
        !           545:                return -1;
        !           546:            }
        !           547:            fprintf(outFile,
        !           548:                    "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           549:                    currentSection, noSections);
        !           550:            fprintf(outFile, "\n");
        !           551:            crc = CRCINIT;
        !           552:        }
        !           553:     }
        !           554:     outcrc(crc, outFile);
        !           555: 
        !           556:     if (noSections == 1)
        !           557:        fprintf(outFile, "-----END PGP %s-----\n", blocktype);
        !           558:     else
        !           559:        fprintf(outFile, "-----END PGP MESSAGE, PART %02d/%02d-----\n",
        !           560:                noSections, noSections);
        !           561: 
        !           562:     /* Done */
        !           563:     fclose(inFile);
        !           564:     rc = write_error(outFile);
        !           565:     if (outFile == stdout)
        !           566:        return rc;
        !           567:     fclose(outFile);
        !           568: 
        !           569:     if (rc)
        !           570:        return -1;
        !           571: 
        !           572:     if (clearfilename) {
        !           573:        fprintf(pgpout,
        !           574:                LANG("\nClear signature file: %s\n"), outfilename);
        !           575:     } else if (noSections == 1) {
        !           576:        fprintf(pgpout,
        !           577:                LANG("\nTransport armor file: %s\n"), outfilename);
        !           578:     } else {
        !           579:        fprintf(pgpout, LANG("\nTransport armor files: "));
        !           580:        for (i = 1; i <= noSections; ++i)
        !           581:            fprintf(pgpout, "%s%s",
        !           582:                    numFilename(outfilename, i, noSections),
        !           583:                    i == noSections ? "\n" : ", ");
        !           584:     }
        !           585:     return 0;
        !           586: }                              /* pem_file */
1.1.1.6   root      587: 
1.1.1.7 ! root      588: /*      End PEM encode routines. */
1.1.1.6   root      589: 
                    590: 
1.1.1.7 ! root      591: /*
        !           592:  * PEM decode routines.
        !           593:  */
1.1.1.6   root      594: static
                    595: int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
                    596: {
1.1.1.7 ! root      597:     unsigned char *bp;
        !           598:     int length;
        !           599:     unsigned int c1, c2, c3, c4;
        !           600:     register int j;
        !           601: 
        !           602:     length = 0;
        !           603:     bp = (unsigned char *) inbuf;
        !           604: 
        !           605:     /* FOUR input characters go into each THREE output charcters */
        !           606: 
        !           607:     while (*bp != '\0') {
        !           608:        if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80)
        !           609:            return -1;
        !           610:        ++bp;
        !           611:        if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80)
        !           612:            return -1;
        !           613:        if (*++bp == PAD) {
        !           614:            c3 = c4 = 0;
        !           615:            length += 1;
        !           616:            if (c2 & 15)
        !           617:                return -1;
        !           618:            if (strcmp((char *) bp, "==") == 0)
        !           619:                bp += 1;
        !           620:            else if (strcmp((char *) bp, "=3D=3D") == 0)
        !           621:                bp += 5;
        !           622:            else
        !           623:                return -1;
        !           624:        } else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
        !           625:            return -1;
        !           626:        } else {
        !           627:            if (*++bp == PAD) {
        !           628:                c4 = 0;
        !           629:                length += 2;
        !           630:                if (c3 & 3)
        !           631:                    return -1;
        !           632:                if (strcmp((char *) bp, "=") == 0);     /* All is well */
        !           633:                else if (strcmp((char *) bp, "=3D") == 0)
        !           634:                    bp += 2;
        !           635:                else
        !           636:                    return -1;
        !           637:            } else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
        !           638:                return -1;
        !           639:            } else {
        !           640:                length += 3;
        !           641:            }
        !           642:        }
        !           643:        ++bp;
        !           644:        j = (c1 << 2) | (c2 >> 4);
        !           645:        *outbuf++ = j;
        !           646:        j = (c2 << 4) | (c3 >> 2);
        !           647:        *outbuf++ = j;
        !           648:        j = (c3 << 6) | c4;
        !           649:        *outbuf++ = j;
        !           650:     }
1.1.1.6   root      651: 
1.1.1.7 ! root      652:     *outlength = length;
        !           653:     return 0;                  /* normal return */
1.1.1.6   root      654: 
1.1.1.7 ! root      655: }                              /* dpem_buffer */
1.1.1.6   root      656: 
                    657: static char pemfilename[MAX_PATH];
                    658: /*
                    659:  * try to open the next file of a multi-part armored file
                    660:  * the sequence number is expected at the end of the file name
                    661:  */
                    662: static FILE *
1.1.1.7 ! root      663:  open_next(void)
1.1.1.6   root      664: {
1.1.1.7 ! root      665:     char *p, *s, c;
        !           666:     FILE *fp;
1.1.1.6   root      667: 
1.1.1.7 ! root      668:     p = pemfilename + strlen(pemfilename);
        !           669:     while (--p >= pemfilename && isdigit(*p)) {
        !           670:        if (*p != '9') {
        !           671:            ++*p;
        !           672:            return fopen(pemfilename, FOPRPEM);
        !           673:        }
        !           674:        *p = '0';
        !           675:     }
        !           676: 
        !           677:     /* need an extra digit */
        !           678:     if (p >= pemfilename) {
        !           679:        /* try replacing character ( .as0 -> .a10 ) */
        !           680:        c = *p;
        !           681:        *p = '1';
        !           682:        if ((fp = fopen(pemfilename, FOPRPEM)) != NULL)
        !           683:            return fp;
        !           684:        *p = c;                 /* restore original character */
        !           685:     }
        !           686:     ++p;
        !           687:     for (s = p + strlen(p); s >= p; --s)
        !           688:        s[1] = *s;
        !           689:     *p = '1';                  /* insert digit ( fn0 -> fn10 ) */
1.1.1.6   root      690: 
1.1.1.7 ! root      691:     return fopen(pemfilename, FOPRPEM);
1.1.1.6   root      692: }
                    693: 
                    694: /*
                    695:  * Copy from in to out, decoding as you go, with handling for multiple
                    696:  * 500-line blocks of encoded data.
                    697:  */
                    698: static
1.1.1.7 ! root      699: int pemdecode(FILE * in, FILE * out)
1.1.1.6   root      700: {
1.1.1.7 ! root      701:     char inbuf[80];
        !           702:     char outbuf[80];
1.1.1.6   root      703: 
1.1.1.7 ! root      704:     int i, n, status;
        !           705:     int line;
        !           706:     int section, currentSection = 1;
        !           707:     int noSections = 0;
        !           708:     int gotcrc = 0;
        !           709:     long crc = CRCINIT, chkcrc = -1;
        !           710:     char crcbuf[4];
        !           711:     int ret_code = 0;
        !           712:     int end_of_message;
        !           713: 
        !           714:     init_crc();
        !           715: 
        !           716:     for (line = 1;; line++) {  /* for each input line */
        !           717:        if (get_armor_line(inbuf, in) == NULL) {
        !           718:            end_of_message = 1;
        !           719:        } else {
        !           720:            end_of_message =
        !           721:                (strncmp(inbuf, "-----END PGP MESSAGE,", 21) == 0);
        !           722:            ++infile_line;
        !           723:        }
1.1.1.6   root      724: 
1.1.1.7 ! root      725:        if (currentSection != noSections && end_of_message) {
        !           726:            /* End of this section */
        !           727:            if (gotcrc) {
        !           728:                if (chkcrc != crc) {
        !           729:                    fprintf(pgpout,
        !           730:  LANG("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
        !           731: /* continue with decoding to see if there are other bad parts */
        !           732:                    ret_code = -1;
        !           733:                }
        !           734:            }
        !           735:            gotcrc = 0;
        !           736:            crc = CRCINIT;
        !           737:            section = 0;
1.1.1.6   root      738: 
1.1.1.7 ! root      739:            /* Try and find start of next section */
        !           740:            do {
1.1.1.6   root      741:                if (get_armor_line(inbuf, in) == NULL) {
1.1.1.7 ! root      742:                    FILE *nextf;
        !           743:                    if ((nextf = open_next()) != NULL) {
        !           744:                        fclose(in);
        !           745:                        in = nextf;
1.1.1.6   root      746:                        continue;
1.1.1.7 ! root      747:                    }
        !           748:                    fprintf(pgpout,
        !           749:                    LANG("Can't find section %d.\n"), currentSection + 1);
        !           750:                    return -1;
1.1.1.6   root      751:                }
1.1.1.7 ! root      752:                ++infile_line;
        !           753:            }
        !           754:            while (strncmp(inbuf, "-----BEGIN PGP MESSAGE", 22));
1.1.1.6   root      755: 
1.1.1.7 ! root      756:            /* Make sure this section is the correct one */
        !           757:            if (2 != sscanf(inbuf,
        !           758:                            "-----BEGIN PGP MESSAGE, PART %d/%d",
        !           759:                            &section, &noSections)) {
        !           760:                fprintf(pgpout,
        !           761:                        LANG("Badly formed section header, part %d.\n"),
        !           762:                        currentSection + 1);
        !           763:                return -1;
        !           764:            }
        !           765:            if (section != ++currentSection) {
        !           766:                fprintf(pgpout,
        !           767: LANG("Sections out of order, expected part %d"), currentSection);
        !           768:                if (section)
        !           769:                    fprintf(pgpout,
        !           770:                            LANG(", got part %d\n"), section);
        !           771:                else
        !           772:                    fputc('\n', pgpout);
        !           773:                return -1;
        !           774:            }
        !           775:            /* Skip header after BEGIN line */
        !           776:            do {
        !           777:                ++infile_line;
        !           778:                if (get_armor_line(inbuf, in) == NULL) {
        !           779:                    fprintf(pgpout,
        !           780:                       LANG("ERROR: Hit EOF in header of section %d.\n"),
        !           781:                            currentSection);
        !           782:                    return -1;
1.1.1.6   root      783:                }
1.1.1.7 ! root      784:            } while (inbuf[0] != '\0');
1.1.1.6   root      785: 
1.1.1.7 ! root      786:            /* Continue decoding */
        !           787:            continue;
1.1.1.6   root      788:        }
1.1.1.7 ! root      789: /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
        !           790:  * or handle checksum
        !           791:  */
        !           792:        if (inbuf[0] == PAD) {  /* Checksum lines start
        !           793:                                   with PAD char */
        !           794:            /* If the already-armored file is sent through MIME
        !           795:             * and gets armored again, '=' will become '=3D'.
        !           796:             * To make life easier, we detect and work around this
        !           797:             * idiosyncracy.
        !           798:             */
        !           799:            if (strlen(inbuf) == 7 &&
        !           800:                inbuf[1] == '3' && inbuf[2] == 'D')
        !           801:                status = dpem_buffer(inbuf + 3, crcbuf, &n);
        !           802:            else
        !           803:                status = dpem_buffer(inbuf + 1, crcbuf, &n);
        !           804:            if (status < 0 || n != 3) {
        !           805:                fprintf(pgpout,
        !           806: LANG("ERROR: Badly formed ASCII armor checksum, line %d.\n"), line);
        !           807:                return -1;
        !           808:            }
        !           809:            chkcrc = (((long) crcbuf[0] << 16) & 0xff0000L) +
        !           810:                ((crcbuf[1] << 8) & 0xff00L) + (crcbuf[2] & 0xffL);
        !           811:            gotcrc = 1;
        !           812:            continue;
        !           813:        }
        !           814:        if (inbuf[0] == '\0') {
        !           815:            fprintf(pgpout,
        !           816:                    LANG("WARNING: No ASCII armor `END' line.\n"));
        !           817:            break;
        !           818:        }
        !           819:        if (strncmp(inbuf, "-----END PGP ", 13) == 0)
        !           820:            break;
        !           821: 
        !           822:        status = dpem_buffer(inbuf, outbuf, &n);
        !           823: 
        !           824:        if (status == -1) {
        !           825:            fprintf(pgpout,
        !           826:             LANG("ERROR: Bad ASCII armor character, line %d.\n"), line);
        !           827:            gotcrc = 1;         /* this will print part number,
        !           828:                                   continue with next part */
        !           829:            ret_code = -1;
        !           830:        }
        !           831:        if (n > sizeof outbuf) {
        !           832:            fprintf(pgpout,
        !           833:             LANG("ERROR: Bad ASCII armor line length %d on line %d.\n"),
        !           834:                    n, line);
        !           835:            return -1;
        !           836:        }
        !           837:        crc = crcbytes((byte *) outbuf, n, crc);
        !           838:        if (fwrite(outbuf, 1, n, out) != n) {
        !           839:            ret_code = -1;
        !           840:            break;
        !           841:        }
        !           842:     }                          /* line */
        !           843: 
        !           844:     if (gotcrc) {
        !           845:        if (chkcrc != crc) {
        !           846:            fprintf(pgpout,
        !           847:                    LANG("ERROR: Bad ASCII armor checksum"));
        !           848:            if (noSections > 0)
        !           849:                fprintf(pgpout,
        !           850:                        LANG(" in section %d"), noSections);
        !           851:            fputc('\n', pgpout);
        !           852:            return -1;
        !           853:        }
        !           854:     } else {
        !           855:        fprintf(pgpout,
        !           856:                LANG("Warning: Transport armor lacks a checksum.\n"));
        !           857:     }
1.1.1.6   root      858: 
1.1.1.7 ! root      859:     return ret_code;           /* normal return */
        !           860: }                              /* pemdecode */
1.1.1.6   root      861: 
                    862: static
                    863: boolean is_pemfile(char *infile)
                    864: {
1.1.1.7 ! root      865:     FILE *in;
        !           866:     char inbuf[80];
        !           867:     char outbuf[80];
        !           868:     int n, status;
        !           869:     long il;
1.1.1.6   root      870: 
1.1.1.7 ! root      871:     if ((in = fopen(infile, FOPRPEM)) == NULL) {
        !           872:        /* can't open file */
        !           873:        return FALSE;
        !           874:     }
        !           875:     /* Read to infile_line before we begin looking */
        !           876:     for (il = 0; il < infile_line; ++il) {
        !           877:        if (get_armor_line(inbuf, in) == NULL) {
        !           878:            fclose(in);
        !           879:            return FALSE;
        !           880:        }
        !           881:     }
        !           882: 
        !           883:     /* search file for header line */
        !           884:     for (;;) {
        !           885:        if (get_armor_line(inbuf, in) == NULL) {
        !           886:            break;
        !           887:        } else {
        !           888:            if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) {
        !           889:                if (strncmp(inbuf,
        !           890:                        "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
        !           891:                    fclose(in);
        !           892:                    return TRUE;
1.1.1.6   root      893:                }
1.1.1.7 ! root      894:                do {
        !           895:                    if (get_armor_line(inbuf, in) == NULL)
1.1.1.6   root      896:                        break;
                    897: #ifndef STRICT_PEM
1.1.1.7 ! root      898:                    if (dpem_buffer(inbuf, outbuf, &n) == 0
        !           899:                        && n == 48) {
        !           900:                        fclose(in);
        !           901:                        return TRUE;
        !           902:                    }
1.1.1.6   root      903: #endif
1.1.1.7 ! root      904:                } while (inbuf[0] != '\0');
        !           905:                if (get_armor_line(inbuf, in) == NULL)
        !           906:                    break;
        !           907:                status = dpem_buffer(inbuf, outbuf, &n);
        !           908:                if (status < 0)
        !           909:                    break;
        !           910:                fclose(in);
        !           911:                return TRUE;
        !           912:            }
1.1.1.6   root      913:        }
1.1.1.7 ! root      914:     }
1.1.1.6   root      915: 
1.1.1.7 ! root      916:     fclose(in);
        !           917:     return FALSE;
1.1.1.6   root      918: 
1.1.1.7 ! root      919: }                              /* is_pemfile */
1.1.1.6   root      920: 
                    921: static
                    922: int dpem_file(char *infile, char *outfile)
                    923: {
1.1.1.7 ! root      924:     FILE *in, *out;
        !           925:     char buf[MAX_LINE_SIZE];
        !           926:     char outbuf[80];
        !           927:     int status, n;
        !           928:     long il, fpos;
        !           929:     char *litfile = NULL;
        !           930: 
        !           931:     if ((in = fopen(infile, FOPRPEM)) == NULL) {
        !           932:        fprintf(pgpout, LANG("ERROR: Can't find file %s\n"), infile);
        !           933:        return 10;
        !           934:     }
        !           935:     strcpy(pemfilename, infile);       /* store filename for multi-parts */
        !           936: 
        !           937:     /* Skip to infile_line */
        !           938:     for (il = 0; il < infile_line; ++il) {
        !           939:        if (get_armor_line(buf, in) == NULL) {
        !           940:            fclose(in);
        !           941:            return -1;
        !           942:        }
        !           943:     }
        !           944: 
        !           945:     /* Loop through file, searching for header.  Decode anything with a
        !           946:        header, complain if there were no headers. */
        !           947: 
        !           948:     /* search file for header line */
        !           949:     for (;;) {
        !           950:        ++infile_line;
        !           951:        if (get_armor_line(buf, in) == NULL) {
        !           952:            fprintf(pgpout,
        !           953:                    LANG("ERROR: No ASCII armor `BEGIN' line!\n"));
        !           954:            fclose(in);
        !           955:            return 12;
        !           956:        }
        !           957:        if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
        !           958:            break;
        !           959:     }
        !           960:     if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
        !           961:        FILE *litout;
        !           962:        char *canonfile, *p;
        !           963:        int nline;
        !           964: 
        !           965:        litfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !           966:        if ((litout = fopen(litfile, FOPWTXT)) == NULL) {
        !           967:            fprintf(pgpout,
        !           968: LANG("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
        !           969:            fclose(in);
        !           970:            return -1;
1.1.1.6   root      971:        }
1.1.1.7 ! root      972:        /* Skip header lines until a blank is hit */
1.1.1.6   root      973:        do {
1.1.1.7 ! root      974:            ++infile_line;
        !           975:            status = skipline(in);
        !           976:        } while (status != 0);
        !           977:        /* Ignore error; getline will discover it again */
        !           978:        status = 0;
        !           979:        for (;;) {
        !           980:            ++infile_line;
        !           981:            nline = status;
        !           982:            status = getline(buf, sizeof buf, in);
        !           983:            if (status < 0) {
        !           984:                fprintf(pgpout,
        !           985: LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
1.1.1.6   root      986:                fclose(in);
1.1.1.7 ! root      987:                fclose(litout);
1.1.1.6   root      988:                rmtemp(litfile);
1.1.1.7 ! root      989:                return 12;
        !           990:            }
        !           991:            if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
        !           992:                break;
        !           993:            if (nline)
        !           994:                putc('\n', litout);
        !           995:            /* De-quote lines starting with '- ' */
        !           996:            fputs(buf + ((buf[0] == '-' && buf[1] == ' ') ? 2 : 0), litout);
        !           997:            /* Copy trailing part of line, if any. */
        !           998:            if (!status)
        !           999:                status = copyline(in, litout);
        !          1000:            /* Ignore error; getline will discover it again */
        !          1001:        }
        !          1002:        fflush(litout);
        !          1003:        if (ferror(litout)) {
        !          1004:            fclose(litout);
        !          1005:            fclose(in);
        !          1006:            rmtemp(litfile);
        !          1007:            return -1;
        !          1008:        }
        !          1009:        fclose(litout);
        !          1010:        canonfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !          1011:        strip_spaces = TRUE;
        !          1012:        make_canonical(litfile, canonfile);
        !          1013:        rmtemp(litfile);
        !          1014:        litfile = canonfile;
        !          1015:     }
        !          1016:     /* Skip header after BEGIN line */
        !          1017:     do {
        !          1018:        ++infile_line;
        !          1019:        fpos = ftell(in);
        !          1020:        if (get_armor_line(buf, in) == NULL) {
        !          1021:            fprintf(pgpout, LANG("ERROR: Hit EOF in header.\n"));
        !          1022:            fclose(in);
        !          1023:            return 13;
        !          1024:        }
        !          1025: #ifndef STRICT_PEM
        !          1026:        if (dpem_buffer(buf, outbuf, &n) == 0 && n == 48) {
        !          1027:            fseek(in, fpos, SEEK_SET);
        !          1028:            --infile_line;
        !          1029:            break;
1.1.1.6   root     1030:        }
1.1.1.7 ! root     1031: #endif
        !          1032:     } while (buf[0] != '\0');
1.1.1.6   root     1033: 
1.1.1.7 ! root     1034:     if ((out = fopen(outfile, FOPWBIN)) == NULL) {
        !          1035:        fprintf(pgpout,
        !          1036: LANG("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
1.1.1.6   root     1037:        fclose(in);
1.1.1.7 ! root     1038:        return -1;
        !          1039:     }
        !          1040:     status = pemdecode(in, out);
        !          1041: 
        !          1042:     if (litfile) {
        !          1043:        /* Glue the literal file read above to the signature */
        !          1044:        char lit_mode = MODE_TEXT;
        !          1045:        word32 dummystamp = 0;
        !          1046:        FILE *f = fopen(litfile, FOPRBIN);
        !          1047:        write_ctb_len(out, CTB_LITERAL2_TYPE, fsize(f) + 6, FALSE);
        !          1048:        fwrite(&lit_mode, 1, 1, out);   /* write lit_mode */
        !          1049:        fputc('\0', out);       /* No filename */
        !          1050:        fwrite(&dummystamp, 1, sizeof(dummystamp), out);
        !          1051:        /* dummy timestamp */
        !          1052:        copyfile(f, out, -1L);  /* Append literal file */
        !          1053:        fclose(f);
        !          1054:        rmtemp(litfile);
        !          1055:     }
        !          1056:     if (write_error(out))
        !          1057:        status = -1;
        !          1058:     fclose(out);
        !          1059:     fclose(in);
        !          1060:     return status;
        !          1061: }                              /* dpem_file */
1.1.1.6   root     1062: 
                   1063: /* Entry points for generic interface names */
1.1.1.7 ! root     1064: int armor_file(char *infile, char *outfile, char *filename, char *clearname)
1.1.1.6   root     1065: {
1.1.1.7 ! root     1066:     if (verbose)
        !          1067:        fprintf(pgpout,
        !          1068: "armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
        !          1069:                infile, outfile, filename, clearname);
        !          1070:     return pem_file(infile, outfile, clearname);
1.1.1.6   root     1071: }
                   1072: 
1.1.1.7 ! root     1073: int de_armor_file(char *infile, char *outfile, long *curline)
1.1.1.6   root     1074: {
1.1.1.7 ! root     1075:     int status;
1.1.1.6   root     1076: 
1.1.1.7 ! root     1077:     if (verbose)
        !          1078:        fprintf(pgpout,
        !          1079:             "de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
        !          1080:                infile, outfile, *curline);
        !          1081:     infile_line = (curline ? *curline : 0);
        !          1082:     status = dpem_file(infile, outfile);
        !          1083:     if (curline)
        !          1084:        *curline = infile_line;
        !          1085:     return status;
1.1.1.6   root     1086: }
                   1087: 
                   1088: boolean
1.1.1.7 ! root     1089: is_armor_file(char *infile, long startline)
1.1.1.6   root     1090: {
1.1.1.7 ! root     1091:     infile_line = startline;
        !          1092:     return is_pemfile(infile);
1.1.1.6   root     1093: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.