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, with or without
   6:  * modification, are permitted provided that the following conditions
   7:  * are met:
   8:  * 1. Redistributions of source code must retain the above copyright
   9:  *    notice, this list of conditions and the following disclaimer.
  10:  * 2. Redistributions in binary form must reproduce the above copyright
  11:  *    notice, this list of conditions and the following disclaimer in the
  12:  *    documentation and/or other materials provided with the distribution.
  13:  * 3. All advertising materials mentioning features or use of this software
  14:  *    must display the following acknowledgement:
  15:  *	This product includes software developed by the University of
  16:  *	California, Berkeley and its contributors.
  17:  * 4. Neither the name of the University nor the names of its contributors
  18:  *    may be used to endorse or promote products derived from this software
  19:  *    without specific prior written permission.
  20:  *
  21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31:  * SUCH DAMAGE.
  32:  */
  33: 
  34: #if !defined(lint) && defined(DOSCCS)
  35: static char sccsid[] = "@(#)fio.c	5.24.2 (2.11BSD) 1997/11/3";
  36: #endif
  37: 
  38: #include "rcv.h"
  39: #include <sys/stat.h>
  40: #include <sys/file.h>
  41: #include <sys/wait.h>
  42: #include <paths.h>
  43: #include <errno.h>
  44: 
  45: /*
  46:  * Mail -- a mail program
  47:  *
  48:  * File I/O.
  49:  */
  50: 
  51: /*
  52:  * Set up the input pointers while copying the mail file into /tmp.
  53:  */
  54: setptr(ibuf)
  55:     register FILE *ibuf;
  56: {
  57:     register int c, count;
  58:     register char *cp, *cp2;
  59:     struct message this;
  60:     FILE *mestmp;
  61:     off_t offset;
  62:     int maybe, inhead;
  63:     char linebuf[LINESIZE];
  64: 
  65:     /* Get temporary file. */
  66:     (void)sprintf(linebuf, "%smail.XXXXXX", _PATH_TMP);
  67:     if ((c = mkstemp(linebuf)) == -1 ||
  68:         (mestmp = Fdopen(c, "r+")) == NULL) {
  69:         (void)fprintf(stderr, "mail: can't open %s\n", linebuf);
  70:         exit(1);
  71:     }
  72:     (void)unlink(linebuf);
  73: 
  74:     msgCount = 0;
  75:     maybe = 1;
  76:     inhead = 0;
  77:     offset = 0;
  78:     this.m_flag = MUSED|MNEW;
  79:     this.m_size = 0;
  80:     this.m_lines = 0;
  81:     this.m_block = 0;
  82:     this.m_offset = 0;
  83:     for (;;) {
  84:         if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
  85:             if (append(&this, mestmp)) {
  86:                 perror("temporary file");
  87:                 exit(1);
  88:             }
  89:             makemessage(mestmp);
  90:             return;
  91:         }
  92:         count = strlen(linebuf);
  93:         (void) fwrite(linebuf, sizeof *linebuf, count, otf);
  94:         if (ferror(otf)) {
  95:             perror("/tmp");
  96:             exit(1);
  97:         }
  98:         linebuf[count - 1] = 0;
  99:         if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
 100:             msgCount++;
 101:             if (append(&this, mestmp)) {
 102:                 perror("temporary file");
 103:                 exit(1);
 104:             }
 105:             this.m_flag = MUSED|MNEW;
 106:             this.m_size = 0;
 107:             this.m_lines = 0;
 108:             this.m_block = blockof(offset);
 109:             this.m_offset = offstof(offset);
 110:             inhead = 1;
 111:         } else if (linebuf[0] == 0) {
 112:             inhead = 0;
 113:         } else if (inhead) {
 114:             for (cp = linebuf, cp2 = "status";; cp++) {
 115:                 if ((c = *cp2++) == 0) {
 116:                     while (isspace(*cp++))
 117:                         ;
 118:                     if (cp[-1] != ':')
 119:                         break;
 120:                     while (c = *cp++)
 121:                         if (c == 'R')
 122:                             this.m_flag |= MREAD;
 123:                         else if (c == 'O')
 124:                             this.m_flag &= ~MNEW;
 125:                     inhead = 0;
 126:                     break;
 127:                 }
 128:                 if (*cp != c && *cp != toupper(c))
 129:                     break;
 130:             }
 131:         }
 132:         offset += count;
 133:         this.m_size += count;
 134:         this.m_lines++;
 135:         maybe = linebuf[0] == 0;
 136:     }
 137: }
 138: 
 139: /*
 140:  * Drop the passed line onto the passed output buffer.
 141:  * If a write error occurs, return -1, else the count of
 142:  * characters written, including the newline.
 143:  */
 144: putline(obuf, linebuf)
 145:     register FILE *obuf;
 146:     char *linebuf;
 147: {
 148:     register int c;
 149: 
 150:     c = strlen(linebuf);
 151:     (void) fwrite(linebuf, sizeof *linebuf, c, obuf);
 152:     (void) putc('\n', obuf);
 153:     if (ferror(obuf))
 154:         return (-1);
 155:     return (c + 1);
 156: }
 157: 
 158: /*
 159:  * Read up a line from the specified input into the line
 160:  * buffer.  Return the number of characters read.  Do not
 161:  * include the newline at the end.
 162:  */
 163: readline(ibuf, linebuf, linesize)
 164:     FILE *ibuf;
 165:     register char *linebuf;
 166: {
 167:     register int n;
 168: 
 169:     clearerr(ibuf);
 170:     if (fgets(linebuf, linesize, ibuf) == NULL)
 171:         return -1;
 172:     n = strlen(linebuf);
 173:     if (n > 0 && linebuf[n - 1] == '\n')
 174:         linebuf[--n] = '\0';
 175:     return n;
 176: }
 177: 
 178: /*
 179:  * Return a file buffer all ready to read up the
 180:  * passed message pointer.
 181:  */
 182: FILE *
 183: setinput(mp)
 184:     register struct message *mp;
 185: {
 186: 
 187:     fflush(otf);
 188:     if (fseek(itf, positionof(mp->m_block, mp->m_offset), 0) < 0) {
 189:         perror("fseek");
 190:         panic("temporary file seek");
 191:     }
 192:     return (itf);
 193: }
 194: 
 195: /*
 196:  * Take the data out of the passed ghost file and toss it into
 197:  * a dynamically allocated message structure.
 198:  */
 199: makemessage(f)
 200:     FILE *f;
 201: {
 202:     register size = (msgCount + 1) * sizeof (struct message);
 203: 
 204:     if (message != 0)
 205:         free((char *) message);
 206:     if ((message = (struct message *) malloc((unsigned) size)) == 0)
 207:         panic("Insufficient memory for %d messages", msgCount);
 208:     dot = message;
 209:     size -= sizeof (struct message);
 210:     fflush(f);
 211:     (void) lseek(fileno(f), (long) sizeof *message, 0);
 212:     if (read(fileno(f), (char *) message, size) != size)
 213:         panic("Message temporary file corrupted");
 214:     message[msgCount].m_size = 0;
 215:     message[msgCount].m_lines = 0;
 216:     Fclose(f);
 217: }
 218: 
 219: /*
 220:  * Append the passed message descriptor onto the temp file.
 221:  * If the write fails, return 1, else 0
 222:  */
 223: append(mp, f)
 224:     struct message *mp;
 225:     FILE *f;
 226: {
 227:     return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
 228: }
 229: 
 230: /*
 231:  * Delete a file, but only if the file is a plain file.
 232:  */
 233: rm(name)
 234:     char *name;
 235: {
 236:     struct stat sb;
 237: 
 238:     if (stat(name, &sb) < 0)
 239:         return(-1);
 240:     if (!S_ISREG(sb.st_mode)) {
 241:         errno = EISDIR;
 242:         return(-1);
 243:     }
 244:     return(unlink(name));
 245: }
 246: 
 247: static int sigdepth;        /* depth of holdsigs() */
 248: static long omask;
 249: /*
 250:  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
 251:  */
 252: holdsigs()
 253: {
 254: 
 255:     if (sigdepth++ == 0)
 256:         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
 257: }
 258: 
 259: /*
 260:  * Release signals SIGHUP, SIGINT, and SIGQUIT.
 261:  */
 262: relsesigs()
 263: {
 264: 
 265:     if (--sigdepth == 0)
 266:         sigsetmask(omask);
 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, 0L, -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:     register 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: }

Defined functions

append defined in line 223; used 2 times
getdeadletter defined in line 404; used 3 times
getfold defined in line 387; used 3 times
holdsigs defined in line 252; used 2 times
makemessage defined in line 199; used 1 times
  • in line 89
putline defined in line 144; used 3 times
relsesigs defined in line 262; used 8 times
setptr defined in line 54; used 1 times

Defined variables

omask defined in line 248; used 2 times
sccsid defined in line 35; never used
sigdepth defined in line 247; used 2 times
Last modified: 1997-11-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3792
Valid CSS Valid XHTML 1.0 Strict