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 13 static char *SccsId = "@(#)fio.c 1.2 10/09/80"; 14 15 /* 16 * Set up the input pointers while copying the mail file into 17 * /tmp. 18 */ 19 20 setptr(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 89 putline(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 109 readline(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 137 FILE * 138 setinput(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 159 makemessage(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 if (message != (struct message *) 0) 171 cfree((char *) message); 172 message = (struct message *) mp; 173 dot = message; 174 lseek(f, 0L, 0); 175 while (count = read(f, mp, BUFSIZ)) 176 mp += count; 177 for (m = &message[0]; m < &message[msgCount]; m++) { 178 m->m_size = (m+1)->m_size; 179 m->m_lines = (m+1)->m_lines; 180 } 181 message[msgCount].m_size = 0; 182 message[msgCount].m_lines = 0; 183 } 184 185 /* 186 * Append the passed message descriptor onto the temp file. 187 * If the write fails, return 1, else 0 188 */ 189 190 append(mp, f) 191 struct message *mp; 192 { 193 if (write(f, (char *) mp, sizeof *mp) != sizeof *mp) 194 return(1); 195 return(0); 196 } 197 198 /* 199 * Delete a file, but only if the file is a plain file. 200 */ 201 202 remove(name) 203 char name[]; 204 { 205 struct stat statb; 206 extern int errno; 207 208 if (stat(name, &statb) < 0) 209 return(-1); 210 if ((statb.st_mode & S_IFMT) != S_IFREG) { 211 errno = EISDIR; 212 return(-1); 213 } 214 return(unlink(name)); 215 } 216 217 /* 218 * Terminate an editing session by attempting to write out the user's 219 * file from the temporary. 220 */ 221 222 edstop() 223 { 224 register int gotcha, c; 225 register struct message *mp; 226 FILE *obuf; 227 228 if (readonly) 229 return; 230 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) 231 if (mp->m_flag & (MODIFY|MDELETED)) { 232 gotcha++; 233 break; 234 } 235 if (!gotcha) 236 return; 237 printf("\"%s\" ", editfile); 238 flush(); 239 if ((obuf = fopen(editfile, "w")) == NULL) { 240 perror(editfile); 241 reset(0); 242 } 243 c = 0; 244 for (mp = &message[0]; mp < &message[msgCount]; mp++) { 245 if ((mp->m_flag & MDELETED) != 0) 246 continue; 247 c++; 248 if (send(mp, obuf) < 0) { 249 perror(editfile); 250 reset(0); 251 } 252 } 253 fflush(obuf); 254 if (ferror(obuf)) { 255 perror(editfile); 256 reset(0); 257 } 258 if (c == 0) { 259 remove(editfile); 260 printf("removed\n"); 261 } 262 else 263 printf("complete\n"); 264 flush(); 265 } 266 267 /* 268 * Empty the output buffer. 269 */ 270 271 clrbuf(buf) 272 register FILE *buf; 273 { 274 275 buf = stdout; 276 buf->_ptr = buf->_base; 277 buf->_cnt = BUFSIZ; 278 } 279 280 /* 281 * Open a temp file by creating, closing, unlinking, and 282 * reopening. Return the open file descriptor. 283 */ 284 285 opentemp(file) 286 char file[]; 287 { 288 register int f; 289 290 if ((f = creat(file, 0600)) < 0) { 291 perror(file); 292 return(-1); 293 } 294 close(f); 295 if ((f = open(file, 2)) < 0) { 296 perror(file); 297 remove(file); 298 return(-1); 299 } 300 remove(file); 301 return(f); 302 } 303 304 /* 305 * Flush the standard output. 306 */ 307 308 flush() 309 { 310 fflush(stdout); 311 fflush(stderr); 312 } 313 314 /* 315 * Determine the size of the file possessed by 316 * the passed buffer. 317 */ 318 319 off_t 320 fsize(iob) 321 FILE *iob; 322 { 323 register int f; 324 struct stat sbuf; 325 326 f = fileno(iob); 327 if (fstat(f, &sbuf) < 0) 328 return(0); 329 return(sbuf.st_size); 330 } 331 332 /* 333 * Take a file name, possibly with shell meta characters 334 * in it and expand it by using "sh -c echo filename" 335 * Return the file name as a dynamic string. 336 */ 337 338 char * 339 expand(name) 340 char name[]; 341 { 342 char xname[BUFSIZ]; 343 char cmdbuf[BUFSIZ]; 344 register int pid, l, rc; 345 register char *cp, *Shell; 346 int s, pivec[2], (*sigint)(); 347 struct stat sbuf; 348 349 if (!anyof(name, "~{[*?$`'\"\\")) 350 return(name); 351 /* sigint = signal(SIGINT, SIG_IGN); */ 352 if (pipe(pivec) < 0) { 353 perror("pipe"); 354 /* signal(SIGINT, sigint) */ 355 return(name); 356 } 357 sprintf(cmdbuf, "echo %s", name); 358 if ((pid = vfork()) == 0) { 359 Shell = value("SHELL"); 360 if (Shell == NOSTR) 361 Shell = SHELL; 362 close(pivec[0]); 363 close(1); 364 dup(pivec[1]); 365 close(pivec[1]); 366 close(2); 367 execl(Shell, Shell, "-c", cmdbuf, 0); 368 _exit(1); 369 } 370 if (pid == -1) { 371 perror("fork"); 372 close(pivec[0]); 373 close(pivec[1]); 374 return(NOSTR); 375 } 376 close(pivec[1]); 377 l = read(pivec[0], xname, BUFSIZ); 378 close(pivec[0]); 379 while (wait(&s) != pid); 380 ; 381 s &= 0377; 382 if (s != 0 && s != SIGPIPE) { 383 fprintf(stderr, "\"Echo\" failed\n"); 384 goto err; 385 } 386 if (l < 0) { 387 perror("read"); 388 goto err; 389 } 390 if (l == 0) { 391 fprintf(stderr, "\"%s\": No match\n", name); 392 goto err; 393 } 394 if (l == BUFSIZ) { 395 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 396 goto err; 397 } 398 xname[l] = 0; 399 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 400 ; 401 *++cp = '\0'; 402 if (any(' ', xname) && stat(xname, &sbuf) < 0) { 403 fprintf(stderr, "\"%s\": Ambiguous\n", name); 404 goto err; 405 } 406 /* signal(SIGINT, sigint) */ 407 return(savestr(xname)); 408 409 err: 410 /* signal(SIGINT, sigint); */ 411 return(NOSTR); 412 } 413 414 /* 415 * A nicer version of Fdopen, which allows us to fclose 416 * without losing the open file. 417 */ 418 419 FILE * 420 Fdopen(fildes, mode) 421 char *mode; 422 { 423 register int f; 424 FILE *fdopen(); 425 426 f = dup(fildes); 427 if (f < 0) { 428 perror("dup"); 429 return(NULL); 430 } 431 return(fdopen(f, mode)); 432 } 433