use shell="" instead of shell=none for no shell,
[unix-history] / usr / src / usr.bin / mail / aux.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
0c5f72fb
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
d0aeaf5a
DF
11 */
12
0c5f72fb 13#ifdef notdef
9c226cb6 14static char sccsid[] = "@(#)aux.c 5.9 (Berkeley) %G%";
0c5f72fb 15#endif /* notdef */
6447a23f
KS
16
17#include "rcv.h"
18#include <sys/stat.h>
6447a23f
KS
19
20/*
21 * Mail -- a mail program
22 *
23 * Auxiliary functions.
24 */
25
6447a23f
KS
26/*
27 * Return a pointer to a dynamic copy of the argument.
28 */
29
30char *
31savestr(str)
32 char *str;
33{
34 register char *cp, *cp2, *top;
35
36 for (cp = str; *cp; cp++)
37 ;
38 top = salloc(cp-str + 1);
39 if (top == NOSTR)
40 return(NOSTR);
41 for (cp = str, cp2 = top; *cp; cp++)
42 *cp2++ = *cp;
43 *cp2 = 0;
44 return(top);
45}
46
6447a23f
KS
47/*
48 * Announce a fatal error and die.
49 */
50
828615a1
EW
51/*VARARGS1*/
52panic(fmt, a, b)
53 char *fmt;
6447a23f 54{
828615a1
EW
55 fprintf(stderr, "panic: ");
56 fprintf(stderr, fmt, a, b);
57 putc('\n', stderr);
6447a23f
KS
58 exit(1);
59}
60
6447a23f
KS
61/*
62 * Touch the named message by setting its MTOUCH flag.
63 * Touched messages have the effect of not being sent
64 * back to the system mailbox on exit.
65 */
66
67touch(mesg)
68{
dffe7e4f
KS
69 register struct message *mp;
70
71 if (mesg < 1 || mesg > msgCount)
72 return;
73 mp = &message[mesg-1];
74 mp->m_flag |= MTOUCH;
75 if ((mp->m_flag & MREAD) == 0)
76 mp->m_flag |= MREAD|MSTATUS;
6447a23f
KS
77}
78
79/*
80 * Test to see if the passed file name is a directory.
81 * Return true if it is.
82 */
83
84isdir(name)
85 char name[];
86{
87 struct stat sbuf;
88
89 if (stat(name, &sbuf) < 0)
90 return(0);
91 return((sbuf.st_mode & S_IFMT) == S_IFDIR);
92}
93
6447a23f
KS
94/*
95 * Count the number of arguments in the given string raw list.
96 */
97
98argcount(argv)
99 char **argv;
100{
101 register char **ap;
102
828615a1 103 for (ap = argv; *ap++ != NOSTR;)
6447a23f 104 ;
828615a1 105 return ap - argv - 1;
6447a23f
KS
106}
107
6447a23f
KS
108/*
109 * Return the desired header line from the passed message
110 * pointer (or NOSTR if the desired header field is not available).
111 */
112
113char *
114hfield(field, mp)
115 char field[];
116 struct message *mp;
117{
118 register FILE *ibuf;
119 char linebuf[LINESIZE];
120 register int lc;
828615a1
EW
121 register char *hfield;
122 char *colon;
6447a23f
KS
123
124 ibuf = setinput(mp);
828615a1
EW
125 if ((lc = mp->m_lines - 1) < 0)
126 return NOSTR;
6447a23f 127 if (readline(ibuf, linebuf) < 0)
828615a1
EW
128 return NOSTR;
129 while (lc > 0) {
130 if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
131 return NOSTR;
132 if (hfield = ishfield(linebuf, colon, field))
133 return savestr(hfield);
134 }
135 return NOSTR;
6447a23f
KS
136}
137
138/*
139 * Return the next header field found in the given message.
828615a1
EW
140 * Return >= 0 if something found, < 0 elsewise.
141 * "colon" is set to point to the colon in the header.
6447a23f
KS
142 * Must deal with \ continuations & other such fraud.
143 */
144
828615a1 145gethfield(f, linebuf, rem, colon)
6447a23f
KS
146 register FILE *f;
147 char linebuf[];
148 register int rem;
828615a1 149 char **colon;
6447a23f
KS
150{
151 char line2[LINESIZE];
6447a23f
KS
152 register char *cp, *cp2;
153 register int c;
154
6447a23f 155 for (;;) {
828615a1
EW
156 if (--rem < 0)
157 return -1;
158 if ((c = readline(f, linebuf)) <= 0)
159 return -1;
160 for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
161 cp++)
162 ;
163 if (*cp != ':' || cp == linebuf)
6447a23f 164 continue;
6447a23f
KS
165 /*
166 * I guess we got a headline.
167 * Handle wraparounding
168 */
828615a1
EW
169 *colon = cp;
170 cp = linebuf + c;
6447a23f 171 for (;;) {
828615a1
EW
172 while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
173 ;
174 cp++;
6447a23f
KS
175 if (rem <= 0)
176 break;
828615a1
EW
177 ungetc(c = getc(f), f);
178 if (c != ' ' && c != '\t')
6447a23f 179 break;
828615a1 180 if ((c = readline(f, line2)) < 0)
6447a23f
KS
181 break;
182 rem--;
828615a1 183 for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
6447a23f 184 ;
828615a1
EW
185 c -= cp2 - line2;
186 if (cp + c >= linebuf + LINESIZE - 2)
6447a23f 187 break;
6447a23f 188 *cp++ = ' ';
828615a1
EW
189 bcopy(cp2, cp, c);
190 cp += c;
6447a23f 191 }
828615a1
EW
192 *cp = 0;
193 return rem;
6447a23f
KS
194 }
195 /* NOTREACHED */
196}
197
198/*
199 * Check whether the passed line is a header line of
828615a1 200 * the desired breed. Return the field body, or 0.
6447a23f
KS
201 */
202
828615a1
EW
203char*
204ishfield(linebuf, colon, field)
6447a23f 205 char linebuf[], field[];
828615a1 206 char *colon;
6447a23f 207{
828615a1 208 register char *cp = colon;
6447a23f 209
6447a23f 210 *cp = 0;
828615a1
EW
211 if (!icequal(linebuf, field)) {
212 *cp = ':';
213 return 0;
6447a23f 214 }
828615a1
EW
215 *cp = ':';
216 for (cp++; *cp == ' ' || *cp == '\t'; cp++)
217 ;
218 return cp;
6447a23f
KS
219}
220
221/*
222 * Compare two strings, ignoring case.
223 */
224
225icequal(s1, s2)
226 register char *s1, *s2;
227{
828615a1 228 register c1, c2;
6447a23f 229
828615a1
EW
230 for (;;) {
231 if ((c1 = (unsigned char)*s1++) !=
232 (c2 = (unsigned char)*s2++)) {
233 if (isupper(c1))
234 c1 = tolower(c1);
235 if (c1 != c2)
236 return 0;
237 }
238 if (c1 == 0)
239 return 1;
240 }
241 /*NOTREACHED*/
6447a23f
KS
242}
243
da0d3a6d
KS
244/*
245 * Copy a string, lowercasing it as we go.
246 */
247istrcpy(dest, src)
828615a1 248 register char *dest, *src;
da0d3a6d 249{
da0d3a6d 250
da0d3a6d 251 do {
828615a1
EW
252 if (isupper(*src))
253 *dest++ = tolower(*src);
254 else
255 *dest++ = *src;
256 } while (*src++ != 0);
da0d3a6d
KS
257}
258
6447a23f
KS
259/*
260 * The following code deals with input stacking to do source
261 * commands. All but the current file pointer are saved on
262 * the stack.
263 */
264
265static int ssp = -1; /* Top of file stack */
e48b42f1
KS
266struct sstack {
267 FILE *s_file; /* File we were in. */
268 int s_cond; /* Saved state of conditionals */
f4aa38b5 269 int s_loading; /* Loading .mailrc, etc. */
46053c99 270} sstack[NOFILE];
6447a23f
KS
271
272/*
273 * Pushdown current input file and switch to a new one.
274 * Set the global flag "sourcing" so that others will realize
275 * that they are no longer reading from a tty (in all probability).
276 */
277
278source(name)
279 char name[];
280{
281 register FILE *fi;
5c7ba847 282 register char *cp;
6447a23f 283
5c7ba847
KS
284 if ((cp = expand(name)) == NOSTR)
285 return(1);
286 if ((fi = fopen(cp, "r")) == NULL) {
287 perror(cp);
6447a23f
KS
288 return(1);
289 }
46053c99 290 if (ssp >= NOFILE - 2) {
6447a23f
KS
291 printf("Too much \"sourcing\" going on.\n");
292 fclose(fi);
293 return(1);
294 }
e48b42f1
KS
295 sstack[++ssp].s_file = input;
296 sstack[ssp].s_cond = cond;
f4aa38b5
KS
297 sstack[ssp].s_loading = loading;
298 loading = 0;
e48b42f1 299 cond = CANY;
6447a23f
KS
300 input = fi;
301 sourcing++;
302 return(0);
303}
304
6447a23f
KS
305/*
306 * Pop the current input back to the previous level.
307 * Update the "sourcing" flag as appropriate.
308 */
309
310unstack()
311{
312 if (ssp < 0) {
313 printf("\"Source\" stack over-pop.\n");
314 sourcing = 0;
315 return(1);
316 }
317 fclose(input);
e48b42f1
KS
318 if (cond != CANY)
319 printf("Unmatched \"if\"\n");
320 cond = sstack[ssp].s_cond;
f4aa38b5 321 loading = sstack[ssp].s_loading;
e48b42f1 322 input = sstack[ssp--].s_file;
6447a23f 323 if (ssp < 0)
f4aa38b5 324 sourcing = loading;
6447a23f
KS
325 return(0);
326}
327
328/*
329 * Touch the indicated file.
330 * This is nifty for the shell.
6447a23f
KS
331 */
332
333alter(name)
334 char name[];
335{
6447a23f
KS
336 struct stat statb;
337 long time();
338 time_t time_p[2];
6447a23f 339
6447a23f
KS
340 if (stat(name, &statb) < 0)
341 return;
342 time_p[0] = time((long *) 0) + 1;
343 time_p[1] = statb.st_mtime;
344 utime(name, time_p);
6447a23f
KS
345}
346
347/*
348 * Examine the passed line buffer and
349 * return true if it is all blanks and tabs.
350 */
351
352blankline(linebuf)
353 char linebuf[];
354{
355 register char *cp;
356
357 for (cp = linebuf; *cp; cp++)
46053c99 358 if (*cp != ' ' && *cp != '\t')
6447a23f
KS
359 return(0);
360 return(1);
361}
362
12388009
KS
363/*
364 * Get sender's name from this message. If the message has
365 * a bunch of arpanet stuff in it, we may have to skin the name
366 * before returning it.
367 */
368char *
369nameof(mp, reptype)
370 register struct message *mp;
371{
8bcfa450 372 register char *cp, *cp2;
12388009 373
8bcfa450
KS
374 cp = skin(name1(mp, reptype));
375 if (reptype != 0 || charcount(cp, '!') < 2)
376 return(cp);
377 cp2 = rindex(cp, '!');
378 cp2--;
379 while (cp2 > cp && *cp2 != '!')
380 cp2--;
381 if (*cp2 == '!')
382 return(cp2 + 1);
383 return(cp);
12388009
KS
384}
385
386/*
b4817aab 387 * Skin an arpa net address according to the RFC 822 interpretation
12388009
KS
388 * of "host-phrase."
389 */
390char *
391skin(name)
392 char *name;
393{
394 register int c;
395 register char *cp, *cp2;
b4817aab 396 char *bufend;
12388009
KS
397 int gotlt, lastsp;
398 char nbuf[BUFSIZ];
46053c99 399 int nesting;
12388009
KS
400
401 if (name == NOSTR)
402 return(NOSTR);
e557a09a 403 if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
828615a1 404 && index(name, ' ') == NOSTR)
12388009
KS
405 return(name);
406 gotlt = 0;
407 lastsp = 0;
b4817aab
KM
408 bufend = nbuf;
409 for (cp = name, cp2 = bufend; c = *cp++; ) {
12388009
KS
410 switch (c) {
411 case '(':
b4817aab
KM
412 /*
413 * Start of a "comment".
414 * Ignore it.
415 */
46053c99 416 nesting = 1;
b4817aab
KM
417 while ((c = *cp) != 0) {
418 cp++;
419 switch (c) {
420 case '\\':
421 if (*cp == 0)
422 goto outcm;
423 cp++;
424 break;
46053c99
S
425 case '(':
426 nesting++;
427 break;
428
429 case ')':
430 --nesting;
431 break;
432 }
433
434 if (nesting <= 0)
435 break;
436 }
b4817aab
KM
437 outcm:
438 lastsp = 0;
439 break;
440
441 case '"':
442 /*
443 * Start of a "quoted-string".
444 * Copy it in its entirety.
445 */
446 while ((c = *cp) != 0) {
447 cp++;
448 switch (c) {
449 case '\\':
450 if ((c = *cp) == 0)
451 goto outqs;
452 cp++;
453 break;
454 case '"':
455 goto outqs;
456 }
457 *cp2++ = c;
458 }
459 outqs:
e557a09a 460 lastsp = 0;
12388009
KS
461 break;
462
463 case ' ':
e557a09a
CL
464 if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
465 cp += 3, *cp2++ = '@';
466 else
467 if (cp[0] == '@' && cp[1] == ' ')
468 cp += 2, *cp2++ = '@';
469 else
470 lastsp = 1;
12388009
KS
471 break;
472
473 case '<':
b4817aab 474 cp2 = bufend;
12388009
KS
475 gotlt++;
476 lastsp = 0;
477 break;
478
479 case '>':
b4817aab
KM
480 if (gotlt) {
481 gotlt = 0;
482 while (*cp != ',' && *cp != 0)
483 cp++;
484 if (*cp == 0 )
485 goto done;
486 *cp2++ = ',';
487 *cp2++ = ' ';
488 bufend = cp2;
489 break;
490 }
12388009
KS
491
492 /* Fall into . . . */
493
494 default:
495 if (lastsp) {
496 lastsp = 0;
497 *cp2++ = ' ';
498 }
499 *cp2++ = c;
500 break;
501 }
502 }
503done:
504 *cp2 = 0;
505
506 return(savestr(nbuf));
507}
508
6447a23f
KS
509/*
510 * Fetch the sender's name from the passed message.
12388009
KS
511 * Reptype can be
512 * 0 -- get sender's name for display purposes
513 * 1 -- get sender's name for reply
514 * 2 -- get sender's name for Reply
6447a23f
KS
515 */
516
517char *
12388009 518name1(mp, reptype)
6447a23f
KS
519 register struct message *mp;
520{
521 char namebuf[LINESIZE];
522 char linebuf[LINESIZE];
523 register char *cp, *cp2;
524 register FILE *ibuf;
525 int first = 1;
526
12388009 527 if ((cp = hfield("from", mp)) != NOSTR)
828615a1 528 return cp;
12388009 529 if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
828615a1 530 return cp;
6447a23f 531 ibuf = setinput(mp);
828615a1
EW
532 namebuf[0] = 0;
533 if (readline(ibuf, linebuf) < 0)
6447a23f
KS
534 return(savestr(namebuf));
535newname:
828615a1 536 for (cp = linebuf; *cp && *cp != ' '; cp++)
6447a23f 537 ;
828615a1 538 for (; *cp == ' ' || *cp == '\t'; cp++)
6447a23f 539 ;
828615a1
EW
540 for (cp2 = &namebuf[strlen(namebuf)];
541 *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
542 *cp2++ = *cp++;
6447a23f 543 *cp2 = '\0';
828615a1 544 if (readline(ibuf, linebuf) < 0)
6447a23f
KS
545 return(savestr(namebuf));
546 if ((cp = index(linebuf, 'F')) == NULL)
547 return(savestr(namebuf));
548 if (strncmp(cp, "From", 4) != 0)
549 return(savestr(namebuf));
550 while ((cp = index(cp, 'r')) != NULL) {
551 if (strncmp(cp, "remote", 6) == 0) {
552 if ((cp = index(cp, 'f')) == NULL)
553 break;
554 if (strncmp(cp, "from", 4) != 0)
555 break;
556 if ((cp = index(cp, ' ')) == NULL)
557 break;
558 cp++;
559 if (first) {
828615a1 560 strcpy(namebuf, cp);
6447a23f
KS
561 first = 0;
562 } else
563 strcpy(rindex(namebuf, '!')+1, cp);
564 strcat(namebuf, "!");
565 goto newname;
566 }
567 cp++;
568 }
569 return(savestr(namebuf));
570}
571
8bcfa450
KS
572/*
573 * Count the occurances of c in str
574 */
575charcount(str, c)
576 char *str;
577{
578 register char *cp;
579 register int i;
580
581 for (i = 0, cp = str; *cp; cp++)
582 if (*cp == c)
583 i++;
584 return(i);
585}
586
6447a23f 587/*
828615a1 588 * Are any of the characters in the two strings the same?
6447a23f
KS
589 */
590
828615a1
EW
591anyof(s1, s2)
592 register char *s1, *s2;
6447a23f 593{
6447a23f 594
828615a1
EW
595 while (*s1)
596 if (index(s2, *s1++))
597 return 1;
598 return 0;
6447a23f
KS
599}
600
601/*
828615a1 602 * Convert c to upper case
6447a23f
KS
603 */
604
828615a1
EW
605raise(c)
606 register c;
607{
608
609 if (islower(c))
610 return toupper(c);
611 return c;
612}
613
614/*
615 * Copy s1 to s2, return pointer to null in s2.
616 */
617
618char *
619copy(s1, s2)
6447a23f
KS
620 register char *s1, *s2;
621{
6447a23f 622
828615a1
EW
623 while (*s2++ = *s1++)
624 ;
625 return s2 - 1;
626}
627
628/*
629 * Add a single character onto a string.
630 */
631
632stradd(str, c)
633 register char *str;
634{
635
636 while (*str++)
637 ;
638 str[-1] = c;
639 *str = 0;
6447a23f
KS
640}
641
da0d3a6d
KS
642/*
643 * See if the given header field is supposed to be ignored.
644 */
887efe38 645isign(field, ignore)
da0d3a6d 646 char *field;
887efe38 647 struct ignoretab ignore[2];
da0d3a6d
KS
648{
649 char realfld[BUFSIZ];
da0d3a6d 650
46053c99
S
651 /*
652 * Lower-case the string, so that "Status" and "status"
653 * will hash to the same place.
654 */
da0d3a6d 655 istrcpy(realfld, field);
887efe38
EW
656 if (ignore[1].i_count > 0)
657 return (!member(realfld, ignore + 1));
46053c99
S
658 else
659 return (member(realfld, ignore));
660}
661
662member(realfield, table)
663 register char *realfield;
887efe38 664 struct ignoretab *table;
46053c99
S
665{
666 register struct ignore *igp;
667
887efe38 668 for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
828615a1
EW
669 if (*igp->i_field == *realfield &&
670 equal(igp->i_field, realfield))
46053c99 671 return (1);
46053c99 672 return (0);
da0d3a6d 673}