1*0b426e12Smillert /* $OpenBSD: fio.c,v 1.16 1998/06/12 17:51:51 millert Exp $ */ 2db59c1a6Smillert /* $NetBSD: fio.c,v 1.8 1997/07/07 22:57:55 phil Exp $ */ 37eb34045Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1980, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 16df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 17df930be7Sderaadt * must display the following acknowledgement: 18df930be7Sderaadt * This product includes software developed by the University of 19df930be7Sderaadt * California, Berkeley and its contributors. 20df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 21df930be7Sderaadt * may be used to endorse or promote products derived from this software 22df930be7Sderaadt * without specific prior written permission. 23df930be7Sderaadt * 24df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df930be7Sderaadt * SUCH DAMAGE. 35df930be7Sderaadt */ 36df930be7Sderaadt 37df930be7Sderaadt #ifndef lint 387eb34045Sderaadt #if 0 39db59c1a6Smillert static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95"; 407eb34045Sderaadt #else 41*0b426e12Smillert static char rcsid[] = "$OpenBSD: fio.c,v 1.16 1998/06/12 17:51:51 millert Exp $"; 427eb34045Sderaadt #endif 43df930be7Sderaadt #endif /* not lint */ 44df930be7Sderaadt 45df930be7Sderaadt #include "rcv.h" 46df930be7Sderaadt #include <sys/file.h> 47df930be7Sderaadt #include <sys/wait.h> 48df930be7Sderaadt 49df930be7Sderaadt #include <unistd.h> 50df930be7Sderaadt #include <paths.h> 51df930be7Sderaadt #include <errno.h> 52df930be7Sderaadt #include "extern.h" 53df930be7Sderaadt 54df930be7Sderaadt /* 55df930be7Sderaadt * Mail -- a mail program 56df930be7Sderaadt * 57df930be7Sderaadt * File I/O. 58df930be7Sderaadt */ 59df930be7Sderaadt 60df930be7Sderaadt /* 61df930be7Sderaadt * Set up the input pointers while copying the mail file into /tmp. 62df930be7Sderaadt */ 63df930be7Sderaadt void 64db59c1a6Smillert setptr(ibuf, offset) 6536999bedSmillert FILE *ibuf; 66db59c1a6Smillert off_t offset; 67df930be7Sderaadt { 6836999bedSmillert int c, count; 6936999bedSmillert char *cp, *cp2; 70df930be7Sderaadt struct message this; 71df930be7Sderaadt FILE *mestmp; 7236999bedSmillert int maybe, inhead, omsgCount; 73c32a3250Sderaadt char linebuf[LINESIZE], pathbuf[PATHSIZE]; 74df930be7Sderaadt 75df930be7Sderaadt /* Get temporary file. */ 76db59c1a6Smillert (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir); 77db59c1a6Smillert if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL) 78db59c1a6Smillert err(1, "can't open %s", pathbuf); 790ecc72fcSmillert (void)rm(pathbuf); 80df930be7Sderaadt 81db59c1a6Smillert if (offset == 0) { 82df930be7Sderaadt msgCount = 0; 83db59c1a6Smillert } else { 84db59c1a6Smillert /* Seek into the file to get to the new messages */ 85db59c1a6Smillert (void)fseek(ibuf, offset, 0); 86db59c1a6Smillert /* 87db59c1a6Smillert * We need to make "offset" a pointer to the end of 88db59c1a6Smillert * the temp file that has the copy of the mail file. 89db59c1a6Smillert * If any messages have been edited, this will be 90db59c1a6Smillert * different from the offset into the mail file. 91db59c1a6Smillert */ 92db59c1a6Smillert (void)fseek(otf, 0L, SEEK_END); 93db59c1a6Smillert offset = ftell(otf); 94db59c1a6Smillert } 95db59c1a6Smillert omsgCount = msgCount; 96df930be7Sderaadt maybe = 1; 97df930be7Sderaadt inhead = 0; 98df930be7Sderaadt this.m_flag = MUSED|MNEW; 99df930be7Sderaadt this.m_size = 0; 100df930be7Sderaadt this.m_lines = 0; 101df930be7Sderaadt this.m_block = 0; 102df930be7Sderaadt this.m_offset = 0; 103df930be7Sderaadt for (;;) { 104db59c1a6Smillert if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) { 105db59c1a6Smillert if (append(&this, mestmp)) 106db59c1a6Smillert err(1, "temporary file"); 107db59c1a6Smillert makemessage(mestmp, omsgCount); 108df930be7Sderaadt return; 109df930be7Sderaadt } 110df930be7Sderaadt count = strlen(linebuf); 1117f7d0dfbSmillert /* 1127f7d0dfbSmillert * Transforms lines ending in <CR><LF> to just <LF>. 1137f7d0dfbSmillert * This allows mail to be able to read Eudora mailboxes 1147f7d0dfbSmillert * that reside on a DOS partition. 1157f7d0dfbSmillert */ 1167f7d0dfbSmillert if (count >= 2 && linebuf[count-1] == '\n' && 1177f7d0dfbSmillert linebuf[count - 2] == '\r') 1187f7d0dfbSmillert linebuf[count - 2] = linebuf[--count]; 1197f7d0dfbSmillert 120db59c1a6Smillert (void)fwrite(linebuf, sizeof(*linebuf), count, otf); 121db59c1a6Smillert if (ferror(otf)) 122db59c1a6Smillert err(1, "/tmp"); 1235da7328bSderaadt if (count) 124db59c1a6Smillert linebuf[count - 1] = '\0'; 125df930be7Sderaadt if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { 126df930be7Sderaadt msgCount++; 127db59c1a6Smillert if (append(&this, mestmp)) 128db59c1a6Smillert err(1, "temporary file"); 129df930be7Sderaadt this.m_flag = MUSED|MNEW; 130df930be7Sderaadt this.m_size = 0; 131df930be7Sderaadt this.m_lines = 0; 132df930be7Sderaadt this.m_block = blockof(offset); 133df930be7Sderaadt this.m_offset = offsetof(offset); 134df930be7Sderaadt inhead = 1; 135df930be7Sderaadt } else if (linebuf[0] == 0) { 136df930be7Sderaadt inhead = 0; 137df930be7Sderaadt } else if (inhead) { 138df930be7Sderaadt for (cp = linebuf, cp2 = "status";; cp++) { 139df930be7Sderaadt if ((c = *cp2++) == 0) { 140df930be7Sderaadt while (isspace(*cp++)) 141df930be7Sderaadt ; 142df930be7Sderaadt if (cp[-1] != ':') 143df930be7Sderaadt break; 1447eb34045Sderaadt while ((c = *cp++) != '\0') 145df930be7Sderaadt if (c == 'R') 146df930be7Sderaadt this.m_flag |= MREAD; 147df930be7Sderaadt else if (c == 'O') 148df930be7Sderaadt this.m_flag &= ~MNEW; 149df930be7Sderaadt inhead = 0; 150df930be7Sderaadt break; 151df930be7Sderaadt } 152df930be7Sderaadt if (*cp != c && *cp != toupper(c)) 153df930be7Sderaadt break; 154df930be7Sderaadt } 155df930be7Sderaadt } 156df930be7Sderaadt offset += count; 157df930be7Sderaadt this.m_size += count; 158df930be7Sderaadt this.m_lines++; 159df930be7Sderaadt maybe = linebuf[0] == 0; 160df930be7Sderaadt } 161df930be7Sderaadt } 162df930be7Sderaadt 163df930be7Sderaadt /* 164df930be7Sderaadt * Drop the passed line onto the passed output buffer. 165df930be7Sderaadt * If a write error occurs, return -1, else the count of 166db59c1a6Smillert * characters written, including the newline if requested. 167df930be7Sderaadt */ 168df930be7Sderaadt int 169db59c1a6Smillert putline(obuf, linebuf, outlf) 170df930be7Sderaadt FILE *obuf; 171df930be7Sderaadt char *linebuf; 172db59c1a6Smillert int outlf; 173df930be7Sderaadt { 17436999bedSmillert int c; 175df930be7Sderaadt 176df930be7Sderaadt c = strlen(linebuf); 177db59c1a6Smillert (void)fwrite(linebuf, sizeof(*linebuf), c, obuf); 178db59c1a6Smillert if (outlf) { 179df930be7Sderaadt (void)putc('\n', obuf); 180db59c1a6Smillert c++; 181db59c1a6Smillert } 182df930be7Sderaadt if (ferror(obuf)) 183df930be7Sderaadt return(-1); 184db59c1a6Smillert return(c); 185df930be7Sderaadt } 186df930be7Sderaadt 187df930be7Sderaadt /* 188df930be7Sderaadt * Read up a line from the specified input into the line 189df930be7Sderaadt * buffer. Return the number of characters read. Do not 1907f7d0dfbSmillert * include the newline (or carriage return) at the end. 191df930be7Sderaadt */ 192df930be7Sderaadt int 193df930be7Sderaadt readline(ibuf, linebuf, linesize) 194df930be7Sderaadt FILE *ibuf; 195df930be7Sderaadt char *linebuf; 196df930be7Sderaadt int linesize; 197df930be7Sderaadt { 19836999bedSmillert int n; 199df930be7Sderaadt 200df930be7Sderaadt clearerr(ibuf); 201df930be7Sderaadt if (fgets(linebuf, linesize, ibuf) == NULL) 202db59c1a6Smillert return(-1); 203db59c1a6Smillert 204df930be7Sderaadt n = strlen(linebuf); 205df930be7Sderaadt if (n > 0 && linebuf[n - 1] == '\n') 206df930be7Sderaadt linebuf[--n] = '\0'; 2077f7d0dfbSmillert if (n > 0 && linebuf[n - 1] == '\r') 2087f7d0dfbSmillert linebuf[--n] = '\0'; 209db59c1a6Smillert return(n); 210df930be7Sderaadt } 211df930be7Sderaadt 212df930be7Sderaadt /* 213df930be7Sderaadt * Return a file buffer all ready to read up the 214df930be7Sderaadt * passed message pointer. 215df930be7Sderaadt */ 216df930be7Sderaadt FILE * 217df930be7Sderaadt setinput(mp) 21836999bedSmillert struct message *mp; 219df930be7Sderaadt { 220df930be7Sderaadt 221df930be7Sderaadt fflush(otf); 22236999bedSmillert if (fseek(itf, (long)positionof(mp->m_block, mp->m_offset), 0) < 0) 22336999bedSmillert err(1, "fseek"); 224df930be7Sderaadt return(itf); 225df930be7Sderaadt } 226df930be7Sderaadt 227df930be7Sderaadt /* 228df930be7Sderaadt * Take the data out of the passed ghost file and toss it into 229df930be7Sderaadt * a dynamically allocated message structure. 230df930be7Sderaadt */ 231df930be7Sderaadt void 232db59c1a6Smillert makemessage(f, omsgCount) 233df930be7Sderaadt FILE *f; 234db59c1a6Smillert int omsgCount; 235df930be7Sderaadt { 23636999bedSmillert size_t size = (msgCount + 1) * sizeof(struct message); 237df930be7Sderaadt 238db59c1a6Smillert if (omsgCount) { 239f0e43013Smillert message = (struct message *)realloc(message, size); 240db59c1a6Smillert if (message == 0) 24136999bedSmillert errx(1, "Insufficient memory for %d messages\n", 24236999bedSmillert msgCount); 243db59c1a6Smillert } else { 244df930be7Sderaadt if (message != 0) 245f0e43013Smillert (void)free(message); 246cb1926ebSmillert if ((message = (struct message *)malloc(size)) == NULL) 24736999bedSmillert errx(1, "Insufficient memory for %d messages", 24836999bedSmillert msgCount); 249df930be7Sderaadt dot = message; 250db59c1a6Smillert } 251db59c1a6Smillert size -= (omsgCount + 1) * sizeof(struct message); 252df930be7Sderaadt fflush(f); 253db59c1a6Smillert (void)lseek(fileno(f), (off_t)sizeof(*message), 0); 254db59c1a6Smillert if (read(fileno(f), (void *) &message[omsgCount], size) != size) 25536999bedSmillert errx(1, "Message temporary file corrupted"); 256df930be7Sderaadt message[msgCount].m_size = 0; 257df930be7Sderaadt message[msgCount].m_lines = 0; 258db59c1a6Smillert (void)Fclose(f); 259df930be7Sderaadt } 260df930be7Sderaadt 261df930be7Sderaadt /* 262df930be7Sderaadt * Append the passed message descriptor onto the temp file. 263df930be7Sderaadt * If the write fails, return 1, else 0 264df930be7Sderaadt */ 265df930be7Sderaadt int 266df930be7Sderaadt append(mp, f) 267df930be7Sderaadt struct message *mp; 268df930be7Sderaadt FILE *f; 269df930be7Sderaadt { 270db59c1a6Smillert return(fwrite((char *) mp, sizeof(*mp), 1, f) != 1); 271df930be7Sderaadt } 272df930be7Sderaadt 273df930be7Sderaadt /* 274*0b426e12Smillert * Delete or truncate a file, but only if the file is a plain file. 275df930be7Sderaadt */ 276df930be7Sderaadt int 277df930be7Sderaadt rm(name) 278df930be7Sderaadt char *name; 279df930be7Sderaadt { 280df930be7Sderaadt struct stat sb; 281df930be7Sderaadt 282df930be7Sderaadt if (stat(name, &sb) < 0) 283df930be7Sderaadt return(-1); 284df930be7Sderaadt if (!S_ISREG(sb.st_mode)) { 285df930be7Sderaadt errno = EISDIR; 286df930be7Sderaadt return(-1); 287df930be7Sderaadt } 288*0b426e12Smillert if (unlink(name) == -1) { 289*0b426e12Smillert if (errno == EPERM) 290*0b426e12Smillert return(truncate(name, 0)); 291*0b426e12Smillert else 292*0b426e12Smillert return(-1); 293*0b426e12Smillert } 294*0b426e12Smillert return(0); 295df930be7Sderaadt } 296df930be7Sderaadt 297df930be7Sderaadt static int sigdepth; /* depth of holdsigs() */ 2987eb34045Sderaadt static sigset_t nset, oset; 299df930be7Sderaadt /* 300df930be7Sderaadt * Hold signals SIGHUP, SIGINT, and SIGQUIT. 301df930be7Sderaadt */ 302df930be7Sderaadt void 303df930be7Sderaadt holdsigs() 304df930be7Sderaadt { 305df930be7Sderaadt 3067eb34045Sderaadt if (sigdepth++ == 0) { 3077eb34045Sderaadt sigemptyset(&nset); 3087eb34045Sderaadt sigaddset(&nset, SIGHUP); 3097eb34045Sderaadt sigaddset(&nset, SIGINT); 3107eb34045Sderaadt sigaddset(&nset, SIGQUIT); 3117eb34045Sderaadt sigprocmask(SIG_BLOCK, &nset, &oset); 3127eb34045Sderaadt } 313df930be7Sderaadt } 314df930be7Sderaadt 315df930be7Sderaadt /* 316df930be7Sderaadt * Release signals SIGHUP, SIGINT, and SIGQUIT. 317df930be7Sderaadt */ 318df930be7Sderaadt void 319df930be7Sderaadt relsesigs() 320df930be7Sderaadt { 321df930be7Sderaadt 322df930be7Sderaadt if (--sigdepth == 0) 3237eb34045Sderaadt sigprocmask(SIG_SETMASK, &oset, NULL); 324df930be7Sderaadt } 325df930be7Sderaadt 326df930be7Sderaadt /* 327df930be7Sderaadt * Determine the size of the file possessed by 328df930be7Sderaadt * the passed buffer. 329df930be7Sderaadt */ 330df930be7Sderaadt off_t 331df930be7Sderaadt fsize(iob) 332df930be7Sderaadt FILE *iob; 333df930be7Sderaadt { 334df930be7Sderaadt struct stat sbuf; 335df930be7Sderaadt 336df930be7Sderaadt if (fstat(fileno(iob), &sbuf) < 0) 337db59c1a6Smillert return(0); 338db59c1a6Smillert return(sbuf.st_size); 339df930be7Sderaadt } 340df930be7Sderaadt 341df930be7Sderaadt /* 342df930be7Sderaadt * Evaluate the string given as a new mailbox name. 343df930be7Sderaadt * Supported meta characters: 344df930be7Sderaadt * % for my system mail box 345df930be7Sderaadt * %user for user's system mail box 346df930be7Sderaadt * # for previous file 347df930be7Sderaadt * & invoker's mbox file 348df930be7Sderaadt * +file file in folder directory 349df930be7Sderaadt * any shell meta character 350df930be7Sderaadt * Return the file name as a dynamic string. 351df930be7Sderaadt */ 352df930be7Sderaadt char * 353df930be7Sderaadt expand(name) 35436999bedSmillert char *name; 355df930be7Sderaadt { 356df930be7Sderaadt char xname[PATHSIZE]; 357df930be7Sderaadt char cmdbuf[PATHSIZE]; /* also used for file names */ 35836999bedSmillert int pid, l; 35936999bedSmillert char *cp, *shell; 360df930be7Sderaadt int pivec[2]; 361df930be7Sderaadt struct stat sbuf; 36259eb7d25Smillert extern int wait_status; 363df930be7Sderaadt 364df930be7Sderaadt /* 365df930be7Sderaadt * The order of evaluation is "%" and "#" expand into constants. 366df930be7Sderaadt * "&" can expand into "+". "+" can expand into shell meta characters. 367df930be7Sderaadt * Shell meta characters expand into constants. 368df930be7Sderaadt * This way, we make no recursive expansion. 369df930be7Sderaadt */ 370df930be7Sderaadt switch (*name) { 371df930be7Sderaadt case '%': 372db59c1a6Smillert findmail(name[1] ? name + 1 : myname, xname, sizeof(xname)); 373db59c1a6Smillert return(savestr(xname)); 374df930be7Sderaadt case '#': 375df930be7Sderaadt if (name[1] != 0) 376df930be7Sderaadt break; 377df930be7Sderaadt if (prevfile[0] == 0) { 378db59c1a6Smillert puts("No previous file"); 379c318c72bSmillert return(NULL); 380df930be7Sderaadt } 381db59c1a6Smillert return(savestr(prevfile)); 382df930be7Sderaadt case '&': 383c318c72bSmillert if (name[1] == 0 && (name = value("MBOX")) == NULL) 384df930be7Sderaadt name = "~/mbox"; 385df930be7Sderaadt /* fall through */ 386df930be7Sderaadt } 387db59c1a6Smillert if (name[0] == '+' && getfold(cmdbuf, sizeof(cmdbuf)) >= 0) { 3880ecc72fcSmillert (void)snprintf(xname, sizeof(xname), "%s/%s", cmdbuf, name + 1); 389df930be7Sderaadt name = savestr(xname); 390df930be7Sderaadt } 391df930be7Sderaadt /* catch the most common shell meta character */ 392df930be7Sderaadt if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) { 3930ecc72fcSmillert (void)snprintf(xname, sizeof(xname), "%s%s", homedir, name + 1); 394df930be7Sderaadt name = savestr(xname); 395df930be7Sderaadt } 396df930be7Sderaadt if (!anyof(name, "~{[*?$`'\"\\")) 397db59c1a6Smillert return(name); 398df930be7Sderaadt if (pipe(pivec) < 0) { 399db59c1a6Smillert warn("pipe"); 400db59c1a6Smillert return(name); 401df930be7Sderaadt } 4020ecc72fcSmillert (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name); 403c318c72bSmillert if ((shell = value("SHELL")) == NULL) 404df930be7Sderaadt shell = _PATH_CSHELL; 405c318c72bSmillert pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NULL); 406df930be7Sderaadt if (pid < 0) { 407db59c1a6Smillert (void)close(pivec[0]); 408db59c1a6Smillert (void)close(pivec[1]); 409c318c72bSmillert return(NULL); 410df930be7Sderaadt } 411db59c1a6Smillert (void)close(pivec[1]); 412db59c1a6Smillert l = read(pivec[0], xname, PATHSIZE); 413db59c1a6Smillert (void)close(pivec[0]); 41459eb7d25Smillert if (wait_child(pid) < 0 && WIFSIGNALED(wait_status) && 41559eb7d25Smillert WTERMSIG(wait_status) != SIGPIPE) { 416df930be7Sderaadt fprintf(stderr, "\"%s\": Expansion failed.\n", name); 417c318c72bSmillert return(NULL); 418df930be7Sderaadt } 419df930be7Sderaadt if (l < 0) { 420db59c1a6Smillert warn("read"); 421c318c72bSmillert return(NULL); 422df930be7Sderaadt } 423df930be7Sderaadt if (l == 0) { 424df930be7Sderaadt fprintf(stderr, "\"%s\": No match.\n", name); 425c318c72bSmillert return(NULL); 426df930be7Sderaadt } 427db59c1a6Smillert if (l == PATHSIZE) { 428df930be7Sderaadt fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name); 429c318c72bSmillert return(NULL); 430df930be7Sderaadt } 431db59c1a6Smillert xname[l] = '\0'; 432df930be7Sderaadt for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 433df930be7Sderaadt ; 434df930be7Sderaadt cp[1] = '\0'; 435180acc8fSmillert if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) { 436df930be7Sderaadt fprintf(stderr, "\"%s\": Ambiguous.\n", name); 437c318c72bSmillert return(NULL); 438df930be7Sderaadt } 439db59c1a6Smillert return(savestr(xname)); 440df930be7Sderaadt } 441df930be7Sderaadt 442df930be7Sderaadt /* 443df930be7Sderaadt * Determine the current folder directory name. 444df930be7Sderaadt */ 445df930be7Sderaadt int 446c32a3250Sderaadt getfold(name, namelen) 447df930be7Sderaadt char *name; 448c32a3250Sderaadt int namelen; 449df930be7Sderaadt { 450df930be7Sderaadt char *folder; 451df930be7Sderaadt 452c318c72bSmillert if ((folder = value("folder")) == NULL) 453df930be7Sderaadt return(-1); 454c32a3250Sderaadt if (*folder == '/') { 455c32a3250Sderaadt strncpy(name, folder, namelen-1); 456c32a3250Sderaadt name[namelen-1] = '\0'; 457c32a3250Sderaadt } else 4580ecc72fcSmillert (void)snprintf(name, namelen, "%s/%s", homedir, folder); 459df930be7Sderaadt return(0); 460df930be7Sderaadt } 461df930be7Sderaadt 462df930be7Sderaadt /* 463df930be7Sderaadt * Return the name of the dead.letter file. 464df930be7Sderaadt */ 465df930be7Sderaadt char * 466df930be7Sderaadt getdeadletter() 467df930be7Sderaadt { 46836999bedSmillert char *cp; 469df930be7Sderaadt 470c318c72bSmillert if ((cp = value("DEAD")) == NULL || (cp = expand(cp)) == NULL) 471df930be7Sderaadt cp = expand("~/dead.letter"); 472df930be7Sderaadt else if (*cp != '/') { 473df930be7Sderaadt char buf[PATHSIZE]; 474df930be7Sderaadt 475db59c1a6Smillert (void)snprintf(buf, sizeof(buf), "~/%s", cp); 476df930be7Sderaadt cp = expand(buf); 477df930be7Sderaadt } 478db59c1a6Smillert return(cp); 479df930be7Sderaadt } 480