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