1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* 26*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999 by Sun Microsystems, Inc. 27*7c478bd9Sstevel@tonic-gate * All rights reserved. 28*7c478bd9Sstevel@tonic-gate */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #ident "%Z%%M% %I% %E% SMI" /* from SVr4.0 1.13.2.2 */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include "rcv.h" 33*7c478bd9Sstevel@tonic-gate #include <locale.h> 34*7c478bd9Sstevel@tonic-gate #include <wordexp.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate /* 37*7c478bd9Sstevel@tonic-gate * mailx -- a modified version of a University of California at Berkeley 38*7c478bd9Sstevel@tonic-gate * mail program 39*7c478bd9Sstevel@tonic-gate * 40*7c478bd9Sstevel@tonic-gate * File I/O. 41*7c478bd9Sstevel@tonic-gate */ 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate static int getln(char *line, int max, FILE *f); 44*7c478bd9Sstevel@tonic-gate static int linecount(char *lp, long size); 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* 47*7c478bd9Sstevel@tonic-gate * Set up the input pointers while copying the mail file into 48*7c478bd9Sstevel@tonic-gate * /tmp. 49*7c478bd9Sstevel@tonic-gate */ 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate void 52*7c478bd9Sstevel@tonic-gate setptr(register FILE *ibuf) 53*7c478bd9Sstevel@tonic-gate { 54*7c478bd9Sstevel@tonic-gate int n, newline = 1, blankline = 1; 55*7c478bd9Sstevel@tonic-gate int StartNewMsg = TRUE; 56*7c478bd9Sstevel@tonic-gate int ToldUser = FALSE; 57*7c478bd9Sstevel@tonic-gate long clen = -1L; 58*7c478bd9Sstevel@tonic-gate int hdr = 0; 59*7c478bd9Sstevel@tonic-gate int cflg = 0; /* found Content-length in header */ 60*7c478bd9Sstevel@tonic-gate register char *cp; 61*7c478bd9Sstevel@tonic-gate register int l; 62*7c478bd9Sstevel@tonic-gate register long s; 63*7c478bd9Sstevel@tonic-gate off_t offset; 64*7c478bd9Sstevel@tonic-gate char linebuf[LINESIZE]; 65*7c478bd9Sstevel@tonic-gate int inhead, newmail, Odot; 66*7c478bd9Sstevel@tonic-gate short flag; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate if (!space) { 69*7c478bd9Sstevel@tonic-gate msgCount = 0; 70*7c478bd9Sstevel@tonic-gate offset = 0; 71*7c478bd9Sstevel@tonic-gate space = 32; 72*7c478bd9Sstevel@tonic-gate newmail = 0; 73*7c478bd9Sstevel@tonic-gate message = 74*7c478bd9Sstevel@tonic-gate (struct message *)calloc(space, sizeof (struct message)); 75*7c478bd9Sstevel@tonic-gate if (message == NULL) { 76*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 77*7c478bd9Sstevel@tonic-gate "calloc: insufficient memory for %d messages\n"), 78*7c478bd9Sstevel@tonic-gate space); 79*7c478bd9Sstevel@tonic-gate exit(1); 80*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 81*7c478bd9Sstevel@tonic-gate } 82*7c478bd9Sstevel@tonic-gate dot = message; 83*7c478bd9Sstevel@tonic-gate } else { 84*7c478bd9Sstevel@tonic-gate newmail = 1; 85*7c478bd9Sstevel@tonic-gate offset = fsize(otf); 86*7c478bd9Sstevel@tonic-gate } 87*7c478bd9Sstevel@tonic-gate s = 0L; 88*7c478bd9Sstevel@tonic-gate l = 0; 89*7c478bd9Sstevel@tonic-gate /* 90*7c478bd9Sstevel@tonic-gate * Set default flags. When reading from 91*7c478bd9Sstevel@tonic-gate * a folder, assume the message has been 92*7c478bd9Sstevel@tonic-gate * previously read. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate if (edit) 95*7c478bd9Sstevel@tonic-gate flag = MUSED|MREAD; 96*7c478bd9Sstevel@tonic-gate else 97*7c478bd9Sstevel@tonic-gate flag = MUSED|MNEW; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate inhead = 0; 100*7c478bd9Sstevel@tonic-gate while ((n = getln(linebuf, sizeof (linebuf), ibuf)) > 0) { 101*7c478bd9Sstevel@tonic-gate if (!newline) { 102*7c478bd9Sstevel@tonic-gate goto putout; 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate top: 105*7c478bd9Sstevel@tonic-gate hdr = inhead && (headerp(linebuf) || 106*7c478bd9Sstevel@tonic-gate (linebuf[0] == ' ' || linebuf[0] == '\t')); 107*7c478bd9Sstevel@tonic-gate if (!hdr && cflg) { /* nonheader, Content-length seen */ 108*7c478bd9Sstevel@tonic-gate if (clen > 0 && clen < n) { /* read too much */ 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * NB: this only can happen if there is a 111*7c478bd9Sstevel@tonic-gate * small content that is NOT \n terminated 112*7c478bd9Sstevel@tonic-gate * and has no leading blank line, i.e., never. 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate if (fwrite(linebuf, 1, (int)clen, otf) != 115*7c478bd9Sstevel@tonic-gate clen) { 116*7c478bd9Sstevel@tonic-gate fclose(ibuf); 117*7c478bd9Sstevel@tonic-gate fflush(otf); 118*7c478bd9Sstevel@tonic-gate } else { 119*7c478bd9Sstevel@tonic-gate l += linecount(linebuf, clen); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate offset += clen; 122*7c478bd9Sstevel@tonic-gate s += clen; 123*7c478bd9Sstevel@tonic-gate n -= (int)clen; 124*7c478bd9Sstevel@tonic-gate /* shift line to the left, copy null as well */ 125*7c478bd9Sstevel@tonic-gate memcpy(linebuf, linebuf+clen, n+1); 126*7c478bd9Sstevel@tonic-gate cflg = 0; 127*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_clen = clen + 1; 128*7c478bd9Sstevel@tonic-gate blankline = 1; 129*7c478bd9Sstevel@tonic-gate StartNewMsg = TRUE; 130*7c478bd9Sstevel@tonic-gate goto top; 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate /* here, clen == 0 or clen >= n */ 133*7c478bd9Sstevel@tonic-gate if (n == 1 && linebuf[0] == '\n') { 134*7c478bd9Sstevel@tonic-gate /* leading empty line */ 135*7c478bd9Sstevel@tonic-gate clen++; /* cheat */ 136*7c478bd9Sstevel@tonic-gate inhead = 0; 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate offset += clen; 139*7c478bd9Sstevel@tonic-gate s += (long)clen; 140*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_clen = clen; 141*7c478bd9Sstevel@tonic-gate for (;;) { 142*7c478bd9Sstevel@tonic-gate if (fwrite(linebuf, 1, n, otf) != n) { 143*7c478bd9Sstevel@tonic-gate fclose(ibuf); 144*7c478bd9Sstevel@tonic-gate fflush(otf); 145*7c478bd9Sstevel@tonic-gate } else { 146*7c478bd9Sstevel@tonic-gate l += linecount(linebuf, n); 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate clen -= n; 149*7c478bd9Sstevel@tonic-gate if (clen <= 0) { 150*7c478bd9Sstevel@tonic-gate break; 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate n = clen < sizeof (linebuf) ? 153*7c478bd9Sstevel@tonic-gate (int)clen : (int)sizeof (linebuf); 154*7c478bd9Sstevel@tonic-gate if ((n = fread(linebuf, 1, n, ibuf)) <= 0) { 155*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 156*7c478bd9Sstevel@tonic-gate "%s:\tYour mailfile was found to be corrupted.\n"), 157*7c478bd9Sstevel@tonic-gate progname); 158*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 159*7c478bd9Sstevel@tonic-gate "\t(Unexpected end-of-file).\n")); 160*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 161*7c478bd9Sstevel@tonic-gate "\tMessage #%d may be truncated.\n\n"), 162*7c478bd9Sstevel@tonic-gate msgCount); 163*7c478bd9Sstevel@tonic-gate offset -= clen; 164*7c478bd9Sstevel@tonic-gate s -= clen; 165*7c478bd9Sstevel@tonic-gate clen = 0; /* stop the loop */ 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate /* All done, go to top for next message */ 169*7c478bd9Sstevel@tonic-gate cflg = 0; 170*7c478bd9Sstevel@tonic-gate blankline = 1; 171*7c478bd9Sstevel@tonic-gate StartNewMsg = TRUE; 172*7c478bd9Sstevel@tonic-gate continue; 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* Look for a From line that starts a new message */ 176*7c478bd9Sstevel@tonic-gate if (blankline && linebuf[0] == 'F' && ishead(linebuf)) { 177*7c478bd9Sstevel@tonic-gate if (msgCount > 0 && !newmail) { 178*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_size = s; 179*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_lines = l; 180*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_flag = flag; 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate if (msgCount >= space) { 183*7c478bd9Sstevel@tonic-gate /* 184*7c478bd9Sstevel@tonic-gate * Limit the speed at which the 185*7c478bd9Sstevel@tonic-gate * allocated space grows. 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate if (space < 512) 188*7c478bd9Sstevel@tonic-gate space = space*2; 189*7c478bd9Sstevel@tonic-gate else 190*7c478bd9Sstevel@tonic-gate space += 512; 191*7c478bd9Sstevel@tonic-gate errno = 0; 192*7c478bd9Sstevel@tonic-gate Odot = dot - &(message[0]); 193*7c478bd9Sstevel@tonic-gate message = (struct message *) 194*7c478bd9Sstevel@tonic-gate realloc(message, 195*7c478bd9Sstevel@tonic-gate space*(sizeof (struct message))); 196*7c478bd9Sstevel@tonic-gate if (message == NULL) { 197*7c478bd9Sstevel@tonic-gate perror("realloc failed"); 198*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 199*7c478bd9Sstevel@tonic-gate "realloc: insufficient memory for %d messages\n"), 200*7c478bd9Sstevel@tonic-gate space); 201*7c478bd9Sstevel@tonic-gate exit(1); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate dot = &message[Odot]; 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate message[msgCount].m_offset = offset; 206*7c478bd9Sstevel@tonic-gate message[msgCount].m_text = TRUE; 207*7c478bd9Sstevel@tonic-gate message[msgCount].m_clen = 0; 208*7c478bd9Sstevel@tonic-gate newmail = 0; 209*7c478bd9Sstevel@tonic-gate msgCount++; 210*7c478bd9Sstevel@tonic-gate if (edit) 211*7c478bd9Sstevel@tonic-gate flag = MUSED|MREAD; 212*7c478bd9Sstevel@tonic-gate else 213*7c478bd9Sstevel@tonic-gate flag = MUSED|MNEW; 214*7c478bd9Sstevel@tonic-gate inhead = 1; 215*7c478bd9Sstevel@tonic-gate s = 0L; 216*7c478bd9Sstevel@tonic-gate l = 0; 217*7c478bd9Sstevel@tonic-gate StartNewMsg = FALSE; 218*7c478bd9Sstevel@tonic-gate ToldUser = FALSE; 219*7c478bd9Sstevel@tonic-gate goto putout; 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate /* if didn't get a header line, we're no longer in the header */ 223*7c478bd9Sstevel@tonic-gate if (!hdr) 224*7c478bd9Sstevel@tonic-gate inhead = 0; 225*7c478bd9Sstevel@tonic-gate if (!inhead) 226*7c478bd9Sstevel@tonic-gate goto putout; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * Look for Status: line. Do quick check for second character, 230*7c478bd9Sstevel@tonic-gate * many headers start with "S" but few have "t" as second char. 231*7c478bd9Sstevel@tonic-gate */ 232*7c478bd9Sstevel@tonic-gate if ((linebuf[1] == 't' || linebuf[1] == 'T') && 233*7c478bd9Sstevel@tonic-gate ishfield(linebuf, "status")) { 234*7c478bd9Sstevel@tonic-gate cp = hcontents(linebuf); 235*7c478bd9Sstevel@tonic-gate flag = MUSED|MNEW; 236*7c478bd9Sstevel@tonic-gate if (strchr(cp, 'R')) 237*7c478bd9Sstevel@tonic-gate flag |= MREAD; 238*7c478bd9Sstevel@tonic-gate if (strchr(cp, 'O')) 239*7c478bd9Sstevel@tonic-gate flag &= ~MNEW; 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate /* 242*7c478bd9Sstevel@tonic-gate * Look for Content-Length and Content-Type headers. Like 243*7c478bd9Sstevel@tonic-gate * above, do a quick check for the "-", which is rare. 244*7c478bd9Sstevel@tonic-gate */ 245*7c478bd9Sstevel@tonic-gate if (linebuf[7] == '-') { 246*7c478bd9Sstevel@tonic-gate if (ishfield(linebuf, "content-length")) { 247*7c478bd9Sstevel@tonic-gate if (!cflg) { 248*7c478bd9Sstevel@tonic-gate clen = atol(hcontents(linebuf)); 249*7c478bd9Sstevel@tonic-gate cflg = clen >= 0; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate } else if (ishfield(linebuf, "content-type")) { 252*7c478bd9Sstevel@tonic-gate char word[LINESIZE]; 253*7c478bd9Sstevel@tonic-gate char *cp2; 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate cp = hcontents(linebuf); 256*7c478bd9Sstevel@tonic-gate cp2 = word; 257*7c478bd9Sstevel@tonic-gate while (!isspace(*cp)) 258*7c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 259*7c478bd9Sstevel@tonic-gate *cp2 = '\0'; 260*7c478bd9Sstevel@tonic-gate if (icequal(word, "binary")) 261*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_text = FALSE; 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate putout: 265*7c478bd9Sstevel@tonic-gate offset += n; 266*7c478bd9Sstevel@tonic-gate s += (long)n; 267*7c478bd9Sstevel@tonic-gate if (fwrite(linebuf, 1, n, otf) != n) { 268*7c478bd9Sstevel@tonic-gate fclose(ibuf); 269*7c478bd9Sstevel@tonic-gate fflush(otf); 270*7c478bd9Sstevel@tonic-gate } else { 271*7c478bd9Sstevel@tonic-gate l++; 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate if (ferror(otf)) { 274*7c478bd9Sstevel@tonic-gate perror("/tmp"); 275*7c478bd9Sstevel@tonic-gate exit(1); 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate if (msgCount == 0) { 278*7c478bd9Sstevel@tonic-gate fclose(ibuf); 279*7c478bd9Sstevel@tonic-gate fflush(otf); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate if (linebuf[n-1] == '\n') { 282*7c478bd9Sstevel@tonic-gate blankline = newline && n == 1; 283*7c478bd9Sstevel@tonic-gate newline = 1; 284*7c478bd9Sstevel@tonic-gate if (n == 1) { 285*7c478bd9Sstevel@tonic-gate /* Blank line. Skip StartNewMsg check below */ 286*7c478bd9Sstevel@tonic-gate continue; 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate } else { 289*7c478bd9Sstevel@tonic-gate newline = 0; 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate if (StartNewMsg && !ToldUser) { 292*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 293*7c478bd9Sstevel@tonic-gate "%s:\tYour mailfile was found to be corrupted\n"), 294*7c478bd9Sstevel@tonic-gate progname); 295*7c478bd9Sstevel@tonic-gate fprintf(stderr, 296*7c478bd9Sstevel@tonic-gate gettext("\t(Content-length mismatch).\n")); 297*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 298*7c478bd9Sstevel@tonic-gate "\tMessage #%d may be truncated,\n"), msgCount); 299*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 300*7c478bd9Sstevel@tonic-gate "\twith another message concatenated to it.\n\n")); 301*7c478bd9Sstevel@tonic-gate ToldUser = TRUE; 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate if (n == 0) { 306*7c478bd9Sstevel@tonic-gate fflush(otf); 307*7c478bd9Sstevel@tonic-gate if (fferror(otf)) { 308*7c478bd9Sstevel@tonic-gate perror("/tmp"); 309*7c478bd9Sstevel@tonic-gate exit(1); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate if (msgCount) { 312*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_size = s; 313*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_lines = l; 314*7c478bd9Sstevel@tonic-gate message[msgCount-1].m_flag = flag; 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate fclose(ibuf); 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate /* 321*7c478bd9Sstevel@tonic-gate * Compute the content length of a message and set it into m_clen. 322*7c478bd9Sstevel@tonic-gate */ 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate void 325*7c478bd9Sstevel@tonic-gate setclen(register struct message *mp) 326*7c478bd9Sstevel@tonic-gate { 327*7c478bd9Sstevel@tonic-gate long c; 328*7c478bd9Sstevel@tonic-gate FILE *ibuf; 329*7c478bd9Sstevel@tonic-gate char line[LINESIZE]; 330*7c478bd9Sstevel@tonic-gate int fline, nread; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate ibuf = setinput(mp); 333*7c478bd9Sstevel@tonic-gate c = mp->m_size; 334*7c478bd9Sstevel@tonic-gate fline = 1; 335*7c478bd9Sstevel@tonic-gate while (c > 0L) { 336*7c478bd9Sstevel@tonic-gate nread = getln(line, sizeof (line), ibuf); 337*7c478bd9Sstevel@tonic-gate c -= nread; 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate * First line is the From line, so no headers 340*7c478bd9Sstevel@tonic-gate * there to worry about. 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate if (fline) { 343*7c478bd9Sstevel@tonic-gate fline = 0; 344*7c478bd9Sstevel@tonic-gate continue; 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * If line is blank, we've reached end of headers. 348*7c478bd9Sstevel@tonic-gate */ 349*7c478bd9Sstevel@tonic-gate if (line[0] == '\n') 350*7c478bd9Sstevel@tonic-gate break; 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * If this line is a continuation 353*7c478bd9Sstevel@tonic-gate * of a previous header field, keep going. 354*7c478bd9Sstevel@tonic-gate */ 355*7c478bd9Sstevel@tonic-gate if (isspace(line[0])) 356*7c478bd9Sstevel@tonic-gate continue; 357*7c478bd9Sstevel@tonic-gate /* 358*7c478bd9Sstevel@tonic-gate * If we are no longer looking at real 359*7c478bd9Sstevel@tonic-gate * header lines, we're done. 360*7c478bd9Sstevel@tonic-gate * This happens in uucp style mail where 361*7c478bd9Sstevel@tonic-gate * there are no headers at all. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate if (!headerp(line)) { 364*7c478bd9Sstevel@tonic-gate c += nread; 365*7c478bd9Sstevel@tonic-gate break; 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate if (c == 0) 369*7c478bd9Sstevel@tonic-gate c = 1; 370*7c478bd9Sstevel@tonic-gate mp->m_clen = c; 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate static int 374*7c478bd9Sstevel@tonic-gate getln(char *line, int max, FILE *f) 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate register int c; 377*7c478bd9Sstevel@tonic-gate register char *cp, *ecp; 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate cp = line; 380*7c478bd9Sstevel@tonic-gate ecp = cp + max - 1; 381*7c478bd9Sstevel@tonic-gate while (cp < ecp && (c = getc(f)) != EOF) 382*7c478bd9Sstevel@tonic-gate if ((*cp++ = (char)c) == '\n') 383*7c478bd9Sstevel@tonic-gate break; 384*7c478bd9Sstevel@tonic-gate *cp = '\0'; 385*7c478bd9Sstevel@tonic-gate return (cp - line); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate /* 389*7c478bd9Sstevel@tonic-gate * Read up a line from the specified input into the line 390*7c478bd9Sstevel@tonic-gate * buffer. Return the number of characters read. Do not 391*7c478bd9Sstevel@tonic-gate * include the newline at the end. 392*7c478bd9Sstevel@tonic-gate */ 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate readline(FILE *ibuf, char *linebuf) 395*7c478bd9Sstevel@tonic-gate { 396*7c478bd9Sstevel@tonic-gate register char *cp; 397*7c478bd9Sstevel@tonic-gate register int c; 398*7c478bd9Sstevel@tonic-gate int seennulls = 0; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate clearerr(ibuf); 401*7c478bd9Sstevel@tonic-gate c = getc(ibuf); 402*7c478bd9Sstevel@tonic-gate for (cp = linebuf; c != '\n' && c != EOF; c = getc(ibuf)) { 403*7c478bd9Sstevel@tonic-gate if (c == 0) { 404*7c478bd9Sstevel@tonic-gate if (!seennulls) { 405*7c478bd9Sstevel@tonic-gate fprintf(stderr, 406*7c478bd9Sstevel@tonic-gate gettext("mailx: NUL changed to @\n")); 407*7c478bd9Sstevel@tonic-gate seennulls++; 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate c = '@'; 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate if (cp - linebuf < LINESIZE-2) 412*7c478bd9Sstevel@tonic-gate *cp++ = (char)c; 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate *cp = 0; 415*7c478bd9Sstevel@tonic-gate if (c == EOF && cp == linebuf) 416*7c478bd9Sstevel@tonic-gate return (0); 417*7c478bd9Sstevel@tonic-gate return (cp - linebuf + 1); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * linecount - determine the number of lines in a printable file. 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate static int 425*7c478bd9Sstevel@tonic-gate linecount(char *lp, long size) 426*7c478bd9Sstevel@tonic-gate { 427*7c478bd9Sstevel@tonic-gate register char *cp, *ecp; 428*7c478bd9Sstevel@tonic-gate register int count; 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate count = 0; 431*7c478bd9Sstevel@tonic-gate cp = lp; 432*7c478bd9Sstevel@tonic-gate ecp = cp + size; 433*7c478bd9Sstevel@tonic-gate while (cp < ecp) 434*7c478bd9Sstevel@tonic-gate if (*cp++ == '\n') 435*7c478bd9Sstevel@tonic-gate count++; 436*7c478bd9Sstevel@tonic-gate return (count); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* 440*7c478bd9Sstevel@tonic-gate * Return a file buffer all ready to read up the 441*7c478bd9Sstevel@tonic-gate * passed message pointer. 442*7c478bd9Sstevel@tonic-gate */ 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate FILE * 445*7c478bd9Sstevel@tonic-gate setinput(register struct message *mp) 446*7c478bd9Sstevel@tonic-gate { 447*7c478bd9Sstevel@tonic-gate fflush(otf); 448*7c478bd9Sstevel@tonic-gate if (fseek(itf, mp->m_offset, 0) < 0) { 449*7c478bd9Sstevel@tonic-gate perror("fseek"); 450*7c478bd9Sstevel@tonic-gate panic("temporary file seek"); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate return (itf); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate /* 457*7c478bd9Sstevel@tonic-gate * Delete a file, but only if the file is a plain file. 458*7c478bd9Sstevel@tonic-gate */ 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate int 461*7c478bd9Sstevel@tonic-gate removefile(char name[]) 462*7c478bd9Sstevel@tonic-gate { 463*7c478bd9Sstevel@tonic-gate struct stat statb; 464*7c478bd9Sstevel@tonic-gate extern int errno; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 467*7c478bd9Sstevel@tonic-gate if (errno == ENOENT) 468*7c478bd9Sstevel@tonic-gate return (0); /* it's already gone, no error */ 469*7c478bd9Sstevel@tonic-gate else 470*7c478bd9Sstevel@tonic-gate return (-1); 471*7c478bd9Sstevel@tonic-gate if ((statb.st_mode & S_IFMT) != S_IFREG) { 472*7c478bd9Sstevel@tonic-gate errno = EISDIR; 473*7c478bd9Sstevel@tonic-gate return (-1); 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate return (unlink(name)); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate /* 479*7c478bd9Sstevel@tonic-gate * Terminate an editing session by attempting to write out the user's 480*7c478bd9Sstevel@tonic-gate * file from the temporary. Save any new stuff appended to the file. 481*7c478bd9Sstevel@tonic-gate */ 482*7c478bd9Sstevel@tonic-gate int 483*7c478bd9Sstevel@tonic-gate edstop( 484*7c478bd9Sstevel@tonic-gate int noremove /* don't allow the file to be removed, trunc instead */ 485*7c478bd9Sstevel@tonic-gate ) 486*7c478bd9Sstevel@tonic-gate { 487*7c478bd9Sstevel@tonic-gate register int gotcha, c; 488*7c478bd9Sstevel@tonic-gate register struct message *mp; 489*7c478bd9Sstevel@tonic-gate FILE *obuf, *ibuf, *tbuf = 0, *readstat; 490*7c478bd9Sstevel@tonic-gate struct stat statb; 491*7c478bd9Sstevel@tonic-gate char tempname[STSIZ], *id; 492*7c478bd9Sstevel@tonic-gate int tmpfd = -1; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate if (readonly) 495*7c478bd9Sstevel@tonic-gate return (0); 496*7c478bd9Sstevel@tonic-gate holdsigs(); 497*7c478bd9Sstevel@tonic-gate if (Tflag != NOSTR) { 498*7c478bd9Sstevel@tonic-gate if ((readstat = fopen(Tflag, "w")) == NULL) 499*7c478bd9Sstevel@tonic-gate Tflag = NOSTR; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { 502*7c478bd9Sstevel@tonic-gate if (mp->m_flag & MNEW) { 503*7c478bd9Sstevel@tonic-gate mp->m_flag &= ~MNEW; 504*7c478bd9Sstevel@tonic-gate mp->m_flag |= MSTATUS; 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) 507*7c478bd9Sstevel@tonic-gate gotcha++; 508*7c478bd9Sstevel@tonic-gate if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { 509*7c478bd9Sstevel@tonic-gate if ((id = hfield("article-id", mp, addone)) != NOSTR) 510*7c478bd9Sstevel@tonic-gate fprintf(readstat, "%s\n", id); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate if (Tflag != NOSTR) 514*7c478bd9Sstevel@tonic-gate fclose(readstat); 515*7c478bd9Sstevel@tonic-gate if (!gotcha || Tflag != NOSTR) 516*7c478bd9Sstevel@tonic-gate goto done; 517*7c478bd9Sstevel@tonic-gate if ((ibuf = fopen(editfile, "r+")) == NULL) { 518*7c478bd9Sstevel@tonic-gate perror(editfile); 519*7c478bd9Sstevel@tonic-gate relsesigs(); 520*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate lock(ibuf, "r+", 1); 523*7c478bd9Sstevel@tonic-gate if (fstat(fileno(ibuf), &statb) >= 0 && statb.st_size > mailsize) { 524*7c478bd9Sstevel@tonic-gate nstrcpy(tempname, STSIZ, "/tmp/mboxXXXXXX"); 525*7c478bd9Sstevel@tonic-gate if ((tmpfd = mkstemp(tempname)) == -1) { 526*7c478bd9Sstevel@tonic-gate perror(tempname); 527*7c478bd9Sstevel@tonic-gate fclose(ibuf); 528*7c478bd9Sstevel@tonic-gate relsesigs(); 529*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate if ((obuf = fdopen(tmpfd, "w")) == NULL) { 532*7c478bd9Sstevel@tonic-gate perror(tempname); 533*7c478bd9Sstevel@tonic-gate fclose(ibuf); 534*7c478bd9Sstevel@tonic-gate removefile(tempname); 535*7c478bd9Sstevel@tonic-gate relsesigs(); 536*7c478bd9Sstevel@tonic-gate (void) close(tmpfd); 537*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate fseek(ibuf, mailsize, 0); 540*7c478bd9Sstevel@tonic-gate while ((c = getc(ibuf)) != EOF) 541*7c478bd9Sstevel@tonic-gate putc(c, obuf); 542*7c478bd9Sstevel@tonic-gate fclose(obuf); 543*7c478bd9Sstevel@tonic-gate if ((tbuf = fopen(tempname, "r")) == NULL) { 544*7c478bd9Sstevel@tonic-gate perror(tempname); 545*7c478bd9Sstevel@tonic-gate fclose(ibuf); 546*7c478bd9Sstevel@tonic-gate removefile(tempname); 547*7c478bd9Sstevel@tonic-gate relsesigs(); 548*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate removefile(tempname); 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate if ((obuf = fopen(editfile, "r+")) == NULL) { 553*7c478bd9Sstevel@tonic-gate if ((obuf = fopen(editfile, "w")) == NULL) { 554*7c478bd9Sstevel@tonic-gate perror(editfile); 555*7c478bd9Sstevel@tonic-gate fclose(ibuf); 556*7c478bd9Sstevel@tonic-gate if (tbuf) 557*7c478bd9Sstevel@tonic-gate fclose(tbuf); 558*7c478bd9Sstevel@tonic-gate relsesigs(); 559*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate printf("\"%s\" ", editfile); 563*7c478bd9Sstevel@tonic-gate flush(); 564*7c478bd9Sstevel@tonic-gate c = 0; 565*7c478bd9Sstevel@tonic-gate for (mp = &message[0]; mp < &message[msgCount]; mp++) { 566*7c478bd9Sstevel@tonic-gate if ((mp->m_flag & MDELETED) != 0) 567*7c478bd9Sstevel@tonic-gate continue; 568*7c478bd9Sstevel@tonic-gate c++; 569*7c478bd9Sstevel@tonic-gate if (msend(mp, obuf, 0, fputs) < 0) { 570*7c478bd9Sstevel@tonic-gate perror(editfile); 571*7c478bd9Sstevel@tonic-gate fclose(ibuf); 572*7c478bd9Sstevel@tonic-gate fclose(obuf); 573*7c478bd9Sstevel@tonic-gate if (tbuf) 574*7c478bd9Sstevel@tonic-gate fclose(tbuf); 575*7c478bd9Sstevel@tonic-gate relsesigs(); 576*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate gotcha = (c == 0 && tbuf == NULL); 580*7c478bd9Sstevel@tonic-gate if (tbuf != NULL) { 581*7c478bd9Sstevel@tonic-gate while ((c = getc(tbuf)) != EOF) 582*7c478bd9Sstevel@tonic-gate putc(c, obuf); 583*7c478bd9Sstevel@tonic-gate fclose(tbuf); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate fflush(obuf); 586*7c478bd9Sstevel@tonic-gate if (fferror(obuf)) { 587*7c478bd9Sstevel@tonic-gate perror(editfile); 588*7c478bd9Sstevel@tonic-gate fclose(ibuf); 589*7c478bd9Sstevel@tonic-gate fclose(obuf); 590*7c478bd9Sstevel@tonic-gate relsesigs(); 591*7c478bd9Sstevel@tonic-gate longjmp(srbuf, 1); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate if (gotcha && !noremove && (value("keep") == NOSTR)) { 594*7c478bd9Sstevel@tonic-gate removefile(editfile); 595*7c478bd9Sstevel@tonic-gate printf(gettext("removed.\n")); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate else 598*7c478bd9Sstevel@tonic-gate printf(gettext("updated.\n")); 599*7c478bd9Sstevel@tonic-gate fclose(ibuf); 600*7c478bd9Sstevel@tonic-gate trunc(obuf); 601*7c478bd9Sstevel@tonic-gate fclose(obuf); 602*7c478bd9Sstevel@tonic-gate flush(); 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate done: 605*7c478bd9Sstevel@tonic-gate relsesigs(); 606*7c478bd9Sstevel@tonic-gate return (1); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate #ifndef OLD_BSD_SIGS 610*7c478bd9Sstevel@tonic-gate static int sigdepth = 0; /* depth of holdsigs() */ 611*7c478bd9Sstevel@tonic-gate #ifdef VMUNIX 612*7c478bd9Sstevel@tonic-gate static int omask = 0; 613*7c478bd9Sstevel@tonic-gate #else 614*7c478bd9Sstevel@tonic-gate static sigset_t mask, omask; 615*7c478bd9Sstevel@tonic-gate #endif 616*7c478bd9Sstevel@tonic-gate #endif 617*7c478bd9Sstevel@tonic-gate /* 618*7c478bd9Sstevel@tonic-gate * Hold signals SIGHUP - SIGQUIT. 619*7c478bd9Sstevel@tonic-gate */ 620*7c478bd9Sstevel@tonic-gate void 621*7c478bd9Sstevel@tonic-gate holdsigs(void) 622*7c478bd9Sstevel@tonic-gate { 623*7c478bd9Sstevel@tonic-gate #ifndef OLD_BSD_SIGS 624*7c478bd9Sstevel@tonic-gate if (sigdepth++ == 0) { 625*7c478bd9Sstevel@tonic-gate #ifdef VMUNIX 626*7c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGHUP) | 627*7c478bd9Sstevel@tonic-gate sigmask(SIGINT)|sigmask(SIGQUIT)); 628*7c478bd9Sstevel@tonic-gate #else 629*7c478bd9Sstevel@tonic-gate sigemptyset(&mask); 630*7c478bd9Sstevel@tonic-gate sigaddset(&mask, SIGHUP); 631*7c478bd9Sstevel@tonic-gate sigaddset(&mask, SIGINT); 632*7c478bd9Sstevel@tonic-gate sigaddset(&mask, SIGQUIT); 633*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_BLOCK, &mask, &omask); 634*7c478bd9Sstevel@tonic-gate #endif 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate #else 637*7c478bd9Sstevel@tonic-gate sighold(SIGHUP); 638*7c478bd9Sstevel@tonic-gate sighold(SIGINT); 639*7c478bd9Sstevel@tonic-gate sighold(SIGQUIT); 640*7c478bd9Sstevel@tonic-gate #endif 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * Release signals SIGHUP - SIGQUIT 645*7c478bd9Sstevel@tonic-gate */ 646*7c478bd9Sstevel@tonic-gate void 647*7c478bd9Sstevel@tonic-gate relsesigs(void) 648*7c478bd9Sstevel@tonic-gate { 649*7c478bd9Sstevel@tonic-gate #ifndef OLD_BSD_SIGS 650*7c478bd9Sstevel@tonic-gate if (--sigdepth == 0) 651*7c478bd9Sstevel@tonic-gate #ifdef VMUNIX 652*7c478bd9Sstevel@tonic-gate sigsetmask(omask); 653*7c478bd9Sstevel@tonic-gate #else 654*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_SETMASK, &omask, NULL); 655*7c478bd9Sstevel@tonic-gate #endif 656*7c478bd9Sstevel@tonic-gate #else 657*7c478bd9Sstevel@tonic-gate sigrelse(SIGHUP); 658*7c478bd9Sstevel@tonic-gate sigrelse(SIGINT); 659*7c478bd9Sstevel@tonic-gate sigrelse(SIGQUIT); 660*7c478bd9Sstevel@tonic-gate #endif 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate #if !defined(OLD_BSD_SIGS) && !defined(VMUNIX) 664*7c478bd9Sstevel@tonic-gate void 665*7c478bd9Sstevel@tonic-gate (*sigset(int sig, void (*act)(int)))(int) 666*7c478bd9Sstevel@tonic-gate { 667*7c478bd9Sstevel@tonic-gate struct sigaction sa, osa; 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate sa.sa_handler = (void (*)())act; 670*7c478bd9Sstevel@tonic-gate sigemptyset(&sa.sa_mask); 671*7c478bd9Sstevel@tonic-gate sa.sa_flags = SA_RESTART; 672*7c478bd9Sstevel@tonic-gate if (sigaction(sig, &sa, &osa) < 0) 673*7c478bd9Sstevel@tonic-gate return ((void (*)(int))-1); 674*7c478bd9Sstevel@tonic-gate return ((void (*)(int))osa.sa_handler); 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate #endif 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate /* 679*7c478bd9Sstevel@tonic-gate * Flush the standard output. 680*7c478bd9Sstevel@tonic-gate */ 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate void 683*7c478bd9Sstevel@tonic-gate flush(void) 684*7c478bd9Sstevel@tonic-gate { 685*7c478bd9Sstevel@tonic-gate fflush(stdout); 686*7c478bd9Sstevel@tonic-gate fflush(stderr); 687*7c478bd9Sstevel@tonic-gate } 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate /* 690*7c478bd9Sstevel@tonic-gate * Determine the size of the file possessed by 691*7c478bd9Sstevel@tonic-gate * the passed buffer. 692*7c478bd9Sstevel@tonic-gate */ 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate off_t 695*7c478bd9Sstevel@tonic-gate fsize(FILE *iob) 696*7c478bd9Sstevel@tonic-gate { 697*7c478bd9Sstevel@tonic-gate register int f; 698*7c478bd9Sstevel@tonic-gate struct stat sbuf; 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate f = fileno(iob); 701*7c478bd9Sstevel@tonic-gate if (fstat(f, &sbuf) < 0) 702*7c478bd9Sstevel@tonic-gate return (0); 703*7c478bd9Sstevel@tonic-gate return (sbuf.st_size); 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate * Check for either a stdio recognized error, or 708*7c478bd9Sstevel@tonic-gate * a possibly delayed write error (in case it's 709*7c478bd9Sstevel@tonic-gate * an NFS file, for instance). 710*7c478bd9Sstevel@tonic-gate */ 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate int 713*7c478bd9Sstevel@tonic-gate fferror(FILE *iob) 714*7c478bd9Sstevel@tonic-gate { 715*7c478bd9Sstevel@tonic-gate return (ferror(iob) || fsync(fileno(iob)) < 0); 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate /* 719*7c478bd9Sstevel@tonic-gate * Take a file name, possibly with shell meta characters 720*7c478bd9Sstevel@tonic-gate * in it and expand it by using wordexp(). 721*7c478bd9Sstevel@tonic-gate * Return the file name as a dynamic string. 722*7c478bd9Sstevel@tonic-gate * If the name cannot be expanded (for whatever reason) 723*7c478bd9Sstevel@tonic-gate * return NULL. 724*7c478bd9Sstevel@tonic-gate */ 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate char * 727*7c478bd9Sstevel@tonic-gate expand(char *name) 728*7c478bd9Sstevel@tonic-gate { 729*7c478bd9Sstevel@tonic-gate char xname[BUFSIZ]; 730*7c478bd9Sstevel@tonic-gate char foldbuf[BUFSIZ]; 731*7c478bd9Sstevel@tonic-gate register char *cp; 732*7c478bd9Sstevel@tonic-gate register int l; 733*7c478bd9Sstevel@tonic-gate wordexp_t wrdexp_buf; 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate if (debug) fprintf(stderr, "expand(%s)=", name); 736*7c478bd9Sstevel@tonic-gate cp = strchr(name, '\0') - 1; /* pointer to last char of name */ 737*7c478bd9Sstevel@tonic-gate if (isspace(*cp)) { 738*7c478bd9Sstevel@tonic-gate /* strip off trailing blanks */ 739*7c478bd9Sstevel@tonic-gate while (cp > name && isspace(*cp)) 740*7c478bd9Sstevel@tonic-gate cp--; 741*7c478bd9Sstevel@tonic-gate l = *++cp; /* save char */ 742*7c478bd9Sstevel@tonic-gate *cp = '\0'; 743*7c478bd9Sstevel@tonic-gate name = savestr(name); 744*7c478bd9Sstevel@tonic-gate *cp = (char)l; /* restore char */ 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate if (name[0] == '+' && getfold(foldbuf) >= 0) { 747*7c478bd9Sstevel@tonic-gate snprintf(xname, sizeof (xname), "%s/%s", foldbuf, name + 1); 748*7c478bd9Sstevel@tonic-gate cp = safeexpand(savestr(xname)); 749*7c478bd9Sstevel@tonic-gate if (debug) fprintf(stderr, "%s\n", cp); 750*7c478bd9Sstevel@tonic-gate return (cp); 751*7c478bd9Sstevel@tonic-gate } 752*7c478bd9Sstevel@tonic-gate if (!anyof(name, "~{[*?$`'\"\\")) { 753*7c478bd9Sstevel@tonic-gate if (debug) fprintf(stderr, "%s\n", name); 754*7c478bd9Sstevel@tonic-gate return (name); 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate if (wordexp(name, &wrdexp_buf, 0) != 0) { 757*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Syntax error in \"%s\"\n"), name); 758*7c478bd9Sstevel@tonic-gate fflush(stderr); 759*7c478bd9Sstevel@tonic-gate return (NOSTR); 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate if (wrdexp_buf.we_wordc > 1) { 762*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("\"%s\": Ambiguous\n"), name); 763*7c478bd9Sstevel@tonic-gate fflush(stderr); 764*7c478bd9Sstevel@tonic-gate return (NOSTR); 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate if (debug) fprintf(stderr, "%s\n", wrdexp_buf.we_wordv[0]); 767*7c478bd9Sstevel@tonic-gate return (savestr(wrdexp_buf.we_wordv[0])); 768*7c478bd9Sstevel@tonic-gate } 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* 771*7c478bd9Sstevel@tonic-gate * Take a file name, possibly with shell meta characters 772*7c478bd9Sstevel@tonic-gate * in it and expand it by using "sh -c echo filename" 773*7c478bd9Sstevel@tonic-gate * Return the file name as a dynamic string. 774*7c478bd9Sstevel@tonic-gate * If the name cannot be expanded (for whatever reason) 775*7c478bd9Sstevel@tonic-gate * return the original file name. 776*7c478bd9Sstevel@tonic-gate */ 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate char * 779*7c478bd9Sstevel@tonic-gate safeexpand(char name[]) 780*7c478bd9Sstevel@tonic-gate { 781*7c478bd9Sstevel@tonic-gate char *t = expand(name); 782*7c478bd9Sstevel@tonic-gate return (t) ? t : savestr(name); 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate /* 786*7c478bd9Sstevel@tonic-gate * Determine the current folder directory name. 787*7c478bd9Sstevel@tonic-gate */ 788*7c478bd9Sstevel@tonic-gate getfold(char *name) 789*7c478bd9Sstevel@tonic-gate { 790*7c478bd9Sstevel@tonic-gate char *folder; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate if ((folder = value("folder")) == NOSTR || *folder == '\0') 793*7c478bd9Sstevel@tonic-gate return (-1); 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * If name looks like a folder name, don't try 796*7c478bd9Sstevel@tonic-gate * to expand it, to prevent infinite recursion. 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate if (*folder != '+' && (folder = expand(folder)) == NOSTR || 799*7c478bd9Sstevel@tonic-gate *folder == '\0') 800*7c478bd9Sstevel@tonic-gate return (-1); 801*7c478bd9Sstevel@tonic-gate if (*folder == '/') { 802*7c478bd9Sstevel@tonic-gate nstrcpy(name, BUFSIZ, folder); 803*7c478bd9Sstevel@tonic-gate } else 804*7c478bd9Sstevel@tonic-gate snprintf(name, BUFSIZ, "%s/%s", homedir, folder); 805*7c478bd9Sstevel@tonic-gate return (0); 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate /* 809*7c478bd9Sstevel@tonic-gate * A nicer version of Fdopen, which allows us to fclose 810*7c478bd9Sstevel@tonic-gate * without losing the open file. 811*7c478bd9Sstevel@tonic-gate */ 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate FILE * 814*7c478bd9Sstevel@tonic-gate Fdopen(int fildes, char *mode) 815*7c478bd9Sstevel@tonic-gate { 816*7c478bd9Sstevel@tonic-gate register int f; 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate f = dup(fildes); 819*7c478bd9Sstevel@tonic-gate if (f < 0) { 820*7c478bd9Sstevel@tonic-gate perror("dup"); 821*7c478bd9Sstevel@tonic-gate return (NULL); 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate return (fdopen(f, mode)); 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate /* 827*7c478bd9Sstevel@tonic-gate * return the filename associated with "s". This function always 828*7c478bd9Sstevel@tonic-gate * returns a non-null string (no error checking is done on the receiving end) 829*7c478bd9Sstevel@tonic-gate */ 830*7c478bd9Sstevel@tonic-gate char * 831*7c478bd9Sstevel@tonic-gate Getf(register char *s) 832*7c478bd9Sstevel@tonic-gate { 833*7c478bd9Sstevel@tonic-gate register char *cp; 834*7c478bd9Sstevel@tonic-gate static char defbuf[PATHSIZE]; 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate if (((cp = value(s)) != 0) && *cp) { 837*7c478bd9Sstevel@tonic-gate return (safeexpand(cp)); 838*7c478bd9Sstevel@tonic-gate } else if (strcmp(s, "MBOX") == 0) { 839*7c478bd9Sstevel@tonic-gate snprintf(defbuf, sizeof (defbuf), "%s/%s", Getf("HOME"), 840*7c478bd9Sstevel@tonic-gate "mbox"); 841*7c478bd9Sstevel@tonic-gate return (defbuf); 842*7c478bd9Sstevel@tonic-gate } else if (strcmp(s, "DEAD") == 0) { 843*7c478bd9Sstevel@tonic-gate snprintf(defbuf, sizeof (defbuf), "%s/%s", Getf("HOME"), 844*7c478bd9Sstevel@tonic-gate "dead.letter"); 845*7c478bd9Sstevel@tonic-gate return (defbuf); 846*7c478bd9Sstevel@tonic-gate } else if (strcmp(s, "MAILRC") == 0) { 847*7c478bd9Sstevel@tonic-gate snprintf(defbuf, sizeof (defbuf), "%s/%s", Getf("HOME"), 848*7c478bd9Sstevel@tonic-gate ".mailrc"); 849*7c478bd9Sstevel@tonic-gate return (defbuf); 850*7c478bd9Sstevel@tonic-gate } else if (strcmp(s, "HOME") == 0) { 851*7c478bd9Sstevel@tonic-gate /* no recursion allowed! */ 852*7c478bd9Sstevel@tonic-gate return ("."); 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate return ("DEAD"); /* "cannot happen" */ 855*7c478bd9Sstevel@tonic-gate } 856