nail.h: use MAXPATHLEN as fallback for struct cw
[s-mailx.git] / nail.h
blob9b724824c9b88c256a133a1d12919b9f03d8d805
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Header inclusion, macros, constants, types and the global var declarations.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
41 * Mail -- a mail program
43 * Author: Kurt Shoens (UCB) March 25, 1978
46 #include "config.h"
48 #include <sys/stat.h>
49 #include <sys/types.h>
51 #include <errno.h>
52 #include <limits.h>
53 #include <setjmp.h>
54 #include <signal.h>
55 #include <stdarg.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <termios.h>
60 #include <time.h>
61 #include <unistd.h>
63 #ifdef HAVE_ASSERTS
64 # include <assert.h>
65 #endif
66 #ifdef HAVE_ICONV
67 # include <iconv.h>
68 #endif
69 #ifdef HAVE_MBRTOWC
70 # include <wchar.h>
71 #endif
72 #ifdef HAVE_WCTYPE_H
73 # include <wctype.h>
74 #endif
77 * Compat
80 #if ! defined NI_MAXHOST || NI_MAXHOST < 1025
81 # undef NI_MAXHOST
82 # define NI_MAXHOST 1025
83 #endif
85 #ifndef MAXPATHLEN
86 # ifdef PATH_MAX
87 # define MAXPATHLEN PATH_MAX
88 # else
89 # define MAXPATHLEN 1024
90 # endif
91 #elif defined PATH_MAX && MAXPATHLEN < PATH_MAX
92 # undef MAXPATHLEN
93 # define MAXPATHLEN PATH_MAX
94 #endif
96 #ifndef STDIN_FILENO
97 # define STDIN_FILENO 0
98 #endif
99 #ifndef STDOUT_FILENO
100 # define STDOUT_FILENO 1
101 #endif
102 #ifndef STDERR_FILENO
103 # define STDERR_FILENO 2
104 #endif
106 #ifdef NSIG_MAX
107 # undef NSIG
108 # define NSIG NSIG_MAX
109 #elif ! defined NSIG
110 # define NSIG ((sizeof(sigset_t) * 8) - 1)
111 #endif
117 #if BUFSIZ > 2560 /* TODO simply use BUFSIZ? */
118 # define LINESIZE BUFSIZ /* max readable line width */
119 #else
120 # define LINESIZE 2560
121 #endif
122 #define BUFFER_SIZE (BUFSIZ >= (1 << 13) ? BUFSIZ : (1 << 14))
124 #define CBAD (-15555)
125 #define APPEND /* New mail goes to end of mailbox */
126 #define ESCAPE '~' /* Default escape for sending */
127 #define HIST_SIZE 242 /* tty.c: history list default size */
128 #define HSHSIZE 23 /* Hash prime (aliases, vars, macros) */
129 #define MAXARGC 1024 /* Maximum list of raw strings */
130 #define MAXEXP 25 /* Maximum expansion of aliases */
131 #define PROMPT_BUFFER_SIZE 80 /* getprompt() bufsize (> 3!) */
133 #define ACCOUNT_NULL "null" /* Name of "null" account */
135 #define FROM_DATEBUF 64 /* Size of RFC 4155 From_ line date */
136 #define DATE_DAYSYEAR 365L
137 #define DATE_SECSMIN 60L
138 #define DATE_MINSHOUR 60L
139 #define DATE_HOURSDAY 24L
140 #define DATE_SECSDAY (DATE_SECSMIN * DATE_MINSHOUR * DATE_HOURSDAY)
142 /* Default *encoding* as enum conversion below */
143 #define MIME_DEFAULT_ENCODING CONV_TOQP
145 /* Maximum allowed line length in a mail before QP folding is necessary), and
146 * the real limit we go for */
147 #define MIME_LINELEN_MAX 1000
148 #define MIME_LINELEN_LIMIT (MIME_LINELEN_MAX - 50)
150 /* Locations of mime.types(5) */
151 #define MIME_TYPES_USR "~/.mime.types"
152 #define MIME_TYPES_SYS "/etc/mime.types"
154 /* Fallback MIME charsets, if *charset-7bit* and *charset-8bit* or not set */
155 #define CHARSET_7BIT "US-ASCII"
156 #ifdef HAVE_ICONV
157 # define CHARSET_8BIT "UTF-8"
158 # define CHARSET_8BIT_VAR "charset-8bit"
159 #else
160 # define CHARSET_8BIT "ISO-8859-1"
161 # define CHARSET_8BIT_VAR "ttycharset"
162 #endif
164 /* Is *W* a quoting (ASCII only) character? */
165 #define ISQUOTE(W) ((W) == L'>' || (W) == L'|' || (W) == L'}')
167 /* Maximum number of quote characters (not bytes!) that'll be used on
168 * follow lines when compressing leading quote characters */
169 #define QUOTE_MAX 42
171 /* Maximum size of a message that is passed through to the spam system */
172 #define SPAM_MAXSIZE 420000
174 /* String dope: dynamic buffer size, and size of the single builtin one that's
175 * used first */
176 #define SBUFFER_SIZE 0x18000u
177 #define SBUFFER_BUILTIN 0x2000u
179 /* These come from the configuration (named Xxy to not clash with sh(1)..) */
180 #ifndef XSHELL
181 # define XSHELL "/bin/sh"
182 #endif
183 #define SHELL XSHELL
184 #ifndef XLISTER
185 # define XLISTER "ls"
186 #endif
187 #define LISTER XLISTER
188 #ifndef XPAGER
189 # define XPAGER "more"
190 #endif
191 #define PAGER XPAGER
194 * Funs, CC support etc.
197 /* Members in constant array */
198 #ifndef NELEM
199 # define NELEM(A) (sizeof(A) / sizeof(A[0]))
200 #endif
202 /* sizeof() for member fields */
203 #define SIZEOF_FIELD(T,F) sizeof(((T *)NULL)->F)
205 /* Casts-away (*NOT* cast-away) */
206 #define UNCONST(P) ((void*)(unsigned long)(void const*)(P))
207 #define UNVOLATILE(P) ((void*)(unsigned long)(void volatile*)(P))
209 /* __STDC_VERSION__ is ISO C99, so also use __STDC__, which should work */
210 #if defined __STDC__ || defined __STDC_VERSION__ /*|| defined __cplusplus*/
211 # define STRING(X) #X
212 # define XSTRING(X) STRING(X)
213 # define CONCAT(S1,S2) _CONCAT(S1, S2)
214 # define _CONCAT(S1,S2) S1 ## S2
215 #else
216 # define STRING(X) "X"
217 # define XSTRING STRING
218 # define CONCAT(S1,S2) S1/**/S2
219 #endif
221 #if defined __STDC_VERSION__ && __STDC_VERSION__ + 0 >= 199901L
222 /* Variable size arrays and structure fields */
223 # define VFIELD_SIZE(X)
224 # define VFIELD_SIZEOF(T,F) (0)
225 /* Inline functions */
226 # define HAVE_INLINE
227 # define INLINE inline
228 # define SINLINE static inline
229 #else
230 # define VFIELD_SIZE(X) (X)
231 # define VFIELD_SIZEOF(T,F) SIZEOF_FIELD(T, F)
232 # define INLINE
233 # define SINLINE static
234 #endif
236 #undef ISPOW2
237 #define ISPOW2(X) ((((X) - 1) & (X)) == 0)
238 #undef MIN
239 #define MIN(A, B) ((A) < (B) ? (A) : (B))
240 #undef MAX
241 #define MAX(A, B) ((A) < (B) ? (B) : (A))
242 #undef ABS
243 #define ABS(A) ((A) < 0 ? -(A) : (A))
245 #define smin(a, b) ((a) < (b) ? (a) : (b)) /* TODO OBSOLETE */
246 #define smax(a, b) ((a) < (b) ? (b) : (a)) /* TODO OBSOLETE */
248 /* Compile-Time-Assert */
249 #define CTA(TEST) _CTA_1(TEST, __LINE__)
250 #define _CTA_1(TEST,L) _CTA_2(TEST, L)
251 #define _CTA_2(TEST,L) \
252 typedef char COMPILE_TIME_ASSERT_failed_at_line_ ## L[(TEST) ? 1 : -1]
254 #ifndef HAVE_ASSERTS
255 # undef assert
256 # define assert(X) ((void)0)
257 #endif
259 /* Translation (init in main.c) */
260 #undef tr
261 #ifdef HAVE_CATGETS
262 # define CATSET 1
263 # define tr(c,d) catgets(catd, CATSET, c, d)
264 #else
265 # define tr(c,d) (d)
266 #endif
269 * Types
272 typedef unsigned long ul_it;
273 typedef unsigned int ui_it;
274 typedef unsigned short us_it;
275 typedef unsigned char uc_it;
277 typedef signed long sl_it;
278 typedef signed int si_it;
279 typedef signed short ss_it;
280 typedef signed char sc_it;
282 typedef enum {FAL0, TRU1} bool_t;
284 typedef void ( *sighandler_type)(int);
286 enum user_options {
287 OPT_NONE = 0,
288 OPT_DEBUG = 1<< 0, /* -d / *debug* */
289 OPT_VERBOSE = 1<< 1, /* -v / *verbose* */
290 OPT_EXISTONLY = 1<< 2, /* -e */
291 OPT_HEADERSONLY = 1<< 3, /* -H */
292 OPT_NOSRC = 1<< 4, /* -n */
293 OPT_E_FLAG = 1<< 5, /* -E / *skipemptybody* */
294 OPT_F_FLAG = 1<< 6, /* -F */
295 OPT_N_FLAG = 1<< 7, /* -N / *header* */
296 OPT_R_FLAG = 1<< 8, /* -R */
297 OPT_r_FLAG = 1<< 9, /* -r (plus option_r_arg) */
298 OPT_t_FLAG = 1<<10, /* -t */
299 OPT_TILDE_FLAG = 1<<11, /* -~ */
300 OPT_BATCH_FLAG = 1<<12, /* -# */
302 OPT_SENDMODE = 1<<13, /* Usage case forces send mode */
303 OPT_INTERACTIVE = 1<<14, /* isatty(0) */
304 OPT_TTYIN = OPT_INTERACTIVE,
305 OPT_TTYOUT = 1<<15,
306 OPT_NOPROMPT = 1<<16 /* *noprompt* has been set */
308 #define IS_TTY_SESSION() \
309 ((options & (OPT_TTYIN | OPT_TTYOUT)) == (OPT_TTYIN | OPT_TTYOUT))
311 enum exit_status {
312 EXIT_OK = EXIT_SUCCESS,
313 EXIT_ERR = EXIT_FAILURE,
314 EXIT_COLL_ABORT = 1<<1, /* Message collection was aborted */
315 EXIT_SEND_ERROR = 1<<2 /* Unspecified send error occurred */
318 enum fexp_mode {
319 FEXP_FULL, /* Full expansion */
320 FEXP_LOCAL = 1<<0, /* Result must be local file/maildir */
321 FEXP_SHELL = 1<<1, /* No folder %,#,&,+ stuff, yet sh(1) */
322 FEXP_NSHORTCUT = 1<<2, /* Don't expand shortcuts */
323 FEXP_SILENT = 1<<3, /* Don't print but only return errors */
324 FEXP_MULTIOK = 1<<4 /* Expansion to many entries is ok */
327 enum lned_mode {
328 LNED_NONE = 0,
329 LNED_LF_ESC = 1<<0, /* LF can be backslash escaped */
330 LNED_HIST_ADD = 1<<1 /* Add completed line to history */
333 /* <0 means "stop" unless *prompt* extensions are enabled. */
334 enum prompt_exp {
335 PROMPT_STOP = -1, /* \c */
336 /* *prompt* extensions: \$, \@ etc. */
337 PROMPT_DOLLAR = -2,
338 PROMPT_AT = -3
341 enum okay {
342 STOP = 0,
343 OKAY = 1
346 enum mimeenc {
347 MIME_NONE, /* message is not in MIME format */
348 MIME_BIN, /* message is in binary encoding */
349 MIME_8B, /* message is in 8bit encoding */
350 MIME_7B, /* message is in 7bit encoding */
351 MIME_QP, /* message is quoted-printable */
352 MIME_B64 /* message is in base64 encoding */
355 enum conversion {
356 CONV_NONE, /* no conversion */
357 CONV_7BIT, /* no conversion, is 7bit */
358 CONV_FROMQP, /* convert from quoted-printable */
359 CONV_TOQP, /* convert to quoted-printable */
360 CONV_8BIT, /* convert to 8bit (iconv) */
361 CONV_FROMB64, /* convert from base64 */
362 CONV_FROMB64_T, /* convert from base64/text */
363 CONV_TOB64, /* convert to base64 */
364 CONV_FROMHDR, /* convert from RFC1522 format */
365 CONV_TOHDR, /* convert to RFC1522 format */
366 CONV_TOHDR_A /* convert addresses for header */
369 enum sendaction {
370 SEND_MBOX, /* no conversion to perform */
371 SEND_RFC822, /* no conversion, no From_ line */
372 SEND_TODISP, /* convert to displayable form */
373 SEND_TODISP_ALL, /* same, include all MIME parts */
374 SEND_SHOW, /* convert to 'show' command form */
375 SEND_TOSRCH, /* convert for IMAP SEARCH */
376 SEND_TOFLTR, /* convert for spam mail filtering */
377 SEND_TOFILE, /* convert for saving body to a file */
378 SEND_TOPIPE, /* convert for pipe-content/subc. */
379 SEND_QUOTE, /* convert for quoting */
380 SEND_QUOTE_ALL, /* same, include all MIME parts */
381 SEND_DECRYPT /* decrypt */
384 enum mimecontent {
385 MIME_UNKNOWN, /* unknown content */
386 MIME_SUBHDR, /* inside a multipart subheader */
387 MIME_822, /* message/rfc822 content */
388 MIME_MESSAGE, /* other message/ content */
389 MIME_TEXT_PLAIN, /* text/plain content */
390 MIME_TEXT_HTML, /* text/html content */
391 MIME_TEXT, /* other text/ content */
392 MIME_ALTERNATIVE, /* multipart/alternative content */
393 MIME_DIGEST, /* multipart/digest content */
394 MIME_MULTI, /* other multipart/ content */
395 MIME_PKCS7, /* PKCS7 content */
396 MIME_DISCARD /* content is discarded */
399 enum tdflags {
400 TD_NONE = 0, /* no display conversion */
401 TD_ISPR = 1<<0, /* use isprint() checks */
402 TD_ICONV = 1<<1, /* use iconv() */
403 TD_DELCTRL = 1<<2, /* delete control characters */
406 * NOTE: _TD_EOF and _TD_BUFCOPY may be ORd with enum conversion and
407 * enum sendaction, and may thus NOT clash with their bit range!
409 _TD_EOF = 1<<14,/* EOF seen, last round! */
410 _TD_BUFCOPY = 1<<15 /* Buffer may be constant, copy it */
413 enum protocol {
414 PROTO_FILE, /* refers to a local file */
415 PROTO_POP3, /* is a pop3 server string */
416 PROTO_IMAP, /* is an imap server string */
417 PROTO_MAILDIR, /* refers to a maildir folder */
418 PROTO_UNKNOWN /* unknown protocol */
421 #ifdef HAVE_SSL
422 enum ssl_vrfy_level {
423 VRFY_IGNORE,
424 VRFY_WARN,
425 VRFY_ASK,
426 VRFY_STRICT
428 #endif
430 struct str {
431 char *s; /* the string's content */
432 size_t l; /* the stings's length */
435 struct time_current {
436 time_t tc_time;
437 struct tm tc_gm;
438 struct tm tc_local;
439 char tc_ctime[32];
442 struct quoteflt {
443 FILE *qf_os; /* Output stream */
444 char const *qf_pfix;
445 ui_it qf_pfix_len; /* Length of prefix: 0: bypass */
446 ui_it qf_qfold_min; /* Simple way: wrote prefix? */
447 #ifdef HAVE_QUOTE_FOLD
448 ui_it qf_qfold_max; /* Otherwise: line lengths */
449 ui_it qf_state; /* *quote-fold* state machine */
450 ui_it qf_brkl; /* Breakpoint */
451 ui_it qf_brkw;
452 bool_t qf_brk_isws;
453 uc_it __dummy[3];
454 ui_it qf_datw; /* Current visual output line width */
455 struct str qf_dat; /* Current visual output line */
456 struct str qf_currq; /* Current quote, compressed */
457 mbstate_t qf_mbps[2];
458 #endif
461 struct termios_state {
462 struct termios ts_tios;
463 char *ts_linebuf;
464 size_t ts_linesize;
465 bool_t ts_needs_reset;
468 #define termios_state_reset() \
469 do {\
470 if (termios_state.ts_needs_reset) {\
471 tcsetattr(0, TCSADRAIN, &termios_state.ts_tios);\
472 termios_state.ts_needs_reset = FAL0;\
474 } while (0)
476 struct sock { /* data associated with a socket */
477 int s_fd; /* file descriptor */
478 #ifdef HAVE_SSL
479 int s_use_ssl; /* SSL is used */
480 # ifdef HAVE_OPENSSL
481 void *s_ssl; /* SSL object */
482 void *s_ctx; /* SSL context object */
483 # endif
484 #endif
485 char *s_wbuf; /* for buffered writes */
486 int s_wbufsize; /* allocated size of s_buf */
487 int s_wbufpos; /* position of first empty data byte */
488 char *s_rbufptr; /* read pointer to s_rbuf */
489 int s_rsz; /* size of last read in s_rbuf */
490 char const *s_desc; /* description of error messages */
491 void (*s_onclose)(void); /* execute on close */
492 char s_rbuf[LINESIZE + 1]; /* for buffered reads */
495 struct mailbox {
496 enum {
497 MB_NONE = 000, /* no reply expected */
498 MB_COMD = 001, /* command reply expected */
499 MB_MULT = 002, /* multiline reply expected */
500 MB_PREAUTH = 004, /* not in authenticated state */
501 MB_BYE = 010 /* may accept a BYE state */
502 } mb_active;
503 FILE *mb_itf; /* temp file with messages, read open */
504 FILE *mb_otf; /* same, write open */
505 char *mb_sorted; /* sort method */
506 enum {
507 MB_VOID, /* no type (e. g. connection failed) */
508 MB_FILE, /* local file */
509 MB_POP3, /* POP3 mailbox */
510 MB_IMAP, /* IMAP mailbox */
511 MB_MAILDIR, /* maildir folder */
512 MB_CACHE /* cached mailbox */
513 } mb_type; /* type of mailbox */
514 enum {
515 MB_DELE = 01, /* may delete messages in mailbox */
516 MB_EDIT = 02 /* may edit messages in mailbox */
517 } mb_perm;
518 int mb_compressed; /* is a compressed mbox file */
519 int mb_threaded; /* mailbox has been threaded */
520 #ifdef HAVE_IMAP
521 enum mbflags {
522 MB_NOFLAGS = 000,
523 MB_UIDPLUS = 001 /* supports IMAP UIDPLUS */
524 } mb_flags;
525 unsigned long mb_uidvalidity; /* IMAP unique identifier validity */
526 char *mb_imap_account; /* name of current IMAP account */
527 char *mb_imap_mailbox; /* name of current IMAP mailbox */
528 char *mb_cache_directory; /* name of cache directory */
529 #endif
530 struct sock mb_sock; /* socket structure */
533 enum needspec {
534 NEED_UNSPEC, /* unspecified need, don't fetch */
535 NEED_HEADER, /* need the header of a message */
536 NEED_BODY /* need header and body of a message */
539 enum havespec {
540 HAVE_NOTHING = 0, /* nothing downloaded yet */
541 HAVE_HEADER = 01, /* header is downloaded */
542 HAVE_BODY = 02 /* entire message is downloaded */
546 * flag bits. Attention: Flags that are used in cache.c may not change.
548 enum mflag {
549 MUSED = (1<<0), /* entry is used, but this bit isn't */
550 MDELETED = (1<<1), /* entry has been deleted */
551 MSAVED = (1<<2), /* entry has been saved */
552 MTOUCH = (1<<3), /* entry has been noticed */
553 MPRESERVE = (1<<4), /* keep entry in sys mailbox */
554 MMARK = (1<<5), /* message is marked! */
555 MODIFY = (1<<6), /* message has been modified */
556 MNEW = (1<<7), /* message has never been seen */
557 MREAD = (1<<8), /* message has been read sometime. */
558 MSTATUS = (1<<9), /* message status has changed */
559 MBOX = (1<<10), /* Send this to mbox, regardless */
560 MNOFROM = (1<<11), /* no From line */
561 MHIDDEN = (1<<12), /* message is hidden to user */
562 MFULLYCACHED = (1<<13), /* message is completely cached */
563 MBOXED = (1<<14), /* message has been sent to mbox */
564 MUNLINKED = (1<<15), /* message was unlinked from cache */
565 MNEWEST = (1<<16), /* message is very new (newmail) */
566 MFLAG = (1<<17), /* message has been flagged recently */
567 MUNFLAG = (1<<18), /* message has been unflagged */
568 MFLAGGED = (1<<19), /* message is `flagged' */
569 MANSWER = (1<<20), /* message has been answered recently */
570 MUNANSWER = (1<<21), /* message has been unanswered */
571 MANSWERED = (1<<22), /* message is `answered' */
572 MDRAFT = (1<<23), /* message has been drafted recently */
573 MUNDRAFT = (1<<24), /* message has been undrafted */
574 MDRAFTED = (1<<25), /* message is marked as `draft' */
575 MOLDMARK = (1<<26), /* messages was marked previously */
576 MSPAM = (1<<27) /* message is classified as spam */
579 struct mimepart {
580 enum mflag m_flag; /* flags */
581 enum havespec m_have; /* downloaded parts of the part */
582 #ifdef HAVE_SPAM
583 ui_it m_spamscore; /* Spam score as int, 24:8 bits */
584 #endif
585 int m_block; /* block number of this part */
586 size_t m_offset; /* offset in block of part */
587 size_t m_size; /* Bytes in the part */
588 size_t m_xsize; /* Bytes in the full part */
589 long m_lines; /* Lines in the message */
590 long m_xlines; /* Lines in the full message */
591 time_t m_time; /* time the message was sent */
592 char const *m_from; /* message sender */
593 struct mimepart *m_nextpart; /* next part at same level */
594 struct mimepart *m_multipart; /* parts of multipart */
595 struct mimepart *m_parent; /* enclosing multipart part */
596 char *m_ct_type; /* content-type */
597 char *m_ct_type_plain; /* content-type without specs */
598 enum mimecontent m_mimecontent; /* same in enum */
599 char const *m_charset; /* charset */
600 char *m_ct_transfer_enc; /* content-transfer-encoding */
601 enum mimeenc m_mimeenc; /* same in enum */
602 char *m_partstring; /* part level string */
603 char *m_filename; /* attachment filename */
606 struct message {
607 enum mflag m_flag; /* flags */
608 enum havespec m_have; /* downloaded parts of the message */
609 #ifdef HAVE_SPAM
610 ui_it m_spamscore; /* Spam score as int, 24:8 bits */
611 #endif
612 int m_block; /* block number of this message */
613 size_t m_offset; /* offset in block of message */
614 size_t m_size; /* Bytes in the message */
615 size_t m_xsize; /* Bytes in the full message */
616 long m_lines; /* Lines in the message */
617 long m_xlines; /* Lines in the full message */
618 time_t m_time; /* time the message was sent */
619 time_t m_date; /* time in the 'Date' field */
620 unsigned m_idhash; /* hash on Message-ID for threads */
621 struct message *m_child; /* first child of this message */
622 struct message *m_younger; /* younger brother of this message */
623 struct message *m_elder; /* elder brother of this message */
624 struct message *m_parent; /* parent of this message */
625 unsigned m_level; /* thread level of message */
626 long m_threadpos; /* position in threaded display */
627 #ifdef HAVE_IMAP
628 unsigned long m_uid; /* IMAP unique identifier */
629 #endif
630 char *m_maildir_file; /* original maildir file of msg */
631 unsigned m_maildir_hash; /* hash of file name in maildir sub */
632 int m_collapsed; /* collapsed thread information */
636 * Given a file address, determine the block number it represents.
638 #define mailx_blockof(off) ((int) ((off) / 4096))
639 #define mailx_offsetof(off) ((int) ((off) % 4096))
640 #define mailx_positionof(block, offset) ((off_t)(block) * 4096 + (offset))
643 * Argument types.
645 enum argtype {
646 MSGLIST = 0, /* Message list type */
647 STRLIST = 1, /* A pure string */
648 RAWLIST = 2, /* Shell string list */
649 NOLIST = 3, /* Just plain 0 */
650 NDMLIST = 4, /* Message list, no defaults */
651 ECHOLIST= 5, /* Like raw list, but keep quote chars */
652 P = 040, /* Autoprint dot after command */
653 I = 0100, /* Interactive command bit */
654 M = 0200, /* Legal from send mode bit */
655 W = 0400, /* Illegal when read only bit */
656 F = 01000, /* Is a conditional command */
657 T = 02000, /* Is a transparent command */
658 R = 04000, /* Cannot be called from collect */
659 A = 010000 /* Needs an active mailbox */
663 * Oft-used mask values
665 #define MMNORM (MDELETED|MSAVED|MHIDDEN) /* Look at save *and* delete bits */
666 #define MMNDEL (MDELETED|MHIDDEN) /* Look only at deleted bit */
668 enum gfield {
669 GTO = 1, /* Grab To: line */
670 GSUBJECT= 2, /* Likewise, Subject: line */
671 GCC = 4, /* And the Cc: line */
672 GBCC = 8, /* And also the Bcc: line */
674 GNL = 16, /* Print blank line after */
675 GDEL = 32, /* Entity removed from list */
676 GCOMMA = 64, /* detract puts in commas */
677 GUA = 128, /* User-Agent field */
678 GMIME = 256, /* MIME 1.0 fields */
679 GMSGID = 512, /* a Message-ID */
680 /* 1024 */ /* unused */
681 GIDENT = 2048, /* From:, Reply-To: and Organization: field */
682 GREF = 4096, /* References: field */
683 GDATE = 8192, /* Date: field */
684 GFULL = 16384, /* include full names */
685 GSKIN = 32768, /* skin names */
686 GEXTRA = 65536, /* extra fields */
687 GFILES = 131072 /* include filename addresses */
690 #define GMASK (GTO|GSUBJECT|GCC|GBCC) /* Mask of places from whence */
692 #define visible(mp) (((mp)->m_flag & (MDELETED|MHIDDEN)) == 0)
695 * Structure used to pass about the current state of a message (header).
697 struct header {
698 struct name *h_to; /* Dynamic "To:" string */
699 char *h_subject; /* Subject string */
700 struct name *h_cc; /* Carbon copies string */
701 struct name *h_bcc; /* Blind carbon copies */
702 struct name *h_ref; /* References */
703 struct attachment *h_attach; /* MIME attachments */
704 char *h_charset; /* preferred charset */
705 struct name *h_from; /* overridden "From:" field */
706 struct name *h_replyto; /* overridden "Reply-To:" field */
707 struct name *h_sender; /* overridden "Sender:" field */
708 char *h_organization; /* overridden "Organization:" field */
712 * Handling of namelist nodes used in processing the recipients of mail and
713 * aliases, inspection of mail-addresses and all that kind of stuff.
716 enum nameflags {
717 NAME_NAME_SALLOC = 1<< 0, /* .n_name is doped */
718 NAME_FULLNAME_SALLOC = 1<< 1, /* .n_fullname is doped */
719 NAME_SKINNED = 1<< 2, /* Is actually skin()ned */
720 NAME_IDNA = 1<< 3, /* IDNA was applied */
721 NAME_ADDRSPEC_CHECKED = 1<< 4, /* Address has been .. and */
722 NAME_ADDRSPEC_ISFILE = 1<< 5, /* ..is a file path */
723 NAME_ADDRSPEC_ISPIPE = 1<< 6, /* ..is a command for piping */
724 NAME_ADDRSPEC_ISFILEORPIPE = NAME_ADDRSPEC_ISFILE |
725 NAME_ADDRSPEC_ISPIPE,
726 NAME_ADDRSPEC_ERR_EMPTY = 1<< 7, /* An empty string (or NULL) */
727 NAME_ADDRSPEC_ERR_ATSEQ = 1<< 8, /* Weird @ sequence */
728 NAME_ADDRSPEC_ERR_CHAR = 1<< 9, /* Invalid character */
729 NAME_ADDRSPEC_ERR_IDNA = 1<<10, /* IDNA convertion failed */
730 NAME_ADDRSPEC_INVALID = NAME_ADDRSPEC_ERR_EMPTY |
731 NAME_ADDRSPEC_ERR_ATSEQ |
732 NAME_ADDRSPEC_ERR_CHAR |
733 NAME_ADDRSPEC_ERR_IDNA,
735 _NAME_SHIFTWC = 11,
736 _NAME_MAXWC = 0xFFFFF,
737 _NAME_MASKWC = _NAME_MAXWC << _NAME_SHIFTWC
740 /* In the !_ERR_EMPTY case, the failing character can be queried */
741 #define NAME_ADDRSPEC_ERR_GETWC(F) \
742 ((((unsigned int)(F) & _NAME_MASKWC) >> _NAME_SHIFTWC) & _NAME_MAXWC)
743 #define NAME_ADDRSPEC_ERR_SET(F, E, WC) \
744 do (F) = ((F) & ~(NAME_ADDRSPEC_INVALID | _NAME_MASKWC)) | \
745 (E) | (((unsigned int)(WC) & _NAME_MAXWC) << _NAME_SHIFTWC); \
746 while (0)
748 struct name {
749 struct name *n_flink; /* Forward link in list. */
750 struct name *n_blink; /* Backward list link */
751 enum gfield n_type; /* From which list it came */
752 enum nameflags n_flags; /* enum nameflags */
753 char *n_name; /* This fella's name */
754 char *n_fullname; /* Sometimes, name including comment */
757 struct addrguts {
758 char const *ag_input; /* Input string as given */
759 size_t ag_ilen; /* strlen() of input */
760 size_t ag_iaddr_start; /* Start of *addr-spec* in .ag_input */
761 size_t ag_iaddr_aend; /* ..and one past its end */
762 char *ag_skinned; /* Output (alloced if !=.ag_input) */
763 size_t ag_slen; /* strlen() of .ag_skinned */
764 size_t ag_sdom_start; /* Start of domain in .ag_skinned, */
765 enum nameflags ag_n_flags; /* enum nameflags of .ag_skinned */
769 * MIME attachments.
772 enum attach_conv {
773 AC_DEFAULT, /* _get_lc() -> _iter_*() */
774 AC_FIX_OUTCS, /* _get_lc() -> "charset=" .a_charset */
775 AC_FIX_INCS, /* "charset=".a_input_charset (nocnv) */
776 AC_TMPFILE /* attachment.a_tmpf is converted */
779 struct attachment {
780 struct attachment *a_flink; /* Forward link in list. */
781 struct attachment *a_blink; /* Backward list link */
782 char const *a_name; /* file name */
783 char const *a_content_type; /* content type */
784 char const *a_content_disposition; /* content disposition */
785 char const *a_content_id; /* content id */
786 char const *a_content_description; /* content description */
787 char const *a_input_charset; /* Interpretation depends on .a_conv */
788 char const *a_charset; /* ... */
789 FILE *a_tmpf; /* If AC_TMPFILE */
790 enum attach_conv a_conv; /* User chosen conversion */
791 int a_msgno; /* message number */
794 struct group {
795 struct group *ge_link; /* Next person in this group */
796 char *ge_name; /* This person's user name */
799 struct grouphead {
800 struct grouphead *g_link; /* Next grouphead in list */
801 char *g_name; /* Name of this group */
802 struct group *g_list; /* Users in group. */
806 * Structure of the hash table of ignored header fields
808 struct ignoretab {
809 int i_count; /* Number of entries */
810 struct ignore {
811 struct ignore *i_link; /* Next ignored field in bucket */
812 char *i_field; /* This ignored field */
813 } *i_head[HSHSIZE];
817 * Token values returned by the scanner used for argument lists.
818 * Also, sizes of scanner-related things.
820 enum ltoken {
821 TEOL = 0, /* End of the command line */
822 TNUMBER = 1, /* A message number */
823 TDASH = 2, /* A simple dash */
824 TSTRING = 3, /* A string (possibly containing -) */
825 TDOT = 4, /* A "." */
826 TUP = 5, /* An "^" */
827 TDOLLAR = 6, /* A "$" */
828 TSTAR = 7, /* A "*" */
829 TOPEN = 8, /* An '(' */
830 TCLOSE = 9, /* A ')' */
831 TPLUS = 10, /* A '+' */
832 TERROR = 11, /* A lexical error */
833 TCOMMA = 12, /* A ',' */
834 TSEMI = 13, /* A ';' */
835 TBACK = 14 /* A '`' */
838 #define REGDEP 2 /* Maximum regret depth. */
841 * Constants for conditional commands. These describe whether
842 * we should be executing stuff or not.
844 enum condition {
845 CANY = 0, /* Execute in send or receive mode */
846 CRCV = 1, /* Execute in receive mode only */
847 CSEND = 2, /* Execute in send mode only */
848 CTERM = 3, /* Execute only if stdin is a tty */
849 CNONTERM= 4 /* Execute only if stdin not tty */
853 * For the 'shortcut' and 'unshortcut' functionality.
855 struct shortcut {
856 struct shortcut *sh_next; /* next shortcut in list */
857 char *sh_short; /* shortcut string */
858 char *sh_long; /* expanded form */
862 * Kludges to handle the change from setexit / reset to setjmp / longjmp
864 #define setexit() (void)sigsetjmp(srbuf, 1)
865 #define reset(x) siglongjmp(srbuf, x)
868 * Content-Transfer-Encodings as defined in RFC 2045:
869 * - Quoted-Printable, section 6.7
870 * - Base64, section 6.8
873 #define QP_LINESIZE (4 * 19 +1) /* Max. compliant QP linesize (+1) */
875 #define B64_LINESIZE (4 * 19 +1) /* Max. compl. Base64 linesize (+1) */
876 #define B64_ENCODE_INPUT_PER_LINE 57 /* Max. input for Base64 encode/line */
878 /* xxx QP came later, maybe rewrite all to use mimecte_flags directly? */
879 enum __mimecte_flags {
880 MIMECTE_NONE,
881 MIMECTE_SALLOC = 1<<0, /* Use salloc(), not srealloc().. */
882 /* ..result .s,.l point to user buffer of *_LINESIZE+ bytes instead */
883 MIMECTE_BUF = 1<<1,
884 MIMECTE_CRLF = 1<<2, /* (encode) Append "\r\n" to lines */
885 MIMECTE_LF = 1<<3, /* (encode) Append "\n" to lines */
886 /* (encode) If one of _CRLF/_LF is set, honour *_LINESIZE and
887 * inject the desired line-ending whenever a linewrap is desired */
888 MIMECTE_MULTILINE = 1<<4,
889 /* (encode) Quote with header rules, do not generate soft NL breaks? */
890 MIMECTE_ISHEAD = 1<<5
893 enum qpflags {
894 QP_NONE = MIMECTE_NONE,
895 QP_SALLOC = MIMECTE_SALLOC,
896 QP_BUF = MIMECTE_BUF,
897 QP_ISHEAD = MIMECTE_ISHEAD
900 enum b64flags {
901 B64_NONE = MIMECTE_NONE,
902 B64_SALLOC = MIMECTE_SALLOC,
903 B64_BUF = MIMECTE_BUF,
904 B64_CRLF = MIMECTE_CRLF,
905 B64_LF = MIMECTE_LF,
906 B64_MULTILINE = MIMECTE_MULTILINE
910 * Locale-independent character classes.
913 enum {
914 C_CNTRL = 0000,
915 C_BLANK = 0001,
916 C_WHITE = 0002,
917 C_SPACE = 0004,
918 C_PUNCT = 0010,
919 C_OCTAL = 0020,
920 C_DIGIT = 0040,
921 C_UPPER = 0100,
922 C_LOWER = 0200
925 extern uc_it const class_char[];
927 #define __ischarof(C, FLAGS) \
928 (asciichar(C) && (class_char[(uc_it)(C)] & (FLAGS)) != 0)
930 #define asciichar(c) ((uc_it)(c) <= 0177)
931 #define alnumchar(c) __ischarof(c, C_DIGIT|C_OCTAL|C_UPPER|C_LOWER)
932 #define alphachar(c) __ischarof(c, C_UPPER|C_LOWER)
933 #define blankchar(c) __ischarof(c, C_BLANK)
934 #define blankspacechar(c) __ischarof(c, C_BLANK|C_SPACE)
935 #define cntrlchar(c) __ischarof(c, C_CNTRL)
936 #define digitchar(c) __ischarof(c, C_DIGIT|C_OCTAL)
937 #define lowerchar(c) __ischarof(c, C_LOWER)
938 #define punctchar(c) __ischarof(c, C_PUNCT)
939 #define spacechar(c) __ischarof(c, C_BLANK|C_SPACE|C_WHITE)
940 #define upperchar(c) __ischarof(c, C_UPPER)
941 #define whitechar(c) __ischarof(c, C_BLANK|C_WHITE)
942 #define octalchar(c) __ischarof(c, C_OCTAL)
944 #define upperconv(c) (lowerchar(c) ? (char)((uc_it)(c) - 'a' + 'A') : (c))
945 #define lowerconv(c) (upperchar(c) ? (char)((uc_it)(c) - 'A' + 'a') : (c))
946 /* RFC 822, 3.2. */
947 #define fieldnamechar(c) \
948 (asciichar(c) && (c) > 040 && (c) != 0177 && (c) != ':')
951 * Try to use alloca() for some function-local buffers and data,
952 * fall back to smalloc()/free() if not available.
954 #ifdef HAVE_ALLOCA
955 # define ac_alloc(n) HAVE_ALLOCA(n)
956 # define ac_free(n) do {} while (0)
957 #else
958 # define ac_alloc(n) smalloc(n)
959 # define ac_free(n) free(n)
960 #endif
963 * Single-threaded, use unlocked I/O.
965 #ifdef HAVE_PUTC_UNLOCKED
966 # undef getc
967 # define getc(c) getc_unlocked(c)
968 # undef putc
969 # define putc(c, f) putc_unlocked(c, f)
970 # undef putchar
971 # define putchar(c) putc_unlocked((c), stdout)
972 #endif
975 * Truncate a file to the last character written. This is
976 * useful just before closing an old file that was opened
977 * for read/write.
979 #define ftrunc(stream) do {\
980 off_t off;\
981 fflush(stream);\
982 off = ftell(stream);\
983 if (off >= 0)\
984 ftruncate(fileno(stream), off);\
985 } while (0)
988 * fflush() and rewind()
990 #define fflush_rewind(stream) do { \
991 fflush(stream); \
992 rewind(stream); \
993 } while (0)
996 * For saving the current directory and later returning.
998 struct cw {
999 #ifdef HAVE_FCHDIR
1000 int cw_fd;
1001 #else
1002 char cw_wd[MAXPATHLEN];
1003 #endif
1007 * Global variable declarations
1009 * These become instantiated in main.c.
1012 #ifdef _MAIN_SOURCE
1013 # undef _E
1014 # define _E
1015 #else
1016 # define _E extern
1017 #endif
1019 _E gid_t effectivegid; /* Saved from when we started up */
1020 _E gid_t realgid; /* Saved from when we started up */
1022 _E int mb_cur_max; /* value of MB_CUR_MAX */
1023 _E int realscreenheight; /* the real screen height */
1024 _E int scrnwidth; /* Screen width, or best guess */
1025 _E int scrnheight; /* Screen height, or best guess,
1026 * for "header" command */
1027 _E int utf8; /* UTF-8 encoding in use for locale */
1028 _E int enc_has_state; /* Encoding has shift states */
1030 _E char **altnames; /* List of alternate names for user */
1031 _E char const *homedir; /* Path name of home directory */
1032 _E char const *myname; /* My login name */
1033 _E char const *progname; /* Our name */
1034 _E char const *tempdir; /* The temporary directory */
1036 _E int exit_status; /* Exit status */
1037 _E int options; /* Bits of enum user_options */
1038 _E char *option_u_arg; /* name given with -u option */
1039 _E char *option_r_arg; /* argument to -r option */
1040 _E char const **smopts; /* sendmail(1) options, command line */
1041 _E size_t smopts_count; /* Entries in smopts */
1043 /* TODO Join as many of these state machine bits into a single carrier! */
1044 _E int inhook; /* currently executing a hook */
1045 _E bool_t exec_last_comm_error; /* Last execute() command failed */
1046 _E bool_t edit; /* Indicates editing a file */
1047 _E bool_t did_print_dot; /* current message has been printed */
1048 _E bool_t msglist_is_single; /* Last NDMLIST/MSGLIST *chose* 1 msg */
1049 _E bool_t loading; /* Loading user definitions */
1050 _E bool_t sourcing; /* Currently reading variant file */
1051 _E bool_t sawcom; /* Set after first command */
1052 _E bool_t starting; /* still in startup code */
1053 _E bool_t unset_allow_undefined; /* allow to unset undefined variables */
1054 _E int noreset; /* String resets suspended */
1056 /* XXX stylish sorting */
1057 _E int msgCount; /* Count of messages read in */
1058 _E enum condition cond; /* Current state of conditional exc. */
1059 _E struct mailbox mb; /* Current mailbox */
1060 _E int image; /* File descriptor for image of msg */
1061 _E char mailname[MAXPATHLEN]; /* Name of current file */
1062 _E char displayname[80 - 40]; /* Prettyfied for display */
1063 _E char prevfile[MAXPATHLEN]; /* Name of previous file */
1064 _E char mboxname[MAXPATHLEN]; /* Name of mbox */
1065 _E char const * account_name; /* Current account name or NULL */
1066 _E off_t mailsize; /* Size of system mailbox */
1067 _E struct message *dot; /* Pointer to current message */
1068 _E struct message *prevdot; /* Previous current message */
1069 _E struct message *message; /* The actual message structure */
1070 _E struct message *threadroot; /* first threaded message */
1071 _E int msgspace; /* Number of allocated struct m */
1072 _E struct grouphead *groups[HSHSIZE]; /* Pointer to active groups */
1073 _E struct ignoretab ignore[2]; /* ignored and retained fields
1074 * 0 is ignore, 1 is retain */
1075 _E struct ignoretab saveignore[2]; /* ignored and retained fields
1076 * on save to folder */
1077 _E struct ignoretab allignore[2]; /* special, ignore all headers */
1078 _E struct ignoretab fwdignore[2]; /* fields to ignore for forwarding */
1079 _E struct shortcut *shortcuts; /* list of shortcuts */
1080 _E int imap_created_mailbox; /* hack to get feedback from imap */
1082 _E struct time_current time_current; /* time(3); send: mail1() XXX->carrier*/
1083 _E struct termios_state termios_state; /* getpassword(); see commands().. */
1085 /* These are initialized strings */
1086 _E char const month_names[12 + 1][4];
1087 _E char const weekday_names[7 + 1][4];
1089 _E char const uagent[]; /* User agent */
1090 _E char const version[]; /* The version string */
1092 #ifdef HAVE_SSL
1093 _E enum ssl_vrfy_level ssl_vrfy_level; /* SSL verification level */
1094 #endif
1096 #ifdef HAVE_ICONV
1097 _E iconv_t iconvd;
1098 #endif
1100 #ifdef HAVE_CATGETS
1101 _E nl_catd catd;
1102 #endif
1104 _E sigjmp_buf srbuf;
1105 _E int interrupts;
1106 _E sighandler_type handlerstacktop;
1107 #define handlerpush(f) (savedtop = handlerstacktop, handlerstacktop = (f))
1108 #define handlerpop() (handlerstacktop = savedtop)
1109 _E sighandler_type dflpipe;
1111 #undef _E
1114 * Finally, let's include the function prototypes XXX embed
1116 #include "extern.h"