/*
 * Program:	Mailbox Access routines
 *
 * Author:	Mark Crispin
 *		Networks and Distributed Computing
 *		Computing & Communications
 *		University of Washington
 *		Administration Building, AG-44
 *		Seattle, WA  98195
 *		Internet: MRC@CAC.Washington.EDU
 *
 * Date:	22 November 1989
 * Last Edited:	4 January 1996
 *
 * Copyright 1996 by the University of Washington
 *
 *  Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appears in all copies and that both the
 * above copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the University of Washington not be
 * used in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  This software is made
 * available "as is", and
 * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
 * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
 * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/* Build parameters */

#define CACHEINCREMENT 100	/* cache growth increments */
#define MAILTMPLEN 1024		/* size of a temporary buffer */
#define MAXMESSAGESIZE 65000	/* MS-DOS: maximum text buffer size
				 * other:  initial text buffer size */
#define NUSERFLAGS 30		/* # of user flags (current servers 30 max) */
#define BASEYEAR 1969		/* the year time began */
				/* default for unqualified addresses */
#define BADHOST ".MISSING-HOST-NAME."


/* Coddle certain compilers' 6-character symbol limitation */

#ifdef __COMPILER_KCC__
#include "shortsym.h"
#endif


/* Constants */

#define NIL 0			/* convenient name */
#define T 1			/* opposite of NIL */
#define LONGT (long) 1		/* long T */

#define WARN (long) 1		/* mm_log warning type */
#define ERROR (long) 2		/* mm_log error type */
#define PARSE (long) 3		/* mm_log parse error type */
#define BYE (long) 4		/* mm_notify stream dying */

#define DELIM '\377'		/* strtok delimiter character */


/* Bits from mail_parse_flags().  Don't change these, since the header format
 * used by tenex, mtx, dawz, and tenexdos corresponds to these bits.
 */

#define fSEEN 1
#define fDELETED 2
#define fFLAGGED 4
#define fANSWERED 8
#define fOLD 16
#define fDRAFT 32


/* Bits for mm_list() and mm_lsub() */

#define LATT_NOINFERIORS (long) 1
#define LATT_NOSELECT (long) 2
#define LATT_MARKED (long) 4
#define LATT_UNMARKED (long) 8

/* Global and Driver Parameters */

	/* 0xx: driver flags */
#define ENABLE_DRIVER (long) 1
#define DISABLE_DRIVER (long) 2
	/* 1xx: c-client globals */
#define GET_DRIVERS (long) 101
#define SET_DRIVERS (long) 102
#define GET_GETS (long) 103
#define SET_GETS (long) 104
#define GET_CACHE (long) 105
#define SET_CACHE (long) 106
	/* 2xx: environment */
#define GET_USERNAME (long) 201
#define SET_USERNAME (long) 202
#define GET_HOMEDIR (long) 203
#define SET_HOMEDIR (long) 204
#define GET_LOCALHOST (long) 205
#define SET_LOCALHOST (long) 206
#define GET_SYSINBOX (long) 207
#define SET_SYSINBOX (long) 208
	/* 3xx: TCP/IP */
#define GET_OPENTIMEOUT (long) 300
#define SET_OPENTIMEOUT (long) 301
#define GET_READTIMEOUT (long) 302
#define SET_READTIMEOUT (long) 303
#define GET_WRITETIMEOUT (long) 304
#define SET_WRITETIMEOUT (long) 305
#define GET_CLOSETIMEOUT (long) 306
#define SET_CLOSETIMEOUT (long) 307
#define GET_TIMEOUT (long) 308
#define SET_TIMEOUT (long) 309
	/* 4xx: network drivers */
#define GET_MAXLOGINTRIALS (long) 400
#define SET_MAXLOGINTRIALS (long) 401
#define GET_LOOKAHEAD (long) 402
#define SET_LOOKAHEAD (long) 403
#define GET_IMAPPORT (long) 404
#define SET_IMAPPORT (long) 405
#define GET_PREFETCH (long) 406
#define SET_PREFETCH (long) 407
#define GET_CLOSEONERROR (long) 408
#define SET_CLOSEONERROR (long) 409
#define GET_POP3PORT (long) 410
#define SET_POP3PORT (long) 411
#define GET_UIDLOOKAHEAD (long) 412
#define SET_UIDLOOKAHEAD (long) 413
	/* 5xx: local file drivers */
