xref: /minix3/minix/commands/mail/mail.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*  mail - send/receive mail 		 Author: Peter S. Housel */
2*433d6423SLionel Sambuc /* Version 0.2 of September 1990: added -e, -t, * options - cwr */
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc /* 2003-07-18: added -s option - ASW */
5*433d6423SLionel Sambuc 
6*433d6423SLionel Sambuc #include <sys/types.h>
7*433d6423SLionel Sambuc #include <sys/stat.h>
8*433d6423SLionel Sambuc #include <errno.h>
9*433d6423SLionel Sambuc #undef EOF			/* temporary hack */
10*433d6423SLionel Sambuc #include <signal.h>
11*433d6423SLionel Sambuc #include <pwd.h>
12*433d6423SLionel Sambuc #include <time.h>
13*433d6423SLionel Sambuc #include <setjmp.h>
14*433d6423SLionel Sambuc #include <string.h>
15*433d6423SLionel Sambuc #include <stdlib.h>
16*433d6423SLionel Sambuc #include <fcntl.h>
17*433d6423SLionel Sambuc #include <unistd.h>
18*433d6423SLionel Sambuc #include <sys/wait.h>
19*433d6423SLionel Sambuc #include <stdio.h>
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc #ifdef DEBUG
22*433d6423SLionel Sambuc #define D(Q) (Q)
23*433d6423SLionel Sambuc #else
24*433d6423SLionel Sambuc #define D(Q)
25*433d6423SLionel Sambuc #endif
26*433d6423SLionel Sambuc 
27*433d6423SLionel Sambuc #define SHELL		"/bin/sh"
28*433d6423SLionel Sambuc 
29*433d6423SLionel Sambuc #define DROPNAME 	"/var/mail/%s"
30*433d6423SLionel Sambuc #define LOCKNAME	"/var/mail/%s.lock"
31*433d6423SLionel Sambuc #define LOCKWAIT	5	/* seconds to wait after collision */
32*433d6423SLionel Sambuc #define LOCKTRIES	4	/* maximum number of collisions */
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc #define MBOX		"mbox"
35*433d6423SLionel Sambuc 
36*433d6423SLionel Sambuc #define HELPFILE	"/usr/lib/mail.help"
37*433d6423SLionel Sambuc #define PROMPT		"? "
38*433d6423SLionel Sambuc #define PATHLEN		80
39*433d6423SLionel Sambuc #define MAXRCPT		100	/* maximum number of recipients */
40*433d6423SLionel Sambuc #define LINELEN		512
41*433d6423SLionel Sambuc 
42*433d6423SLionel Sambuc /* #define MAILER		"/usr/bin/smail"	*/ /* smart mailer */
43*433d6423SLionel Sambuc #define MAILERARGS		/* (unused) */
44*433d6423SLionel Sambuc 
45*433d6423SLionel Sambuc #define UNREAD		1	/* 'not read yet' status */
46*433d6423SLionel Sambuc #define DELETED		2	/* 'deleted' status */
47*433d6423SLionel Sambuc #define READ		3	/* 'has been read' status */
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc struct letter {
50*433d6423SLionel Sambuc   struct letter *prev, *next;	/* linked letter list */
51*433d6423SLionel Sambuc   int status;			/* letter status */
52*433d6423SLionel Sambuc   off_t location;		/* location within mailbox file */
53*433d6423SLionel Sambuc };
54*433d6423SLionel Sambuc 
55*433d6423SLionel Sambuc struct letter *firstlet, *lastlet;
56*433d6423SLionel Sambuc 
57*433d6423SLionel Sambuc int usemailer = 1;		/* use MAILER to deliver (if any) */
58*433d6423SLionel Sambuc int printmode = 0;		/* print-and-exit mode */
59*433d6423SLionel Sambuc int quitmode = 0;		/* take interrupts */
60*433d6423SLionel Sambuc int reversemode = 0;		/* print mailbox in reverse order */
61*433d6423SLionel Sambuc int usedrop = 1;		/* read the maildrop (no -f given) */
62*433d6423SLionel Sambuc int verbose = 0;		/* pass "-v" flag on to mailer */
63*433d6423SLionel Sambuc int needupdate = 0;		/* need to update mailbox */
64*433d6423SLionel Sambuc int msgstatus = 0;		/* return the mail status */
65*433d6423SLionel Sambuc int distlist = 0;		/* include distribution list */
66*433d6423SLionel Sambuc char mailbox[PATHLEN];		/* user's mailbox/maildrop */
67*433d6423SLionel Sambuc char tempname[PATHLEN] = "/tmp/mailXXXXXX";	/* temporary file */
68*433d6423SLionel Sambuc char *subject = NULL;
69*433d6423SLionel Sambuc FILE *boxfp = NULL;		/* mailbox file */
70*433d6423SLionel Sambuc jmp_buf printjump;		/* for quitting out of letters */
71*433d6423SLionel Sambuc unsigned oldmask;		/* saved umask() */
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc extern int optind;
74*433d6423SLionel Sambuc extern char *optarg;
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc int main(int argc, char **argv);
77*433d6423SLionel Sambuc int deliver(int count, char *vec []);
78*433d6423SLionel Sambuc FILE *makerewindable(void);
79*433d6423SLionel Sambuc int copy(FILE *fromfp, FILE *tofp);
80*433d6423SLionel Sambuc void readbox(void);
81*433d6423SLionel Sambuc void printall(void);
82*433d6423SLionel Sambuc void interact(void);
83*433d6423SLionel Sambuc void onint(int dummy);
84*433d6423SLionel Sambuc void savelet(struct letter *let, char *savefile);
85*433d6423SLionel Sambuc void updatebox(void);
86*433d6423SLionel Sambuc void printlet(struct letter *let, FILE *tofp);
87*433d6423SLionel Sambuc void doshell(char *command);
88*433d6423SLionel Sambuc void usage(void);
89*433d6423SLionel Sambuc char *basename(char *name);
90*433d6423SLionel Sambuc char *whoami(void);
91*433d6423SLionel Sambuc void dohelp(void);
92*433d6423SLionel Sambuc int filesize(char *name);
93*433d6423SLionel Sambuc 
94*433d6423SLionel Sambuc int main(argc, argv)
95*433d6423SLionel Sambuc int argc;
96*433d6423SLionel Sambuc char *argv[];
97*433d6423SLionel Sambuc {
98*433d6423SLionel Sambuc   int c;
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc   if ('l' == (basename(argv[0]))[0])	/* 'lmail' link? */
101*433d6423SLionel Sambuc 	usemailer = 0;		/* yes, let's deliver it */
102*433d6423SLionel Sambuc 
103*433d6423SLionel Sambuc   (void) mktemp(tempname);	/* name the temp file */
104*433d6423SLionel Sambuc 
105*433d6423SLionel Sambuc   oldmask = umask(022);		/* change umask for security */
106*433d6423SLionel Sambuc 
107*433d6423SLionel Sambuc   while (EOF != (c = getopt(argc, argv, "epqrf:tdvs:"))) switch (c) {
108*433d6423SLionel Sambuc 	    case 'e':	++msgstatus;	break;
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc 	    case 't':	++distlist;	break;
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc 	    case 'p':	++printmode;	break;
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc 	    case 'q':	++quitmode;	break;
115*433d6423SLionel Sambuc 
116*433d6423SLionel Sambuc 	    case 'r':	++reversemode;	break;
117*433d6423SLionel Sambuc 
118*433d6423SLionel Sambuc 	    case 'f':
119*433d6423SLionel Sambuc 		setuid(getuid());	/* won't need to lock */
120*433d6423SLionel Sambuc 		usedrop = 0;
121*433d6423SLionel Sambuc 		strncpy(mailbox, optarg, (size_t)(PATHLEN - 1));
122*433d6423SLionel Sambuc 		break;
123*433d6423SLionel Sambuc 
124*433d6423SLionel Sambuc 	    case 'd':	usemailer = 0;	break;
125*433d6423SLionel Sambuc 
126*433d6423SLionel Sambuc 	    case 'v':	++verbose;	break;
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc 	    case 's':	subject = optarg; break;
129*433d6423SLionel Sambuc 
130*433d6423SLionel Sambuc 	    default:
131*433d6423SLionel Sambuc 		usage();
132*433d6423SLionel Sambuc 		exit(1);
133*433d6423SLionel Sambuc 	}
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc   if (optind < argc) {
136*433d6423SLionel Sambuc 	if (deliver(argc - optind, argv + optind) < 0)
137*433d6423SLionel Sambuc 		exit(1);
138*433d6423SLionel Sambuc 	else
139*433d6423SLionel Sambuc 		exit(0);
140*433d6423SLionel Sambuc   }
141*433d6423SLionel Sambuc   if (usedrop) sprintf(mailbox, DROPNAME, whoami());
142*433d6423SLionel Sambuc 
143*433d6423SLionel Sambuc   D(printf("mailbox=%s\n", mailbox));
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc   if (msgstatus) {
146*433d6423SLionel Sambuc 	if (filesize(mailbox))
147*433d6423SLionel Sambuc 		exit(0);
148*433d6423SLionel Sambuc 	else
149*433d6423SLionel Sambuc 		exit(1);
150*433d6423SLionel Sambuc   }
151*433d6423SLionel Sambuc 
152*433d6423SLionel Sambuc   readbox();
153*433d6423SLionel Sambuc 
154*433d6423SLionel Sambuc   if (printmode)
155*433d6423SLionel Sambuc 	printall();
156*433d6423SLionel Sambuc   else
157*433d6423SLionel Sambuc 	interact();
158*433d6423SLionel Sambuc 
159*433d6423SLionel Sambuc   if (needupdate) updatebox();
160*433d6423SLionel Sambuc 
161*433d6423SLionel Sambuc   return(0);
162*433d6423SLionel Sambuc }
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc int deliver(count, vec)
165*433d6423SLionel Sambuc int count;
166*433d6423SLionel Sambuc char *vec[];
167*433d6423SLionel Sambuc {
168*433d6423SLionel Sambuc   int i, j;
169*433d6423SLionel Sambuc   int errs = 0;			/* count of errors */
170*433d6423SLionel Sambuc   int dropfd;			/* file descriptor for user's drop */
171*433d6423SLionel Sambuc   int created = 0;		/* true if we created the maildrop */
172*433d6423SLionel Sambuc   FILE *mailfp;			/* fp for mail */
173*433d6423SLionel Sambuc   struct stat stb;		/* for checking drop modes, owners */
174*433d6423SLionel Sambuc #ifdef __STDC__
175*433d6423SLionel Sambuc   void (*sigint)(int), (*sighup)(int), (*sigquit)(int);/* saving signal state */
176*433d6423SLionel Sambuc #else
177*433d6423SLionel Sambuc   void (*sigint) (), (*sighup) (), (*sigquit) ();      /* saving signal state */
178*433d6423SLionel Sambuc #endif
179*433d6423SLionel Sambuc   time_t now;			/* for datestamping the postmark */
180*433d6423SLionel Sambuc   char sender[32];		/* sender's login name */
181*433d6423SLionel Sambuc   char lockname[PATHLEN];	/* maildrop lock */
182*433d6423SLionel Sambuc   int locktries;		/* tries when box is locked */
183*433d6423SLionel Sambuc   struct passwd *pw;		/* sender and recipent */
184*433d6423SLionel Sambuc   int to_console;		/* deliver to console if everything fails */
185*433d6423SLionel Sambuc 
186*433d6423SLionel Sambuc   if (count > MAXRCPT) {
187*433d6423SLionel Sambuc 	fprintf(stderr, "mail: too many recipients\n");
188*433d6423SLionel Sambuc 	return -1;
189*433d6423SLionel Sambuc   }
190*433d6423SLionel Sambuc #ifdef MAILER
191*433d6423SLionel Sambuc   if (usemailer) {
192*433d6423SLionel Sambuc 	char *argvec[MAXRCPT + 3];
193*433d6423SLionel Sambuc 	char **argp;
194*433d6423SLionel Sambuc 
195*433d6423SLionel Sambuc 	setuid(getuid());
196*433d6423SLionel Sambuc 
197*433d6423SLionel Sambuc 	argp = argvec;
198*433d6423SLionel Sambuc 	*argp++ = "send-mail";
199*433d6423SLionel Sambuc 	if (verbose) *argp++ = "-v";
200*433d6423SLionel Sambuc 
201*433d6423SLionel Sambuc 	for (i = 0; i < count; ++i) *argp++ = vec[i];
202*433d6423SLionel Sambuc 
203*433d6423SLionel Sambuc 	*argp = NULL;
204*433d6423SLionel Sambuc 	execv(MAILER, argvec);
205*433d6423SLionel Sambuc 	fprintf(stderr, "mail: couldn't exec %s\n", MAILER);
206*433d6423SLionel Sambuc 	return -1;
207*433d6423SLionel Sambuc   }
208*433d6423SLionel Sambuc #endif /* MAILER */
209*433d6423SLionel Sambuc 
210*433d6423SLionel Sambuc   if (NULL == (pw = getpwuid(getuid()))) {
211*433d6423SLionel Sambuc 	fprintf(stderr, "mail: unknown sender\n");
212*433d6423SLionel Sambuc 	return -1;
213*433d6423SLionel Sambuc   }
214*433d6423SLionel Sambuc   strcpy(sender, pw->pw_name);
215*433d6423SLionel Sambuc 
216*433d6423SLionel Sambuc   /* If we need to rewind stdin and it isn't rewindable, make a copy */
217*433d6423SLionel Sambuc   if (isatty(0) || (count > 1 && lseek(0, 0L, 0) == (off_t) -1)) {
218*433d6423SLionel Sambuc 	mailfp = makerewindable();
219*433d6423SLionel Sambuc   } else
220*433d6423SLionel Sambuc 	mailfp = stdin;
221*433d6423SLionel Sambuc 
222*433d6423SLionel Sambuc   /* Shut off signals during the delivery */
223*433d6423SLionel Sambuc   sigint = signal(SIGINT, SIG_IGN);
224*433d6423SLionel Sambuc   sighup = signal(SIGHUP, SIG_IGN);
225*433d6423SLionel Sambuc   sigquit = signal(SIGQUIT, SIG_IGN);
226*433d6423SLionel Sambuc 
227*433d6423SLionel Sambuc   for (i = 0; i < count; ++i) {
228*433d6423SLionel Sambuc 	if (count > 1) rewind(mailfp);
229*433d6423SLionel Sambuc 
230*433d6423SLionel Sambuc 	D(printf("deliver to %s\n", vec[i]));
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc 	if (NULL == (pw = getpwnam(vec[i]))) {
233*433d6423SLionel Sambuc 		fprintf(stderr, "mail: user %s not known\n", vec[i]);
234*433d6423SLionel Sambuc 		++errs;
235*433d6423SLionel Sambuc 		continue;
236*433d6423SLionel Sambuc 	}
237*433d6423SLionel Sambuc 	sprintf(mailbox, DROPNAME, pw->pw_name);
238*433d6423SLionel Sambuc 	sprintf(lockname, LOCKNAME, pw->pw_name);
239*433d6423SLionel Sambuc 
240*433d6423SLionel Sambuc 	D(printf("maildrop='%s', lock='%s'\n", mailbox, lockname));
241*433d6423SLionel Sambuc 
242*433d6423SLionel Sambuc 	/* Lock the maildrop while we're messing with it. Races are
243*433d6423SLionel Sambuc 	 * possible (though not very likely) when we have to create
244*433d6423SLionel Sambuc 	 * the maildrop, but not otherwise. If the box is already
245*433d6423SLionel Sambuc 	 * locked, wait awhile and try again. */
246*433d6423SLionel Sambuc 	locktries = created = to_console = 0;
247*433d6423SLionel Sambuc trylock:
248*433d6423SLionel Sambuc 	if (link(mailbox, lockname) != 0) {
249*433d6423SLionel Sambuc 		if (ENOENT == errno) {	/* user doesn't have a drop yet */
250*433d6423SLionel Sambuc 			dropfd = creat(mailbox, 0600);
251*433d6423SLionel Sambuc 			if (dropfd < 0 && errno == ENOENT) {
252*433d6423SLionel Sambuc 				/* Probably missing spool dir; to console. */
253*433d6423SLionel Sambuc 				boxfp = fopen("/dev/console", "w");
254*433d6423SLionel Sambuc 				if (boxfp != NULL) {
255*433d6423SLionel Sambuc 					to_console = 1;
256*433d6423SLionel Sambuc 					goto nobox;
257*433d6423SLionel Sambuc 				}
258*433d6423SLionel Sambuc 			}
259*433d6423SLionel Sambuc 			if (dropfd < 0) {
260*433d6423SLionel Sambuc 				fprintf(stderr, "mail: couln't create a maildrop for user %s\n",
261*433d6423SLionel Sambuc 					vec[i]);
262*433d6423SLionel Sambuc 				++errs;
263*433d6423SLionel Sambuc 				continue;
264*433d6423SLionel Sambuc 			}
265*433d6423SLionel Sambuc 			++created;
266*433d6423SLionel Sambuc 			goto trylock;
267*433d6423SLionel Sambuc 		} else {	/* somebody else has it locked, it seems -
268*433d6423SLionel Sambuc 			 * wait */
269*433d6423SLionel Sambuc 			if (++locktries >= LOCKTRIES) {
270*433d6423SLionel Sambuc 				fprintf(stderr, "mail: couldn't lock maildrop for user %s\n",
271*433d6423SLionel Sambuc 					vec[i]);
272*433d6423SLionel Sambuc 				++errs;
273*433d6423SLionel Sambuc 				continue;
274*433d6423SLionel Sambuc 			}
275*433d6423SLionel Sambuc 			sleep(LOCKWAIT);
276*433d6423SLionel Sambuc 			goto trylock;
277*433d6423SLionel Sambuc 		}
278*433d6423SLionel Sambuc 	}
279*433d6423SLionel Sambuc 	if (created) {
280*433d6423SLionel Sambuc 		(void) chown(mailbox, pw->pw_uid, pw->pw_gid);
281*433d6423SLionel Sambuc 		boxfp = fdopen(dropfd, "a");
282*433d6423SLionel Sambuc 	} else
283*433d6423SLionel Sambuc 		boxfp = fopen(mailbox, "a");
284*433d6423SLionel Sambuc 
285*433d6423SLionel Sambuc 	if (NULL == boxfp || stat(mailbox, &stb) < 0) {
286*433d6423SLionel Sambuc 		fprintf(stderr, "mail: serious maildrop problems for %s\n", vec[i]);
287*433d6423SLionel Sambuc 		unlink(lockname);
288*433d6423SLionel Sambuc 		++errs;
289*433d6423SLionel Sambuc 		continue;
290*433d6423SLionel Sambuc 	}
291*433d6423SLionel Sambuc 	if (stb.st_uid != pw->pw_uid || (stb.st_mode & S_IFMT) != S_IFREG) {
292*433d6423SLionel Sambuc 		fprintf(stderr, "mail: mailbox for user %s is illegal\n", vec[i]);
293*433d6423SLionel Sambuc 		unlink(lockname);
294*433d6423SLionel Sambuc 		++errs;
295*433d6423SLionel Sambuc 		continue;
296*433d6423SLionel Sambuc 	}
297*433d6423SLionel Sambuc nobox:
298*433d6423SLionel Sambuc 	if (to_console) {
299*433d6423SLionel Sambuc 		fprintf(boxfp,
300*433d6423SLionel Sambuc 			"-------------\n| Mail from %s to %s\n-------------\n",
301*433d6423SLionel Sambuc 			sender, vec[i]);
302*433d6423SLionel Sambuc 	} else {
303*433d6423SLionel Sambuc 		(void) time(&now);
304*433d6423SLionel Sambuc 		fprintf(boxfp, "From %s %24.24s\n", sender, ctime(&now));
305*433d6423SLionel Sambuc 	}
306*433d6423SLionel Sambuc 
307*433d6423SLionel Sambuc 	/* Add the To: header line */
308*433d6423SLionel Sambuc 	fprintf(boxfp, "To: %s\n", vec[i]);
309*433d6423SLionel Sambuc 
310*433d6423SLionel Sambuc 	if (distlist) {
311*433d6423SLionel Sambuc 		fprintf(boxfp, "Dist: ");
312*433d6423SLionel Sambuc 		for (j = 0; j < count; ++j)
313*433d6423SLionel Sambuc 			if (getpwnam(vec[j]) != NULL && j != i)
314*433d6423SLionel Sambuc 				fprintf(boxfp, "%s ", vec[j]) ;
315*433d6423SLionel Sambuc 		fprintf(boxfp, "\n");
316*433d6423SLionel Sambuc 	}
317*433d6423SLionel Sambuc 
318*433d6423SLionel Sambuc 	/* Add the Subject: header line */
319*433d6423SLionel Sambuc 	if (subject != NULL) fprintf(boxfp, "Subject: %s\n", subject);
320*433d6423SLionel Sambuc 
321*433d6423SLionel Sambuc 	fprintf(boxfp, "\n");
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc 	if ((copy(mailfp, boxfp) < 0) || (fclose(boxfp) != 0)) {
324*433d6423SLionel Sambuc 		fprintf(stderr, "mail: error delivering to user %s", vec[i]);
325*433d6423SLionel Sambuc 		perror(" ");
326*433d6423SLionel Sambuc 		++errs;
327*433d6423SLionel Sambuc 	}
328*433d6423SLionel Sambuc 	unlink(lockname);
329*433d6423SLionel Sambuc   }
330*433d6423SLionel Sambuc 
331*433d6423SLionel Sambuc   fclose(mailfp);
332*433d6423SLionel Sambuc 
333*433d6423SLionel Sambuc   /* Put signals back the way they were */
334*433d6423SLionel Sambuc   signal(SIGINT, sigint);
335*433d6423SLionel Sambuc   signal(SIGHUP, sighup);
336*433d6423SLionel Sambuc   signal(SIGQUIT, sigquit);
337*433d6423SLionel Sambuc 
338*433d6423SLionel Sambuc   return(0 == errs) ? 0 : -1;
339*433d6423SLionel Sambuc }
340*433d6423SLionel Sambuc 
341*433d6423SLionel Sambuc /* 'stdin' isn't rewindable. Make a temp file that is.
342*433d6423SLionel Sambuc  * Note that if one wanted to catch SIGINT and write a '~/dead.letter'
343*433d6423SLionel Sambuc  * for interactive mails, this might be the place to do it (though the
344*433d6423SLionel Sambuc  * case where a MAILER is being used would also need to be handled).
345*433d6423SLionel Sambuc  */
346*433d6423SLionel Sambuc FILE *makerewindable()
347*433d6423SLionel Sambuc {
348*433d6423SLionel Sambuc   FILE *tempfp;			/* temp file used for copy */
349*433d6423SLionel Sambuc   int c;			/* character being copied */
350*433d6423SLionel Sambuc   int state;			/* ".\n" detection state */
351*433d6423SLionel Sambuc 
352*433d6423SLionel Sambuc   if (NULL == (tempfp = fopen(tempname, "w"))) {
353*433d6423SLionel Sambuc 	fprintf(stderr, "mail: can't create temporary file\n");
354*433d6423SLionel Sambuc 	return NULL;
355*433d6423SLionel Sambuc   }
356*433d6423SLionel Sambuc 
357*433d6423SLionel Sambuc   /* Here we copy until we reach the end of the letter (end of file or
358*433d6423SLionel Sambuc    * a line containing only a '.'), painstakingly avoiding setting a
359*433d6423SLionel Sambuc    * line length limit. */
360*433d6423SLionel Sambuc   state = '\n';
361*433d6423SLionel Sambuc   while (EOF != (c = getc(stdin))) switch (state) {
362*433d6423SLionel Sambuc 	    case '\n':
363*433d6423SLionel Sambuc 		if ('.' == c)
364*433d6423SLionel Sambuc 			state = '.';
365*433d6423SLionel Sambuc 		else {
366*433d6423SLionel Sambuc 			if ('\n' != c) state = '\0';
367*433d6423SLionel Sambuc 			putc(c, tempfp);
368*433d6423SLionel Sambuc 		}
369*433d6423SLionel Sambuc 		break;
370*433d6423SLionel Sambuc 	    case '.':
371*433d6423SLionel Sambuc 		if ('\n' == c) goto done;
372*433d6423SLionel Sambuc 		state = '\0';
373*433d6423SLionel Sambuc 		putc('.', tempfp);
374*433d6423SLionel Sambuc 		putc(c, tempfp);
375*433d6423SLionel Sambuc 		break;
376*433d6423SLionel Sambuc 	    default:
377*433d6423SLionel Sambuc 		state = ('\n' == c) ? '\n' : '\0';
378*433d6423SLionel Sambuc 		putc(c, tempfp);
379*433d6423SLionel Sambuc 	}
380*433d6423SLionel Sambuc done:
381*433d6423SLionel Sambuc   if (ferror(tempfp) || fclose(tempfp)) {
382*433d6423SLionel Sambuc 	fprintf(stderr, "mail: couldn't copy letter to temporary file\n");
383*433d6423SLionel Sambuc 	return NULL;
384*433d6423SLionel Sambuc   }
385*433d6423SLionel Sambuc   tempfp = freopen(tempname, "r", stdin);
386*433d6423SLionel Sambuc   unlink(tempname);		/* unlink name; file lingers on in limbo */
387*433d6423SLionel Sambuc   return tempfp;
388*433d6423SLionel Sambuc }
389*433d6423SLionel Sambuc 
390*433d6423SLionel Sambuc int copy(fromfp, tofp)
391*433d6423SLionel Sambuc FILE *fromfp, *tofp;
392*433d6423SLionel Sambuc {
393*433d6423SLionel Sambuc   int c;			/* character being copied */
394*433d6423SLionel Sambuc   int state;			/* ".\n" and postmark detection state */
395*433d6423SLionel Sambuc   int blankline = 0;		/* was most recent line completely blank? */
396*433d6423SLionel Sambuc   static char postmark[] = "From ";
397*433d6423SLionel Sambuc   char *p, *q;
398*433d6423SLionel Sambuc 
399*433d6423SLionel Sambuc   /* Here we copy until we reach the end of the letter (end of file or
400*433d6423SLionel Sambuc    * a line containing only a '.'). Postmarks (lines beginning with
401*433d6423SLionel Sambuc    * "From ") are copied with a ">" prepended. Here we also complicate
402*433d6423SLionel Sambuc    * things by not setting a line limit. */
403*433d6423SLionel Sambuc   state = '\n';
404*433d6423SLionel Sambuc   p = postmark;
405*433d6423SLionel Sambuc   while (EOF != (c = getc(fromfp))) {
406*433d6423SLionel Sambuc 	switch (state) {
407*433d6423SLionel Sambuc 	    case '\n':
408*433d6423SLionel Sambuc 		if ('.' == c)	/* '.' at BOL */
409*433d6423SLionel Sambuc 			state = '.';
410*433d6423SLionel Sambuc 		else if (*p == c) {	/* start of postmark */
411*433d6423SLionel Sambuc 			++p;
412*433d6423SLionel Sambuc 			state = 'P';
413*433d6423SLionel Sambuc 		} else {	/* anything else */
414*433d6423SLionel Sambuc 			if ('\n' == c)
415*433d6423SLionel Sambuc 				blankline = 1;
416*433d6423SLionel Sambuc 			else {
417*433d6423SLionel Sambuc 				state = '\0';
418*433d6423SLionel Sambuc 				blankline = 0;
419*433d6423SLionel Sambuc 			}
420*433d6423SLionel Sambuc 			putc(c, tofp);
421*433d6423SLionel Sambuc 		}
422*433d6423SLionel Sambuc 		break;
423*433d6423SLionel Sambuc 	    case '.':
424*433d6423SLionel Sambuc 		if ('\n' == c) goto done;
425*433d6423SLionel Sambuc 		state = '\0';
426*433d6423SLionel Sambuc 		putc('.', tofp);
427*433d6423SLionel Sambuc 		putc(c, tofp);
428*433d6423SLionel Sambuc 		break;
429*433d6423SLionel Sambuc 	    case 'P':
430*433d6423SLionel Sambuc 		if (*p == c) {
431*433d6423SLionel Sambuc 			if (*++p == '\0') {	/* successfully reached end */
432*433d6423SLionel Sambuc 				p = postmark;
433*433d6423SLionel Sambuc 				putc('>', tofp);
434*433d6423SLionel Sambuc 				fputs(postmark, tofp);
435*433d6423SLionel Sambuc 				state = '\0';
436*433d6423SLionel Sambuc 				break;
437*433d6423SLionel Sambuc 			}
438*433d6423SLionel Sambuc 			break;	/* not there yet */
439*433d6423SLionel Sambuc 		}
440*433d6423SLionel Sambuc 		state = ('\n' == c) ? '\n' : '\0';
441*433d6423SLionel Sambuc 		for (q = postmark; q < p; ++q) putc(*q, tofp);
442*433d6423SLionel Sambuc 		putc(c, tofp);
443*433d6423SLionel Sambuc 		blankline = 0;
444*433d6423SLionel Sambuc 		p = postmark;
445*433d6423SLionel Sambuc 		break;
446*433d6423SLionel Sambuc 	    default:
447*433d6423SLionel Sambuc 		state = ('\n' == c) ? '\n' : '\0';
448*433d6423SLionel Sambuc 		putc(c, tofp);
449*433d6423SLionel Sambuc 	}
450*433d6423SLionel Sambuc   }
451*433d6423SLionel Sambuc   if ('\n' != state) putc('\n', tofp);
452*433d6423SLionel Sambuc done:
453*433d6423SLionel Sambuc   if (!blankline) putc('\n', tofp);
454*433d6423SLionel Sambuc   if (ferror(tofp)) return -1;
455*433d6423SLionel Sambuc   return 0;
456*433d6423SLionel Sambuc }
457*433d6423SLionel Sambuc 
458*433d6423SLionel Sambuc void readbox()
459*433d6423SLionel Sambuc {
460*433d6423SLionel Sambuc   char linebuf[512];
461*433d6423SLionel Sambuc   struct letter *let;
462*433d6423SLionel Sambuc   off_t current;
463*433d6423SLionel Sambuc 
464*433d6423SLionel Sambuc   firstlet = lastlet = NULL;
465*433d6423SLionel Sambuc 
466*433d6423SLionel Sambuc   if (access(mailbox, 4) < 0 || NULL == (boxfp = fopen(mailbox, "r"))) {
467*433d6423SLionel Sambuc 	if (usedrop && ENOENT == errno) return;
468*433d6423SLionel Sambuc 	fprintf(stderr, "can't access mailbox ");
469*433d6423SLionel Sambuc 	perror(mailbox);
470*433d6423SLionel Sambuc 	exit(1);
471*433d6423SLionel Sambuc   }
472*433d6423SLionel Sambuc   current = 0L;
473*433d6423SLionel Sambuc   while (1) {
474*433d6423SLionel Sambuc 	if (NULL == fgets(linebuf, sizeof linebuf, boxfp)) break;
475*433d6423SLionel Sambuc 
476*433d6423SLionel Sambuc 	if (!strncmp(linebuf, "From ", (size_t)5)) {
477*433d6423SLionel Sambuc 		if (NULL == (let = (struct letter *) malloc(sizeof(struct letter)))) {
478*433d6423SLionel Sambuc 			fprintf(stderr, "Out of memory.\n");
479*433d6423SLionel Sambuc 			exit(1);
480*433d6423SLionel Sambuc 		}
481*433d6423SLionel Sambuc 		if (NULL == lastlet) {
482*433d6423SLionel Sambuc 			firstlet = let;
483*433d6423SLionel Sambuc 			let->prev = NULL;
484*433d6423SLionel Sambuc 		} else {
485*433d6423SLionel Sambuc 			let->prev = lastlet;
486*433d6423SLionel Sambuc 			lastlet->next = let;
487*433d6423SLionel Sambuc 		}
488*433d6423SLionel Sambuc 		lastlet = let;
489*433d6423SLionel Sambuc 		let->next = NULL;
490*433d6423SLionel Sambuc 
491*433d6423SLionel Sambuc 		let->status = UNREAD;
492*433d6423SLionel Sambuc 		let->location = current;
493*433d6423SLionel Sambuc 		D(printf("letter at %ld\n", current));
494*433d6423SLionel Sambuc 	}
495*433d6423SLionel Sambuc 	current += strlen(linebuf);
496*433d6423SLionel Sambuc   }
497*433d6423SLionel Sambuc }
498*433d6423SLionel Sambuc 
499*433d6423SLionel Sambuc void printall()
500*433d6423SLionel Sambuc {
501*433d6423SLionel Sambuc   struct letter *let;
502*433d6423SLionel Sambuc 
503*433d6423SLionel Sambuc   let = reversemode ? firstlet : lastlet;
504*433d6423SLionel Sambuc 
505*433d6423SLionel Sambuc   if (NULL == let) {
506*433d6423SLionel Sambuc 	printf("No mail.\n");
507*433d6423SLionel Sambuc 	return;
508*433d6423SLionel Sambuc   }
509*433d6423SLionel Sambuc   while (NULL != let) {
510*433d6423SLionel Sambuc 	printlet(let, stdout);
511*433d6423SLionel Sambuc 	let = reversemode ? let->next : let->prev;
512*433d6423SLionel Sambuc   }
513*433d6423SLionel Sambuc }
514*433d6423SLionel Sambuc 
515*433d6423SLionel Sambuc void interact()
516*433d6423SLionel Sambuc {
517*433d6423SLionel Sambuc   char linebuf[512];		/* user input line */
518*433d6423SLionel Sambuc   struct letter *let, *next;	/* current and next letter */
519*433d6423SLionel Sambuc   int interrupted = 0;		/* SIGINT hit during letter print */
520*433d6423SLionel Sambuc   int needprint = 1;		/* need to print this letter */
521*433d6423SLionel Sambuc   char *savefile;		/* filename to save into */
522*433d6423SLionel Sambuc 
523*433d6423SLionel Sambuc   if (NULL == firstlet) {
524*433d6423SLionel Sambuc 	printf("No mail.\n");
525*433d6423SLionel Sambuc 	return;
526*433d6423SLionel Sambuc   }
527*433d6423SLionel Sambuc   let = reversemode ? firstlet : lastlet;
528*433d6423SLionel Sambuc 
529*433d6423SLionel Sambuc   while (1) {
530*433d6423SLionel Sambuc 	next = reversemode ? let->next : let->prev;
531*433d6423SLionel Sambuc 	if (NULL == next) next = let;
532*433d6423SLionel Sambuc 
533*433d6423SLionel Sambuc 	if (!quitmode) {
534*433d6423SLionel Sambuc 		interrupted = setjmp(printjump);
535*433d6423SLionel Sambuc 		signal(SIGINT, onint);
536*433d6423SLionel Sambuc 	}
537*433d6423SLionel Sambuc 	if (!interrupted && needprint) {
538*433d6423SLionel Sambuc 		if (DELETED != let->status) let->status = READ;
539*433d6423SLionel Sambuc 		printlet(let, stdout);
540*433d6423SLionel Sambuc 	}
541*433d6423SLionel Sambuc 	if (interrupted) putchar('\n');
542*433d6423SLionel Sambuc 	needprint = 0;
543*433d6423SLionel Sambuc 	fputs(PROMPT, stdout);
544*433d6423SLionel Sambuc 	fflush(stdout);
545*433d6423SLionel Sambuc 
546*433d6423SLionel Sambuc 	if (fgets(linebuf, sizeof linebuf, stdin) == NULL) break;
547*433d6423SLionel Sambuc 
548*433d6423SLionel Sambuc 	if (!quitmode) signal(SIGINT, SIG_IGN);
549*433d6423SLionel Sambuc 
550*433d6423SLionel Sambuc 	switch (linebuf[0]) {
551*433d6423SLionel Sambuc 	    case '\n':
552*433d6423SLionel Sambuc 		let = next;
553*433d6423SLionel Sambuc 		needprint = 1;
554*433d6423SLionel Sambuc 		continue;
555*433d6423SLionel Sambuc 	    case 'd':
556*433d6423SLionel Sambuc 		let->status = DELETED;
557*433d6423SLionel Sambuc 		if (next != let)/* look into this */
558*433d6423SLionel Sambuc 			needprint = 1;
559*433d6423SLionel Sambuc 		needupdate = 1;
560*433d6423SLionel Sambuc 		let = next;
561*433d6423SLionel Sambuc 		continue;
562*433d6423SLionel Sambuc 	    case 'p':
563*433d6423SLionel Sambuc 		needprint = 1;
564*433d6423SLionel Sambuc 		continue;
565*433d6423SLionel Sambuc 	    case '-':
566*433d6423SLionel Sambuc 		next = reversemode ? let->prev : let->next;
567*433d6423SLionel Sambuc 		if (NULL == next) next = let;
568*433d6423SLionel Sambuc 		let = next;
569*433d6423SLionel Sambuc 		needprint = 1;
570*433d6423SLionel Sambuc 		continue;
571*433d6423SLionel Sambuc 	    case 's':
572*433d6423SLionel Sambuc 		for (savefile = strtok(linebuf + 1, " \t\n");
573*433d6423SLionel Sambuc 		     savefile != NULL;
574*433d6423SLionel Sambuc 		     savefile = strtok((char *) NULL, " \t\n")) {
575*433d6423SLionel Sambuc 			savelet(let, savefile);
576*433d6423SLionel Sambuc 		}
577*433d6423SLionel Sambuc 		continue;
578*433d6423SLionel Sambuc 	    case '!':
579*433d6423SLionel Sambuc 		doshell(linebuf + 1);
580*433d6423SLionel Sambuc 		continue;
581*433d6423SLionel Sambuc 	    case '*':
582*433d6423SLionel Sambuc 		dohelp();
583*433d6423SLionel Sambuc 		continue;
584*433d6423SLionel Sambuc 	    case 'q':
585*433d6423SLionel Sambuc 		return;
586*433d6423SLionel Sambuc 	    case 'x':
587*433d6423SLionel Sambuc 		exit(0);
588*433d6423SLionel Sambuc 	    default:
589*433d6423SLionel Sambuc 		fprintf(stderr, "Illegal command\n");
590*433d6423SLionel Sambuc 		continue;
591*433d6423SLionel Sambuc 	}
592*433d6423SLionel Sambuc   }
593*433d6423SLionel Sambuc }
594*433d6423SLionel Sambuc 
595*433d6423SLionel Sambuc void onint(dummy)
596*433d6423SLionel Sambuc int dummy;	/* to satisfy ANSI compilers */
597*433d6423SLionel Sambuc {
598*433d6423SLionel Sambuc   longjmp(printjump, 1);
599*433d6423SLionel Sambuc }
600*433d6423SLionel Sambuc 
601*433d6423SLionel Sambuc void savelet(let, savefile)
602*433d6423SLionel Sambuc struct letter *let;
603*433d6423SLionel Sambuc char *savefile;
604*433d6423SLionel Sambuc {
605*433d6423SLionel Sambuc   int waitstat, pid;
606*433d6423SLionel Sambuc   FILE *savefp;
607*433d6423SLionel Sambuc 
608*433d6423SLionel Sambuc   if ((pid = fork()) < 0) {
609*433d6423SLionel Sambuc 	perror("mail: couldn't fork");
610*433d6423SLionel Sambuc 	return;
611*433d6423SLionel Sambuc   } else if (pid != 0) {	/* parent */
612*433d6423SLionel Sambuc 	wait(&waitstat);
613*433d6423SLionel Sambuc 	return;
614*433d6423SLionel Sambuc   }
615*433d6423SLionel Sambuc 
616*433d6423SLionel Sambuc   /* Child */
617*433d6423SLionel Sambuc   setgid(getgid());
618*433d6423SLionel Sambuc   setuid(getuid());
619*433d6423SLionel Sambuc   if ((savefp = fopen(savefile, "a")) == NULL) {
620*433d6423SLionel Sambuc 	perror(savefile);
621*433d6423SLionel Sambuc 	exit(0);
622*433d6423SLionel Sambuc   }
623*433d6423SLionel Sambuc   printlet(let, savefp);
624*433d6423SLionel Sambuc   if ((ferror(savefp) != 0) | (fclose(savefp) != 0)) {
625*433d6423SLionel Sambuc 	fprintf(stderr, "savefile write error:");
626*433d6423SLionel Sambuc 	perror(savefile);
627*433d6423SLionel Sambuc   }
628*433d6423SLionel Sambuc   exit(0);
629*433d6423SLionel Sambuc }
630*433d6423SLionel Sambuc 
631*433d6423SLionel Sambuc void updatebox()
632*433d6423SLionel Sambuc {
633*433d6423SLionel Sambuc   FILE *tempfp;			/* fp for tempfile */
634*433d6423SLionel Sambuc   char lockname[PATHLEN];	/* maildrop lock */
635*433d6423SLionel Sambuc   int locktries = 0;		/* tries when box is locked */
636*433d6423SLionel Sambuc   struct letter *let;		/* current letter */
637*433d6423SLionel Sambuc   int c;
638*433d6423SLionel Sambuc 
639*433d6423SLionel Sambuc   sprintf(lockname, LOCKNAME, whoami());
640*433d6423SLionel Sambuc 
641*433d6423SLionel Sambuc   if (NULL == (tempfp = fopen(tempname, "w"))) {
642*433d6423SLionel Sambuc 	perror("mail: can't create temporary file");
643*433d6423SLionel Sambuc 	return;
644*433d6423SLionel Sambuc   }
645*433d6423SLionel Sambuc   for (let = firstlet; let != NULL; let = let->next) {
646*433d6423SLionel Sambuc 	if (let->status != DELETED) {
647*433d6423SLionel Sambuc 		printlet(let, tempfp);
648*433d6423SLionel Sambuc 		D(printf("printed letter at %ld\n", let->location));
649*433d6423SLionel Sambuc 	}
650*433d6423SLionel Sambuc   }
651*433d6423SLionel Sambuc 
652*433d6423SLionel Sambuc   if (ferror(tempfp) || NULL == (tempfp = freopen(tempname, "r", tempfp))) {
653*433d6423SLionel Sambuc 	perror("mail: temporary file write error");
654*433d6423SLionel Sambuc 	unlink(tempname);
655*433d6423SLionel Sambuc 	return;
656*433d6423SLionel Sambuc   }
657*433d6423SLionel Sambuc 
658*433d6423SLionel Sambuc   /* Shut off signals during the update */
659*433d6423SLionel Sambuc   signal(SIGINT, SIG_IGN);
660*433d6423SLionel Sambuc   signal(SIGHUP, SIG_IGN);
661*433d6423SLionel Sambuc   signal(SIGQUIT, SIG_IGN);
662*433d6423SLionel Sambuc 
663*433d6423SLionel Sambuc   if (usedrop) while (link(mailbox, lockname) != 0) {
664*433d6423SLionel Sambuc 		if (++locktries >= LOCKTRIES) {
665*433d6423SLionel Sambuc 			fprintf(stderr, "mail: couldn't lock maildrop for update\n");
666*433d6423SLionel Sambuc 			return;
667*433d6423SLionel Sambuc 		}
668*433d6423SLionel Sambuc 		sleep(LOCKWAIT);
669*433d6423SLionel Sambuc 	}
670*433d6423SLionel Sambuc 
671*433d6423SLionel Sambuc   if (NULL == (boxfp = freopen(mailbox, "w", boxfp))) {
672*433d6423SLionel Sambuc 	perror("mail: couldn't reopen maildrop");
673*433d6423SLionel Sambuc 	fprintf(stderr, "mail may have been lost; look in %s\n", tempname);
674*433d6423SLionel Sambuc 	if (usedrop) unlink(lockname);
675*433d6423SLionel Sambuc 	return;
676*433d6423SLionel Sambuc   }
677*433d6423SLionel Sambuc   unlink(tempname);
678*433d6423SLionel Sambuc 
679*433d6423SLionel Sambuc   while ((c = getc(tempfp)) != EOF) putc(c, boxfp);
680*433d6423SLionel Sambuc 
681*433d6423SLionel Sambuc   fclose(boxfp);
682*433d6423SLionel Sambuc 
683*433d6423SLionel Sambuc   if (usedrop) unlink(lockname);
684*433d6423SLionel Sambuc }
685*433d6423SLionel Sambuc 
686*433d6423SLionel Sambuc void printlet(let, tofp)
687*433d6423SLionel Sambuc struct letter *let;
688*433d6423SLionel Sambuc FILE *tofp;
689*433d6423SLionel Sambuc {
690*433d6423SLionel Sambuc   off_t current, limit;
691*433d6423SLionel Sambuc   int c;
692*433d6423SLionel Sambuc 
693*433d6423SLionel Sambuc   fseek(boxfp, (current = let->location), 0);
694*433d6423SLionel Sambuc   limit = (NULL != let->next) ? let->next->location : -1;
695*433d6423SLionel Sambuc 
696*433d6423SLionel Sambuc   while (current != limit && (c = getc(boxfp)) != EOF) {
697*433d6423SLionel Sambuc 	putc(c, tofp);
698*433d6423SLionel Sambuc 	++current;
699*433d6423SLionel Sambuc   }
700*433d6423SLionel Sambuc }
701*433d6423SLionel Sambuc 
702*433d6423SLionel Sambuc void doshell(command)
703*433d6423SLionel Sambuc char *command;
704*433d6423SLionel Sambuc {
705*433d6423SLionel Sambuc   int waitstat, pid;
706*433d6423SLionel Sambuc   char *shell;
707*433d6423SLionel Sambuc 
708*433d6423SLionel Sambuc   if (NULL == (shell = getenv("SHELL"))) shell = SHELL;
709*433d6423SLionel Sambuc 
710*433d6423SLionel Sambuc   if ((pid = fork()) < 0) {
711*433d6423SLionel Sambuc 	perror("mail: couldn't fork");
712*433d6423SLionel Sambuc 	return;
713*433d6423SLionel Sambuc   } else if (pid != 0) {	/* parent */
714*433d6423SLionel Sambuc 	wait(&waitstat);
715*433d6423SLionel Sambuc 	return;
716*433d6423SLionel Sambuc   }
717*433d6423SLionel Sambuc 
718*433d6423SLionel Sambuc   /* Child */
719*433d6423SLionel Sambuc   setgid(getgid());
720*433d6423SLionel Sambuc   setuid(getuid());
721*433d6423SLionel Sambuc   umask(oldmask);
722*433d6423SLionel Sambuc 
723*433d6423SLionel Sambuc   execl(shell, shell, "-c", command, (char *) NULL);
724*433d6423SLionel Sambuc   fprintf(stderr, "can't exec shell\n");
725*433d6423SLionel Sambuc   exit(127);
726*433d6423SLionel Sambuc }
727*433d6423SLionel Sambuc 
728*433d6423SLionel Sambuc void usage()
729*433d6423SLionel Sambuc {
730*433d6423SLionel Sambuc   fprintf(stderr, "usage: mail [-epqr] [-f file]\n");
731*433d6423SLionel Sambuc   fprintf(stderr, "       mail [-dtv] [-s subject] user [...]\n");
732*433d6423SLionel Sambuc }
733*433d6423SLionel Sambuc 
734*433d6423SLionel Sambuc char *basename(name)
735*433d6423SLionel Sambuc char *name;
736*433d6423SLionel Sambuc {
737*433d6423SLionel Sambuc   char *p;
738*433d6423SLionel Sambuc 
739*433d6423SLionel Sambuc   if (NULL == (p = rindex(name, '/')))
740*433d6423SLionel Sambuc 	return name;
741*433d6423SLionel Sambuc   else
742*433d6423SLionel Sambuc 	return p + 1;
743*433d6423SLionel Sambuc }
744*433d6423SLionel Sambuc 
745*433d6423SLionel Sambuc char *whoami()
746*433d6423SLionel Sambuc {
747*433d6423SLionel Sambuc   struct passwd *pw;
748*433d6423SLionel Sambuc 
749*433d6423SLionel Sambuc   if (NULL != (pw = getpwuid(getuid())))
750*433d6423SLionel Sambuc 	return pw->pw_name;
751*433d6423SLionel Sambuc   else
752*433d6423SLionel Sambuc 	return "nobody";
753*433d6423SLionel Sambuc }
754*433d6423SLionel Sambuc 
755*433d6423SLionel Sambuc void dohelp()
756*433d6423SLionel Sambuc {
757*433d6423SLionel Sambuc   FILE *fp;
758*433d6423SLionel Sambuc   char buffer[80];
759*433d6423SLionel Sambuc 
760*433d6423SLionel Sambuc   if ( (fp = fopen(HELPFILE, "r")) == NULL)
761*433d6423SLionel Sambuc 	fprintf(stdout, "can't open helpfile %s\n", HELPFILE);
762*433d6423SLionel Sambuc   else
763*433d6423SLionel Sambuc 	while (fgets(buffer, 80, fp))
764*433d6423SLionel Sambuc 		fputs(buffer, stdout);
765*433d6423SLionel Sambuc }
766*433d6423SLionel Sambuc 
767*433d6423SLionel Sambuc int filesize(name)
768*433d6423SLionel Sambuc char *name ;
769*433d6423SLionel Sambuc {
770*433d6423SLionel Sambuc   struct stat buf;
771*433d6423SLionel Sambuc 
772*433d6423SLionel Sambuc   if (stat(name, &buf) == -1)
773*433d6423SLionel Sambuc 	buf.st_size = 0L;
774*433d6423SLionel Sambuc 
775*433d6423SLionel Sambuc   return (buf.st_size ? 1 : 0);
776*433d6423SLionel Sambuc }
777