1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the BSD package               *
4 *Copyright (c) 1978-2012 The Regents of the University of California an*
5 *                                                                      *
6 * Redistribution and use in source and binary forms, with or           *
7 * without modification, are permitted provided that the following      *
8 * conditions are met:                                                  *
9 *                                                                      *
10 *    1. Redistributions of source code must retain the above           *
11 *       copyright notice, this list of conditions and the              *
12 *       following disclaimer.                                          *
13 *                                                                      *
14 *    2. Redistributions in binary form must reproduce the above        *
15 *       copyright notice, this list of conditions and the              *
16 *       following disclaimer in the documentation and/or other         *
17 *       materials provided with the distribution.                      *
18 *                                                                      *
19 *    3. Neither the name of The Regents of the University of California*
20 *       names of its contributors may be used to endorse or            *
21 *       promote products derived from this software without            *
22 *       specific prior written permission.                             *
23 *                                                                      *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND               *
25 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,          *
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF             *
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE             *
28 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS    *
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,             *
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED      *
31 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,        *
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    *
33 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,      *
34 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY       *
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE              *
36 * POSSIBILITY OF SUCH DAMAGE.                                          *
37 *                                                                      *
38 * Redistribution and use in source and binary forms, with or without   *
39 * modification, are permitted provided that the following conditions   *
40 * are met:                                                             *
41 * 1. Redistributions of source code must retain the above copyright    *
42 *    notice, this list of conditions and the following disclaimer.     *
43 * 2. Redistributions in binary form must reproduce the above copyright *
44 *    notice, this list of conditions and the following disclaimer in   *
45 *    the documentation and/or other materials provided with the        *
46 *    distribution.                                                     *
47 * 3. Neither the name of the University nor the names of its           *
48 *    contributors may be used to endorse or promote products derived   *
49 *    from this software without specific prior written permission.     *
50 *                                                                      *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS"    *
52 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED    *
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A      *
54 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS    *
55 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      *
56 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
57 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF     *
58 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND  *
59 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,   *
60 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT   *
61 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   *
62 * SUCH DAMAGE.                                                         *
63 *                                                                      *
64 *                          Kurt Shoens (UCB)                           *
65 *                                 gsf                                  *
66 *                                                                      *
67 ***********************************************************************/
68 #pragma prototyped
69 /*
70  * Mail -- a mail program
71  *
72  * Author:
73  *
74  *	Kurt Shoens (UCB) March 25, 1978
75  *
76  * Contributors:
77  *
78  *	Glenn Fowler (AT&T Research) 1996-09-11
79  */
80 
81 #if _PACKAGE_ast
82 
83 #include <ast.h>
84 #include <error.h>
85 #include <getopt.h>
86 #include <ls.h>
87 #include <sig.h>
88 #include <times.h>
89 #include <wait.h>
90 
91 #else /*_PACKAGE_ast*/
92 
93 #include <sys/param.h>
94 #include <sys/stat.h>
95 #include <sys/time.h>
96 #include <sys/wait.h>
97 
98 #include <limits.h>
99 #include <signal.h>
100 #include <fcntl.h>
101 #include <unistd.h>
102 #include <stdlib.h>
103 #include <string.h>
104 #include <time.h>
105 
106 #ifndef O_BINARY
107 #define O_BINARY	0
108 #endif
109 #ifndef O_CLOEXEC
110 #define O_CLOEXEC	0
111 #endif
112 
113 extern char*	optarg;
114 extern int	optind;
115 extern int	opterr;
116 
117 #endif /*_PACKAGE_ast*/
118 
119 #include <cdt.h>
120 #include <ctype.h>
121 #include <errno.h>
122 #include <mime.h>
123 #include <setjmp.h>
124 #include <stdio.h>
125 
126 #include "local.h"
127 
128 #define APPEND_MAILBOX		1	/* New mail goes to end of mailbox */
129 #if defined(SFIO_VERSION) && defined(SF_READ) && defined(SF_WRITE)
130 #define MORE_DISCIPLINE		1	/* Sfio more discipline on stdout */
131 #endif
132 
133 #define CALL(f)		(*(state.folder==FIMAP?imap_##f:f))
134 #define TRACE(c)	(state.trace|=(1<<((c)-'a')))
135 #define TRACING(c)	(state.trace&(1<<((c)-'a')))
136 
137 #define sig_t		Sig_handler_t
138 
139 #define holdsigs()	sigcritical(SIG_REG_EXEC)
140 #define relsesigs()	sigcritical(SIG_REG_POP)
141 
142 #define initargs(ap)	((ap)->argp=(ap)->argv)
143 #define endargs(ap)	(*(ap)->argp=0,(ap)->argp-(ap)->argv)
144 
145 #if MORE_DISCIPLINE
146 #define moretop()	(state.more.match=0,state.more.row=state.more.col=1)
147 #else
148 #define moretop()
149 #endif
150 
151 #define shquote		shellquote	/* netbsd has one in <stdlib.h>! */
152 
153 #define ESCAPE		'~'		/* Default escape for sending */
154 #define NMLSIZE		1024		/* max names in a message list */
155 #define PATHSIZE	MAXPATHLEN	/* Size of pathnames throughout */
156 #define LINESIZE	(32*STRINGLEN)	/* max readable line width */
157 #define HEADSIZE	128		/* maximum header line length */
158 #define LASTSIZE	256		/* max saved cmd line size */
159 #define STRINGSIZE	((unsigned)128)	/* Dynamic allocation units */
160 #define MAILMODE	(S_IRUSR|S_IWUSR) /* private mail file mode */
161 #define METAFILE	"%#&+/"		/* `Metafile' prefix */
162 #define REGDEP		2		/* Maximum regret depth. */
163 #define STRINGLEN	1024		/* Maximum length of string token */
164 #define MARGIN		72		/* Right line margin */
165 #define REFLEN		(12*MARGIN)	/* Maximum length or References: */
166 
167 typedef struct msg {
168 	int	m_index;		/* command address vector index */
169 	short	m_flag;			/* flags, see below */
170 	short	m_offset;		/* offset in block of message */
171 	long	m_block;		/* block number of this message */
172 	off_t	m_size;			/* Bytes in the message */
173 	off_t	m_lines;		/* Lines in the message */
174 	void*	m_info;			/* Folder type specific info */
175 } Msg_t;
176 
177 /*
178  * Folder types.
179  */
180 
181 #define FFILE		1		/* File folder */
182 #define FIMAP		2		/* IMAP folder */
183 #define FMH		3		/* MH folder */
184 
185 /*
186  * Command flag bits.
187  */
188 
189 #define MBOX		(1<<0)		/* send this to mbox, regardless */
190 #define MDELETE		(1<<1)		/* entry has been deleted */
191 #define MINIT		(1<<2)		/* folder specific init mark */
192 #define MMARK		(1<<3)		/* message is marked! */
193 #define MNEW		(1<<4)		/* message has never been seen */
194 #define MNONE		(1<<5)		/* never matches */
195 #define MODIFY		(1<<6)		/* message has been modified */
196 #define MPRESERVE	(1<<7)		/* keep entry in sys mailbox */
197 #define MREAD		(1<<8)		/* message has been read sometime */
198 #define MSAVE		(1<<9)		/* entry has been saved */
199 #define MSCAN		(1<<10)		/* entry has been scanned */
200 #define MSPAM		(1<<11)		/* message is probably spam */
201 #define MSTATUS		(1<<12)		/* message status has changed */
202 #define MTOUCH		(1<<13)		/* entry has been noticed */
203 #define MUSED		(1<<14)		/* entry is used, but this bit isn't */
204 #define MZOMBIE		(1<<15)		/* deleted but still there */
205 
206 /*
207  * Given a file address, determine the block number it represents.
208  */
209 
210 #define blocknumber(off)		((int) ((off) / 4096))
211 #define blockoffset(off)		((int) ((off) % 4096))
212 #define blockposition(block,offset)	((off_t)(block) * 4096 + (offset))
213 
214 /*
215  * Format of the command description table.
216  */
217 
218 typedef int (*Cmd_f)(void*);
219 
220 struct cmd {
221 	const char*	c_name;		/* Name of command */
222 	Cmd_f		c_func;		/* Implementor of the command */
223 	unsigned long	c_argtype;	/* Type of arglist (see below) */
224 	unsigned long	c_msgflag;	/* Required flags of messages */
225 	size_t		c_msgmask;	/* Relevant flags of messages */
226 	const char*	c_help;		/* Command help text */
227 };
228 
229 /*
230  * Yechh, can't initialize unions.
231  */
232 
233 #define c_minargs c_msgflag		/* Minimum argcount for RAWLIST */
234 #define c_maxargs c_msgmask		/* Max argcount for RAWLIST */
235 
236 struct esc {
237 	const char*	e_name;		/* Name of command */
238 	const char*	e_help;		/* Command help text */
239 };
240 
241 /*
242  * Common header labels.
243  */
244 
245 struct lab {
246 	const char*	name;		/* Header label name */
247 	long		type;		/* G* type */
248 };
249 
250 /*
251  * Header parse state.
252  */
253 
254 struct parse {
255 	struct msg*	mp;		/* Parsing this message */
256 	struct header*	hp;		/* Matched headers here */
257 	Dt_t**		ignore;		/* Ignore these headers */
258 	FILE*		fp;		/* Message io */
259 	long		count;		/* Remaining message size */
260 	char*		name;		/* Header name */
261 	char*		data;		/* Header data */
262 	char*		separator;	/* Header name separator position */
263 	int		length;		/* Total header length */
264 	unsigned long	flags;		/* G* flags */
265 	unsigned long	type;		/* Matched header type */
266 	char		buf[LINESIZE];	/* Work buffer */
267 };
268 
269 /*
270  * Argument types.
271  */
272 
273 #define MSGLIST	 0		/* Message list type */
274 #define STRLIST	 1		/* A pure string */
275 #define RAWLIST	 2		/* Shell string list */
276 #define NOLIST	 3		/* Just plain 0 */
277 #define NDMLIST	 4		/* Message list, no defaults */
278 
279 #define LISTMASK 07		/* Mask list type from argument type */
280 
281 #define A	(1<<4)		/* Var alias */
282 #define C	(1<<5)		/* Is a conditional command, Cmd line var set */
283 #define D	(1<<6)		/* Var unset default to initial value */
284 #define E	(1<<7)		/* Var init from environ */
285 #define I	(1<<8)		/* Interactive command, Var is integer */
286 #define L	(1<<9)		/* Append line values */
287 #define M	(1<<10)		/* Valid from send mode */
288 #define N	(1<<11)		/* Var null value means off */
289 #define P	(1<<12)		/* Autoprint dot after command */
290 #define R	(1<<13)		/* Cannot call from collect, Readonly var */
291 #define S	(1<<14)		/* Var cannot change while sourcing */
292 #define W	(1<<15)		/* Invalid for readonly */
293 #define Z	(1L<<16)	/* Is a transparent command */
294 
295 /*
296  * Oft-used mask values
297  */
298 
299 #define MMNORM		(MDELETE|MSAVE)/* Look at both save and delete bits */
300 #define MMNDEL		MDELETE	/* Look only at deleted bit */
301 
302 /*
303  * note() type bits.
304  */
305 
306 #define DEBUG		(1<<0)		/* debug trace */
307 #define ERROR		(1<<1)		/* stderr message */
308 #define FATAL		(1<<2)		/* message and exit(1) */
309 #define IDENTIFY	(1<<3)		/* prefix with command name */
310 #define PANIC		(1<<4)		/* message and abort() */
311 #define PROMPT		(1<<5)		/* no trailing newline */
312 #define SYSTEM		(1<<6)		/* append errno message */
313 #define WARNING		(1<<7)		/* warning prefix */
314 
315 /*
316  * Structure used to return a break down of a head
317  * line (hats off to Bill Joy!)
318  */
319 
320 struct headline {
321 	char*	l_from;		/* The name of the sender */
322 	char*	l_info;		/* Special info (tty or article number) */
323 	char*	l_date;		/* The entire date string */
324 };
325 
326 /*
327  * Name extraction and name dictionary node flags.
328  */
329 
330 #define GALIAS		(1<<0)		/* Alias name */
331 #define GALTERNATE	(1<<1)		/* Alternate name */
332 #define GBCC		(1<<2)		/* Grab Bcc: line */
333 #define GCC		(1<<3)		/* Grab Cc: line */
334 #define GCOMMA		(1<<4)		/* Comma separated */
335 #define GCOMPARE	(1<<5)		/* For comparison */
336 #define GDISPLAY	(1<<6)		/* For display */
337 #define GDONE		(1<<7)		/* Done with it */
338 #define GFIRST		(1<<8)		/* First recipient */
339 #define GFROM		(1<<9)		/* Don't skip initial `From ' */
340 #define GINTERPOLATE	(1<<10)		/* Check headers for interpolate() */
341 #define GLAST		(1<<11)		/* Get last instance */
342 #define GMAP		(1<<12)		/* Already mapped */
343 #define GMESSAGEID	(1<<13)		/* Grab Message-ID: line */
344 #define GMETOO		(1<<14)		/* Send to state.var.user too */
345 #define GMIME		(1L<<15)	/* Check MIME content headers */
346 #define GMISC		(1L<<16)	/* Grab miscellaneous headers */
347 #define GNEWS		(1L<<17)	/* For newsgroup article id */
348 #define GNL		(1L<<18)	/* Print blank line after headers */
349 #define GREFERENCES	(1L<<19)	/* Grab References: line */
350 #define GREPLY		(1L<<20)	/* For reply to sender */
351 #define GRULE		(1L<<21)	/* Ouput rule if GNL */
352 #define GSEND		(1L<<22)	/* Get it ready to send */
353 #define GSENDER		(1L<<23)	/* Get state.var.sender address only */
354 #define GSTACK		(1L<<24)	/* savestr() unmapped names */
355 #define GSTATUS		(1L<<25)	/* Grab Status: line */
356 #define GSUB		(1L<<26)	/* Grab Subject: line */
357 #define GTO		(1L<<27)	/* Grab To: line */
358 #define GUSER		(1L<<28)	/* Stop if ${user}@ */
359 
360 #define GCOMPOSE	(GEDIT|GSTATUS)	/* Composable headers */
361 #define GEDIT		(GSTD|GMISC)	/* Editable headers */
362 #define GEXTERN		(GEDIT&~GBCC)	/* External headers */
363 #define GMASK		(GNAME|GDONE)	/* Active mask */
364 #define GNAME		(GBCC|GCC|GTO)	/* Name fields */
365 #define GSTD		(GNAME|GSUB)	/* Standard headers */
366 
367 /*
368  * Structure of a variable node.
369  */
370 
371 struct var {
372 	const char*	name;
373 	char**		variable;
374 	unsigned long	flags;
375 	const char*	initialize;
376 	void		(*set)(struct var*, const char*);
377 	const char*	help;
378 };
379 
380 struct list {
381 	struct list*	next;
382 	char		name[1];
383 };
384 
385 struct name {
386 	Dtlink_t	link;
387 	void*		value;
388 	unsigned long	flags;
389 	char		name[1];
390 };
391 
392 struct argvec {
393 	char*		argv[64 * 1024];
394 	char**		argp;
395 };
396 
397 struct child {
398 	struct child*	link;
399 	int		pid;
400 	short		done;
401 	short		free;
402 };
403 
404 struct file {
405 	struct file*	link;
406 	FILE*		fp;
407 	int		pid;
408 };
409 
410 struct mhcontext {
411 	int		type;
412 	unsigned long	dot;
413 	unsigned long	next;
414 	struct {
415 	unsigned long	dot;
416 	unsigned long	next;
417 	}		old;
418 };
419 
420 typedef struct {
421 	int		type;
422 	void*		state;
423 } Imapcontext_t;
424 
425 #define PART_application	(1<<0)
426 #define PART_body		(1<<1)
427 #define PART_disposition	(1<<2)
428 #define PART_inline		(1<<3)
429 #define PART_message		(1<<4)
430 #define PART_text		(1<<5)
431 
432 typedef struct part {
433 	struct part*	next;
434 	off_t		offset;
435 	off_t		size;
436 	off_t		lines;
437 	struct {
438 	off_t		offset;
439 	off_t		size;
440 	}		raw;
441 	unsigned long	flags;
442 	int		count;
443 	char		name[HEADSIZE];
444 	char		type[HEADSIZE];
445 	char		opts[HEADSIZE];
446 	char		code[HEADSIZE];
447 } Part_t;
448 
449 struct bound {
450 	struct bound*	next;
451 	int		size;
452 	char		data[1];
453 };
454 
455 /*
456  * Structure used to pass about the current
457  * state of the user-typed message header.
458  */
459 
460 struct header {
461 	unsigned long	h_flags;	/* Active fields */
462 	Dt_t*		h_names;	/* Recipients */
463 	char**		h_options;	/* Mailer options */
464 	char*		h_subject;	/* Subject string */
465 	char*		h_first;	/* First recipient */
466 	char*		h_messageid;	/* Parent message-id */
467 	char*		h_references;	/* References */
468 	struct {
469 	struct list*	head;
470 	struct list*	tail;
471 	}		h_misc;		/* Miscellaneous headers */
472 	unsigned long	h_clear;	/* Clear these on change */
473 };
474 
475 struct dict {
476 	Dtdisc_t	disc;		/* Object discipline */
477 	unsigned long	flags;		/* Member node flags */
478 	Dt_t*		next;		/* Next STACK dict */
479 };
480 
481 struct match {
482 	struct match*	next;		/* next in list */
483 	int		length;		/* string length */
484 	int		beg;		/* begin character match */
485 	int		mid;		/* mid character match */
486 	int		end;		/* end character match */
487 	char		string[1];	/* match string */
488 };
489 
490 struct linematch {
491 	int		minline;	/* minimum line size */
492 	unsigned char	beg[256];	/* begin character match */
493 	unsigned char	mid[256];	/* mid character match */
494 	unsigned char	end[256];	/* end character match */
495 	struct match*	match;		/* exact match list */
496 	struct match*	last;		/* last match list item */
497 };
498 
499 struct sendand {
500 	struct sendand*	next;		/* next in and list */
501 	char*		head;		/* head	*/
502 	char*		pattern;	/* match pattern */
503 	unsigned long	flags;		/* grab*() flags */
504 };
505 
506 struct sendor {
507 	struct sendor*	next;		/* next in or list */
508 	struct sendand	sendand;	/* and list */
509 };
510 
511 struct sender {
512 	struct sender*	next;		/* next in list */
513 	struct sendor	sendor;		/* or list */
514 	char		address[1];	/* sender address override */
515 };
516 
517 /*
518  * dictsearch() flag values
519  */
520 
521 #define LOOKUP		0
522 #define COPY		(1<<0)
523 #define CREATE		(1<<1)
524 #define DELETE		(1<<2)
525 #define IGNORECASE	(1<<3)
526 #define INSERT		(1<<4)
527 #define OBJECT		(1<<5)
528 #define STACK		(1<<6)
529 
530 /*
531  * ignore flags
532  */
533 
534 #define dictflags(p)	(((struct dict*)(*(p))->disc)->flags)
535 
536 #define HIT		(1<<0)		/* Global table flag */
537 #define IGNORE		(1<<1)		/* Global table flag */
538 #define RETAIN		(1<<2)		/* Global table flag */
539 
540 /*
541  * collect() and mail() flags
542  */
543 
544 #define FOLLOWUP	(1<<0)
545 #define HEADERS		(1<<1)
546 #define INTERPOLATE	(1<<2)
547 #define MARK		(1<<3)
548 #define REPLY		(1<<4)
549 
550 /*
551  * Token values returned by the scanner used for argument lists.
552  */
553 
554 #define TEOL	0			/* End of the command line */
555 #define TNUMBER	1			/* A message number */
556 #define TDASH	2			/* A simple dash */
557 #define TSTRING	3			/* A string (possibly containing -) */
558 #define TDOT	4			/* A "." */
559 #define TUP	5			/* An "^" */
560 #define TDOLLAR	6			/* A "$" */
561 #define TSTAR	7			/* A "*" */
562 #define TOPEN	8			/* An '(' */
563 #define TCLOSE	9			/* A ')' */
564 #define TPLUS	10			/* A '+' */
565 #define TERROR	11			/* A lexical error */
566 
567 /*
568  * Constants for conditional commands.  These describe whether
569  * we should be executing stuff or not.
570  */
571 
572 #define RECEIVE		(-1)		/* Execute in receive mode only */
573 #define SEND		(1)		/* Execute in send mode only */
574 
575 /*
576  * Kludges to handle the change from setexit / reset to setjmp / longjmp
577  */
578 
579 #define setexit()	do {						\
580 				int x = setjmp(state.jump.sr);		\
581 				if (x) sigunblock(x);			\
582 			} while(0)
583 #define reset(x)	longjmp(state.jump.sr, x)
584 
585 /*
586  * <unistd.h> etc encroachment
587  * we asked for extentions -- and now pay for it ...
588  */
589 
590 #define undelete	mail_undelete
591 
592 /*
593  * The pointers for the string allocation routines,
594  * there are NSPACE independent areas.
595  * The first holds STRINGSIZE bytes, the next
596  * twice as much, and so on.
597  */
598 
599 #define NSPACE	25			/* Total number of string spaces */
600 struct strings {
601 	char*		s_topfree;	/* Beginning of this area */
602 	char*		s_nextfree;	/* Next alloctable place here */
603 	unsigned int	s_nleft;	/* Number of bytes left here */
604 };
605 
606 typedef struct {
607 	const char*		version;	/* Version string */
608 	const char*		license;	/* License text */
609 	char*			on;		/* Variable on value */
610 	const struct cmd*	cmdtab;		/* Command table */
611 	int			cmdnum;		/* Number of commands */
612 	const struct esc*	esctab;		/* Escape command table */
613 	int			escnum;		/* Number of escape commands */
614 	const struct var*	vartab;		/* Variable table */
615 	int			varnum;		/* Number of variables */
616 	const struct lab*	hdrtab;		/* Header label table */
617 	int			hdrnum;		/* Number of header labels */
618 	unsigned long		askheaders;	/* Ask for these headers */
619 
620 	/* the rest are implicitly initialized */
621 
622 	int	clobber;		/* Last command had ! */
623 	int	cmdline;		/* Currently reading cmd line options */
624 	int	colmod;			/* Mark bit */
625 	int	cond;			/* Current state of conditional exc. */
626 	int	edit;			/* Indicates editing a file */
627 	int	incorporating;		/* Executing incorporate command */
628 	int	folder;			/* Folder type */
629 	int	hung;			/* Op hung til alarm */
630 	int	loading;		/* Loading user definitions */
631 	int	mode;			/* SEND or RECEIVE */
632 	int	noreset;		/* String resets suspended */
633 	int	onstack;		/* salloc() != malloc() */
634 	int	readonly;		/* Will be unable to rewrite file */
635 	int	realscreenheight;	/* Real screen height */
636 	int	sawcom;			/* Set after first command */
637 	int	screenheight;		/* Screen height, or best guess */
638 	int	screenwidth;		/* Screen width, or best guess */
639 	int	scroll;			/* Current scroll size */
640 	int	senderr;		/* An error while checking */
641 	int	sourcing;		/* Currently reading variant file */
642 	int	startup;		/* Listing startup headers */
643 	int	stopreset;		/* Reset on stop */
644 
645 	FILE*	input;			/* Current command input file */
646 	off_t	mailsize;		/* Size of system mailbox */
647 	int	lexnumber;		/* Number of TNUMBER from scan() */
648 	char	lexstring[STRINGLEN];	/* String from TSTRING, scan() */
649 	int	regretp;		/* Pointer to TOS of regret tokens */
650 	int	regretstack[REGDEP];	/* Stack of regretted tokens */
651 	char*	string_stack[REGDEP];	/* Stack of regretted strings */
652 	int	numberstack[REGDEP];	/* Stack of regretted numbers */
653 	char	number[16];		/* Temp variable number string */
654 	char	counts[32];		/* Temp counts number string */
655 
656 	unsigned long	trace;		/* Trace bits */
657 	unsigned long	editheaders;	/* These headers in edit template */
658 	struct child*	children;	/* Child list */
659 	struct cmd*	cmd;		/* Current command table entry */
660 	struct file*	files;		/* fileopen() list */
661 	struct linematch* bodymatch;	/* compiled state.var.spambody */
662 	struct sender*	sender;		/* compiled state.var.sender */
663 	struct stat	openstat;	/* fileopen stat */
664 	Dt_t* 		ignore;		/* Ignored fields */
665 	Dt_t*		saveignore;	/* Ignored fields on save to folder */
666 	Dt_t*		ignoreall;	/* Special: ignore all headers */
667 	Dt_t*		aliases;	/* aliases */
668 	Dt_t*		userid;		/* User name -> id map */
669 	Dt_t*		stacked;	/* STACK dict list */
670 
671 	struct strings	stringdope[NSPACE];
672 
673 	struct {
674 	sig_t	sigint;			/* Previous SIGINT value */
675 	sig_t	sighup;			/* Previous SIGHUP value */
676 	sig_t	sigtstp;		/* Previous SIGTSTP value */
677 	sig_t	sigttou;		/* Previous SIGTTOU value */
678 	sig_t	sigttin;		/* Previous SIGTTIN value */
679 	FILE*	fp;			/* File for saving away */
680 	int	hadintr;		/* Have seen one SIGINT so far */
681 	jmp_buf	work;			/* To get back to work */
682 	int	working;		/* Whether to long jump */
683 	jmp_buf	abort;			/* To end collection with error */
684 	}	collect;
685 
686 	struct {
687 	jmp_buf	header;			/* Printing headers */
688 	jmp_buf	sr;			/* set/reset longjmp buffer */
689 	jmp_buf	sigpipe;		/* SIGPIPE longjmp buffer */
690 	}	jump;
691 
692 	struct {
693 	char	bang[LASTSIZE];		/* Last ! command */
694 	char	scan[LASTSIZE];		/* Last message search string */
695 	}	last;
696 
697 	struct {
698 	int		count;		/* Count of messages read in */
699 	int		inbox;		/* Current folder mh state.var.inbox */
700 	Imapcontext_t	imap;		/* imap message format */
701 	struct mhcontext mh;		/* mh message format */
702 	int		size;		/* Max messages in vector */
703 	int*		vec;		/* Current message vector */
704 	FILE*		ap;		/* Actual file pointer */
705 	FILE*		ip;		/* Input temp file buffer */
706 	FILE*		op;		/* Output temp file buffer */
707 	struct msg*	active;		/* ip points to this message */
708 	struct msg*	context;	/* Folder read context */
709 	struct msg*	dot;		/* Pointer to current message */
710 	struct msg*	list;		/* The actual message structure */
711 	}		msg;
712 
713 	struct {
714 	char	pwd[2][PATHSIZE];	/* pwd and oldpwd paths */
715 	char	mail[PATHSIZE];		/* Name of current file */
716 	char	path[PATHSIZE];		/* Very temporary fixed path buffer */
717 	char	prev[PATHSIZE];		/* Name of previous file */
718 	Sfio_t*	buf;			/* Very temporary name buffer */
719 	Sfio_t*	move;			/* Very temporary name buffer */
720 	Sfio_t*	part;			/* Very temporary name buffer */
721 	Sfio_t*	temp;			/* Very temporary name buffer */
722 	}	path;
723 
724 	struct {
725 	int	sp;			/* Top of stack */
726 	struct {
727 	FILE*	input;			/* Saved state.input */
728 	int	cond;			/* Saved state.cond */
729 	int	loading;		/* Saved state.loading */
730 	}	stack[NOFILE];
731 	}	source;
732 
733 	struct more {
734 #if MORE_DISCIPLINE
735 	Sfdisc_t	disc;
736 	int		row;
737 	int		col;
738 	int		match;
739 	char		pattern[HEADSIZE];
740 	char		tmp[HEADSIZE];
741 #endif
742 	int		discipline;
743 	int		init;
744 	}		more;
745 
746 	struct state_part {
747 
748 	Mimedisc_t	disc;
749 	Mime_t*		mime;
750 	Part_t*		head;
751 	Part_t		global;
752 	int		init;
753 
754 	struct {
755 	int		multi;
756 	int		count;
757 	Part_t*		head;
758 	Part_t*		tail;
759 	struct bound*	boundary;
760 	}		in;
761 
762 	struct {
763 	int		multi;
764 	int		boundlen;
765 	char		boundary[HEADSIZE];
766 	}		out;
767 
768 	}		part;
769 
770 	struct {
771 	char	edit[256];
772 	char	mail[256];
773 	char	mesg[256];
774 	char	more[256];
775 	char	quit[256];
776 	char*	dir;
777 	}	tmp;
778 
779 	struct
780 	{
781 	char*	allnet;
782 	char*	append;
783 	char*	askbcc;
784 	char*	askcc;
785 	char*	askheaders;
786 	char*	asksub;
787 	char*	attachments;
788 	char*	autoinc;
789 	char*	autoprint;
790 	char*	bang;
791 	char*	cdpath;
792 	char*	cmd;
793 	char*	coprocess;
794 	long	crt;
795 	char*	dead;
796 	char*	debug;
797 	char*	domain;
798 	char*	dot;
799 	char*	editheaders;
800 	char*	editor;
801 	char*	escape;
802 	char*	fixedheaders;
803 	char*	flipr;
804 	char*	folder;
805 	char*	followup;
806 	char*	header;
807 	char*	headerbotch;
808 	char*	headfake;
809 	char*	hold;
810 	char*	home;
811 	char*	hostname;
812 	char*	ignore;
813 	char*	ignoreeof;
814 	char*	imap;
815 	char*	inbox;
816 	char*	indentprefix;
817 	char*	interactive;
818 	char*	justcheck;
819 	long	justfrom;
820 	char*	justheaders;
821 	char*	keep;
822 	char*	keepsave;
823 	char*	lister;
824 	char*	local;
825 	char*	lock;
826 	char*	log;
827 	char*	mail;
828 	char*	mailcap;
829 	char*	mailrc;
830 	char*	master;
831 	char*	mbox;
832 	char*	metoo;
833 	char*	more;
834 	char*	news;
835 	char*	oldpwd;
836 	char*	onehop;
837 	char*	outfolder;
838 	char*	page;
839 	char*	pager;
840 	char*	prompt;
841 	char*	pwd;
842 	char*	quiet;
843 	char*	receive;
844 	char*	recent;
845 	char*	rule;
846 	char*	save;
847 	long	screen;
848 	char*	searchheaders;
849 	char*	sender;
850 	char*	sendheaders;
851 	char*	sendmail;
852 	char*	sendwait;
853 	char*	shell;
854 	char*	showto;
855 	char*	Sign;
856 	char*	sign;
857 	char*	signature;
858 	char*	smtp;
859 	char*	spam;
860 	char*	spambody;
861 	long	spamdelay;
862 	char*	spamfrom;
863 	char*	spamfromok;
864 	char*	spamlog;
865 	char*	spamsub;
866 	char*	spamsubhead;
867 	long	spamtest;
868 	char*	spamto;
869 	char*	spamtook;
870 	char*	spamvia;
871 	char*	spamviaok;
872 	long	toplines;
873 	char*	trace;
874 	char*	user;
875 	char*	verbose;
876 	char*	visual;
877 	}	var;
878 
879 } State_t;
880 
881 extern State_t		state;
882 
883 extern int		Blast(struct msg*);
884 extern int		Copy(char*);
885 extern int		Followup(struct msg*);
886 extern int		From(struct msg*);
887 extern int		Get(char**);
888 extern int		Join(struct msg*);
889 extern int		More(struct msg*);
890 extern int		Reply(struct msg*);
891 extern int		Save(char*);
892 extern int		Split(char*);
893 extern int		Type(struct msg*);
894 extern int		addarg(struct argvec*, const char*);
895 extern int		alias(char**);
896 extern void		alter(char*);
897 extern int		alternates(char**);
898 extern void		announce();
899 extern int		anyof(char*, char*);
900 extern int		blankline(char*);
901 extern int		blast(struct msg*);
902 extern void		boundary(void);
903 extern int		capability(char**);
904 extern int		cd(char**);
905 extern int		check(int, int);
906 extern int		cmdcopy(char*);
907 extern int		cmddelete(struct msg*);
908 extern int		cmdelse(void);
909 extern int		cmdendif(void);
910 extern int		cmdexit(int);
911 extern int		cmdif(char**);
912 extern int		cmdmkdir(char**);
913 extern int		cmdpipe(char*);
914 extern int		cmdquit(void);
915 extern int		cmdrename(char**);
916 extern int		cmdrmdir(char**);
917 extern int		cmdtouch(char*);
918 extern int		cmdwrite(char*);
919 extern FILE*		collect(struct header*, unsigned long);
920 extern void		commands(void);
921 extern int		copy(struct msg*, FILE*, Dt_t**, char*, unsigned long);
922 extern char*		counts(int, off_t, off_t);
923 extern void		dictclear(Dt_t**);
924 extern void		dictreset(void);
925 extern struct name*	dictsearch(Dt_t**, const char*, int);
926 extern int		dictwalk(Dt_t**, int(*)(Dt_t*, void*, void*), void*);
927 extern int		deltype(struct msg*);
928 extern void		demail(void);
929 extern char*		detract(struct header*, unsigned long);
930 extern int		dot(void);
931 extern int		duplicate(char*);
932 extern int		echo(char**);
933 extern int		editor(struct msg*);
934 extern int		execute(char*, int);
935 extern char*		expand(char*, int);
936 extern void		extract(struct header*, unsigned long, char*);
937 extern void		fileclear(void);
938 extern int		fileclose(FILE*);
939 extern FILE*		filefd(int, char*);
940 extern int		filecopy(const char*, FILE*, const char*, FILE*, FILE*, off_t, off_t*, off_t*, unsigned long);
941 extern int		filelock(const char*, FILE*, int);
942 extern FILE*		fileopen(char*, char*);
943 extern off_t		filesize(FILE*);
944 extern FILE*		filestd(char*, char*);
945 extern FILE*		filetemp(char*, int, int, int);
946 extern int		filetrunc(FILE*);
947 extern int		first(int, int);
948 extern int		folder(char**);
949 extern struct msg*	folderinfo(int);
950 extern int		folders(void);
951 extern int		followup(struct msg*);
952 extern void		free_command(int);
953 extern int		from(struct msg*);
954 extern int		get(char**);
955 extern void		getargs(struct argvec*, char*);
956 extern int		getfolder(char*, size_t);
957 extern int		getmsglist(char*, unsigned long);
958 extern char*		grab(struct msg*, unsigned long, char*);
959 extern void		grabedit(struct header*, unsigned long);
960 extern void		headclear(struct header*, unsigned long);
961 extern int		headers(struct msg*);
962 extern int		headget(struct parse*);
963 extern int		headout(FILE*, struct header*, unsigned long);
964 extern int		headset(struct parse*, struct msg*, FILE*, struct header*, Dt_t**, unsigned long);
965 extern int		help(char**);
966 extern int		ignore(char**);
967 extern int		ignored(Dt_t**, const char*);
968 extern int		incorporate(void);
969 extern int		incfile(void);
970 extern int		isall(const char*);
971 extern char*		iscmd(char*);
972 extern int		isdate(char*);
973 extern int		isdir(char*);
974 extern int		ishead(char*, int);
975 extern int		isreg(char*);
976 extern int		join(struct msg*);
977 extern int		license(void*);
978 extern int		list(void);
979 extern void		load(char*);
980 extern char*		localize(char*);
981 extern int		lower(int);
982 extern int		mail(char*);
983 extern char*		mailbox(const char*, const char*);
984 extern int		map(char*);
985 extern int		mark(char*);
986 extern int		mboxit(char*);
987 extern void		mhgetcontext(struct mhcontext*, const char*, int);
988 extern void		mhputcontext(struct mhcontext*, const char*);
989 extern int		mime(int);
990 extern int		more(struct msg*);
991 extern void		msgflags(struct msg*, int, int);
992 extern struct msg*	newmsg(off_t offset);
993 extern int		next(struct msg*);
994 extern char*		normalize(char*, unsigned long, char*, size_t);
995 extern void		note(int, const char*, ...);
996 extern int		notyet(char*);
997 extern int		null(int);
998 extern void		parse(struct msg*, char*, struct headline*, char*, size_t);
999 extern FILE*		pipeopen(char*, char*);
1000 extern int		preserve(char*);
1001 extern int		puthead(FILE*, struct header*, int);
1002 extern int		putline(FILE*, char*);
1003 extern int		pwd(void);
1004 extern void		quit(void);
1005 extern int		readline(FILE*, char*, int);
1006 extern char*		record(char*, unsigned long);
1007 extern int		regular(FILE*);
1008 extern int		reply(struct msg*);
1009 extern int		replyall(struct msg*);
1010 extern int		replysender(struct msg*);
1011 extern void		resume(int);
1012 extern int		retain(char**);
1013 extern int		rm(char*);
1014 extern int		run_command(char*, int, int, int, char*, char*, char*);
1015 extern FILE*		run_editor(FILE*, off_t, struct header*, int, int);
1016 extern char*		salloc(int);
1017 extern int		save(char*);
1018 extern void		savedeadletter(FILE*);
1019 extern int		saveignore(char**);
1020 extern int		saveretain(char**);
1021 extern char*		savestr(char*);
1022 extern int		scan(char**);
1023 extern int		scroll(char*);
1024 extern int		sender(char*, int);
1025 extern void		sendmail(struct header*, unsigned long);
1026 extern int		sendsmtp(FILE*, char*, char**, off_t);
1027 extern int		set(char**);
1028 extern void		set_askbcc(struct var*, const char*);
1029 extern void		set_askcc(struct var*, const char*);
1030 extern void		set_askheaders(struct var*, const char*);
1031 extern void		set_asksub(struct var*, const char*);
1032 extern void		set_coprocess(struct var*, const char*);
1033 extern void		set_crt(struct var*, const char*);
1034 extern void		set_editheaders(struct var*, const char*);
1035 extern void		set_justfrom(struct var*, const char*);
1036 extern void		set_list(struct var*, const char*);
1037 extern void		set_mail(struct var*, const char*);
1038 extern void		set_mailcap(struct var*, const char*);
1039 extern void		set_more(struct var*, const char*);
1040 extern void		set_news(struct var*, const char*);
1041 extern void		set_notyet(struct var*, const char*);
1042 extern void		set_pwd(struct var*, const char*);
1043 extern void		set_screen(struct var*, const char*);
1044 extern void		set_sender(struct var*, const char*);
1045 extern void		set_sendmail(struct var*, const char*);
1046 extern void		set_shell(struct var*, const char*);
1047 extern void		set_spambody(struct var*, const char*);
1048 extern void		set_spamtest(struct var*, const char*);
1049 extern void		set_toplines(struct var*, const char*);
1050 extern void		set_trace(struct var*, const char*);
1051 extern void		set_user(struct var*, const char*);
1052 extern int		setfolder(char*);
1053 extern FILE*		setinput(struct msg*);
1054 extern void		setptr(FILE*, off_t);
1055 extern void		setscreensize(void);
1056 extern void		settmp(const char*, int);
1057 extern int		shell(char*);
1058 extern void		shquote(Sfio_t*, char*);
1059 extern int		size(struct msg*);
1060 extern char*		skin(char*, unsigned long);
1061 extern char*		snarf(char*, int*);
1062 extern int		source(char**);
1063 extern int		spammed(struct msg*);
1064 extern int		split(char*);
1065 extern void		sreset(void);
1066 extern int		start_command(char*, int, int, int, char*, char*, char*);
1067 extern char*		strlower(char*);
1068 extern char*		strncopy(char*, const char*, size_t);
1069 extern char*		struse(Sfio_t*);
1070 extern void		tempinit(void);
1071 extern int		top(struct msg*);
1072 extern void		touchmsg(struct msg*);
1073 extern int		ttyedit(int, int, const char*, char*, size_t);
1074 extern int		ttyquery(int, int, const char*);
1075 extern int		type(struct msg*);
1076 extern int		unalias(char**);
1077 extern int		undelete(struct msg*);
1078 extern int		unread(char*);
1079 extern int		unset(char**);
1080 extern int		unstack(void);
1081 extern int		upper(int);
1082 extern int		userid(char*);
1083 extern int		usermap(struct header*, int);
1084 extern char*		username(void);
1085 extern char*		varget(const char*);
1086 extern void		varinit(void);
1087 extern char*		varkeep(const char*);
1088 extern int		varlist(int);
1089 extern int		varset(const char*, const char*);
1090 extern int		version(void*);
1091 extern int		visual(struct msg*);
1092 extern int		wait_command(int);
1093 extern char*		wordnext(char**, char*);
1094 extern char*		yankword(char*, char*);
1095 
1096 /*
1097  * IMAP support
1098  */
1099 
1100 #define imap_name(p)	((p)[0]=='@'||strneq(p,"imap://",7))
1101 
1102 extern int		imap_command(char*);
1103 extern int		imap_copy(struct msg*, FILE*, Dt_t**, char*, unsigned long);
1104 extern void		imap_exit(int);
1105 extern int		imap_folders(void);
1106 extern int		imap_get1(char**, unsigned long);
1107 extern int		imap_mkdir(char*);
1108 extern void		imap_msgflags(struct msg*, int, int);
1109 extern int		imap_msglist(char*);
1110 extern void		imap_printhead(int, int);
1111 extern void		imap_quit(void);
1112 extern int		imap_rename(char*, char*);
1113 extern int		imap_rmdir(char*);
1114 extern int		imap_save(struct msg*, char*);
1115 extern FILE*		imap_setinput(struct msg*);
1116 extern int		imap_setptr(char*, int);
1117 
1118 #if _PACKAGE_ast
1119 
1120 #define T(s)		ERROR_translate(0,0,0,s)
1121 #define X(s)		ERROR_catalog(s)
1122 
1123 #else
1124 
1125 #define T(s)		(s)	/* Dynamic translation string */
1126 #define X(s)		(s)	/* Static translation string */
1127 
1128 #define imap_command(a)		(-1)
1129 #define imap_copy(a,b,c,d,e)	(-1)
1130 #define	imap_exit(a)
1131 #define imap_folders()		(-1)
1132 #define imap_get1(a,b)		(-1)
1133 #define imap_mkdir(a)		(-1)
1134 #define imap_msgflags(a,b,c)	(-1)
1135 #define imap_msglist(a)		(-1)
1136 #define imap_printhead(a)
1137 #define imap_quit()
1138 #define imap_rename(a,b)	(-1)
1139 #define imap_rmdir(a)		(-1)
1140 #define imap_save(a)		(-1)
1141 #define imap_setinput(a)	((FILE*)0)
1142 
1143 #endif
1144 
1145 /*
1146  * MH support
1147  */
1148 
1149 extern int		mh_setptr(char*, int);
1150