#define GET_MBXPROTECTION (long) 500
#define SET_MBXPROTECTION (long) 501
#define GET_DIRPROTECTION (long) 502
#define SET_DIRPROTECTION (long) 503
#define GET_LOCKPROTECTION (long) 504
#define SET_LOCKPROTECTION (long) 505
#define GET_FROMWIDGET (long) 506
#define SET_FROMWIDGET (long) 507
#define GET_NEWSACTIVE (long) 508
#define SET_NEWSACTIVE (long) 509
#define GET_NEWSSPOOL (long) 510
#define SET_NEWSSPOOL (long) 511
#define GET_NEWSRC (long) 512
#define SET_NEWSRC (long) 513
#define GET_EXTENSION (long) 514
#define SET_EXTENSION (long) 515
#define GET_DISABLEFCNTLLOCK (long) 516
#define SET_DISABLEFCNTLLOCK (long) 517
#define GET_LOCKEACCESERROR (long) 518
#define SET_LOCKEACCESERROR (long) 519
#define GET_LISTMAXLEVEL (long) 520
#define SET_LISTMAXLEVEL (long) 521

#ifndef WOGGLE
#define SET_IMAP2FINDALL (long) 888
#endif /* WOGGLE */


/* Driver flags */

#define DR_DISABLE (long) 1	/* driver is disabled */
#define DR_LOCAL (long) 2	/* local file driver */
#define DR_MAIL (long) 4	/* supports mail */
#define DR_NEWS (long) 8	/* supports news */
#define DR_READONLY (long) 16	/* driver only allows readonly access */
#define DR_NOFAST (long) 32	/* "fast" data is slow (whole msg fetch) */
#define DR_NAMESPACE (long) 64	/* driver accepts namespace format names */
#define DR_LOWMEM (long) 128	/* low amounts of memory available */


/* Cache management function codes */

#define CH_INIT (long) 10	/* initialize cache */
#define CH_SIZE (long) 11	/* (re-)size the cache */
#define CH_MAKELELT (long) 20	/* return long elt, make if needed */
#define CH_LELT (long) 21	/* return long elt if exists */
#define CH_MAKEELT (long) 30	/* return short elt, make if needed */
#define CH_ELT (long) 31	/* return short elt if exists */
#define CH_FREE (long) 40	/* free space used by elt */
#define CH_EXPUNGE (long) 45	/* delete elt pointer from list */


/* Open options */

#define OP_DEBUG (long) 1	/* debug protocol negotiations */
#define OP_READONLY (long) 2	/* read-only open */
#define OP_ANONYMOUS (long) 4	/* anonymous open of newsgroup */
#define OP_SHORTCACHE (long) 8	/* short (elt-only) caching */
#define OP_SILENT (long) 16	/* don't pass up events (internal use) */
#define OP_PROTOTYPE (long) 32	/* return driver prototype */
#define OP_HALFOPEN (long) 64	/* half-open (IMAP connect but no select) */
#define OP_EXPUNGE (long) 128	/* silently expunge recycle stream */


/* Close options */

#define CL_EXPUNGE (long) 1	/* expunge silently */


/* Fetch options */

#define FT_UID (long) 1		/* argument is a UID */
#define FT_PEEK (long) 2	/* peek at data */
#define FT_NOT (long) 4		/* NOT flag for header lines fetch */
#define FT_INTERNAL (long) 8	/* text can be internal strings */
#define FT_PREFETCHTEXT (long) 16 /* IMAP prefetch text when fetching header */


/* Store options */

#define ST_UID (long) 1		/* argument is a UID sequence */
#define ST_SILENT (long) 2	/* don't return results */

/* Copy options */

#define CP_UID (long) 1		/* argument is a UID sequence */
#define CP_MOVE (long) 2	/* delete from source after copying */


/* Search options */

#define SE_UID (long) 1		/* return UID */
#define SE_FREE (long) 2	/* free search program after finished */
#define SE_NOPREFETCH (long) 4	/* no search prefetching */


/* Status options */

#define SA_MESSAGES (long) 1	/* number of messages */
#define SA_RECENT (long) 2	/* number of recent messages */
#define SA_UNSEEN (long) 4	/* number of unseen messages */
#define SA_UIDNEXT (long) 8	/* next UID to be assigned */
#define SA_UIDVALIDITY (long) 16/* UID validity value */


/* Garbage collection flags */

#define GC_ELT (long) 1		/* message cache elements */
#define GC_ENV (long) 2		/* envelopes and bodies */
#define GC_TEXTS (long) 4	/* cached texts */

/* Message structures */


/* Item in an address list */
	
#define ADDRESS struct mail_address
ADDRESS {
  char *personal;		/* personal name phrase */
  char *adl;			/* at-domain-list source route */
  char *mailbox;		/* mailbox name */
  char *host;			/* domain name of mailbox's host */
  char *error;			/* error in address from SMTP module */
  ADDRESS *next;		/* pointer to next address in list */
};


