date and time created 80/10/08 09:51:16 by kas
[unix-history] / usr / src / usr.bin / mail / fio.c
CommitLineData
77a2ce8a
KS
1#
2
3#include "rcv.h"
4#include <sys/stat.h>
5#include <errno.h>
6
7/*
8 * Mail -- a mail program
9 *
10 * File I/O.
11 */
12
13static char *SccsId = "@(#)fio.c 1.1 %G%";
14
15/*
16 * Set up the input pointers while copying the mail file into
17 * /tmp.
18 */
19
20setptr(ibuf)
21 FILE *ibuf;
22{
23 register int count, s, l;
24 off_t offset;
25 char linebuf[LINESIZE];
26 int maybe, mestmp, flag;
27 struct message this;
28 extern char tempSet[];
29
30 if ((mestmp = opentemp(tempSet)) < 0)
31 exit(1);
32 msgCount = 0;
33 offset = 0;
34 s = 0;
35 l = 0;
36 maybe = 1;
37 flag = MUSED;
38 if (value("hold") != NOSTR)
39 flag = MPRESERVE|MUSED;
40 for (;;) {
41 if ((count = readline(ibuf, linebuf)) == 0) {
42 this.m_flag = flag;
43 this.m_offset = offsetof(offset);
44 this.m_block = blockof(offset);
45 this.m_size = s;
46 this.m_lines = l;
47 if (append(&this, mestmp)) {
48 perror(tempSet);
49 exit(1);
50 }
51 fclose(ibuf);
52 makemessage(mestmp);
53 close(mestmp);
54 return;
55 }
56 if (putline(otf, linebuf) < 0) {
57 perror("/tmp");
58 exit(1);
59 }
60 if (maybe && ishead(linebuf)) {
61 msgCount++;
62 this.m_flag = flag;
63 this.m_block = blockof(offset);
64 this.m_offset = offsetof(offset);
65 this.m_size = s;
66 this.m_lines = l;
67 s = 0;
68 l = 0;
69 if (append(&this, mestmp)) {
70 perror(tempSet);
71 exit(1);
72 }
73 }
74 offset += count;
75 s += count;
76 l++;
77 maybe = 0;
78 if (linebuf[0] == 0)
79 maybe = 1;
80 }
81}
82
83/*
84 * Drop the passed line onto the passed output buffer.
85 * If a write error occurs, return -1, else the count of
86 * characters written, including the newline.
87 */
88
89putline(obuf, linebuf)
90 FILE *obuf;
91 char *linebuf;
92{
93 register int c;
94
95 c = strlen(linebuf);
96 fputs(linebuf, obuf);
97 putc('\n', obuf);
98 if (ferror(obuf))
99 return(-1);
100 return(c+1);
101}
102
103/*
104 * Read up a line from the specified input into the line
105 * buffer. Return the number of characters read. Do not
106 * include the newline at the end.
107 */
108
109readline(ibuf, linebuf)
110 FILE *ibuf;
111 char *linebuf;
112{
113 register char *cp;
114 register int c;
115
116 do {
117 clearerr(ibuf);
118 c = getc(ibuf);
119 for (cp = linebuf; c != '\n' && c != EOF; c = getc(ibuf)) {
120 if (c == 0)
121 continue;
122 if (cp - linebuf < LINESIZE-2)
123 *cp++ = c;
124 }
125 } while (ferror(ibuf) && ibuf == stdin);
126 *cp = 0;
127 if (c == EOF && cp == linebuf)
128 return(0);
129 return(cp - linebuf + 1);
130}
131
132/*
133 * Return a file buffer all ready to read up the
134 * passed message pointer.
135 */
136
137FILE *
138setinput(mp)
139 register struct message *mp;
140{
141 off_t off;
142
143 fflush(otf);
144 off = mp->m_block;
145 off <<= 9;
146 off += mp->m_offset;
147 if (fseek(itf, off, 0) < 0) {
148 perror("fseek");
149 panic("temporary file seek");
150 }
151 return(itf);
152}
153
154/*
155 * Take the data out of the passed ghost file and toss it into
156 * a dynamically allocated message structure.
157 */
158
159makemessage(f)
160{
161 register struct message *m;
162 register char *mp;
163 register count;
164
165 mp = calloc((unsigned) (msgCount + 1), sizeof *m);
166 if (mp == NOSTR) {
167 printf("Insufficient memory for %d messages\n", msgCount);
168 exit(1);
169 }
170 message = (struct message *) mp;
171 dot = message;
172 lseek(f, 0L, 0);
173 while (count = read(f, mp, BUFSIZ))
174 mp += count;
175 for (m = &message[0]; m < &message[msgCount]; m++) {
176 m->m_size = (m+1)->m_size;
177 m->m_lines = (m+1)->m_lines;
178 }
179 message[msgCount].m_size = 0;
180 message[msgCount].m_lines = 0;
181}
182
183/*
184 * Append the passed message descriptor onto the temp file.
185 * If the write fails, return 1, else 0
186 */
187
188append(mp, f)
189 struct message *mp;
190{
191 if (write(f, (char *) mp, sizeof *mp) != sizeof *mp)
192 return(1);
193 return(0);
194}
195
196/*
197 * Delete a file, but only if the file is a plain file.
198 */
199
200remove(name)
201 char name[];
202{
203 struct stat statb;
204 extern int errno;
205
206 if (stat(name, &statb) < 0)
207 return(-1);
208 if ((statb.st_mode & S_IFMT) != S_IFREG) {
209 errno = EISDIR;
210 return(-1);
211 }
212 return(unlink(name));
213}
214
215/*
216 * Terminate an editing session by attempting to write out the user's
217 * file from the temporary.
218 */
219
220edstop()
221{
222 register int gotcha, c;
223 register struct message *mp;
224 FILE *obuf;
225
226 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++)
227 if (mp->m_flag & (MODIFY|MDELETED)) {
228 gotcha++;
229 break;
230 }
231 if (!gotcha)
232 return;
233 printf("\"%s\" ", editfile);
234 flush();
235 if ((obuf = fopen(editfile, "w")) == NULL) {
236 perror(editfile);
237 reset(0);
238 }
239 c = 0;
240 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
241 if ((mp->m_flag & MDELETED) != 0)
242 continue;
243 c++;
244 if (send(mp, obuf) < 0) {
245 perror(editfile);
246 reset(0);
247 }
248 }
249 fflush(obuf);
250 if (ferror(obuf)) {
251 perror(editfile);
252 reset(0);
253 }
254 if (c == 0) {
255 remove(editfile);
256 printf("removed\n");
257 }
258 else
259 printf("complete\n");
260 flush();
261}
262
263/*
264 * Empty the output buffer.
265 */
266
267clrbuf(buf)
268 register FILE *buf;
269{
270
271 buf = stdout;
272 buf->_ptr = buf->_base;
273 buf->_cnt = BUFSIZ;
274}
275
276/*
277 * Open a temp file by creating, closing, unlinking, and
278 * reopening. Return the open file descriptor.
279 */
280
281opentemp(file)
282 char file[];
283{
284 register int f;
285
286 if ((f = creat(file, 0600)) < 0) {
287 perror(file);
288 return(-1);
289 }
290 close(f);
291 if ((f = open(file, 2)) < 0) {
292 perror(file);
293 remove(file);
294 return(-1);
295 }
296 remove(file);
297 return(f);
298}
299
300/*
301 * Flush the standard output.
302 */
303
304flush()
305{
306 fflush(stdout);
307 fflush(stderr);
308}
309
310/*
311 * Determine the size of the file possessed by
312 * the passed buffer.
313 */
314
315off_t
316fsize(iob)
317 FILE *iob;
318{
319 register int f;
320 struct stat sbuf;
321
322 f = fileno(iob);
323 if (fstat(f, &sbuf) < 0)
324 return(0);
325 return(sbuf.st_size);
326}
327
328/*
329 * Take a file name, possibly with shell meta characters
330 * in it and expand it by using "sh -c echo filename"
331 * Return the file name as a dynamic string.
332 */
333
334char *
335expand(name)
336 char name[];
337{
338 char xname[BUFSIZ];
339 char cmdbuf[BUFSIZ];
340 register int pid, l, rc;
341 register char *cp, *Shell;
342 int s, pivec[2], (*sigint)();
343 struct stat sbuf;
344
345 if (!anyof(name, "~{[*?$`'\"\\"))
346 return(name);
347 /* sigint = signal(SIGINT, SIG_IGN); */
348 if (pipe(pivec) < 0) {
349 perror("pipe");
350 /* signal(SIGINT, sigint) */
351 return(name);
352 }
353 sprintf(cmdbuf, "echo %s", name);
354 if ((pid = vfork()) == 0) {
355 Shell = value("SHELL");
356 if (Shell == NOSTR)
357 Shell = SHELL;
358 close(pivec[0]);
359 close(1);
360 dup(pivec[1]);
361 close(pivec[1]);
362 close(2);
363 execl(Shell, Shell, "-c", cmdbuf, 0);
364 _exit(1);
365 }
366 if (pid == -1) {
367 perror("fork");
368 close(pivec[0]);
369 close(pivec[1]);
370 return(NOSTR);
371 }
372 close(pivec[1]);
373 l = read(pivec[0], xname, BUFSIZ);
374 close(pivec[0]);
375 while (wait(&s) != pid);
376 ;
377 s &= 0377;
378 if (s != 0 && s != SIGPIPE) {
379 fprintf(stderr, "\"Echo\" failed\n");
380 goto err;
381 }
382 if (l < 0) {
383 perror("read");
384 goto err;
385 }
386 if (l == 0) {
387 fprintf(stderr, "\"%s\": No match\n", name);
388 goto err;
389 }
390 if (l == BUFSIZ) {
391 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
392 goto err;
393 }
394 xname[l] = 0;
395 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
396 ;
397 *++cp = '\0';
398 if (any(' ', xname) && stat(xname, &sbuf) < 0) {
399 fprintf(stderr, "\"%s\": Ambiguous\n", name);
400 goto err;
401 }
402 /* signal(SIGINT, sigint) */
403 return(savestr(xname));
404
405err:
406 /* signal(SIGINT, sigint); */
407 return(NOSTR);
408}
409
410/*
411 * A nicer version of Fdopen, which allows us to fclose
412 * without losing the open file.
413 */
414
415FILE *
416Fdopen(fildes, mode)
417 char *mode;
418{
419 register int f;
420 FILE *fdopen();
421
422 f = dup(fildes);
423 if (f < 0) {
424 perror("dup");
425 return(NULL);
426 }
427 return(fdopen(f, mode));
428}