|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.