/* Message envelope */

typedef struct mail_envelope {
  char *remail;			/* remail header if any */
  ADDRESS *return_path;		/* error return address */
  char *date;			/* message composition date string */
  ADDRESS *from;		/* originator address list */
  ADDRESS *sender;		/* sender address list */
  ADDRESS *reply_to;		/* reply address list */
  char *subject;		/* message subject string */
  ADDRESS *to;			/* primary recipient list */
  ADDRESS *cc;			/* secondary recipient list */
  ADDRESS *bcc;			/* blind secondary recipient list */
  char *in_reply_to;		/* replied message ID */
  char *message_id;		/* message ID */
  char *newsgroups;		/* USENET newsgroups */
  char *followup_to;		/* USENET reply newsgroups */
  char *references;		/* USENET references */
} ENVELOPE;

/* Primary body types */
/* If you change any of these you must also change body_types in rfc822.c */

extern char *body_types[];	/* defined body type strings */

#define TYPETEXT 0		/* unformatted text */
#define TYPEMULTIPART 1		/* multiple part */
#define TYPEMESSAGE 2		/* encapsulated message */
#define TYPEAPPLICATION 3	/* application data */
#define TYPEAUDIO 4		/* audio */
#define TYPEIMAGE 5		/* static image */
#define TYPEVIDEO 6		/* video */
#define TYPEOTHER 7		/* unknown */
#define TYPEMAX 15		/* maximum type code */


/* Body encodings */
/* If you change any of these you must also change body_encodings in rfc822.c
 */

extern char *body_encodings[];	/* defined body encoding strings */

#define ENC7BIT 0		/* 7 bit SMTP semantic data */
#define ENC8BIT 1		/* 8 bit SMTP semantic data */
#define ENCBINARY 2		/* 8 bit binary data */
#define ENCBASE64 3		/* base-64 encoded data */
#define ENCQUOTEDPRINTABLE 4	/* human-readable 8-as-7 bit data */
#define ENCOTHER 5		/* unknown */
#define ENCMAX 10		/* maximum encoding code */


/* Body contents */

#define BINARY void
#define BODY struct mail_body
#define MESSAGE struct mail_body_message
#define PARAMETER struct mail_body_parameter
#define PART struct mail_body_part

/* Message content (ONLY for parsed messages) */

MESSAGE {
  ENVELOPE *env;		/* message envelope */
  BODY *body;			/* message body */
  char *hdr;			/* message header */
  unsigned long hdrsize;	/* message header size */
  char *text;			/* message in RFC-822 form */
  unsigned long offset;		/* offset of text from header */
};


/* Parameter list */

PARAMETER {
  char *attribute;		/* parameter attribute name */
  char *value;			/* parameter value */
  PARAMETER *next;		/* next parameter in list */
};


/* Message body structure */

BODY {
  unsigned short type;		/* body primary type */
  unsigned short encoding;	/* body transfer encoding */
  char *subtype;		/* subtype string */
  PARAMETER *parameter;		/* parameter list */
  char *id;			/* body identifier */
  char *description;		/* body description */
  union {			/* different ways of accessing contents */
    unsigned char *text;	/* body text (+ enc. message in composing) */
    BINARY *binary;		/* body binary */
    PART *part;			/* body part list */
    MESSAGE msg;		/* body encapsulated message (PARSE ONLY) */
  } contents;
  struct {
    unsigned long lines;	/* size in lines */
    unsigned long bytes;	/* size in bytes */
    unsigned long ibytes;	/* internal size in bytes (drivers ONLY!!) */
  } size;
  char *md5;			/* MD5 checksum */
};


/* Multipart content list */

PART {
  BODY body;			/* body information for this part */
  unsigned long offset;		/* offset from body origin */
  PART *next;			/* next body part */
};

/* Entry in the message cache array */

