Commit | Line | Data |
---|---|---|
c9104e93 KS |
1 | /* Copyright (c) 1979 Regents of the University of California */ |
2 | # | |
3 | ||
4 | #include "rcv.h" | |
5 | #include <sys/stat.h> | |
6 | #include <sgtty.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 | ||
18 | char * | |
19 | savestr(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 | ||
40 | copyname(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 | ||
55 | panic(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 | ||
81 | prs(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 | ||
97 | touch(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 | ||
108 | isdir(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 | ||
122 | unsigned int | |
123 | msize(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 | ||
136 | argcount(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 | ||
151 | blockof(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 | ||
166 | offsetof(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 | ||
180 | isatty(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 | ||
194 | char * | |
195 | hfield(field, mp) | |
196 | char field[]; | |
197 | struct message *mp; | |
198 | { | |
199 | FILE *ibuf; | |
200 | char linebuf[LINESIZE]; | |
201 | register char *cp, *cp2; | |
202 | int hfc; | |
203 | ||
204 | ibuf = setinput(mp); | |
205 | hfc = 0; | |
206 | while (readline(ibuf, linebuf) > 0 && hfc < HDRFIELDS) { | |
207 | if (equal(linebuf, "")) | |
208 | return(NOSTR); | |
209 | cp = linebuf; | |
210 | cp2 = field; | |
211 | while (raise(*cp++) == raise(*cp2++)) | |
212 | ; | |
213 | if (*--cp == ':' && *--cp2 == '\0') { | |
214 | cp++; | |
215 | while (any(*cp, " \t")) | |
216 | cp++; | |
217 | return(savestr(cp)); | |
218 | } | |
219 | hfc++; | |
220 | } | |
221 | return(NOSTR); | |
222 | } | |
223 | ||
224 | /* | |
225 | * The following code deals with input stacking to do source | |
226 | * commands. All but the current file pointer are saved on | |
227 | * the stack. | |
228 | */ | |
229 | ||
230 | static int ssp = -1; /* Top of file stack */ | |
231 | static FILE *sstack[_NFILE]; /* Saved input files */ | |
232 | ||
233 | /* | |
234 | * Pushdown current input file and switch to a new one. | |
235 | * Set the global flag "sourcing" so that others will realize | |
236 | * that they are no longer reading from a tty (in all probability). | |
237 | */ | |
238 | ||
239 | source(name) | |
240 | char name[]; | |
241 | { | |
242 | register FILE *fi; | |
243 | ||
244 | if ((fi = fopen(name, "r")) == NULL) { | |
245 | perror(name); | |
246 | return(1); | |
247 | } | |
248 | if (ssp >= _NFILE-2) { | |
249 | printf("Too much \"sourcing\" going on.\n"); | |
250 | fclose(fi); | |
251 | return(1); | |
252 | } | |
253 | sstack[++ssp] = input; | |
254 | input = fi; | |
255 | sourcing++; | |
256 | return(0); | |
257 | } | |
258 | ||
259 | /* | |
260 | * Source a file, but do nothing if the file cannot be opened. | |
261 | */ | |
262 | ||
263 | source1(name) | |
264 | char name[]; | |
265 | { | |
266 | register int f; | |
267 | ||
268 | if ((f = open(name, 0)) < 0) | |
269 | return(0); | |
270 | close(f); | |
271 | source(name); | |
272 | } | |
273 | ||
274 | /* | |
275 | * Pop the current input back to the previous level. | |
276 | * Update the "sourcing" flag as appropriate. | |
277 | */ | |
278 | ||
279 | unstack() | |
280 | { | |
281 | if (ssp < 0) { | |
282 | printf("\"Source\" stack over-pop.\n"); | |
283 | sourcing = 0; | |
284 | return(1); | |
285 | } | |
286 | fclose(input); | |
287 | input = sstack[ssp--]; | |
288 | if (ssp < 0) | |
289 | sourcing = 0; | |
290 | return(0); | |
291 | } | |
292 | ||
293 | /* | |
294 | * Touch the indicated file. | |
295 | * This is nifty for the shell. | |
296 | */ | |
297 | ||
298 | alter(name) | |
299 | char name[]; | |
300 | { | |
301 | register int pid, f; | |
302 | char w; | |
303 | ||
304 | if ((pid = fork()) != 0) | |
305 | return; | |
306 | clrbuf(stdout); | |
307 | clrbuf(stderr); | |
308 | clrbuf(stdin); | |
309 | sleep(1); | |
310 | if ((f = open(name, 0)) < 0) | |
311 | exit(1); | |
312 | read(f, &w, 1); | |
313 | exit(0); | |
314 | } | |
315 | ||
316 | /* | |
317 | * Examine the passed line buffer and | |
318 | * return true if it is all blanks and tabs. | |
319 | */ | |
320 | ||
321 | blankline(linebuf) | |
322 | char linebuf[]; | |
323 | { | |
324 | register char *cp; | |
325 | ||
326 | for (cp = linebuf; *cp; cp++) | |
327 | if (!any(*cp, " \t")) | |
328 | return(0); | |
329 | return(1); | |
330 | } | |
331 | ||
332 | /* | |
333 | * Fetch the sender's name from the passed message. | |
334 | */ | |
335 | ||
336 | char * | |
337 | nameof(mp) | |
338 | register struct message *mp; | |
339 | { | |
340 | static char namebuf[NAMESIZE]; | |
341 | char linebuf[LINESIZE]; | |
342 | register char *cp, *cp2; | |
343 | register FILE *ibuf; | |
344 | ||
345 | ibuf = setinput(mp); | |
346 | copy("", namebuf); | |
347 | if (readline(ibuf, linebuf) <= 0) | |
348 | return(namebuf); | |
349 | for (cp = linebuf; *cp != ' '; cp++) | |
350 | ; | |
351 | while (any(*cp, " \t")) | |
352 | cp++; | |
353 | for (cp2 = namebuf; *cp && !any(*cp, " \t") && | |
354 | cp2-namebuf < NAMESIZE-1; *cp2++ = *cp++) | |
355 | ; | |
356 | *cp2 = '\0'; | |
357 | return(namebuf); | |
358 | } |