1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
|
/* mh.h -- main header file for all of nmh
*/
#include "nmh.h"
/* It's undefined behaviour in C99 to convert from a function pointer to
* a data-object pointer, e.g. void pointer. gcc's -pedantic warns of
* this and can stop compilation. POSIX requires the operation however,
* e.g. for dlsym(3), and so we know it's safe on POSIX platforms, e.g.
* the pointers are of the same size. Thus use a union to subvert gcc's
* check. The function-pointer equivalent of a void pointer is any
* function-pointer type as all function pointers are defined to be
* convertible from one another; use the simplest available. */
typedef union {
void *v;
void (*f)(void);
} generic_pointer;
/*
* Well-used constants
*/
#define NOTOK (-1) /* syscall()s return this on error */
#define OK 0 /* ditto on success */
#define DONE 1 /* ternary logic */
#define MAXARGS 1000 /* max arguments to exec */
#define NFOLDERS 1000 /* max folder arguments on command line */
#define DMAXFOLDER 4 /* typical number of digits */
#define MAXFOLDER 1000 /* message increment */
/*
* This macro is for use by scan, for example, so that platforms with
* a small BUFSIZ can easily allocate larger buffers.
*/
#define NMH_BUFSIZ max(BUFSIZ, 8192)
/* If we're using gcc then tell it extra information so it can do more
* compile-time checks. */
#if __GNUC__ > 2
#define NORETURN __attribute__((__noreturn__))
#define CONST __attribute__((const))
#define MALLOC __attribute__((malloc))
#define NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
#define PURE __attribute__((pure))
#define ENDNULL __attribute__((sentinel))
#else
#define NORETURN
#define CHECK_PRINTF(fmt, arg)
#define ALLOC_SIZE(...)
#define CONST
#define MALLOC
#define NONNULL(...)
#define PURE
#define ENDNULL
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
#define ALLOC_SIZE(...) __attribute__((alloc_size(__VA_ARGS__)))
#define CHECK_PRINTF(fmt, arg) __attribute__((format(printf, fmt, arg)))
#else
#define ALLOC_SIZE(...)
#define CHECK_PRINTF(fmt, arg)
#endif
/* Silence the compiler's "unused variable" warning. */
#define NMH_UNUSED(i) (void)i
/* DIM gives the number of elements in the one-dimensional array a. */
#define DIM(a) (sizeof (a) / sizeof (*(a)))
/* LEN gives the strlen() of string constant s, excluding the
* terminating NUL. */
#define LEN(s) (sizeof (s) - 1)
/* FENDNULL fends off NULL by giving an empty string instead. */
#define FENDNULL(s) ((s) ? (s) : "")
/* If not specified in a file and PAGER is NULL or empty. */
#define DEFAULT_PAGER "more"
/*
* user context/profile structure
*/
struct node {
char *n_name; /* key */
char *n_field; /* value */
char n_context; /* context, not profile */
struct node *n_next; /* next entry */
};
/*
* switches structure
*/
#define AMBIGSW (-2) /* from smatch() on ambiguous switch */
#define UNKWNSW (-1) /* from smatch() on unknown switch */
struct swit {
/*
* Switch name
*/
char *sw;
/*
* The previous comments here about minchars was incorrect; this is
* (AFAIK) the correct information.
*
* A minchars of "0" means this switch can be abbreviated to any number
* of characters (assuming the abbreviation does not match any other
* switches).
*
* A positive value for minchars means that when the user specifies
* the switch on the command line, it MUST be at least that many
* characters.
*
* A negative value for minchars means that the user-given switch must
* be that many characters, but will NOT be shown in -help output.
*
* So what should I use? Well, for nearly all switches you want to specify
* a minchars of 0. smatch will report an error if the switch given
* matches more than one entry. Let's say you have the following
* two switches: -append and -apply. -app will return AMBIGSW from
* smatch. -appe and -appl will work fine. So 0 is the correct choice
* here.
*
* The only time you want to specify a minimum length is if you have
* a switch who's name is a substring of a longer switch. The example
* you see sometimes in the code is -form and -format. If you gave a
* minchars of 0 for both, -form would match both -form AND -format,
* and you'd always get AMBIGSW. The solution is to specify a minchars
* of 5 for -format; that way just -form will just match -form. When
* a minchars is given, the -help output will specify the minimum
* switch length, like this:
*
* -(forma)t string
*
* A negative value works the same way, except the switch isn't printed
* in -help. Why would you do that? Well, there are a few instances
* of internal switches and some switches which only appear if a particular
* feature is enabled (such as SASL or TLS). Lately I've been of the
* opinion that all switches should be specified, even if they are
* internal or use non-available features, but currently the smatch
* code still supports this.
*
* This isn't the appropriate place to make this note, but since I was
* here ... when creating switches, you should make a negation switch
* right after the enabling switch. E.g. you should have:
*
* X("sasl", 0, SASLSW) \
* X("nosasl", 0, NOSASLSW) \
*
* in the switch array, because when you run -help, print_sw will detect
* this and output:
*
* -[no]sasl
*/
int minchars;
/*
* If we pick this switch, return this value from smatch
*/
int swret;
};
/*
* Macros to use when declaring struct swit arrays.
*
* These macros use a technique known as X-Macros. In your source code you
* use them like this:
*
* #define FOO_SWITCHES \
* X("switch1", 0, SWITCHSW) \
* X("switch2", 0, SWITCH2SW) \
* X("thirdswitch", 2, SWITCH3SW) \
*
* The argument to each entry in FOO_SWITCHES are the switch name (sw),
* the minchars field (see above) and the return value for this switch.
* Note that the last entry in the above definition must either omit the
* continuation backslash, or be followed by a blank line. In the nmh
* code the style is to have every line include a backslash and follow
* the SWITCHES macro definition by a blank line.
*
* After you define FOO_SWITCHES, you instantiate it as follows:
*
* #define X(sw, minchars, id) id,
* DEFINE_SWITCH_ENUM(FOO);
* #undef X
*
* #define X(sw, minchars, id) { sw, minchars, id },
* DEFINE_SWITCH_ARRAY(FOO);
* #undef X
*
* DEFINE_SWITCH_ENUM defines an extra enum at the end of the list called
* LEN_FOO.
*/
#define DEFINE_SWITCH_ENUM(name) \
enum { \
name ## _SWITCHES \
LEN_ ## name \
}
#define DEFINE_SWITCH_ARRAY(name, array) \
static struct swit array[] = { \
name ## _SWITCHES \
{ NULL, 0, 0 } \
}
/*
* general folder attributes
*/
#define READONLY (1<<0) /* No write access to folder */
#define SEQMOD (1<<1) /* folder's sequences modified */
#define ALLOW_NEW (1<<2) /* allow the "new" sequence */
#define OTHERS (1<<3) /* folder has other files */
#define FBITS "\020\01READONLY\02SEQMOD\03ALLOW_NEW\04OTHERS"
/*
* first free slot for user defined sequences
* and attributes
*/
#define FFATTRSLOT 4
/*
* internal messages attributes (sequences)
*/
#define EXISTS (0) /* exists */
#define SELECTED (1) /* selected for use */
#define SELECT_EMPTY (2) /* "new" message */
#define SELECT_UNSEEN (3) /* inc/show "unseen" */
#define MBITS "\020\01EXISTS\02SELECTED\03NEW\04UNSEEN"
#include "sbr/vector.h"
/*
* Primary structure of folder/message information
*/
struct msgs {
int lowmsg; /* Lowest msg number */
int hghmsg; /* Highest msg number */
int nummsg; /* Actual Number of msgs */
int lowsel; /* Lowest selected msg number */
int hghsel; /* Highest selected msg number */
int numsel; /* Number of msgs selected */
int curmsg; /* Number of current msg if any */
int msgflags; /* Folder attributes (READONLY, etc) */
char *foldpath; /* Pathname of folder */
/*
* Name of sequences in this folder.
*/
svector_t msgattrs;
/*
* bit flags for whether sequence
* is public (0), or private (1)
*/
bvector_t attrstats;
/*
* These represent the lowest and highest possible
* message numbers we can put in the message status
* area, without calling folder_realloc().
*/
int lowoff;
int hghoff;
/*
* This is an array of bvector_t which we allocate dynamically.
* Each bvector_t is a set of bits flags for a particular message.
* These bit flags represent general attributes such as
* EXISTS, SELECTED, etc. as well as track if message is
* in a particular sequence.
*/
size_t num_msgstats;
struct bvector *msgstats; /* msg status */
/*
* A FILE handle containing an open filehandle for the sequence file
* for this folder. If non-NULL, use it when the sequence file is
* written.
*/
FILE *seqhandle;
/*
* The name of the public sequence file; required by lkfclose()
*/
char *seqname;
};
/*
* Amount of space to allocate for msgstats. Allocate
* the array to have space for messages numbered lo to hi.
* Use MSGSTATNUM to load mp->num_msgstats first.
*/
#define MSGSTATNUM(lo, hi) ((size_t) ((hi) - (lo) + 1))
#define MSGSTATSIZE(mp) ((mp)->num_msgstats * sizeof *(mp)->msgstats)
/*
* macros for message and sequence manipulation
*/
#define msgstat(mp,n) ((mp)->msgstats + (n) - mp->lowoff)
#define clear_msg_flags(mp,msgnum) bvector_clear_all (msgstat(mp, msgnum))
#define copy_msg_flags(mp,i,j) bvector_copy (msgstat(mp,i), msgstat(mp,j))
#define get_msg_flags(mp,ptr,msgnum) bvector_copy (ptr, msgstat(mp, msgnum))
#define set_msg_flags(mp,ptr,msgnum) bvector_copy (msgstat(mp, msgnum), ptr)
#define does_exist(mp,msgnum) bvector_at (msgstat(mp, msgnum), EXISTS)
#define unset_exists(mp,msgnum) bvector_clear (msgstat(mp, msgnum), EXISTS)
#define set_exists(mp,msgnum) bvector_set (msgstat(mp, msgnum), EXISTS)
#define is_selected(mp,msgnum) bvector_at (msgstat(mp, msgnum), SELECTED)
#define unset_selected(mp,msgnum) bvector_clear (msgstat(mp, msgnum), SELECTED)
#define set_selected(mp,msgnum) bvector_set (msgstat(mp, msgnum), SELECTED)
#define is_select_empty(mp,msgnum) \
bvector_at (msgstat(mp, msgnum), SELECT_EMPTY)
#define set_select_empty(mp,msgnum) \
bvector_set (msgstat(mp, msgnum), SELECT_EMPTY)
#define is_unseen(mp,msgnum) \
bvector_at (msgstat(mp, msgnum), SELECT_UNSEEN)
#define unset_unseen(mp,msgnum) \
bvector_clear (msgstat(mp, msgnum), SELECT_UNSEEN)
#define set_unseen(mp,msgnum) \
bvector_set (msgstat(mp, msgnum), SELECT_UNSEEN)
#define in_sequence(mp,seqnum,msgnum) \
bvector_at (msgstat(mp, msgnum), FFATTRSLOT + seqnum)
#define clear_sequence(mp,seqnum,msgnum) \
bvector_clear (msgstat(mp, msgnum), FFATTRSLOT + seqnum)
#define add_sequence(mp,seqnum,msgnum) \
bvector_set (msgstat(mp, msgnum), FFATTRSLOT + seqnum)
#define is_seq_private(mp,seqnum) \
bvector_at (mp->attrstats, FFATTRSLOT + seqnum)
#define make_seq_public(mp,seqnum) \
bvector_clear (mp->attrstats, FFATTRSLOT + seqnum)
#define make_seq_private(mp,seqnum) \
bvector_set (mp->attrstats, FFATTRSLOT + seqnum)
#define make_all_public(mp) \
mp->attrstats = bvector_create(); bvector_clear_all (mp->attrstats)
/*
* macros for folder attributes
*/
#define clear_folder_flags(mp) ((mp)->msgflags = 0)
#define is_readonly(mp) ((mp)->msgflags & READONLY)
#define set_readonly(mp) ((mp)->msgflags |= READONLY)
#define other_files(mp) ((mp)->msgflags & OTHERS)
#define set_other_files(mp) ((mp)->msgflags |= OTHERS)
/*
* m_getfld() message parsing
*/
#define NAMESZ 999 /* Limit on component name size.
RFC 2822 limits line lengths to
998 characters, so a header name
can be at most that long.
m_getfld limits header names to 2
less than NAMESZ, which is fine,
because header names must be
followed by a colon. Add one for
terminating NULL. */
/* Token type or error returned from m_getfld(), and its internal state
* for the next call. */
/* FLD detects the header's name is too long to fit in the fixed size
* array. */
#define LENERR (-2)
/* FLD reaches EOF after the header's name, or the name is followed by
* a linefeed rather than a colon and the body buffer isn't large enough
* to pretend this header line starts the body. */
#define FMTERR (-3)
/* The initial state, looking for headers. Returned when the header's
* value finishes. */
#define FLD 0
/* Another chunk of the header's value has been returned, but there's
* more to come. */
#define FLDPLUS 1
/* A chunk of the email's body has been returned. */
#define BODY 3
/* Either the end of the input file has been reached, or the delimiter
* between emails has been found and the caller should
* m_getfld_state_reset() to reset the state to FLD for continuing
* through the file. */
#define FILEEOF 5
typedef struct m_getfld_state *m_getfld_state_t;
#define NOUSE 0 /* draft being re-used */
#define TFOLDER 0 /* path() given a +folder */
#define TFILE 1 /* path() given a file */
#define TSUBCWF 2 /* path() given a @folder */
#define OUTPUTLINELEN 72 /* default line length for headers */
#define LINK "@" /* Name of link to file to which you are */
/* replying. */
/*
* credentials management
*/
typedef struct nmh_creds *nmh_creds_t;
/*
* miscellaneous macros
*/
#define pidXwait(pid,cp) pidstatus (pidwait (pid, NOTOK), stdout, cp)
#ifndef max
# define max(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
# define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef abs
# define abs(a) ((a) > 0 ? (a) : -(a))
#endif
|