typedef struct message_cache {
  unsigned long msgno;		/* message number */
  unsigned long uid;		/* message unique ID */
  /* The next 8 bytes is ordered in this way so that it will be reasonable even
   * on a 36-bit machine.  Maybe someday I'll port this to TOPS-20.  ;-)
   */
			/* internal time/zone, system flags (4 bytes) */
  unsigned int hours: 5;	/* hours (0-23) */
  unsigned int minutes: 6;	/* minutes (0-59) */
  unsigned int seconds: 6;	/* seconds (0-59) */
  /* It may seem easier to have zhours be signed.  Unfortunately, a certain
   * cretinous C compiler from a well-known software vendor in Redmond, WA
   * does not allow signed bit fields.
   */
  unsigned int zoccident : 1;	/* non-zero if west of UTC */
  unsigned int zhours : 4;	/* hours from UTC (0-12) */
  unsigned int zminutes: 6;	/* minutes (0-59) */
  unsigned int seen : 1;	/* system Seen flag */
  unsigned int deleted : 1;	/* system Deleted flag */
  unsigned int flagged : 1; 	/* system Flagged flag */
  unsigned int answered : 1;	/* system Answered flag */
			/* flags, lock count (2 bytes) */
  unsigned int draft : 1;	/* system Draft flag */
  unsigned int valid : 1;	/* elt has valid flags */
  unsigned int recent : 1;	/* message is new as of this mailbox open */
  unsigned int searched : 1;	/* message was searched */
  unsigned int sequence : 1;	/* (driver use) message is in sequence */
  unsigned int spare : 1;	/* reserved for use by main program */
  unsigned int spare2 : 1;	/* reserved for use by main program */
  unsigned int spare3 : 1;	/* reserved for use by main program */
  unsigned int lockcount : 8;	/* non-zero if multiple references */
			/* internal date (2 bytes) */
  unsigned int day : 5;		/* day of month (1-31) */
  unsigned int month : 4;	/* month of year (1-12) */
  unsigned int year : 7;	/* year since 1969 (expires 2097) */
  unsigned long user_flags;	/* user-assignable flags */
  unsigned long rfc822_size;	/* # of bytes of message as raw RFC822 */
  unsigned long data1;		/* (driver use) first data item */
  unsigned long data2;		/* (driver use) second data item */
  unsigned long data3;		/* (driver use) third data item */
  unsigned long data4;		/* (driver use) fourth data item */
} MESSAGECACHE;


typedef struct long_cache {
  MESSAGECACHE elt;
  ENVELOPE *env;		/* pointer to message envelope */
  BODY *body;			/* pointer to message body */
} LONGCACHE;

/* String list */

#define STRINGLIST struct string_list

STRINGLIST {
  char *text;			/* string text */
  unsigned long size;		/* string length */
  STRINGLIST *next;
};


/* String structure */

#define STRINGDRIVER struct string_driver

typedef struct mailstring {
  void *data;			/* driver-dependent data */
  unsigned long data1;		/* driver-dependent data */
  unsigned long size;		/* total length of string */
  char *chunk;			/* base address of chunk */
  unsigned long chunksize;	/* size of chunk */
  unsigned long offset;		/* offset of this chunk in base */
  char *curpos;			/* current position in chunk */
  unsigned long cursize;	/* number of bytes remaining in chunk */
  STRINGDRIVER *dtb;		/* driver that handles this type of string */
} STRING;


/* Dispatch table for string driver */

STRINGDRIVER {
				/* initialize string driver */
  void (*init) (STRING *s,void *data,unsigned long size);
				/* get next character in string */
  char (*next) (STRING *s);
				/* set position in string */
  void (*setpos) (STRING *s,unsigned long i);
};


/* Stringstruct access routines */

#define INIT(s,d,data,size) ((*((s)->dtb = &d)->init) (s,data,size))
#define SIZE(s) ((s)->size - GETPOS (s))
#define CHR(s) (*(s)->curpos)
#define SNX(s) (--(s)->cursize ? *(s)->curpos++ : (*(s)->dtb->next) (s))
#define GETPOS(s) ((s)->offset + ((s)->curpos - (s)->chunk))
#define SETPOS(s,i) (*(s)->dtb->setpos) (s,i)

/* Search program */

#define SEARCHPGM struct search_program
#define SEARCHHEADER struct search_header
#define SEARCHSET struct search_set
#define SEARCHOR struct search_or
#define SEARCHPGMLIST struct search_pgm_list


SEARCHHEADER {			/* header search */
  char *line;			/* header line */
  char *text;			/* text in header */
  SEARCHHEADER *next;		/* next in list */
};


SEARCHSET {			/* message set */
  unsigned long first;		/* sequence number */
  unsigned long last;		/* last value, if a range */
  SEARCHSET *next;		/* next in list */
};


SEARCHOR {
  SEARCHPGM *first;		/* first program */
  SEARCHPGM *second;		/* second program */
  SEARCHOR *next;		/* next in list */
};


SEARCHPGMLIST {
  SEARCHPGM *pgm;		/* search program */
  SEARCHPGMLIST *next;		/* next in list */
};

