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