calls to nonexistant fonts (from gbergman@cartan)
[unix-history] / usr / src / usr.bin / mail / fio.c
CommitLineData
9552e6b8
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
2ae9f53f 7#ifndef lint
87d10954 8static char *sccsid = "@(#)fio.c 5.3 (Berkeley) %G%";
9552e6b8 9#endif not lint
77a2ce8a
KS
10
11#include "rcv.h"
12#include <sys/stat.h>
13#include <errno.h>
14
15/*
16 * Mail -- a mail program
17 *
18 * File I/O.
19 */
20
77a2ce8a
KS
21/*
22 * Set up the input pointers while copying the mail file into
23 * /tmp.
24 */
25
26setptr(ibuf)
27 FILE *ibuf;
28{
9008b544 29 register int c;
9b888765 30 register char *cp, *cp2;
0154300b
CS
31 register int count, l;
32 long s;
77a2ce8a
KS
33 off_t offset;
34 char linebuf[LINESIZE];
9b888765
KS
35 char wbuf[LINESIZE];
36 int maybe, mestmp, flag, inhead;
77a2ce8a
KS
37 struct message this;
38 extern char tempSet[];
39
40 if ((mestmp = opentemp(tempSet)) < 0)
41 exit(1);
42 msgCount = 0;
43 offset = 0;
0154300b 44 s = 0L;
77a2ce8a
KS
45 l = 0;
46 maybe = 1;
9b888765 47 flag = MUSED|MNEW;
77a2ce8a 48 for (;;) {
87d10954 49 if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
77a2ce8a 50 this.m_flag = flag;
9b888765 51 flag = MUSED|MNEW;
77a2ce8a
KS
52 this.m_offset = offsetof(offset);
53 this.m_block = blockof(offset);
54 this.m_size = s;
55 this.m_lines = l;
56 if (append(&this, mestmp)) {
57 perror(tempSet);
58 exit(1);
59 }
60 fclose(ibuf);
61 makemessage(mestmp);
62 close(mestmp);
63 return;
64 }
87d10954
DS
65 count = strlen(linebuf);
66 fputs(linebuf, otf);
67 cp = linebuf + (count - 1);
68 if (*cp == '\n')
69 *cp = 0;
9008b544 70 if (ferror(otf)) {
77a2ce8a
KS
71 perror("/tmp");
72 exit(1);
73 }
9b888765 74 if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
77a2ce8a
KS
75 msgCount++;
76 this.m_flag = flag;
9b888765 77 flag = MUSED|MNEW;
29c01f3c 78 inhead = 1;
77a2ce8a
KS
79 this.m_block = blockof(offset);
80 this.m_offset = offsetof(offset);
81 this.m_size = s;
82 this.m_lines = l;
0154300b 83 s = 0L;
77a2ce8a
KS
84 l = 0;
85 if (append(&this, mestmp)) {
86 perror(tempSet);
87 exit(1);
88 }
89 }
9b888765
KS
90 if (linebuf[0] == 0)
91 inhead = 0;
87d10954
DS
92 if (inhead && (cp = index(linebuf, ':'))) {
93 *cp = 0;
94 if (icequal(linebuf, "status")) {
95 ++cp;
9b888765
KS
96 if (index(cp, 'R'))
97 flag |= MREAD;
98 if (index(cp, 'O'))
99 flag &= ~MNEW;
100 inhead = 0;
101 }
102 }
77a2ce8a 103 offset += count;
0154300b 104 s += (long) count;
77a2ce8a
KS
105 l++;
106 maybe = 0;
107 if (linebuf[0] == 0)
108 maybe = 1;
109 }
110}
111
112/*
113 * Drop the passed line onto the passed output buffer.
114 * If a write error occurs, return -1, else the count of
115 * characters written, including the newline.
116 */
117
118putline(obuf, linebuf)
119 FILE *obuf;
120 char *linebuf;
121{
122 register int c;
123
124 c = strlen(linebuf);
125 fputs(linebuf, obuf);
126 putc('\n', obuf);
127 if (ferror(obuf))
128 return(-1);
129 return(c+1);
130}
131
132/*
133 * Read up a line from the specified input into the line
134 * buffer. Return the number of characters read. Do not
135 * include the newline at the end.
136 */
137
138readline(ibuf, linebuf)
139 FILE *ibuf;
140 char *linebuf;
141{
87d10954 142 register int n;
77a2ce8a 143
87d10954
DS
144 clearerr(ibuf);
145 if (fgets(linebuf, LINESIZE, ibuf) == NULL)
77a2ce8a 146 return(0);
87d10954
DS
147 n = strlen(linebuf);
148 if (n >= 1 && linebuf[n-1] == '\n')
149 linebuf[n-1] = '\0';
150 return(n);
77a2ce8a
KS
151}
152
153/*
154 * Return a file buffer all ready to read up the
155 * passed message pointer.
156 */
157
158FILE *
159setinput(mp)
160 register struct message *mp;
161{
162 off_t off;
163
164 fflush(otf);
165 off = mp->m_block;
166 off <<= 9;
167 off += mp->m_offset;
168 if (fseek(itf, off, 0) < 0) {
169 perror("fseek");
170 panic("temporary file seek");
171 }
172 return(itf);
173}
174
175/*
176 * Take the data out of the passed ghost file and toss it into
177 * a dynamically allocated message structure.
178 */
179
180makemessage(f)
181{
182 register struct message *m;
183 register char *mp;
184 register count;
185
186 mp = calloc((unsigned) (msgCount + 1), sizeof *m);
187 if (mp == NOSTR) {
188 printf("Insufficient memory for %d messages\n", msgCount);
189 exit(1);
190 }
838681f8
KS
191 if (message != (struct message *) 0)
192 cfree((char *) message);
77a2ce8a
KS
193 message = (struct message *) mp;
194 dot = message;
195 lseek(f, 0L, 0);
196 while (count = read(f, mp, BUFSIZ))
197 mp += count;
198 for (m = &message[0]; m < &message[msgCount]; m++) {
199 m->m_size = (m+1)->m_size;
200 m->m_lines = (m+1)->m_lines;
9b888765 201 m->m_flag = (m+1)->m_flag;
77a2ce8a 202 }
0154300b 203 message[msgCount].m_size = 0L;
77a2ce8a
KS
204 message[msgCount].m_lines = 0;
205}
206
207/*
208 * Append the passed message descriptor onto the temp file.
209 * If the write fails, return 1, else 0
210 */
211
212append(mp, f)
213 struct message *mp;
214{
215 if (write(f, (char *) mp, sizeof *mp) != sizeof *mp)
216 return(1);
217 return(0);
218}
219
220/*
221 * Delete a file, but only if the file is a plain file.
222 */
223
224remove(name)
225 char name[];
226{
227 struct stat statb;
228 extern int errno;
229
230 if (stat(name, &statb) < 0)
231 return(-1);
232 if ((statb.st_mode & S_IFMT) != S_IFREG) {
233 errno = EISDIR;
234 return(-1);
235 }
236 return(unlink(name));
237}
238
239/*
240 * Terminate an editing session by attempting to write out the user's
5ab0568d 241 * file from the temporary. Save any new stuff appended to the file.
77a2ce8a 242 */
77a2ce8a
KS
243edstop()
244{
245 register int gotcha, c;
246 register struct message *mp;
8b5a06af 247 FILE *obuf, *ibuf, *readstat;
5ab0568d 248 struct stat statb;
8b5a06af 249 char tempname[30], *id;
b3d49ad3 250 int (*sigs[3])();
77a2ce8a 251
838681f8
KS
252 if (readonly)
253 return;
985c722d 254 holdsigs();
8b5a06af
KS
255 if (Tflag != NOSTR) {
256 if ((readstat = fopen(Tflag, "w")) == NULL)
257 Tflag = NOSTR;
258 }
953c713a
KS
259 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
260 if (mp->m_flag & MNEW) {
261 mp->m_flag &= ~MNEW;
262 mp->m_flag |= MSTATUS;
263 }
8b5a06af 264 if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
77a2ce8a 265 gotcha++;
8b5a06af
KS
266 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
267 if ((id = hfield("article-id", mp)) != NOSTR)
268 fprintf(readstat, "%s\n", id);
77a2ce8a 269 }
953c713a 270 }
8b5a06af
KS
271 if (Tflag != NOSTR)
272 fclose(readstat);
d85bd93d 273 if (!gotcha || Tflag != NOSTR)
b3d49ad3 274 goto done;
5ab0568d
KS
275 ibuf = NULL;
276 if (stat(editfile, &statb) >= 0 && statb.st_size > mailsize) {
277 strcpy(tempname, "/tmp/mboxXXXXXX");
278 mktemp(tempname);
279 if ((obuf = fopen(tempname, "w")) == NULL) {
280 perror(tempname);
985c722d 281 relsesigs();
5ab0568d
KS
282 reset(0);
283 }
284 if ((ibuf = fopen(editfile, "r")) == NULL) {
285 perror(editfile);
286 fclose(obuf);
287 remove(tempname);
985c722d 288 relsesigs();
5ab0568d
KS
289 reset(0);
290 }
0c3a2f40 291 fseek(ibuf, mailsize, 0);
5ab0568d
KS
292 while ((c = getc(ibuf)) != EOF)
293 putc(c, obuf);
294 fclose(ibuf);
295 fclose(obuf);
296 if ((ibuf = fopen(tempname, "r")) == NULL) {
297 perror(tempname);
298 remove(tempname);
985c722d 299 relsesigs();
5ab0568d
KS
300 reset(0);
301 }
302 remove(tempname);
303 }
77a2ce8a 304 printf("\"%s\" ", editfile);
80187484 305 fflush(stdout);
b17445e6 306 if ((obuf = fopen(editfile, "r+")) == NULL) {
77a2ce8a 307 perror(editfile);
985c722d 308 relsesigs();
77a2ce8a
KS
309 reset(0);
310 }
b17445e6 311 trunc(obuf);
77a2ce8a
KS
312 c = 0;
313 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
314 if ((mp->m_flag & MDELETED) != 0)
315 continue;
316 c++;
c718ab56 317 if (send(mp, obuf, 0) < 0) {
77a2ce8a 318 perror(editfile);
985c722d 319 relsesigs();
77a2ce8a
KS
320 reset(0);
321 }
322 }
5ab0568d
KS
323 gotcha = (c == 0 && ibuf == NULL);
324 if (ibuf != NULL) {
325 while ((c = getc(ibuf)) != EOF)
326 putc(c, obuf);
327 fclose(ibuf);
328 }
77a2ce8a
KS
329 fflush(obuf);
330 if (ferror(obuf)) {
331 perror(editfile);
985c722d 332 relsesigs();
77a2ce8a
KS
333 reset(0);
334 }
5ab0568d
KS
335 fclose(obuf);
336 if (gotcha) {
77a2ce8a
KS
337 remove(editfile);
338 printf("removed\n");
339 }
340 else
341 printf("complete\n");
80187484 342 fflush(stdout);
b3d49ad3
KS
343
344done:
985c722d 345 relsesigs();
b3d49ad3
KS
346}
347
f5df67b9 348static int sigdepth = 0; /* depth of holdsigs() */
56d6aa4a 349static int omask = 0;
b3d49ad3 350/*
985c722d 351 * Hold signals SIGHUP - SIGQUIT.
b3d49ad3 352 */
985c722d 353holdsigs()
b3d49ad3
KS
354{
355 register int i;
356
f5df67b9 357 if (sigdepth++ == 0)
56d6aa4a 358 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
b3d49ad3
KS
359}
360
361/*
985c722d 362 * Release signals SIGHUP - SIGQUIT
b3d49ad3 363 */
985c722d 364relsesigs()
b3d49ad3
KS
365{
366 register int i;
985c722d 367
f5df67b9 368 if (--sigdepth == 0)
56d6aa4a 369 sigsetmask(omask);
77a2ce8a
KS
370}
371
77a2ce8a
KS
372/*
373 * Open a temp file by creating, closing, unlinking, and
374 * reopening. Return the open file descriptor.
375 */
376
377opentemp(file)
378 char file[];
379{
380 register int f;
381
382 if ((f = creat(file, 0600)) < 0) {
383 perror(file);
384 return(-1);
385 }
386 close(f);
387 if ((f = open(file, 2)) < 0) {
388 perror(file);
389 remove(file);
390 return(-1);
391 }
392 remove(file);
393 return(f);
394}
395
77a2ce8a
KS
396/*
397 * Determine the size of the file possessed by
398 * the passed buffer.
399 */
400
401off_t
402fsize(iob)
403 FILE *iob;
404{
405 register int f;
406 struct stat sbuf;
407
408 f = fileno(iob);
409 if (fstat(f, &sbuf) < 0)
410 return(0);
411 return(sbuf.st_size);
412}
413
414/*
415 * Take a file name, possibly with shell meta characters
416 * in it and expand it by using "sh -c echo filename"
417 * Return the file name as a dynamic string.
418 */
419
420char *
421expand(name)
422 char name[];
423{
424 char xname[BUFSIZ];
425 char cmdbuf[BUFSIZ];
426 register int pid, l, rc;
427 register char *cp, *Shell;
428 int s, pivec[2], (*sigint)();
429 struct stat sbuf;
430
df3c4fbd
KS
431 if (name[0] == '+' && getfold(cmdbuf) >= 0) {
432 sprintf(xname, "%s/%s", cmdbuf, name + 1);
38a42545
KS
433 return(expand(savestr(xname)));
434 }
77a2ce8a
KS
435 if (!anyof(name, "~{[*?$`'\"\\"))
436 return(name);
77a2ce8a
KS
437 if (pipe(pivec) < 0) {
438 perror("pipe");
77a2ce8a
KS
439 return(name);
440 }
441 sprintf(cmdbuf, "echo %s", name);
442 if ((pid = vfork()) == 0) {
9ff57b47 443 sigchild();
77a2ce8a
KS
444 Shell = value("SHELL");
445 if (Shell == NOSTR)
446 Shell = SHELL;
447 close(pivec[0]);
448 close(1);
449 dup(pivec[1]);
450 close(pivec[1]);
451 close(2);
452 execl(Shell, Shell, "-c", cmdbuf, 0);
453 _exit(1);
454 }
455 if (pid == -1) {
456 perror("fork");
457 close(pivec[0]);
458 close(pivec[1]);
459 return(NOSTR);
460 }
461 close(pivec[1]);
462 l = read(pivec[0], xname, BUFSIZ);
463 close(pivec[0]);
464 while (wait(&s) != pid);
465 ;
466 s &= 0377;
467 if (s != 0 && s != SIGPIPE) {
468 fprintf(stderr, "\"Echo\" failed\n");
469 goto err;
470 }
471 if (l < 0) {
472 perror("read");
473 goto err;
474 }
475 if (l == 0) {
476 fprintf(stderr, "\"%s\": No match\n", name);
477 goto err;
478 }
479 if (l == BUFSIZ) {
480 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
481 goto err;
482 }
483 xname[l] = 0;
484 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
485 ;
486 *++cp = '\0';
487 if (any(' ', xname) && stat(xname, &sbuf) < 0) {
488 fprintf(stderr, "\"%s\": Ambiguous\n", name);
489 goto err;
490 }
77a2ce8a
KS
491 return(savestr(xname));
492
493err:
77a2ce8a
KS
494 return(NOSTR);
495}
496
df3c4fbd
KS
497/*
498 * Determine the current folder directory name.
499 */
500getfold(name)
501 char *name;
502{
503 char *folder;
504
505 if ((folder = value("folder")) == NOSTR)
506 return(-1);
507 if (*folder == '/')
508 strcpy(name, folder);
509 else
510 sprintf(name, "%s/%s", homedir, folder);
511 return(0);
512}
513
77a2ce8a
KS
514/*
515 * A nicer version of Fdopen, which allows us to fclose
516 * without losing the open file.
517 */
518
519FILE *
520Fdopen(fildes, mode)
521 char *mode;
522{
523 register int f;
524 FILE *fdopen();
525
526 f = dup(fildes);
527 if (f < 0) {
528 perror("dup");
529 return(NULL);
530 }
531 return(fdopen(f, mode));
532}