SEARCHPGM {			/* search program */
  SEARCHSET *msgno;		/* message numbers */
  SEARCHSET *uid;		/* unique identifiers */
  SEARCHOR *or;			/* or'ed in programs */
  SEARCHPGMLIST *not;		/* and'ed not program */
  SEARCHHEADER *header;		/* list of headers */
  STRINGLIST *bcc;		/* bcc recipients */
  STRINGLIST *body;		/* text in message body */
  STRINGLIST *cc;		/* cc recipients */
  STRINGLIST *from;		/* originator */
  STRINGLIST *keyword;		/* keywords */
  STRINGLIST *unkeyword;	/* unkeywords */
  STRINGLIST *subject;		/* text in subject */
  STRINGLIST *text;		/* text in headers and body */
  STRINGLIST *to;		/* to recipients */
  unsigned long larger;		/* larger than this size */
  unsigned long smaller;	/* smaller than this size */
  unsigned short sentbefore;	/* sent before this date */
  unsigned short senton;	/* sent on this date */
  unsigned short sentsince;	/* sent since this date */
  unsigned short before;	/* before this date */
  unsigned short on;		/* on this date */
  unsigned short since;		/* since this date */
  unsigned int answered : 1;	/* answered messages */
  unsigned int unanswered : 1;	/* unanswered messages */
  unsigned int deleted : 1;	/* deleted messages */
  unsigned int undeleted : 1;	/* undeleted messages */
  unsigned int draft : 1;	/* message draft */
  unsigned int undraft : 1;	/* message undraft */
  unsigned int flagged : 1;	/* flagged messages */
  unsigned int unflagged : 1;	/* unflagged messages */
  unsigned int recent : 1;	/* recent messages */
  unsigned int old : 1;		/* old messages */
  unsigned int seen : 1;	/* seen messages */
  unsigned int unseen : 1;	/* unseen messages */
};


/* Mailbox status */

typedef struct mbx_status {
  long flags;			/* validity flags */
  unsigned long messages;	/* number of messages */
  unsigned long recent;		/* number of recent messages */
  unsigned long unseen;		/* number of unseen messages */
  unsigned long uidnext;	/* next UID to be assigned */
  unsigned long uidvalidity;	/* UID validity value */
} MAILSTATUS;

/* Mail Access I/O stream */


/* Structure for mail driver dispatch */

#define DRIVER struct driver	


/* Mail I/O stream */
	
typedef struct mail_stream {
  DRIVER *dtb;			/* dispatch table for this driver */
  void *local;			/* pointer to driver local data */
  char *mailbox;		/* mailbox name */
  unsigned short use;		/* stream use count */
  unsigned short sequence;	/* stream sequence */
  unsigned int lock : 1;	/* stream lock flag */
  unsigned int debug : 1;	/* stream debug flag */
  unsigned int silent : 1;	/* silent stream from Tenex */
  unsigned int rdonly : 1;	/* stream read-only flag */
  unsigned int anonymous : 1;	/* stream anonymous access flag */
  unsigned int scache : 1;	/* stream short cache flag */
  unsigned int halfopen : 1;	/* stream half-open flag */
  unsigned int perm_seen : 1;	/* permanent Seen flag */
  unsigned int perm_deleted : 1;/* permanent Deleted flag */
  unsigned int perm_flagged : 1;/* permanent Flagged flag */
  unsigned int perm_answered :1;/* permanent Answered flag */
  unsigned int perm_draft : 1;	/* permanent Draft flag */
  unsigned int kwd_create : 1;	/* can create new keywords */
  unsigned long perm_user_flags;/* mask of permanent user flags */
  unsigned long gensym;		/* generated tag */
  unsigned long nmsgs;		/* # of associated msgs */
  unsigned long recent;		/* # of recent msgs */
  unsigned long uid_validity;	/* UID validity sequence */
  unsigned long uid_last;	/* last assigned UID */
  char *user_flags[NUSERFLAGS];	/* pointers to user flags in bit order */
  unsigned long cachesize;	/* size of message cache */
  union {
    void **c;			/* to get at the cache in general */
    MESSAGECACHE **s;		/* message cache array */
    LONGCACHE **l;		/* long cache array */
  } cache;
  unsigned long msgno;		/* message number of `current' message */
  ENVELOPE *env;		/* pointer to `current' message envelope */
  BODY *body;			/* pointer to `current' message body */
  char *text;			/* pointer to `current' text */
} MAILSTREAM;


/* Mail I/O stream handle */

typedef struct mail_stream_handle {
  MAILSTREAM *stream;		/* pointer to mail stream */
  unsigned short sequence;	/* sequence of what we expect stream to be */
} MAILHANDLE;

/* Mail driver dispatch */

