Annotation of 43BSD/ucb/sendbug/unixtomh.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char SccsId[] = "@(#)unixtomh.c 1.1     5/16/85";
                      3: #endif
                      4: 
                      5: /*
                      6:  * This program copies the mail file in standard unix format
                      7:  * given as $1 to the file $2 in Rand Message Handler format.
                      8:  * The change made is to bracket each message with a line
                      9:  * containing 4 control-A's and to split the From line into
                     10:  * a From: field and a Date: field, with the date in Arpanet
                     11:  * standard format.
                     12:  *
                     13:  * This program is designed to be called from the rand mh program
                     14:  * ``inc''
                     15:  *
                     16:  * Set SENDMAIL if you are running sendmail -- this guarantees that
                     17:  * From: and Date: lines will appear already, and will put the info
                     18:  * in the UNIX-From line into a Received-From: field.
                     19:  */
                     20: 
                     21: #include <stdio.h>
                     22: #include <sys/types.h>
                     23: #include <sys/timeb.h>
                     24: #include <ctype.h>
                     25: 
                     26: #define SENDMAIL
                     27: 
                     28: struct headline {
                     29:        char    *l_from;        /* The name of the sender */
                     30:        char    *l_tty;         /* His tty string (if any) */
                     31:        char    *l_date;        /* The entire date string */
                     32: };
                     33: 
                     34: char *savestr(), *copyin(), *copy(), *nextword(), *calloc();
                     35: char *index();
                     36: 
                     37: #define        NOSTR           ((char *) 0)
                     38: #define        UUCP                    /* Undo strange uucp naming */
                     39: 
                     40: main(argc, argv)
                     41:        char **argv;
                     42: {
                     43:        char linebuf[BUFSIZ];
                     44:        register int maybe;
                     45:        register FILE *inf, *outf;
                     46:        int inhdr, infld;
                     47: 
                     48:        if (argc > 3) {
                     49:                fprintf(stderr, "Usage: unixtomh name1 name2\n");
                     50:                exit(1);
                     51:        }
                     52:        outf = inf = NULL;
                     53:        if (argc < 3)
                     54:                outf = stdout;
                     55:        if (argc < 2)
                     56:                inf = stdin;
                     57:        if (inf == NULL && (inf = fopen(argv[1], "r")) == NULL) {
                     58:                perror(argv[1]);
                     59:                exit(1);
                     60:        }
                     61:        if (outf == NULL && (outf = fopen(argv[2], "w")) == NULL) {
                     62:                perror(argv[2]);
                     63:                exit(1);
                     64:        }
                     65:        maybe = 1;
                     66:        inhdr = 0;
                     67:        infld = 0;
                     68:        while (nullgets(linebuf, BUFSIZ, inf) > 0) {
                     69:                if (maybe && ishead(linebuf)) {
                     70:                        fputs("\1\1\1\1\n", outf);
                     71:                        inhdr++;
                     72:                        dohead(linebuf, inf, outf);
                     73:                        continue;
                     74:                }
                     75:                if (strlen(linebuf) == 0) {
                     76:                        maybe = 1;
                     77:                        inhdr = 0;
                     78:                        infld = 0;
                     79:                        putc('\n', outf);
                     80:                        continue;
                     81:                }
                     82:                else
                     83:                        maybe = 0;
                     84: #ifndef SENDMAIL
                     85:                if (inhdr && strcmpn(linebuf, "Date: ", 6) == 0)
                     86:                        continue;
                     87:                if (inhdr && strcmpn(linebuf, "From: ", 6) == 0)
                     88:                        continue;
                     89: #endif SENDMAIL
                     90:                if (infld && isspace(linebuf[0])) {
                     91:                        fputs(linebuf, outf);
                     92:                        putc('\n', outf);
                     93:                        continue;
                     94:                }
                     95:                if (inhdr && !isspace(linebuf[0])) {
                     96:                        char *colp, *sp;
                     97: 
                     98:                        colp = index(linebuf, ':');
                     99:                        sp = index(linebuf, ' ');
                    100:                        if (colp == NOSTR || sp == NOSTR || sp < colp) {
                    101:                                putc('\n', outf);
                    102:                                inhdr = 0;
                    103:                        }
                    104:                        else
                    105:                                infld = 1;
                    106:                }
                    107:                fputs(linebuf, outf);
                    108:                putc('\n', outf);
                    109:        }
                    110:        fputs("\1\1\1\1\n", outf);
                    111:        fflush(outf);
                    112:        if (ferror(outf)) {
                    113:                fprintf(stderr, "unixtomh: write: ");
                    114:                perror(argv[2]);
                    115:                exit(1);
                    116:        }
                    117:        exit(0);
                    118: }
                    119: 
                    120: /*
                    121:  * Get a line from the given file descriptor, don't return the
                    122:  * terminating newline.
                    123:  */
                    124: 
                    125: nullgets(linebuf, sz, file)
                    126:        char linebuf[];
                    127:        register FILE *file;
                    128: {
                    129:        register char *cp;
                    130:        register int c, cnt;
                    131: 
                    132:        cp = linebuf;
                    133:        cnt = sz;
                    134:        do {
                    135:                if (--cnt <= 0) {
                    136:                        *cp = 0;
                    137:                        return(1);
                    138:                }
                    139:                c = getc(file);
                    140:                *cp++ = c;
                    141:        } while (c != EOF && c != '\n');
                    142:        if (c == EOF && cp == linebuf+1)
                    143:                return(0);
                    144:        *--cp = 0;
                    145:        return(1);
                    146: }
                    147: 
                    148: /*
                    149:  * Output the fields extracted from the From line --
                    150:  * From: and Date:  Untangle UUCP stuff if appropriate.
                    151:  */
                    152: 
                    153: dohead(line, infile, outfile)
                    154:        char line[];
                    155:        register FILE *infile, *outfile;
                    156: {
                    157:        register char *cp;
                    158:        struct headline hl;
                    159:        char parbuf[BUFSIZ];
                    160: #ifdef UUCP
                    161:        char *word();
                    162:        char namebuf[BUFSIZ];
                    163:        char linebuf[BUFSIZ];
                    164:        int first;
                    165:        long curoff;
                    166: #endif UUCP
                    167: 
                    168:        parse(line, &hl, parbuf);
                    169: #ifndef SENDMAIL
                    170:        putdate(hl.l_date, outfile);
                    171: #endif SENDMAIL
                    172: #ifdef UUCP
                    173:        if (strcmp(hl.l_from, "uucp") == 0) {
                    174:                strcpy(namebuf, "");
                    175:                first = 1;
                    176:                for (;;) {
                    177:                        curoff = ftell(infile);
                    178:                        if (fgets(linebuf, BUFSIZ, infile) == NULL)
                    179:                                break;
                    180:                        if (strcmp(word(1, linebuf), ">From") != 0)
                    181:                                break;
                    182:                        if (strcmp(word(-3, linebuf), "remote") != 0)
                    183:                                break;
                    184:                        if (strcmp(word(-2, linebuf), "from") != 0)
                    185:                                break;
                    186:                        if (first) {
                    187:                                strcpy(namebuf, word(-1, linebuf));
                    188:                                strcat(namebuf, "!");
                    189:                                strcat(namebuf, word(2, linebuf));
                    190:                                first = 0;
                    191:                        }
                    192:                        else {
                    193:                                strcpy(rindex(namebuf, '!')+1,
                    194:                                    word(-1, linebuf));
                    195:                                strcat(namebuf, "!");
                    196:                                strcat(namebuf, word(2, linebuf));
                    197:                        }
                    198:                }
                    199:                fseek(infile, curoff, 0);
                    200: #ifdef SENDMAIL
                    201:                if (!first)
                    202:                        fprintf(outfile, "Return-Path: <%s>\n", namebuf);
                    203: #else SENDMAIL
                    204:                if (first)
                    205:                        fprintf(outfile, "From: uucp\n");
                    206:                else
                    207:                        fprintf(outfile, "From: %s\n", namebuf);
                    208: #endif SENDMAIL
                    209:                return;
                    210:        }
                    211: #endif UUCP
                    212: #ifdef SENDMAIL
                    213:        if (hl.l_from[0] == '<')
                    214:                fprintf(outfile, "Return-Path: %s\n", hl.l_from);
                    215:        else
                    216:                fprintf(outfile, "Return-Path: <%s>\n", hl.l_from);
                    217: #else SENDMAIL
                    218:        fprintf(outfile, "From: %s\n", hl.l_from);
                    219: #endif SENDMAIL
                    220: }
                    221: 
                    222: #ifdef UUCP
                    223: 
                    224: /*
                    225:  * Return liberal word i from the given string.
                    226:  * The words are numbered 1, 2, 3, . . .  from the left
                    227:  * and -1, -2, . . . from the right.
                    228:  */
                    229: 
                    230: char *
                    231: word(index, str)
                    232:        char str[];
                    233: {
                    234:        register char *cp;
                    235:        char *secbuf;
                    236:        register int c;
                    237:        static char retbuf[100];
                    238:        char *gword();
                    239: 
                    240:        cp = str;
                    241:        if ((c = index) > 0) {
                    242:                while (c-- > 0)
                    243:                        cp = gword(cp, retbuf);
                    244:                return(retbuf);
                    245:        }
                    246:        if (c == 0)
                    247:                return("");
                    248:        secbuf = (char *) alloca(strlen(str) + 1);
                    249:        strcpy(secbuf, str);
                    250:        rev(secbuf);
                    251:        cp = word(-index, secbuf);
                    252:        rev(cp);
                    253:        return(cp);
                    254: }
                    255: 
                    256: /*
                    257:  * Skip leading blanks in the string, return
                    258:  * first liberal word collected.
                    259:  */
                    260: 
                    261: char *
                    262: gword(cp, buf)
                    263:        register char *cp;
                    264:        char buf[];
                    265: {
                    266:        register char *cp2;
                    267: 
                    268:        cp2 = buf;
                    269:        while (*cp && any(*cp, " \t\n"))
                    270:                cp++;
                    271:        while (*cp && !any(*cp, " \t\n"))
                    272:                *cp2++ = *cp++;
                    273:        *cp2 = 0;
                    274:        return(cp);
                    275: }
                    276: 
                    277: /*
                    278:  * Reverse the characters in the string in place
                    279:  */
                    280: 
                    281: rev(str)
                    282:        char str[];
                    283: {
                    284:        register char *cpl, *cpr;
                    285:        register int s;
                    286: 
                    287:        s = strlen(str);
                    288:        cpl = str;
                    289:        cpr = &str[s-1];
                    290:        while (cpl < cpr) {
                    291:                s = *cpl;
                    292:                *cpl++ = *cpr;
                    293:                *cpr-- = s;
                    294:        }
                    295: }
                    296: #endif UUCP
                    297: 
                    298: /*
                    299:  * Save a string in dynamic space.
                    300:  * This little goodie is needed for
                    301:  * a headline detector in head.c
                    302:  */
                    303: 
                    304: char *
                    305: savestr(str)
                    306:        char str[];
                    307: {
                    308:        register char *top;
                    309: 
                    310:        top = calloc(strlen(str) + 1, 1);
                    311:        if (top == NOSTR) {
                    312:                fprintf(stderr, "unixtomh:  Ran out of memory\n");
                    313:                exit(1);
                    314:        }
                    315:        copy(str, top);
                    316:        return(top);
                    317: }
                    318: 
                    319: /*
                    320:  * See if the passed line buffer is a mail header.
                    321:  * Return true if yes.  Note the extreme pains to
                    322:  * accomodate all funny formats.
                    323:  */
                    324: 
                    325: ishead(linebuf)
                    326:        char linebuf[];
                    327: {
                    328:        register char *cp;
                    329:        struct headline hl;
                    330:        char parbuf[BUFSIZ];
                    331: 
                    332:        cp = linebuf;
                    333:        if (!isname("From ", cp, 5))
                    334:                return(0);
                    335:        parse(cp, &hl, parbuf);
                    336:        if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
                    337:                fail(linebuf, "No from or date field");
                    338:                return(0);
                    339:        }
                    340:        if (!isdate(hl.l_date)) {
                    341:                fail(linebuf, "Date field not legal date");
                    342:                return(0);
                    343:        }
                    344:        
                    345:        /*
                    346:         * I guess we got it!
                    347:         */
                    348: 
                    349:        return(1);
                    350: }
                    351: 
                    352: fail(linebuf, reason)
                    353:        char linebuf[], reason[];
                    354: {
                    355:        return;
                    356: }
                    357: 
                    358: /*
                    359:  * Split a headline into its useful components.
                    360:  * Copy the line into dynamic string space, then set
                    361:  * pointers into the copied line in the passed headline
                    362:  * structure.  Actually, it scans.
                    363:  */
                    364: 
                    365: parse(line, hl, pbuf)
                    366:        char line[], pbuf[];
                    367:        struct headline *hl;
                    368: {
                    369:        register char *cp, *dp;
                    370:        char *sp;
                    371:        char word[BUFSIZ];
                    372: 
                    373:        hl->l_from = NOSTR;
                    374:        hl->l_tty = NOSTR;
                    375:        hl->l_date = NOSTR;
                    376:        cp = line;
                    377:        sp = pbuf;
                    378: 
                    379:        /*
                    380:         * Skip the first "word" of the line, which should be "From"
                    381:         * anyway.
                    382:         */
                    383: 
                    384:        cp = nextword(cp, word);
                    385:        dp = nextword(cp, word);
                    386:        if (word[0] != 0)
                    387:                hl->l_from = copyin(word, &sp);
                    388:        if (isname(dp, "tty", 3)) {
                    389:                cp = nextword(dp, word);
                    390:                hl->l_tty = copyin(word, &sp);
                    391:                if (cp != NOSTR)
                    392:                        hl->l_date = copyin(cp, &sp);
                    393:        }
                    394:        else
                    395:                if (dp != NOSTR)
                    396:                        hl->l_date = copyin(dp, &sp);
                    397: }
                    398: 
                    399: /*
                    400:  * Copy the string on the left into the string on the right
                    401:  * and bump the right (reference) string pointer by the length.
                    402:  * Thus, dynamically allocate space in the right string, copying
                    403:  * the left string into it.
                    404:  */
                    405: 
                    406: char *
                    407: copyin(src, space)
                    408:        char src[];
                    409:        char **space;
                    410: {
                    411:        register char *cp, *top;
                    412:        register int s;
                    413: 
                    414:        s = strlen(src);
                    415:        cp = *space;
                    416:        top = cp;
                    417:        strcpy(cp, src);
                    418:        cp += s + 1;
                    419:        *space = cp;
                    420:        return(top);
                    421: }
                    422: 
                    423: /*
                    424:  * See if the two passed strings agree in the first n characters.
                    425:  * Return true if they do, gnu.
                    426:  */
                    427: 
                    428: isname(as1, as2, acount)
                    429:        char *as1, *as2;
                    430: {
                    431:        register char *s1, *s2;
                    432:        register count;
                    433: 
                    434:        s1 = as1;
                    435:        s2 = as2;
                    436:        count = acount;
                    437:        if (count > 0)
                    438:                do
                    439:                        if (*s1++ != *s2++)
                    440:                                return(0);
                    441:                while (--count);
                    442:        return(1);
                    443: }
                    444: 
                    445: /*
                    446:  * Test to see if the passed string is a ctime(3) generated
                    447:  * date string as documented in the manual.  The template
                    448:  * below is used as the criterion of correctness.
                    449:  * Also, we check for a possible trailing time zone using
                    450:  * the auxtype template.
                    451:  */
                    452: 
                    453: #define        L       1               /* A lower case char */
                    454: #define        S       2               /* A space */
                    455: #define        D       3               /* A digit */
                    456: #define        O       4               /* An optional digit or space */
                    457: #define        C       5               /* A colon */
                    458: #define        N       6               /* A new line */
                    459: #define U      7               /* An upper case char */
                    460: 
                    461: char ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
                    462: char tmztypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
                    463: 
                    464: isdate(date)
                    465:        char date[];
                    466: {
                    467:        register char *cp;
                    468: 
                    469:        cp = date;
                    470:        if (cmatch(cp, ctypes))
                    471:                return(1);
                    472:        return(cmatch(cp, tmztypes));
                    473: }
                    474: 
                    475: /*
                    476:  * Match the given string against the given template.
                    477:  * Return 1 if they match, 0 if they don't
                    478:  */
                    479: 
                    480: cmatch(str, temp)
                    481:        char str[], temp[];
                    482: {
                    483:        register char *cp, *tp;
                    484:        register int c;
                    485: 
                    486:        cp = str;
                    487:        tp = temp;
                    488:        while (*cp != '\0' && *tp != 0) {
                    489:                c = *cp++;
                    490:                switch (*tp++) {
                    491:                case L:
                    492:                        if (!islower(c))
                    493:                                return(0);
                    494:                        break;
                    495: 
                    496:                case S:
                    497:                        if (c != ' ')
                    498:                                return(0);
                    499:                        break;
                    500: 
                    501:                case D:
                    502:                        if (!isdigit(c))
                    503:                                return(0);
                    504:                        break;
                    505: 
                    506:                case O:
                    507:                        if (c != ' ' && !isdigit(c))
                    508:                                return(0);
                    509:                        break;
                    510: 
                    511:                case C:
                    512:                        if (c != ':')
                    513:                                return(0);
                    514:                        break;
                    515: 
                    516:                case N:
                    517:                        if (c != '\n')
                    518:                                return(0);
                    519:                        break;
                    520: 
                    521:                case U:
                    522:                        if (!isupper(c))
                    523:                                return(0);
                    524:                        break;
                    525:                }
                    526:        }
                    527:        if (*cp != '\0' || *tp != 0)
                    528:                return(0);
                    529:        return(1);
                    530: }
                    531: 
                    532: /*
                    533:  * Collect a liberal (space, tab delimited) word into the word buffer
                    534:  * passed.  Also, return a pointer to the next word following that,
                    535:  * or NOSTR if none follow.
                    536:  */
                    537: 
                    538: char *
                    539: nextword(wp, wbuf)
                    540:        char wp[], wbuf[];
                    541: {
                    542:        register char *cp, *cp2;
                    543: 
                    544:        if ((cp = wp) == NOSTR) {
                    545:                copy("", wbuf);
                    546:                return(NOSTR);
                    547:        }
                    548:        cp2 = wbuf;
                    549:        while (!any(*cp, " \t") && *cp != '\0')
                    550:                if (*cp == '"') {
                    551:                        *cp2++ = *cp++;
                    552:                        while (*cp != '\0' && *cp != '"')
                    553:                                *cp2++ = *cp++;
                    554:                        if (*cp == '"')
                    555:                                *cp2++ = *cp++;
                    556:                } else
                    557:                        *cp2++ = *cp++;
                    558:        *cp2 = '\0';
                    559:        while (any(*cp, " \t"))
                    560:                cp++;
                    561:        if (*cp == '\0')
                    562:                return(NOSTR);
                    563:        return(cp);
                    564: }
                    565: 
                    566: /*
                    567:  * Copy str1 to str2, return pointer to null in str2.
                    568:  */
                    569: 
                    570: char *
                    571: copy(str1, str2)
                    572:        char *str1, *str2;
                    573: {
                    574:        register char *s1, *s2;
                    575: 
                    576:        s1 = str1;
                    577:        s2 = str2;
                    578:        while (*s1)
                    579:                *s2++ = *s1++;
                    580:        *s2 = 0;
                    581:        return(s2);
                    582: }
                    583: 
                    584: /*
                    585:  * Is ch any of the characters in str?
                    586:  */
                    587: 
                    588: any(ch, str)
                    589:        char *str;
                    590: {
                    591:        register char *f;
                    592:        register c;
                    593: 
                    594:        f = str;
                    595:        c = ch;
                    596:        while (*f)
                    597:                if (c == *f++)
                    598:                        return(1);
                    599:        return(0);
                    600: }
                    601: 
                    602: /*
                    603:  * Convert lower case letters to upper case.
                    604:  */
                    605: 
                    606: raise(c)
                    607:        register int c;
                    608: {
                    609:        if (c >= 'a' && c <= 'z')
                    610:                c += 'A' - 'a';
                    611:        return(c);
                    612: }

unix.superglobalmegacorp.com

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