missing param to longjmp
[unix-history] / usr / src / usr.bin / mail / aux.c
CommitLineData
6447a23f
KS
1#
2
3#include "rcv.h"
4#include <sys/stat.h>
5#include <sgtty.h>
6#include <ctype.h>
7
8/*
9 * Mail -- a mail program
10 *
11 * Auxiliary functions.
12 */
13
a0852086 14static char *SccsId = "@(#)aux.c 2.2 %G%";
6447a23f
KS
15
16/*
17 * Return a pointer to a dynamic copy of the argument.
18 */
19
20char *
21savestr(str)
22 char *str;
23{
24 register char *cp, *cp2, *top;
25
26 for (cp = str; *cp; cp++)
27 ;
28 top = salloc(cp-str + 1);
29 if (top == NOSTR)
30 return(NOSTR);
31 for (cp = str, cp2 = top; *cp; cp++)
32 *cp2++ = *cp;
33 *cp2 = 0;
34 return(top);
35}
36
37/*
38 * Copy the name from the passed header line into the passed
39 * name buffer. Null pad the name buffer.
40 */
41
42copyname(linebuf, nbuf)
43 char *linebuf, *nbuf;
44{
45 register char *cp, *cp2;
46
47 for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++)
48 *cp2++ = *cp;
49 while (cp2-nbuf < 8)
50 *cp2++ = 0;
51}
52
53/*
54 * Announce a fatal error and die.
55 */
56
57panic(str)
58 char *str;
59{
60 prs("panic: ");
61 prs(str);
62 prs("\n");
63 exit(1);
64}
65
66/*
67 * Catch stdio errors and report them more nicely.
68 */
69
70_error(str)
71 char *str;
72{
73 prs("Stdio Error: ");
74 prs(str);
75 prs("\n");
76 abort();
77}
78
79/*
80 * Print a string on diagnostic output.
81 */
82
83prs(str)
84 char *str;
85{
86 register char *s;
87
88 for (s = str; *s; s++)
89 ;
90 write(2, str, s-str);
91}
92
93/*
94 * Touch the named message by setting its MTOUCH flag.
95 * Touched messages have the effect of not being sent
96 * back to the system mailbox on exit.
97 */
98
99touch(mesg)
100{
dffe7e4f
KS
101 register struct message *mp;
102
103 if (mesg < 1 || mesg > msgCount)
104 return;
105 mp = &message[mesg-1];
106 mp->m_flag |= MTOUCH;
107 if ((mp->m_flag & MREAD) == 0)
108 mp->m_flag |= MREAD|MSTATUS;
6447a23f
KS
109}
110
111/*
112 * Test to see if the passed file name is a directory.
113 * Return true if it is.
114 */
115
116isdir(name)
117 char name[];
118{
119 struct stat sbuf;
120
121 if (stat(name, &sbuf) < 0)
122 return(0);
123 return((sbuf.st_mode & S_IFMT) == S_IFDIR);
124}
125
126/*
127 * Compute the size in characters of the passed message
128 */
129
130unsigned int
131msize(messp)
132 struct message *messp;
133{
134 register struct message *mp;
135
136 mp = messp;
137 return(mp->m_size);
138}
139
140/*
141 * Count the number of arguments in the given string raw list.
142 */
143
144argcount(argv)
145 char **argv;
146{
147 register char **ap;
148
149 for (ap = argv; *ap != NOSTR; ap++)
150 ;
151 return(ap-argv);
152}
153
154/*
155 * Given a file address, determine the
156 * block number it represents.
157 */
158
159blockof(off)
160 off_t off;
161{
162 off_t a;
163
164 a = off >> 9;
165 a &= 077777;
166 return((int) a);
167}
168
169/*
170 * Take a file address, and determine
171 * its offset in the current block.
172 */
173
174offsetof(off)
175 off_t off;
176{
177 off_t a;
178
179 a = off & 0777;
180 return((int) a);
181}
182
183/*
184 * Determine if the passed file is actually a tty, via a call to
185 * gtty. This is not totally reliable, but . . .
186 */
187
188isatty(f)
189{
190 struct sgttyb buf;
191
192 if (gtty(f, &buf) < 0)
193 return(0);
194 return(1);
195}
196
197/*
198 * Return the desired header line from the passed message
199 * pointer (or NOSTR if the desired header field is not available).
200 */
201
202char *
203hfield(field, mp)
204 char field[];
205 struct message *mp;
206{
207 register FILE *ibuf;
208 char linebuf[LINESIZE];
209 register int lc;
210
211 ibuf = setinput(mp);
212 if ((lc = mp->m_lines) <= 0)
213 return(NOSTR);
214 if (readline(ibuf, linebuf) < 0)
215 return(NOSTR);
216 lc--;
217 do {
218 lc = gethfield(ibuf, linebuf, lc);
219 if (lc == -1)
220 return(NOSTR);
221 if (ishfield(linebuf, field))
222 return(savestr(hcontents(linebuf)));
223 } while (lc > 0);
224 return(NOSTR);
225}
226
227/*
228 * Return the next header field found in the given message.
229 * Return > 0 if something found, <= 0 elsewise.
230 * Must deal with \ continuations & other such fraud.
231 */
232
233gethfield(f, linebuf, rem)
234 register FILE *f;
235 char linebuf[];
236 register int rem;
237{
238 char line2[LINESIZE];
239 long loc;
240 register char *cp, *cp2;
241 register int c;
242
243
244 for (;;) {
245 if (rem <= 0)
246 return(-1);
247 if (readline(f, linebuf) < 0)
248 return(-1);
249 rem--;
250 if (strlen(linebuf) == 0)
251 return(-1);
252 if (isspace(linebuf[0]))
253 continue;
254 if (linebuf[0] == '>')
255 continue;
256 cp = index(linebuf, ':');
257 if (cp == NOSTR)
258 continue;
259 for (cp2 = linebuf; cp2 < cp; cp2++)
260 if (isdigit(*cp2))
261 continue;
262
263 /*
264 * I guess we got a headline.
265 * Handle wraparounding
266 */
267
268 for (;;) {
269 if (rem <= 0)
270 break;
271#ifdef CANTELL
272 loc = ftell(f);
273 if (readline(f, line2) < 0)
274 break;
275 rem--;
276 if (!isspace(line2[0])) {
277 fseek(f, loc, 0);
278 rem++;
279 break;
280 }
281#else
282 c = getc(f);
283 ungetc(c, f);
284 if (!isspace(c) || c == '\n')
285 break;
286 if (readline(f, line2) < 0)
287 break;
288 rem--;
289#endif
290 cp2 = line2;
291 for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
292 ;
293 if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2)
294 break;
295 cp = &linebuf[strlen(linebuf)];
296 while (cp > linebuf &&
297 (isspace(cp[-1]) || cp[-1] == '\\'))
298 cp--;
299 *cp++ = ' ';
300 for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
301 ;
302 strcpy(cp, cp2);
303 }
304 if ((c = strlen(linebuf)) > 0) {
305 cp = &linebuf[c-1];
306 while (cp > linebuf && isspace(*cp))
307 cp--;
308 *++cp = 0;
309 }
310 return(rem);
311 }
312 /* NOTREACHED */
313}
314
315/*
316 * Check whether the passed line is a header line of
317 * the desired breed.
318 */
319
320ishfield(linebuf, field)
321 char linebuf[], field[];
322{
323 register char *cp;
324 register int c;
325
326 if ((cp = index(linebuf, ':')) == NOSTR)
327 return(0);
328 if (cp == linebuf)
329 return(0);
330 cp--;
331 while (cp > linebuf && isspace(*cp))
332 cp--;
333 c = *++cp;
334 *cp = 0;
335 if (icequal(linebuf ,field)) {
336 *cp = c;
337 return(1);
338 }
339 *cp = c;
340 return(0);
341}
342
343/*
344 * Extract the non label information from the given header field
345 * and return it.
346 */
347
348char *
349hcontents(hfield)
350 char hfield[];
351{
352 register char *cp;
353
354 if ((cp = index(hfield, ':')) == NOSTR)
355 return(NOSTR);
356 cp++;
357 while (*cp && isspace(*cp))
358 cp++;
359 return(cp);
360}
361
362/*
363 * Compare two strings, ignoring case.
364 */
365
366icequal(s1, s2)
367 register char *s1, *s2;
368{
369
370 while (raise(*s1++) == raise(*s2))
371 if (*s2++ == 0)
372 return(1);
373 return(0);
374}
375
376/*
377 * The following code deals with input stacking to do source
378 * commands. All but the current file pointer are saved on
379 * the stack.
380 */
381
382static int ssp = -1; /* Top of file stack */
e48b42f1
KS
383struct sstack {
384 FILE *s_file; /* File we were in. */
385 int s_cond; /* Saved state of conditionals */
386} sstack[_NFILE];
6447a23f
KS
387
388/*
389 * Pushdown current input file and switch to a new one.
390 * Set the global flag "sourcing" so that others will realize
391 * that they are no longer reading from a tty (in all probability).
392 */
393
394source(name)
395 char name[];
396{
397 register FILE *fi;
5c7ba847 398 register char *cp;
6447a23f 399
5c7ba847
KS
400 if ((cp = expand(name)) == NOSTR)
401 return(1);
402 if ((fi = fopen(cp, "r")) == NULL) {
403 perror(cp);
6447a23f
KS
404 return(1);
405 }
406 if (ssp >= _NFILE-2) {
407 printf("Too much \"sourcing\" going on.\n");
408 fclose(fi);
409 return(1);
410 }
e48b42f1
KS
411 sstack[++ssp].s_file = input;
412 sstack[ssp].s_cond = cond;
413 cond = CANY;
6447a23f
KS
414 input = fi;
415 sourcing++;
416 return(0);
417}
418
419/*
420 * Source a file, but do nothing if the file cannot be opened.
421 */
422
423source1(name)
424 char name[];
425{
426 register int f;
427
428 if ((f = open(name, 0)) < 0)
429 return(0);
430 close(f);
431 source(name);
432}
433
434/*
435 * Pop the current input back to the previous level.
436 * Update the "sourcing" flag as appropriate.
437 */
438
439unstack()
440{
441 if (ssp < 0) {
442 printf("\"Source\" stack over-pop.\n");
443 sourcing = 0;
444 return(1);
445 }
446 fclose(input);
e48b42f1
KS
447 if (cond != CANY)
448 printf("Unmatched \"if\"\n");
449 cond = sstack[ssp].s_cond;
450 input = sstack[ssp--].s_file;
6447a23f
KS
451 if (ssp < 0)
452 sourcing = 0;
453 return(0);
454}
455
456/*
457 * Touch the indicated file.
458 * This is nifty for the shell.
459 * If we have the utime() system call, this is better served
460 * by using that, since it will work for empty files.
461 * On non-utime systems, we must sleep a second, then read.
462 */
463
464alter(name)
465 char name[];
466{
467#ifdef UTIME
468 struct stat statb;
469 long time();
470 time_t time_p[2];
471#else
472 register int pid, f;
473 char w;
474#endif UTIME
475
476#ifdef UTIME
477 if (stat(name, &statb) < 0)
478 return;
479 time_p[0] = time((long *) 0) + 1;
480 time_p[1] = statb.st_mtime;
481 utime(name, time_p);
482#else
6447a23f
KS
483 sleep(1);
484 if ((f = open(name, 0)) < 0)
a0852086 485 return;
6447a23f
KS
486 read(f, &w, 1);
487 exit(0);
488#endif
489}
490
491/*
492 * Examine the passed line buffer and
493 * return true if it is all blanks and tabs.
494 */
495
496blankline(linebuf)
497 char linebuf[];
498{
499 register char *cp;
500
501 for (cp = linebuf; *cp; cp++)
502 if (!any(*cp, " \t"))
503 return(0);
504 return(1);
505}
506
12388009
KS
507/*
508 * Get sender's name from this message. If the message has
509 * a bunch of arpanet stuff in it, we may have to skin the name
510 * before returning it.
511 */
512char *
513nameof(mp, reptype)
514 register struct message *mp;
515{
516
517 return(skin(name1(mp, reptype)));
518}
519
520/*
521 * Skin an arpa net address according to the RFC 733 interpretation
522 * of "host-phrase."
523 */
524char *
525skin(name)
526 char *name;
527{
528 register int c;
529 register char *cp, *cp2;
530 int gotlt, lastsp;
531 char nbuf[BUFSIZ];
532
533 if (name == NOSTR)
534 return(NOSTR);
535 if (index(name, '(') == NOSTR && index(name, '<') == NOSTR)
536 return(name);
537 gotlt = 0;
538 lastsp = 0;
539 for (cp = name, cp2 = nbuf, c = *cp++; *cp; c = *cp++) {
540 switch (c) {
541 case '(':
542 while (*cp != ')' && *cp != 0)
543 cp++;
544 if (*cp)
545 cp++;
546 break;
547
548 case ' ':
549 lastsp = 1;
550 break;
551
552 case '<':
553 cp2 = nbuf;
554 gotlt++;
555 lastsp = 0;
556 break;
557
558 case '>':
559 if (gotlt)
560 goto done;
561
562 /* Fall into . . . */
563
564 default:
565 if (lastsp) {
566 lastsp = 0;
567 *cp2++ = ' ';
568 }
569 *cp2++ = c;
570 break;
571 }
572 }
573done:
574 *cp2 = 0;
575
576 return(savestr(nbuf));
577}
578
6447a23f
KS
579/*
580 * Fetch the sender's name from the passed message.
12388009
KS
581 * Reptype can be
582 * 0 -- get sender's name for display purposes
583 * 1 -- get sender's name for reply
584 * 2 -- get sender's name for Reply
6447a23f
KS
585 */
586
587char *
12388009 588name1(mp, reptype)
6447a23f
KS
589 register struct message *mp;
590{
591 char namebuf[LINESIZE];
592 char linebuf[LINESIZE];
593 register char *cp, *cp2;
594 register FILE *ibuf;
595 int first = 1;
596
12388009
KS
597#ifndef DELIVERMAIL
598 if ((cp = hfield("from", mp)) != NOSTR)
599 return(cp);
600 if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
601 return(cp);
602#endif
6447a23f
KS
603 ibuf = setinput(mp);
604 copy("", namebuf);
605 if (readline(ibuf, linebuf) <= 0)
606 return(savestr(namebuf));
607newname:
608 for (cp = linebuf; *cp != ' '; cp++)
609 ;
610 while (any(*cp, " \t"))
611 cp++;
612 for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
613 cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
614 ;
615 *cp2 = '\0';
616 if (readline(ibuf, linebuf) <= 0)
617 return(savestr(namebuf));
618 if ((cp = index(linebuf, 'F')) == NULL)
619 return(savestr(namebuf));
620 if (strncmp(cp, "From", 4) != 0)
621 return(savestr(namebuf));
622 while ((cp = index(cp, 'r')) != NULL) {
623 if (strncmp(cp, "remote", 6) == 0) {
624 if ((cp = index(cp, 'f')) == NULL)
625 break;
626 if (strncmp(cp, "from", 4) != 0)
627 break;
628 if ((cp = index(cp, ' ')) == NULL)
629 break;
630 cp++;
631 if (first) {
632 copy(cp, namebuf);
633 first = 0;
634 } else
635 strcpy(rindex(namebuf, '!')+1, cp);
636 strcat(namebuf, "!");
637 goto newname;
638 }
639 cp++;
640 }
641 return(savestr(namebuf));
642}
643
644/*
645 * Find the rightmost pointer to an instance of the
646 * character in the string and return it.
647 */
648
649char *
650rindex(str, c)
651 char str[];
652 register int c;
653{
654 register char *cp, *cp2;
655
656 for (cp = str, cp2 = NOSTR; *cp; cp++)
657 if (c == *cp)
658 cp2 = cp;
659 return(cp2);
660}
661
662/*
663 * See if the string is a number.
664 */
665
666numeric(str)
667 char str[];
668{
669 register char *cp = str;
670
671 while (*cp)
672 if (!isdigit(*cp++))
673 return(0);
674 return(1);
675}
676
677/*
678 * Are any of the characters in the two strings the same?
679 */
680
681anyof(s1, s2)
682 register char *s1, *s2;
683{
684 register int c;
685
686 while (c = *s1++)
687 if (any(c, s2))
688 return(1);
689 return(0);
690}
691
692/*
693 * Determine the leftmost index of the character
694 * in the string.
695 */
696
697char *
698index(str, ch)
699 char *str;
700{
701 register char *cp;
702 register int c;
703
704 for (c = ch, cp = str; *cp; cp++)
705 if (*cp == c)
706 return(cp);
707 return(NOSTR);
708}
709
710/*
711 * String compare two strings of bounded length.
712 */
713
714strncmp(as1, as2, an)
715 char *as1, *as2;
716{
717 register char *s1, *s2;
718 register int n;
719
720 s1 = as1;
721 s2 = as2;
722 n = an;
723 while (--n >= 0 && *s1 == *s2++)
724 if (*s1++ == '\0')
725 return(0);
726 return(n<0 ? 0 : *s1 - *--s2);
727}
728