DRIVER {
  char *name;			/* driver name */
  unsigned long flags;		/* driver flags */
  DRIVER *next;			/* next driver */
				/* mailbox is valid for us */
  DRIVER *(*valid) (char *mailbox);
				/* manipulate driver parameters */
  void *(*parameters) (long function,void *value);
				/* scan mailboxes */
  void (*scan) (MAILSTREAM *stream,char *ref,char *pat,char *contents);
				/* list mailboxes */
  void (*list) (MAILSTREAM *stream,char *ref,char *pat);
				/* list subscribed mailboxes */
  void (*lsub) (MAILSTREAM *stream,char *ref,char *pat);
				/* subscribe to mailbox */
  long (*subscribe) (MAILSTREAM *stream,char *mailbox);
				/* unsubscribe from mailbox */
  long (*unsubscribe) (MAILSTREAM *stream,char *mailbox);
				/* create mailbox */
  long (*create) (MAILSTREAM *stream,char *mailbox);
				/* delete mailbox */
  long (*mbxdel) (MAILSTREAM *stream,char *mailbox);
				/* rename mailbox */
  long (*rename) (MAILSTREAM *stream,char *old,char *newname);
				/* status of mailbox */
  long (*status) (MAILSTREAM *stream,char *mbx,long flags);

				/* open mailbox */
  MAILSTREAM *(*open) (MAILSTREAM *stream);
				/* close mailbox */
  void (*close) (MAILSTREAM *stream,long options);
				/* fetch message "fast" attributes */
  void (*fetchfast) (MAILSTREAM *stream,char *sequence,long flags);
				/* fetch message flags */
  void (*fetchflags) (MAILSTREAM *stream,char *sequence,long flags);
				/* fetch message envelopes */
  ENVELOPE *(*fetchstructure) (MAILSTREAM *stream,unsigned long msgno,
			       BODY **body,long flags);
				/* fetch message header only */
  char *(*fetchheader) (MAILSTREAM *stream,unsigned long msgno,
			STRINGLIST *lines,unsigned long *len,long flags);
				/* fetch message body only */
  char *(*fetchtext) (MAILSTREAM *stream,unsigned long msgno,
		      unsigned long *len,long flags);
				/* fetch message body section */
  char *(*fetchbody) (MAILSTREAM *stream,unsigned long msgno,char *sec,
		      unsigned long* len,long flags);
				/* return UID for message */
  unsigned long (*uid) (MAILSTREAM *stream,unsigned long msgno);
				/* set message flag */
  void (*setflag) (MAILSTREAM *stream,char *sequence,char *flag,long flags);
				/* clear message flag */
  void (*clearflag) (MAILSTREAM *stream,char *sequence,char *flag,long flags);
				/* search for message based on criteria */
  void (*search) (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
				/* ping mailbox to see if still alive */
  long (*ping) (MAILSTREAM *stream);
				/* check for new messages */
  void (*check) (MAILSTREAM *stream);
				/* expunge deleted messages */
  void (*expunge) (MAILSTREAM *stream);
				/* copy messages to another mailbox */
  long (*copy) (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
				/* append string message to mailbox */
  long (*append) (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
		  STRING *message);
				/* garbage collect stream */
  void (*gc) (MAILSTREAM *stream,long gcflags);
};


/* Parse results from mail_valid_net_parse */

#define NETMAXHOST 65
#define NETMAXUSER 65
#define NETMAXMBX 256
#define NETMAXSRV 21
typedef struct net_mailbox {
  char host[NETMAXHOST];	/* host name */
  char user[NETMAXUSER];	/* user name */
  char mailbox[NETMAXMBX];	/* mailbox name */
  char service[NETMAXSRV];	/* service name */
  unsigned long port;		/* TCP port number */
  unsigned int anoflag : 1;	/* anonymous */
  unsigned int dbgflag : 1;	/* debug flag */
} NETMBX;

/* Mail delivery I/O stream */

typedef struct send_stream {
  void *tcpstream;		/* TCP I/O stream */
  char *reply;			/* last reply string */
  unsigned long size;		/* size limit */
  unsigned int debug : 1;	/* stream debug flag */
  unsigned int ok_8bitmime : 1;	/* supports 8-bit MIME */
  union {
    struct {
      unsigned int ok_ehlo : 1;	/* support ESMTP */
      unsigned int ok_send : 1;	/* ESMTP supports SEND */
      unsigned int ok_soml : 1;	/* ESMTP supports SOML */
      unsigned int ok_saml : 1;	/* ESMTP supports SAML */
      unsigned int ok_expn : 1;	/* ESMTP supports EXPN */
      unsigned int ok_help : 1;	/* ESMTP supports HELP */
      unsigned int ok_turn : 1;	/* ESMTP supports TURN */
      unsigned int ok_size : 1;	/* ESMTP supports SIZE */
    } esmtp;
    struct {
      unsigned int ok_post : 1;	/* supports POST */
    } nntp;
  } local;
} SENDSTREAM;

/* Jacket into external interfaces */

typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer);
typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size);
typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
typedef long (*tcptimeout_t) (long time);
typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
typedef long (*authclient_t) (authchallenge_t challenger,
			      authrespond_t responder,NETMBX *mb,void *s,
			      unsigned long trial);
