date and time created 80/10/08 09:50:02 by kas
[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
14static char *SccsId = "@(#)aux.c 1.1 %G%";
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{
101 if (mesg >= 1 && mesg <= msgCount)
102 message[mesg-1].m_flag |= MTOUCH;
103}
104
105/*
106 * Test to see if the passed file name is a directory.
107 * Return true if it is.
108 */
109
110isdir(name)
111 char name[];
112{
113 struct stat sbuf;
114
115 if (stat(name, &sbuf) < 0)
116 return(0);
117 return((sbuf.st_mode & S_IFMT) == S_IFDIR);
118}
119
120/*
121 * Compute the size in characters of the passed message
122 */
123
124unsigned int
125msize(messp)
126 struct message *messp;
127{
128 register struct message *mp;
129
130 mp = messp;
131 return(mp->m_size);
132}
133
134/*
135 * Count the number of arguments in the given string raw list.
136 */
137
138argcount(argv)
139 char **argv;
140{
141 register char **ap;
142
143 for (ap = argv; *ap != NOSTR; ap++)
144 ;
145 return(ap-argv);
146}
147
148/*
149 * Given a file address, determine the
150 * block number it represents.
151 */
152
153blockof(off)
154 off_t off;
155{
156 off_t a;
157
158 a = off >> 9;
159 a &= 077777;
160 return((int) a);
161}
162
163/*
164 * Take a file address, and determine
165 * its offset in the current block.
166 */
167
168offsetof(off)
169 off_t off;
170{
171 off_t a;
172
173 a = off & 0777;
174 return((int) a);
175}
176
177/*
178 * Determine if the passed file is actually a tty, via a call to
179 * gtty. This is not totally reliable, but . . .
180 */
181
182isatty(f)
183{
184 struct sgttyb buf;
185
186 if (gtty(f, &buf) < 0)
187 return(0);
188 return(1);
189}
190
191/*
192 * Return the desired header line from the passed message
193 * pointer (or NOSTR if the desired header field is not available).
194 */
195
196char *
197hfield(field, mp)
198 char field[];
199 struct message *mp;
200{
201 register FILE *ibuf;
202 char linebuf[LINESIZE];
203 register int lc;
204
205 ibuf = setinput(mp);
206 if ((lc = mp->m_lines) <= 0)
207 return(NOSTR);
208 if (readline(ibuf, linebuf) < 0)
209 return(NOSTR);
210 lc--;
211 do {
212 lc = gethfield(ibuf, linebuf, lc);
213 if (lc == -1)
214 return(NOSTR);
215 if (ishfield(linebuf, field))
216 return(savestr(hcontents(linebuf)));
217 } while (lc > 0);
218 return(NOSTR);
219}
220
221/*
222 * Return the next header field found in the given message.
223 * Return > 0 if something found, <= 0 elsewise.
224 * Must deal with \ continuations & other such fraud.
225 */
226
227gethfield(f, linebuf, rem)
228 register FILE *f;
229 char linebuf[];
230 register int rem;
231{
232 char line2[LINESIZE];
233 long loc;
234 register char *cp, *cp2;
235 register int c;
236
237
238 for (;;) {
239 if (rem <= 0)
240 return(-1);
241 if (readline(f, linebuf) < 0)
242 return(-1);
243 rem--;
244 if (strlen(linebuf) == 0)
245 return(-1);
246 if (isspace(linebuf[0]))
247 continue;
248 if (linebuf[0] == '>')
249 continue;
250 cp = index(linebuf, ':');
251 if (cp == NOSTR)
252 continue;
253 for (cp2 = linebuf; cp2 < cp; cp2++)
254 if (isdigit(*cp2))
255 continue;
256
257 /*
258 * I guess we got a headline.
259 * Handle wraparounding
260 */
261
262 for (;;) {
263 if (rem <= 0)
264 break;
265#ifdef CANTELL
266 loc = ftell(f);
267 if (readline(f, line2) < 0)
268 break;
269 rem--;
270 if (!isspace(line2[0])) {
271 fseek(f, loc, 0);
272 rem++;
273 break;
274 }
275#else
276 c = getc(f);
277 ungetc(c, f);
278 if (!isspace(c) || c == '\n')
279 break;
280 if (readline(f, line2) < 0)
281 break;
282 rem--;
283#endif
284 cp2 = line2;
285 for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
286 ;
287 if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2)
288 break;
289 cp = &linebuf[strlen(linebuf)];
290 while (cp > linebuf &&
291 (isspace(cp[-1]) || cp[-1] == '\\'))
292 cp--;
293 *cp++ = ' ';
294 for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
295 ;
296 strcpy(cp, cp2);
297 }
298 if ((c = strlen(linebuf)) > 0) {
299 cp = &linebuf[c-1];
300 while (cp > linebuf && isspace(*cp))
301 cp--;
302 *++cp = 0;
303 }
304 return(rem);
305 }
306 /* NOTREACHED */
307}
308
309/*
310 * Check whether the passed line is a header line of
311 * the desired breed.
312 */
313
314ishfield(linebuf, field)
315 char linebuf[], field[];
316{
317 register char *cp;
318 register int c;
319
320 if ((cp = index(linebuf, ':')) == NOSTR)
321 return(0);
322 if (cp == linebuf)
323 return(0);
324 cp--;
325 while (cp > linebuf && isspace(*cp))
326 cp--;
327 c = *++cp;
328 *cp = 0;
329 if (icequal(linebuf ,field)) {
330 *cp = c;
331 return(1);
332 }
333 *cp = c;
334 return(0);
335}
336
337/*
338 * Extract the non label information from the given header field
339 * and return it.
340 */
341
342char *
343hcontents(hfield)
344 char hfield[];
345{
346 register char *cp;
347
348 if ((cp = index(hfield, ':')) == NOSTR)
349 return(NOSTR);
350 cp++;
351 while (*cp && isspace(*cp))
352 cp++;
353 return(cp);
354}
355
356/*
357 * Compare two strings, ignoring case.
358 */
359
360icequal(s1, s2)
361 register char *s1, *s2;
362{
363
364 while (raise(*s1++) == raise(*s2))
365 if (*s2++ == 0)
366 return(1);
367 return(0);
368}
369
370/*
371 * The following code deals with input stacking to do source
372 * commands. All but the current file pointer are saved on
373 * the stack.
374 */
375
376static int ssp = -1; /* Top of file stack */
377static FILE *sstack[_NFILE]; /* Saved input files */
378
379/*
380 * Pushdown current input file and switch to a new one.
381 * Set the global flag "sourcing" so that others will realize
382 * that they are no longer reading from a tty (in all probability).
383 */
384
385source(name)
386 char name[];
387{
388 register FILE *fi;
389
390 if ((fi = fopen(name, "r")) == NULL) {
391 perror(name);
392 return(1);
393 }
394 if (ssp >= _NFILE-2) {
395 printf("Too much \"sourcing\" going on.\n");
396 fclose(fi);
397 return(1);
398 }
399 sstack[++ssp] = input;
400 input = fi;
401 sourcing++;
402 return(0);
403}
404
405/*
406 * Source a file, but do nothing if the file cannot be opened.
407 */
408
409source1(name)
410 char name[];
411{
412 register int f;
413
414 if ((f = open(name, 0)) < 0)
415 return(0);
416 close(f);
417 source(name);
418}
419
420/*
421 * Pop the current input back to the previous level.
422 * Update the "sourcing" flag as appropriate.
423 */
424
425unstack()
426{
427 if (ssp < 0) {
428 printf("\"Source\" stack over-pop.\n");
429 sourcing = 0;
430 return(1);
431 }
432 fclose(input);
433 input = sstack[ssp--];
434 if (ssp < 0)
435 sourcing = 0;
436 return(0);
437}
438
439/*
440 * Touch the indicated file.
441 * This is nifty for the shell.
442 * If we have the utime() system call, this is better served
443 * by using that, since it will work for empty files.
444 * On non-utime systems, we must sleep a second, then read.
445 */
446
447alter(name)
448 char name[];
449{
450#ifdef UTIME
451 struct stat statb;
452 long time();
453 time_t time_p[2];
454#else
455 register int pid, f;
456 char w;
457#endif UTIME
458
459#ifdef UTIME
460 if (stat(name, &statb) < 0)
461 return;
462 time_p[0] = time((long *) 0) + 1;
463 time_p[1] = statb.st_mtime;
464 utime(name, time_p);
465#else
466 if ((pid = fork()) != 0)
467 return;
468 clrbuf(stdout);
469 clrbuf(stderr);
470 clrbuf(stdin);
471 sleep(1);
472 if ((f = open(name, 0)) < 0)
473 exit(1);
474 read(f, &w, 1);
475 exit(0);
476#endif
477}
478
479/*
480 * Examine the passed line buffer and
481 * return true if it is all blanks and tabs.
482 */
483
484blankline(linebuf)
485 char linebuf[];
486{
487 register char *cp;
488
489 for (cp = linebuf; *cp; cp++)
490 if (!any(*cp, " \t"))
491 return(0);
492 return(1);
493}
494
495/*
496 * Fetch the sender's name from the passed message.
497 */
498
499char *
500nameof(mp)
501 register struct message *mp;
502{
503 char namebuf[LINESIZE];
504 char linebuf[LINESIZE];
505 register char *cp, *cp2;
506 register FILE *ibuf;
507 int first = 1;
508
509 if ((cp = hfield("reply-to", mp)) != NOSTR) {
510 strcpy(namebuf, cp);
511 return(namebuf);
512 }
513 ibuf = setinput(mp);
514 copy("", namebuf);
515 if (readline(ibuf, linebuf) <= 0)
516 return(savestr(namebuf));
517newname:
518 for (cp = linebuf; *cp != ' '; cp++)
519 ;
520 while (any(*cp, " \t"))
521 cp++;
522 for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
523 cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
524 ;
525 *cp2 = '\0';
526 if (readline(ibuf, linebuf) <= 0)
527 return(savestr(namebuf));
528 if ((cp = index(linebuf, 'F')) == NULL)
529 return(savestr(namebuf));
530 if (strncmp(cp, "From", 4) != 0)
531 return(savestr(namebuf));
532 while ((cp = index(cp, 'r')) != NULL) {
533 if (strncmp(cp, "remote", 6) == 0) {
534 if ((cp = index(cp, 'f')) == NULL)
535 break;
536 if (strncmp(cp, "from", 4) != 0)
537 break;
538 if ((cp = index(cp, ' ')) == NULL)
539 break;
540 cp++;
541 if (first) {
542 copy(cp, namebuf);
543 first = 0;
544 } else
545 strcpy(rindex(namebuf, '!')+1, cp);
546 strcat(namebuf, "!");
547 goto newname;
548 }
549 cp++;
550 }
551 return(savestr(namebuf));
552}
553
554/*
555 * Find the rightmost pointer to an instance of the
556 * character in the string and return it.
557 */
558
559char *
560rindex(str, c)
561 char str[];
562 register int c;
563{
564 register char *cp, *cp2;
565
566 for (cp = str, cp2 = NOSTR; *cp; cp++)
567 if (c == *cp)
568 cp2 = cp;
569 return(cp2);
570}
571
572/*
573 * See if the string is a number.
574 */
575
576numeric(str)
577 char str[];
578{
579 register char *cp = str;
580
581 while (*cp)
582 if (!isdigit(*cp++))
583 return(0);
584 return(1);
585}
586
587/*
588 * Are any of the characters in the two strings the same?
589 */
590
591anyof(s1, s2)
592 register char *s1, *s2;
593{
594 register int c;
595
596 while (c = *s1++)
597 if (any(c, s2))
598 return(1);
599 return(0);
600}
601
602/*
603 * Determine the leftmost index of the character
604 * in the string.
605 */
606
607char *
608index(str, ch)
609 char *str;
610{
611 register char *cp;
612 register int c;
613
614 for (c = ch, cp = str; *cp; cp++)
615 if (*cp == c)
616 return(cp);
617 return(NOSTR);
618}
619
620/*
621 * String compare two strings of bounded length.
622 */
623
624strncmp(as1, as2, an)
625 char *as1, *as2;
626{
627 register char *s1, *s2;
628 register int n;
629
630 s1 = as1;
631 s2 = as2;
632 n = an;
633 while (--n >= 0 && *s1 == *s2++)
634 if (*s1++ == '\0')
635 return(0);
636 return(n<0 ? 0 : *s1 - *--s2);
637}
638