|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)fio.c 5.23 (Berkeley) 6/25/90";
22: #endif /* not lint */
23:
24: #include "rcv.h"
25: #include <sys/stat.h>
26: #include <sys/file.h>
27: #include <sys/wait.h>
28: #include <errno.h>
29:
30: /*
31: * Mail -- a mail program
32: *
33: * File I/O.
34: */
35:
36: /*
37: * Set up the input pointers while copying the mail file into
38: * /tmp.
39: */
40: setptr(ibuf)
41: register FILE *ibuf;
42: {
43: register c;
44: register char *cp, *cp2;
45: register count;
46: char linebuf[LINESIZE];
47: int maybe, inhead;
48: FILE *mestmp;
49: off_t offset;
50: struct message this;
51: extern char tempSet[];
52:
53: if ((c = opentemp(tempSet)) < 0)
54: exit(1);
55: if ((mestmp = Fdopen(c, "r+")) == NULL)
56: panic("Can't open temporary");
57: msgCount = 0;
58: maybe = 1;
59: inhead = 0;
60: offset = 0;
61: this.m_flag = MUSED|MNEW;
62: this.m_size = 0;
63: this.m_lines = 0;
64: this.m_block = 0;
65: this.m_offset = 0;
66: for (;;) {
67: if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
68: if (append(&this, mestmp)) {
69: perror(tempSet);
70: exit(1);
71: }
72: makemessage(mestmp);
73: return;
74: }
75: count = strlen(linebuf);
76: (void) fwrite(linebuf, sizeof *linebuf, count, otf);
77: if (ferror(otf)) {
78: perror("/tmp");
79: exit(1);
80: }
81: linebuf[count - 1] = 0;
82: if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
83: msgCount++;
84: if (append(&this, mestmp)) {
85: perror(tempSet);
86: exit(1);
87: }
88: this.m_flag = MUSED|MNEW;
89: this.m_size = 0;
90: this.m_lines = 0;
91: this.m_block = blockof(offset);
92: this.m_offset = offsetof(offset);
93: inhead = 1;
94: } else if (linebuf[0] == 0) {
95: inhead = 0;
96: } else if (inhead) {
97: for (cp = linebuf, cp2 = "status";; cp++) {
98: if ((c = *cp2++) == 0) {
99: while (isspace(*cp++))
100: ;
101: if (cp[-1] != ':')
102: break;
103: while (c = *cp++)
104: if (c == 'R')
105: this.m_flag |= MREAD;
106: else if (c == 'O')
107: this.m_flag &= ~MNEW;
108: inhead = 0;
109: break;
110: }
111: if (*cp != c && *cp != toupper(c))
112: break;
113: }
114: }
115: offset += count;
116: this.m_size += count;
117: this.m_lines++;
118: maybe = linebuf[0] == 0;
119: }
120: }
121:
122: /*
123: * Drop the passed line onto the passed output buffer.
124: * If a write error occurs, return -1, else the count of
125: * characters written, including the newline.
126: */
127: putline(obuf, linebuf)
128: FILE *obuf;
129: char *linebuf;
130: {
131: register int c;
132:
133: c = strlen(linebuf);
134: (void) fwrite(linebuf, sizeof *linebuf, c, obuf);
135: (void) putc('\n', obuf);
136: if (ferror(obuf))
137: return (-1);
138: return (c + 1);
139: }
140:
141: /*
142: * Read up a line from the specified input into the line
143: * buffer. Return the number of characters read. Do not
144: * include the newline at the end.
145: */
146: readline(ibuf, linebuf, linesize)
147: FILE *ibuf;
148: char *linebuf;
149: {
150: register int n;
151:
152: clearerr(ibuf);
153: if (fgets(linebuf, linesize, ibuf) == NULL)
154: return -1;
155: n = strlen(linebuf);
156: if (n > 0 && linebuf[n - 1] == '\n')
157: linebuf[--n] = '\0';
158: return n;
159: }
160:
161: /*
162: * Return a file buffer all ready to read up the
163: * passed message pointer.
164: */
165: FILE *
166: setinput(mp)
167: register struct message *mp;
168: {
169:
170: fflush(otf);
171: if (fseek(itf, positionof(mp->m_block, mp->m_offset), 0) < 0) {
172: perror("fseek");
173: panic("temporary file seek");
174: }
175: return (itf);
176: }
177:
178: /*
179: * Take the data out of the passed ghost file and toss it into
180: * a dynamically allocated message structure.
181: */
182: makemessage(f)
183: FILE *f;
184: {
185: register size = (msgCount + 1) * sizeof (struct message);
186: off_t lseek();
187:
188: if (message != 0)
189: free((char *) message);
190: if ((message = (struct message *) malloc((unsigned) size)) == 0)
191: panic("Insufficient memory for %d messages", msgCount);
192: dot = message;
193: size -= sizeof (struct message);
194: fflush(f);
195: (void) lseek(fileno(f), (long) sizeof *message, 0);
196: if (read(fileno(f), (char *) message, size) != size)
197: panic("Message temporary file corrupted");
198: message[msgCount].m_size = 0;
199: message[msgCount].m_lines = 0;
200: Fclose(f);
201: }
202:
203: /*
204: * Append the passed message descriptor onto the temp file.
205: * If the write fails, return 1, else 0
206: */
207: append(mp, f)
208: struct message *mp;
209: FILE *f;
210: {
211: return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
212: }
213:
214: /*
215: * Delete a file, but only if the file is a plain file.
216: */
217: remove(name)
218: char name[];
219: {
220: struct stat statb;
221: extern int errno;
222:
223: if (stat(name, &statb) < 0)
224: return(-1);
225: if ((statb.st_mode & S_IFMT) != S_IFREG) {
226: errno = EISDIR;
227: return(-1);
228: }
229: return unlink(name);
230: }
231:
232: static int sigdepth; /* depth of holdsigs() */
233: static int omask;
234: /*
235: * Hold signals SIGHUP, SIGINT, and SIGQUIT.
236: */
237: holdsigs()
238: {
239:
240: if (sigdepth++ == 0)
241: omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
242: }
243:
244: /*
245: * Release signals SIGHUP, SIGINT, and SIGQUIT.
246: */
247: relsesigs()
248: {
249:
250: if (--sigdepth == 0)
251: sigsetmask(omask);
252: }
253:
254: /*
255: * Open a temp file by creating and unlinking.
256: * Return the open file descriptor.
257: */
258: opentemp(file)
259: char file[];
260: {
261: int f;
262:
263: if ((f = open(file, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0)
264: perror(file);
265: remove(file);
266: return (f);
267: }
268:
269: /*
270: * Determine the size of the file possessed by
271: * the passed buffer.
272: */
273: off_t
274: fsize(iob)
275: FILE *iob;
276: {
277: struct stat sbuf;
278:
279: if (fstat(fileno(iob), &sbuf) < 0)
280: return 0;
281: return sbuf.st_size;
282: }
283:
284: /*
285: * Evaluate the string given as a new mailbox name.
286: * Supported meta characters:
287: * % for my system mail box
288: * %user for user's system mail box
289: * # for previous file
290: * & invoker's mbox file
291: * +file file in folder directory
292: * any shell meta character
293: * Return the file name as a dynamic string.
294: */
295: char *
296: expand(name)
297: register char *name;
298: {
299: char xname[PATHSIZE];
300: char cmdbuf[PATHSIZE]; /* also used for file names */
301: register int pid, l;
302: register char *cp, *shell;
303: int pivec[2];
304: struct stat sbuf;
305: extern union wait wait_status;
306:
307: /*
308: * The order of evaluation is "%" and "#" expand into constants.
309: * "&" can expand into "+". "+" can expand into shell meta characters.
310: * Shell meta characters expand into constants.
311: * This way, we make no recursive expansion.
312: */
313: switch (*name) {
314: case '%':
315: findmail(name[1] ? name + 1 : myname, xname);
316: return savestr(xname);
317: case '#':
318: if (name[1] != 0)
319: break;
320: if (prevfile[0] == 0) {
321: printf("No previous file\n");
322: return NOSTR;
323: }
324: return savestr(prevfile);
325: case '&':
326: if (name[1] == 0 && (name = value("MBOX")) == NOSTR)
327: name = "~/mbox";
328: /* fall through */
329: }
330: if (name[0] == '+' && getfold(cmdbuf) >= 0) {
331: sprintf(xname, "%s/%s", cmdbuf, name + 1);
332: name = savestr(xname);
333: }
334: /* catch the most common shell meta character */
335: if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) {
336: sprintf(xname, "%s%s", homedir, name + 1);
337: name = savestr(xname);
338: }
339: if (!anyof(name, "~{[*?$`'\"\\"))
340: return name;
341: if (pipe(pivec) < 0) {
342: perror("pipe");
343: return name;
344: }
345: sprintf(cmdbuf, "echo %s", name);
346: if ((shell = value("SHELL")) == NOSTR)
347: shell = _PATH_CSHELL;
348: pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR);
349: if (pid < 0) {
350: close(pivec[0]);
351: close(pivec[1]);
352: return NOSTR;
353: }
354: close(pivec[1]);
355: l = read(pivec[0], xname, BUFSIZ);
356: close(pivec[0]);
357: if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) {
358: fprintf(stderr, "\"%s\": Expansion failed.\n", name);
359: return NOSTR;
360: }
361: if (l < 0) {
362: perror("read");
363: return NOSTR;
364: }
365: if (l == 0) {
366: fprintf(stderr, "\"%s\": No match.\n", name);
367: return NOSTR;
368: }
369: if (l == BUFSIZ) {
370: fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
371: return NOSTR;
372: }
373: xname[l] = 0;
374: for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
375: ;
376: cp[1] = '\0';
377: if (index(xname, ' ') && stat(xname, &sbuf) < 0) {
378: fprintf(stderr, "\"%s\": Ambiguous.\n", name);
379: return NOSTR;
380: }
381: return savestr(xname);
382: }
383:
384: /*
385: * Determine the current folder directory name.
386: */
387: getfold(name)
388: char *name;
389: {
390: char *folder;
391:
392: if ((folder = value("folder")) == NOSTR)
393: return (-1);
394: if (*folder == '/')
395: strcpy(name, folder);
396: else
397: sprintf(name, "%s/%s", homedir, folder);
398: return (0);
399: }
400:
401: /*
402: * Return the name of the dead.letter file.
403: */
404: char *
405: getdeadletter()
406: {
407: register char *cp;
408:
409: if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR)
410: cp = expand("~/dead.letter");
411: else if (*cp != '/') {
412: char buf[PATHSIZE];
413:
414: (void) sprintf(buf, "~/%s", cp);
415: cp = expand(buf);
416: }
417: return cp;
418: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.