typedef char *(*authresponse_t) (void *challenge,unsigned long clen,
				 unsigned long *rlen);
typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]);


#define AUTHENTICATOR struct mail_authenticator

AUTHENTICATOR {
  char *name;			/* name of this authenticator */
  authclient_t client;		/* client function that supports it */
  authserver_t server;		/* server function that supports it */
  AUTHENTICATOR *next;		/* next authenticator */
};


/* Other symbols */

				/* list of authenticators */
extern AUTHENTICATOR *authenticators;
extern const char *days[];	/* day name strings */
extern const char *months[];	/* month name strings */


#include "linkage.h"

/* Additional support names */

#define mail_close(stream) \
  mail_close_full (stream,NIL)
#define mail_fetchfast(stream,sequence) \
  mail_fetchfast_full (stream,sequence,NIL)
#define mail_fetchflags(stream,sequence) \
  mail_fetchflags_full (stream,sequence,NIL)
#define mail_fetchenvelope(stream,msgno) \
  mail_fetchstructure_full (stream,msgno,NIL,NIL)
#define mail_fetchstructure(stream,msgno,body) \
  mail_fetchstructure_full (stream,msgno,body,NIL)
#define mail_fetchheader(stream,msgno) \
  mail_fetchheader_full (stream,msgno,NIL,NIL,NIL)
#define mail_fetchtext(stream,msgno) \
  mail_fetchtext_full (stream,msgno,NIL,NIL)
#define mail_fetchbody(stream,msgno,section,len) \
  mail_fetchbody_full (stream,msgno,section,len,NIL)
#define mail_setflag(stream,sequence,flag) \
  mail_setflag_full (stream,sequence,flag,NIL)
#define mail_clearflag(stream,sequence,flag) \
  mail_clearflag_full (stream,sequence,flag,NIL)
#define mail_search(stream,criteria) \
  mail_search_full (stream,NIL,mail_criteria (criteria),SE_FREE);
#define mail_copy(stream,sequence,mailbox) \
  mail_copy_full (stream,sequence,mailbox,NIL)
#define mail_move(stream,sequence,mailbox) \
  mail_copy_full (stream,sequence,mailbox,CP_MOVE)
#define mail_append(stream,mailbox,message) \
  mail_append_full (stream,mailbox,NIL,NIL,message)

/* Function prototypes */

void mm_searched (MAILSTREAM *stream,unsigned long number);
void mm_exists (MAILSTREAM *stream,unsigned long number);
void mm_expunged (MAILSTREAM *stream,unsigned long number);
void mm_flags (MAILSTREAM *stream,unsigned long number);
void mm_notify (MAILSTREAM *stream,char *string,long errflg);
void mm_list (MAILSTREAM *stream,char delimiter,char *name,long attributes);
void mm_lsub (MAILSTREAM *stream,char delimiter,char *name,long attributes);
void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
void mm_log (char *string,long errflg);
void mm_dlog (char *string);
void mm_login (NETMBX *mb,char *user,char *pwd,long trial);
void mm_critical (MAILSTREAM *stream);
void mm_nocritical (MAILSTREAM *stream);
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious);
void mm_fatal (char *string);
char *mm_gets (readfn_t f,void *stream,unsigned long size);
void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op);

extern STRINGDRIVER mail_string;
void mail_string_init (STRING *s,void *data,unsigned long size);
char mail_string_next (STRING *s);
void mail_string_setpos (STRING *s,unsigned long i);
void mail_link (DRIVER *driver);
void *mail_parameters (MAILSTREAM *stream,long function,void *value);
DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose);
DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox);
long mail_valid_net_parse (char *name,NETMBX *mb);
void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
void mail_list (MAILSTREAM *stream,char *ref,char *pat);
void mail_lsub (MAILSTREAM *stream,char *ref,char *pat);
long mail_subscribe (MAILSTREAM *stream,char *mailbox);
long mail_unsubscribe (MAILSTREAM *stream,char *mailbox);
long mail_create (MAILSTREAM *stream,char *mailbox);
long mail_delete (MAILSTREAM *stream,char *mailbox);
long mail_rename (MAILSTREAM *stream,char *old,char *newname);
long mail_status (MAILSTREAM *stream,char *mbx,long flags);
MAILSTREAM *mail_open (MAILSTREAM *oldstream,char *name,long options);
MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options);
MAILHANDLE *mail_makehandle (MAILSTREAM *stream);
void mail_free_handle (MAILHANDLE **handle);
MAILSTREAM *mail_stream (MAILHANDLE *handle);
void mail_fetchfast_full (MAILSTREAM *stream,char *sequence,long flags);
void mail_fetchflags_full (MAILSTREAM *stream,char *sequence,long flags);
ENVELOPE *mail_fetchstructure_full (MAILSTREAM *stream,unsigned long msgno,
				    BODY **body,long flags);
char *mail_fetchheader_full (MAILSTREAM *stream,unsigned long msgno,
			     STRINGLIST *lines,unsigned long *len,long flags);
char *mail_fetchtext_full (MAILSTREAM *stream,unsigned long msgno,
			   unsigned long *len,long flags);
char *mail_fetchbody_full (MAILSTREAM *stream,unsigned long msgno,char *sec,
			   unsigned long *len,long flags);
unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno);
void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
		     long length);
void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
			long length);
LONGCACHE *mail_lelt (MAILSTREAM *stream,unsigned long msgno);
MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno);

void mail_setflag_full (MAILSTREAM *stream,char *sequence,char *flag,
			long flags);
void mail_clearflag_full (MAILSTREAM *stream,char *sequence,char *flag,
			  long flags);
void mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
		       long flags);
long mail_ping (MAILSTREAM *stream);
void mail_check (MAILSTREAM *stream);
void mail_expunge (MAILSTREAM *stream);
long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
		     long options);
long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
		       STRING *message);
void mail_gc (MAILSTREAM *stream,long gcflags);

char *mail_date (char *string,MESSAGECACHE *elt);
char *mail_cdate (char *string,MESSAGECACHE *elt);
long mail_parse_date (MESSAGECACHE *elt,char *string);
void mail_exists (MAILSTREAM *stream,unsigned long nmsgs);
void mail_recent (MAILSTREAM *stream,unsigned long recent);
void mail_expunged (MAILSTREAM *stream,unsigned long msgno);
void mail_lock (MAILSTREAM *stream);
void mail_unlock (MAILSTREAM *stream);
void mail_debug (MAILSTREAM *stream);
void mail_nodebug (MAILSTREAM *stream);
unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
			   long flags);
long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *charset,
		      SEARCHPGM *pgm);
long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st);
long mail_search_addr (ADDRESS *adr,char *charset,STRINGLIST *st);
long mail_search_string (char *txt,char *charset,STRINGLIST *st);
char *mail_search_gets (readfn_t f,void *stream,unsigned long size);
long mail_search_text (char *txt,long len,char *charset,STRINGLIST *st);
SEARCHPGM *mail_criteria (char *criteria);
int mail_criteria_date (unsigned short *date);
int mail_criteria_string (STRINGLIST **s);
long mail_sequence (MAILSTREAM *stream,char *sequence);
long mail_uid_sequence (MAILSTREAM *stream,char *sequence);
long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf);
ENVELOPE *mail_newenvelope (void);
ADDRESS *mail_newaddr (void);
BODY *mail_newbody (void);
BODY *mail_initbody (BODY *body);
PARAMETER *mail_newbody_parameter (void);
PART *mail_newbody_part (void);
STRINGLIST *mail_newstringlist (void);
SEARCHPGM *mail_newsearchpgm (void);
SEARCHHEADER *mail_newsearchheader (char *line);
SEARCHSET *mail_newsearchset (void);
SEARCHOR *mail_newsearchor (void);
SEARCHPGMLIST *mail_newsearchpgmlist (void);
void mail_free_body (BODY **body);
void mail_free_body_data (BODY *body);
void mail_free_body_parameter (PARAMETER **parameter);
void mail_free_body_part (PART **part);
void mail_free_cache (MAILSTREAM *stream);
void mail_free_elt (MESSAGECACHE **elt);
void mail_free_lelt (LONGCACHE **lelt);
void mail_free_envelope (ENVELOPE **env);
void mail_free_address (ADDRESS **address);
void mail_free_stringlist (STRINGLIST **string);
void mail_free_searchpgm (SEARCHPGM **pgm);
void mail_free_searchheader (SEARCHHEADER **hdr);
void mail_free_searchset (SEARCHSET **set);
void mail_free_searchor (SEARCHOR **orl);
void mail_free_searchpgmlist (SEARCHPGMLIST **pgl);
void auth_link (AUTHENTICATOR *auth);
char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]);

long sm_subscribe (char *mailbox);
long sm_unsubscribe (char *mailbox);
char *sm_read (void **sdb);


syntax highlighted by Code2HTML, v. 0.9.1