summaryrefslogtreecommitdiff
path: root/imap/src/osdep/dos
diff options
context:
space:
mode:
Diffstat (limited to 'imap/src/osdep/dos')
-rw-r--r--imap/src/osdep/dos/bezrkdos.c901
-rw-r--r--imap/src/osdep/dos/drivers.bat33
-rw-r--r--imap/src/osdep/dos/drivraux.bat28
-rw-r--r--imap/src/osdep/dos/dummy.h43
-rw-r--r--imap/src/osdep/dos/dummydos.c689
-rw-r--r--imap/src/osdep/dos/env_dos.c300
-rw-r--r--imap/src/osdep/dos/env_dos.h68
-rw-r--r--imap/src/osdep/dos/fdstring.c99
-rw-r--r--imap/src/osdep/dos/fdstring.h39
-rw-r--r--imap/src/osdep/dos/fs_dos.c62
-rw-r--r--imap/src/osdep/dos/ftl_dos.c38
-rw-r--r--imap/src/osdep/dos/makefile98
-rw-r--r--imap/src/osdep/dos/mkautaux.bat29
-rw-r--r--imap/src/osdep/dos/mkauths.bat33
-rw-r--r--imap/src/osdep/dos/mtestdbw.bat27
-rw-r--r--imap/src/osdep/dos/mtestdnf.bat27
-rw-r--r--imap/src/osdep/dos/mtestdnv.bat27
-rw-r--r--imap/src/osdep/dos/mtestdpc.bat27
-rw-r--r--imap/src/osdep/dos/mtestdwa.bat27
-rw-r--r--imap/src/osdep/dos/mtestwsk.bat27
-rw-r--r--imap/src/osdep/dos/mtxdos.c875
-rw-r--r--imap/src/osdep/dos/nl_dos.c61
-rw-r--r--imap/src/osdep/dos/os_dbw.c91
-rw-r--r--imap/src/osdep/dos/os_dbw.h43
-rw-r--r--imap/src/osdep/dos/os_dnf.c95
-rw-r--r--imap/src/osdep/dos/os_dnf.h44
-rw-r--r--imap/src/osdep/dos/os_dnv.c95
-rw-r--r--imap/src/osdep/dos/os_dnv.h43
-rw-r--r--imap/src/osdep/dos/os_dpc.c102
-rw-r--r--imap/src/osdep/dos/os_dpc.h41
-rw-r--r--imap/src/osdep/dos/os_dwa.c72
-rw-r--r--imap/src/osdep/dos/os_dwa.h43
-rw-r--r--imap/src/osdep/dos/os_wsk.c45
-rw-r--r--imap/src/osdep/dos/os_wsk.h48
-rw-r--r--imap/src/osdep/dos/pmatch.c89
-rw-r--r--imap/src/osdep/dos/tcp_dos.c434
-rw-r--r--imap/src/osdep/dos/tcp_dos.h51
-rw-r--r--imap/src/osdep/dos/tcp_dwa.c344
-rw-r--r--imap/src/osdep/dos/tcp_dwa.h45
-rw-r--r--imap/src/osdep/dos/tcp_wsk.c818
-rw-r--r--imap/src/osdep/dos/tcp_wsk.h50
-rw-r--r--imap/src/osdep/dos/write.c59
42 files changed, 6210 insertions, 0 deletions
diff --git a/imap/src/osdep/dos/bezrkdos.c b/imap/src/osdep/dos/bezrkdos.c
new file mode 100644
index 00000000..81617380
--- /dev/null
+++ b/imap/src/osdep/dos/bezrkdos.c
@@ -0,0 +1,901 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Berkeley mail 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: 24 June 1992
+ * Last Edited: 30 August 2006
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to those Merry Marvels of Musical
+ * Madness . . .
+ * -> The Incomparable Leland Stanford Junior University Marching Band <-
+ * who entertain, awaken, and outrage Stanford fans in the fact of repeated
+ * losing seasons and shattered Rose Bowl dreams [Cardinal just don't have
+ * HUSKY FEVER!!!].
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys\stat.h>
+#include <dos.h>
+#include "rfc822.h"
+#include "dummy.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* Berkeley I/O stream local data */
+
+typedef struct bezerk_local {
+ int fd; /* file descriptor for I/O */
+ off_t filesize; /* file size parsed */
+ char *buf; /* temporary buffer */
+} BEZERKLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((BEZERKLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *bezerk_valid (char *name);
+long bezerk_isvalid (char *name,char *tmp);
+int bezerk_valid_line (char *s,char **rx,int *rzn);
+void *bezerk_parameters (long function,void *value);
+void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void bezerk_list (MAILSTREAM *stream,char *ref,char *pat);
+void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long bezerk_create (MAILSTREAM *stream,char *mailbox);
+long bezerk_delete (MAILSTREAM *stream,char *mailbox);
+long bezerk_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *bezerk_open (MAILSTREAM *stream);
+void bezerk_close (MAILSTREAM *stream,long options);
+char *bezerk_header (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *length,long flags);
+long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,
+ long flags);
+long bezerk_ping (MAILSTREAM *stream);
+void bezerk_check (MAILSTREAM *stream);
+long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options);
+long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+ long options);
+long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+ STRING *msg);
+void bezerk_gc (MAILSTREAM *stream,long gcflags);
+char *bezerk_file (char *dst,char *name);
+long bezerk_badname (char *tmp,char *s);
+long bezerk_parse (MAILSTREAM *stream);
+unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *size);
+
+/* Berkeley mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER bezerkdriver = {
+ "bezerk", /* driver name */
+ /* driver flags */
+ DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY,
+ (DRIVER *) NIL, /* next driver */
+ bezerk_valid, /* mailbox is valid for us */
+ bezerk_parameters, /* manipulate parameters */
+ bezerk_scan, /* scan mailboxes */
+ bezerk_list, /* list mailboxes */
+ bezerk_lsub, /* list subscribed mailboxes */
+ NIL, /* subscribe to mailbox */
+ NIL, /* unsubscribe from mailbox */
+ bezerk_create, /* create mailbox */
+ bezerk_delete, /* delete mailbox */
+ bezerk_rename, /* rename mailbox */
+ mail_status_default, /* status of mailbox */
+ bezerk_open, /* open mailbox */
+ bezerk_close, /* close mailbox */
+ NIL, /* fetch message "fast" attributes */
+ NIL, /* fetch message flags */
+ NIL, /* fetch overview */
+ NIL, /* fetch message envelopes */
+ bezerk_header, /* fetch message header */
+ bezerk_text, /* fetch message text */
+ NIL, /* fetch partial message text */
+ NIL, /* unique identifier */
+ NIL, /* message number */
+ NIL, /* modify flags */
+ NIL, /* per-message modify flags */
+ NIL, /* search for message based on criteria */
+ NIL, /* sort messages */
+ NIL, /* thread messages */
+ bezerk_ping, /* ping mailbox to see if still alive */
+ bezerk_check, /* check for new messages */
+ bezerk_expunge, /* expunge deleted messages */
+ bezerk_copy, /* copy messages to another mailbox */
+ bezerk_append, /* append string message to mailbox */
+ NIL /* garbage collect stream */
+};
+
+ /* prototype stream */
+MAILSTREAM bezerkproto = {&bezerkdriver};
+
+/* Berkeley mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *bezerk_valid (char *name)
+{
+ char tmp[MAILTMPLEN];
+ return bezerk_isvalid (name,tmp) ? &bezerkdriver : (DRIVER *) NIL;
+}
+
+
+/* Berkeley mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+long bezerk_isvalid (char *name,char *tmp)
+{
+ int fd;
+ long ret = NIL;
+ struct stat sbuf;
+ errno = EINVAL; /* assume invalid argument */
+ /* if file, get its status */
+ if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) {
+ if (!sbuf.st_size)errno = 0;/* empty file */
+ else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) {
+ memset (tmp,'\0',MAILTMPLEN);
+ errno = -1; /* in case bezerk_valid_line fails */
+ if (read (fd,tmp,MAILTMPLEN-1) >= 0)
+ ret = bezerk_valid_line (tmp,NIL,NIL);
+ close (fd); /* close the file */
+ }
+ }
+ /* in case INBOX but not bezerk format */
+ else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) &&
+ ((name[1] == 'N') || (name[1] == 'n')) &&
+ ((name[2] == 'B') || (name[2] == 'b')) &&
+ ((name[3] == 'O') || (name[3] == 'o')) &&
+ ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1;
+ return ret; /* return what we should */
+}
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ * return pointer to end of date/time field
+ * return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ * return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+int bezerk_valid_line (char *s,char **rx,int *rzn)
+{
+ char *x;
+ int zn;
+ int ti = 0;
+ /* line must begin with "From " */
+ if ((*s != 'F') || (s[1] != 'r') || (s[2] != 'o') || (s[3] != 'm') ||
+ (s[4] != ' ')) return NIL;
+ /* find end of line */
+ for (x = s + 5; *x && *x != '\012'; x++);
+ if (!x) return NIL; /* end of line not found */
+ if (x[-1] == '\015') x--; /* ignore CR */
+ if ((x - s < 27)) return NIL; /* line too short */
+ if (x - s >= 41) { /* possible search for " remote from " */
+ for (zn = -1; x[zn] != ' '; zn--);
+ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&
+ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&
+ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&
+ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))
+ x += zn - 12;
+ }
+ if (x[-5] == ' ') { /* ends with year? */
+ /* no timezone? */
+ if (x[-8] == ':') zn = 0,ti = -5;
+ /* three letter timezone? */
+ else if (x[-9] == ' ') ti = zn = -9;
+ /* numeric timezone? */
+ else if ((x[-11]==' ') && ((x[-10]=='+') || (x[-10]=='-'))) ti = zn = -11;
+ }
+ else if (x[-4] == ' ') { /* no year and three leter timezone? */
+ if (x[-9] == ' ') zn = -4,ti = -9;
+ }
+ else if (x[-6] == ' ') { /* no year and numeric timezone? */
+ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))
+ zn = -6,ti = -11;
+ }
+ /* time must be www mmm dd hh:mm[:ss] */
+ if (ti && !((x[ti - 3] == ':') &&
+ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&
+ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&
+ (x[ti - 11] == ' '))) return NIL;
+ if (rx) *rx = x; /* set return values */
+ if (rzn) *rzn = zn;
+ return ti;
+}
+
+/* Berkeley manipulate driver parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *bezerk_parameters (long function,void *value)
+{
+ return NIL;
+}
+
+
+/* Berkeley mail scan mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ * string to scan
+ */
+
+void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+ if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* Berkeley mail list mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ */
+
+void bezerk_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+ if (stream) dummy_list (stream,ref,pat);
+}
+
+
+/* Berkeley mail list subscribed mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ */
+
+void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+ if (stream) dummy_lsub (stream,ref,pat);
+}
+
+/* Berkeley mail create mailbox
+ * Accepts: MAIL stream
+ * mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long bezerk_create (MAILSTREAM *stream,char *mailbox)
+{
+ return dummy_create (stream,mailbox);
+}
+
+
+/* Berkeley mail delete mailbox
+ * Accepts: MAIL stream
+ * mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long bezerk_delete (MAILSTREAM *stream,char *mailbox)
+{
+ return dummy_delete (stream,mailbox);
+}
+
+
+/* Berkeley mail rename mailbox
+ * Accepts: MAIL stream
+ * old mailbox name
+ * new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long bezerk_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+ return dummy_rename (stream,old,newname);
+}
+
+/* Berkeley mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *bezerk_open (MAILSTREAM *stream)
+{
+ long i;
+ int fd;
+ char *s;
+ char tmp[MAILTMPLEN];
+ /* return prototype for OP_PROTOTYPE call */
+ if (!stream) return &bezerkproto;
+ if (stream->local) fatal ("bezerk recycle stream");
+ if (!mailboxfile (tmp,stream->mailbox))
+ return (MAILSTREAM *) bezerk_badname (tmp,stream->mailbox);
+ if (((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0)) {
+ sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ stream->rdonly = T; /* this driver is readonly */
+ stream->local = fs_get (sizeof (BEZERKLOCAL));
+ /* canonicalize the stream mailbox name */
+ fs_give ((void **) &stream->mailbox);
+ if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0';
+ stream->mailbox = cpystr (tmp);
+ LOCAL->fd = fd; /* note the file */
+ LOCAL->filesize = 0; /* initialize parsed file size */
+ LOCAL->buf = NIL; /* initially no local buffer */
+ stream->sequence++; /* bump sequence number */
+ stream->uid_validity = time (0);
+ /* parse mailbox */
+ stream->nmsgs = stream->recent = 0;
+ if (!bezerk_ping (stream)) return NIL;
+ if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL);
+ stream->perm_seen = stream->perm_deleted =
+ stream->perm_flagged = stream->perm_answered = stream->perm_draft = NIL;
+ stream->perm_user_flags = NIL;
+ return stream; /* return stream to caller */
+}
+
+/* Berkeley mail close
+ * Accepts: MAIL stream
+ * close options
+ */
+
+void bezerk_close (MAILSTREAM *stream,long options)
+{
+ if (stream && LOCAL) { /* only if a file is open */
+ int silent = stream->silent;
+ stream->silent = T;
+ if (options & CL_EXPUNGE) bezerk_expunge (stream,NIL,NIL);
+ close (LOCAL->fd); /* close the local file */
+ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+ /* nuke the local data */
+ fs_give ((void **) &stream->local);
+ stream->dtb = NIL; /* log out the DTB */
+ }
+}
+
+/* Berkeley mail fetch message header
+ * Accepts: MAIL stream
+ * message # to fetch
+ * pointer to returned header text length
+ * option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *bezerk_header (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *length,long flags)
+{
+ char tmp[MAILTMPLEN];
+ *length = 0; /* default to empty */
+ if (flags & FT_UID) return "";/* UID call "impossible" */
+ /* get to header position */
+ lseek (LOCAL->fd,bezerk_hdrpos (stream,msgno,length),L_SET);
+ /* is buffer big enough? */
+ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+ LOCAL->buf = (char *) fs_get ((size_t) *length + 1);
+ LOCAL->buf[*length] = '\0'; /* tie off string */
+ /* slurp the data */
+ read (LOCAL->fd,LOCAL->buf,(size_t) *length);
+ return LOCAL->buf;
+}
+
+
+/* Berkeley mail fetch message text (body only)
+ * Accepts: MAIL stream
+ * message # to fetch
+ * pointer to returned header text length
+ * option flags
+ * Returns: T, always
+ */
+
+long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+ MESSAGECACHE *elt;
+ FDDATA d;
+ unsigned long hdrsize,hdrpos;
+ /* UID call "impossible" */
+ if (flags & FT_UID) return NIL;
+ elt = mail_elt (stream,msgno);/* if message not seen */
+ /* mark message as seen */
+ if (elt->seen && !(flags & FT_PEEK)) {
+ elt->seen = T;
+ mm_flags (stream,msgno);
+ }
+ /* get location of text data */
+ hdrpos = bezerk_hdrpos (stream,msgno,&hdrsize);
+ d.fd = LOCAL->fd; /* set initial stringstruct */
+ d.pos = hdrpos + hdrsize;
+ /* flush old buffer */
+ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+ d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE);
+ INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize);
+ return T; /* success */
+}
+
+/* Berkeley mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long bezerk_ping (MAILSTREAM *stream)
+{
+ /* punt if stream no longer alive */
+ if (!(stream && LOCAL)) return NIL;
+ /* parse mailbox, punt if parse dies */
+ return (bezerk_parse (stream)) ? T : NIL;
+}
+
+
+/* Berkeley mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void bezerk_check (MAILSTREAM *stream)
+{
+ unsigned long i = 1;
+ if (bezerk_ping (stream)) { /* ping mailbox */
+ /* get new message status */
+ while (i <= stream->nmsgs) mail_elt (stream,i++);
+ mm_log ("Check completed",(long) NIL);
+ }
+}
+
+/* Berkeley mail expunge mailbox
+ * Accepts: MAIL stream
+ * sequence to expunge if non-NIL
+ * expunge options
+ * Returns: T, always
+ */
+
+long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+ if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",WARN);
+ return LONGT;
+}
+
+/* Berkeley mail copy message(s)
+ * Accepts: MAIL stream
+ * sequence
+ * destination mailbox
+ * copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+ char tmp[MAILTMPLEN];
+ struct stat sbuf;
+ MESSAGECACHE *elt;
+ unsigned long i,j,k;
+ int fd;
+ mailproxycopy_t pc =
+ (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+ if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+ mail_sequence (stream,sequence))) return NIL;
+ /* make sure valid mailbox */
+ if (!bezerk_isvalid (mailbox,tmp) && errno) {
+ if (errno == ENOENT)
+ mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+ (long) NIL);
+ else if (pc) return (*pc) (stream,sequence,mailbox,options);
+ else if (mailboxfile (tmp,mailbox)) {
+ sprintf (tmp,"Not a Bezerk-format mailbox: %s",mailbox);
+ mm_log (tmp,ERROR);
+ }
+ else bezerk_badname (tmp,mailbox);
+ return NIL;
+ }
+ /* open the destination */
+ if (!mailboxfile (tmp,mailbox) ||
+ (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+ S_IREAD|S_IWRITE)) < 0) {
+ sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+
+ mm_critical (stream); /* go critical */
+ fstat (fd,&sbuf); /* get current file size */
+ /* for each requested message */
+ for (i = 1; i <= stream->nmsgs; i++)
+ if ((elt = mail_elt (stream,i))->sequence) {
+ lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET);
+ /* number of bytes to copy */
+ j = elt->private.msg.full.offset + elt->rfc822_size;
+ do { /* read from source position */
+ k = min (j,(unsigned long) MAILTMPLEN);
+ read (LOCAL->fd,tmp,(unsigned int) k);
+ if (write (fd,tmp,(unsigned int) k) < 0) {
+ sprintf (tmp,"Unable to write message: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ chsize (fd,sbuf.st_size);
+ close (fd); /* punt */
+ mm_nocritical (stream);
+ return NIL;
+ }
+ } while (j -= k); /* until done */
+ }
+ close (fd); /* close the file */
+ mm_nocritical (stream); /* release critical */
+ /* delete all requested messages */
+ if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+ if ((elt = mail_elt (stream,i))->sequence) elt->deleted = T;
+ if (mail_parameters (NIL,GET_COPYUID,NIL))
+ mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+ return T;
+}
+
+/* Berkeley mail append message from stringstruct
+ * Accepts: MAIL stream
+ * destination mailbox
+ * append callback
+ * data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN MAILTMPLEN
+
+long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+ struct stat sbuf;
+ int fd;
+ unsigned long i,j;
+ char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
+ FILE *sf,*df;
+ MESSAGECACHE elt;
+ STRING *message;
+ long ret = LONGT;
+ /* default stream to prototype */
+ if (!stream) stream = &bezerkproto;
+ /* make sure valid mailbox */
+ if (!bezerk_isvalid (mailbox,tmp) && errno) {
+ if (errno == ENOENT) {
+ if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
+ ((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
+ ((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
+ ((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
+ ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5])
+ bezerk_create (NIL,"INBOX");
+ else {
+ mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+ return NIL;
+ }
+ }
+ else if (mailboxfile (tmp,mailbox)) {
+ sprintf (tmp,"Not a Bezerk-format mailbox: %.80ss",mailbox);
+ mm_log (tmp,ERROR);
+ }
+ else bezerk_badname (tmp,mailbox);
+ return NIL;
+ }
+ tzset (); /* initialize timezone stuff */
+ /* get first message */
+ if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+ if (!(sf = tmpfile ())) { /* must have scratch file */
+ sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+ mm_log (tmp,ERROR);
+ }
+
+ do { /* parse date */
+ if (!date) rfc822_date (date = tmp);
+ if (!mail_parse_date (&elt,date)) {
+ sprintf (tmp,"Bad date in append: %.80s",date);
+ mm_log (tmp,ERROR);
+ }
+ else { /* user wants to suppress time zones? */
+ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+ time_t when = mail_longdate (&elt);
+ date = ctime (&when); /* use traditional date */
+ }
+ /* use POSIX-style date */
+ else date = mail_cdate (tmp,&elt);
+ if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
+ else if (!bezerk_append_msg (stream,sf,flags,date,message)) {
+ sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+ mm_log (tmp,ERROR);
+ }
+ /* get next message */
+ else if ((*af) (stream,data,&flags,&date,&message)) continue;
+ }
+ fclose (sf); /* punt scratch file */
+ return NIL; /* give up */
+ } while (message); /* until no more messages */
+ if (fflush (sf) || fstat (fileno (sf),&sbuf)) {
+ sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+ mm_log (tmp,ERROR);
+ fclose (sf); /* punt scratch file */
+ return NIL; /* give up */
+ }
+ i = sbuf.st_size; /* size of scratch file */
+
+ mm_critical (stream); /* go critical */
+ /* open the destination */
+ if (!mailboxfile (tmp,mailbox) ||
+ ((fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+ S_IREAD|S_IWRITE)) < 0) ||
+ !(df = fdopen (fd,"ab"))) {
+ mm_nocritical (stream); /* done with critical */
+ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ fstat (fd,&sbuf); /* get current file size */
+ while (i) /* until written all bytes */
+ if ((j = fread (buf,1,min ((long) BUFLEN,i),sf)) &&
+ (fwrite (buf,1,j,df) == j)) i -= j;
+ fclose (sf); /* done with scratch file */
+ /* make sure append wins */
+ if (i || (fflush (df) == EOF)) {
+ chsize (fd,sbuf.st_size); /* revert file */
+ close (fd); /* make sure fclose() doesn't corrupt us */
+ sprintf (buf,"Message append failed: %s",strerror (errno));
+ mm_log (buf,ERROR);
+ ret = NIL; /* return error */
+ }
+ fclose (df);
+ mm_nocritical (stream); /* release critical */
+ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+ mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+ WARN);
+ return ret;
+}
+
+/* Write single message to append scratch file
+ * Accepts: MAIL stream
+ * scratch file
+ * flags
+ * message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+ STRING *msg)
+{
+ int c;
+ unsigned long i,uf;
+ char tmp[MAILTMPLEN];
+ long f = mail_parse_flags (stream,flags,&uf);
+ /* build initial header */
+ if ((fprintf (sf,"From %s@%s %sStatus: ",
+ myusername (),mylocalhost (),date) < 0) ||
+ (f&fSEEN && (putc ('R',sf) == EOF)) ||
+ (fputs ("\nX-Status: ",sf) == EOF) ||
+ (f&fDELETED && (putc ('D',sf) == EOF)) ||
+ (f&fFLAGGED && (putc ('F',sf) == EOF)) ||
+ (f&fANSWERED && (putc ('A',sf) == EOF)) ||
+ (f&fDRAFT && (putc ('T',sf) == EOF)) ||
+ (fputs ("\nX-Keywords:",sf) == EOF)) return NIL;
+ while (uf) /* write user flags */
+ if (fprintf (sf," %s",stream->user_flags[find_rightmost_bit (&uf)]) < 0)
+ return NIL;
+ /* tie off flags */
+ if (putc ('\n',sf) == EOF) return NIL;
+ while (SIZE (msg)) { /* copy text to scratch file */
+ /* possible delimiter if line starts with F */
+ if ((c = 0xff & SNX (msg)) == 'F') {
+ /* copy line to buffer */
+ for (i = 1,tmp[0] = c; SIZE (msg) && (c != '\n') && (i < MAILTMPLEN);)
+ if (((c = 0xff & SNX (msg)) != '\r') || !(SIZE (msg)) ||
+ (CHR (msg) != '\n')) tmp[i++] = c;
+ if ((i > 4) && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') &&
+ (tmp[4] == ' ')) { /* possible "From " line? */
+ /* yes, see if need to write a widget */
+ if (((c != '\n') || bezerk_valid_line (tmp,NIL,NIL)) &&
+ (putc ('>',sf) == EOF)) return NIL;
+ }
+ /* write buffered text */
+ if (fwrite (tmp,1,i,sf) != i) return NIL;
+ if (c == '\n') continue; /* all done if got a complete line */
+ }
+ /* copy line, toss out CR from CRLF */
+ do if (((c == '\r') && SIZE (msg) && ((c = 0xff & SNX (msg)) != '\n') &&
+ (putc ('\r',sf) == EOF)) || (putc (c,sf) == EOF)) return NIL;
+ while ((c != '\n') && SIZE (msg) && ((c = 0xff & SNX (msg)) ? c : T));
+ }
+ /* write trailing newline and return */
+ return (putc ('\n',sf) == EOF) ? NIL : T;
+}
+
+
+/* Return bad file name error message
+ * Accepts: temporary buffer
+ * file name
+ * Returns: long NIL always
+ */
+
+long bezerk_badname (char *tmp,char *s)
+{
+ sprintf (tmp,"Invalid mailbox name: %s",s);
+ mm_log (tmp,ERROR);
+ return (long) NIL;
+}
+
+/* Parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ * NIL if failure, stream aborted
+ */
+
+long bezerk_parse (MAILSTREAM *stream)
+{
+ struct stat sbuf;
+ MESSAGECACHE *elt;
+ char *s,*t,tmp[MAILTMPLEN + 1],*db,datemsg[100];
+ long i;
+ int j,ti,zn;
+ long curpos = LOCAL->filesize;
+ long nmsgs = stream->nmsgs;
+ long recent = stream->recent;
+ short silent = stream->silent;
+ fstat (LOCAL->fd,&sbuf); /* get status */
+ if (sbuf.st_size < curpos) { /* sanity check */
+ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+ mm_log (tmp,ERROR);
+ bezerk_close (stream,NIL);
+ return NIL;
+ }
+ stream->silent = T; /* don't pass up mm_exists() events yet */
+ db = datemsg + strlen (strcpy (datemsg,"Unparsable date: "));
+ /* while there is data to read */
+ while (i = sbuf.st_size - curpos){
+ /* get to that position in the file */
+ lseek (LOCAL->fd,curpos,SEEK_SET);
+ /* read first buffer's worth */
+ read (LOCAL->fd,tmp,j = (int) min (i,(long) MAILTMPLEN));
+ tmp[j] = '\0'; /* tie off buffer */
+ if (!(ti = bezerk_valid_line (tmp,&t,&zn))) {
+ mm_log ("Mailbox format invalidated (consult an expert), aborted",ERROR);
+ bezerk_close (stream,NIL);
+ return NIL;
+ }
+
+ /* swell the cache */
+ mail_exists (stream,++nmsgs);
+ /* instantiate an elt for this message */
+ (elt = mail_elt (stream,nmsgs))->valid = T;
+ elt->private.uid = ++stream->uid_last;
+ /* note file offset of header */
+ elt->private.special.offset = curpos;
+ /* note offset of message */
+ elt->private.msg.full.offset =
+ (s = ((*t == '\015') ? (t + 2) : (t + 1))) - tmp;
+ /* generate plausable IMAPish date string */
+ db[2] = db[6] = db[20] = '-'; db[11] = ' '; db[14] = db[17] = ':';
+ /* dd */
+ db[0] = t[ti - 2]; db[1] = t[ti - 1];
+ /* mmm */
+ db[3] = t[ti - 6]; db[4] = t[ti - 5]; db[5] = t[ti - 4];
+ /* hh */
+ db[12] = t[ti + 1]; db[13] = t[ti + 2];
+ /* mm */
+ db[15] = t[ti + 4]; db[16] = t[ti + 5];
+ if (t[ti += 6] == ':') { /* ss if present */
+ db[18] = t[++ti]; db[19] = t[++ti];
+ ti++; /* move to space */
+ }
+ else db[18] = db[19] = '0'; /* assume 0 seconds */
+ /* yy -- advance over timezone if necessary */
+ if (++zn == ++ti) ti += (((t[zn] == '+') || (t[zn] == '-')) ? 6 : 4);
+ db[7] = t[ti]; db[8] = t[ti + 1]; db[9] = t[ti + 2]; db[10] = t[ti + 3];
+ t = zn ? (t + zn) : "LCL"; /* zzz */
+ db[21] = *t++; db[22] = *t++; db[23] = *t++;
+ if ((db[21] != '+') && (db[21] != '-')) db[24] = '\0';
+ else { /* numeric time zone */
+ db[20] = ' '; db[24] = *t++; db[25] = *t++; db[26] = '\0';
+ }
+ /* set internal date */
+ if (!mail_parse_date (elt,db)) mm_log (datemsg,WARN);
+
+ curpos += s - tmp; /* advance position after header */
+ t = strchr (s,'\012'); /* start of next line */
+ /* find start of next message */
+ while (!(bezerk_valid_line (s,NIL,NIL))) {
+ if (t) { /* have next line? */
+ t++; /* advance to new line */
+ curpos += t - s; /* update position and size */
+ elt->rfc822_size += ((t - s) + ((t[-2] == '\015') ? 0 : 1));
+ s = t; /* move to next line */
+ t = strchr (s,'\012');
+ }
+ else { /* try next buffer */
+ j = strlen (s); /* length of unread data in buffer */
+ if ((i = sbuf.st_size - curpos) && (i != j)) {
+ /* get to that position in the file */
+ lseek (LOCAL->fd,curpos,SEEK_SET);
+ /* read another buffer's worth */
+ read (LOCAL->fd,s = tmp,j = (int) min (i,(long) MAILTMPLEN));
+ tmp[j] = '\0'; /* tie off buffer */
+ if (!(t = strchr (s,'\012'))) fatal ("Line too long in mailbox");
+ }
+ else {
+ curpos += j; /* last bit of data */
+ elt->rfc822_size += j;
+ break;
+ }
+ }
+ }
+ }
+ /* update parsed file size */
+ LOCAL->filesize = sbuf.st_size;
+ stream->silent = silent; /* can pass up events now */
+ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */
+ mail_recent (stream,recent); /* and of change in recent messages */
+ return T; /* return the winnage */
+}
+
+/* Berkeley locate header for a message
+ * Accepts: MAIL stream
+ * message number
+ * pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *size)
+{
+ long siz;
+ size_t i = 0;
+ char c = '\0';
+ char *s;
+ char tmp[MAILTMPLEN];
+ MESSAGECACHE *elt = mail_elt (stream,msgno);
+ long pos = elt->private.special.offset + elt->private.msg.full.offset;
+ /* is size known? */
+ if (!(*size = elt->private.msg.header.text.size)) {
+ /* get to header position */
+ lseek (LOCAL->fd,pos,SEEK_SET);
+ /* search message for CRLF CRLF */
+ for (siz = 1; siz <= elt->rfc822_size; siz++) {
+ if (!i && /* buffer empty? */
+ (read (LOCAL->fd,s = tmp,
+ i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0))
+ return pos;
+ else i--;
+ /* two newline sequence? */
+ if ((c == '\012') && (*s == '\012')) {
+ /* yes, note for later */
+ elt->private.msg.header.text.size = (*size = siz);
+ return pos; /* return to caller */
+ }
+ else if ((c == '\012') && (*s == '\015')) {
+ /* yes, note for later */
+ elt->private.msg.header.text.size = (*size = siz + 1);
+ return pos; /* return to caller */
+ }
+ else c = *s++; /* next character */
+ }
+ }
+ return pos; /* have position */
+}
diff --git a/imap/src/osdep/dos/drivers.bat b/imap/src/osdep/dos/drivers.bat
new file mode 100644
index 00000000..0964f537
--- /dev/null
+++ b/imap/src/osdep/dos/drivers.bat
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Driver Linkage Generator for DOS/NT
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 11 October 1989
+REM Last Edited:30 August 2006
+
+REM Erase old driver linkage
+IF EXIST LINKAGE.* DEL LINKAGE.*
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
+
+EXIT 0
diff --git a/imap/src/osdep/dos/drivraux.bat b/imap/src/osdep/dos/drivraux.bat
new file mode 100644
index 00000000..a0b354cd
--- /dev/null
+++ b/imap/src/osdep/dos/drivraux.bat
@@ -0,0 +1,28 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Driver Linkage Generator auxillary for DOS
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 11 October 1989
+REM Last Edited:30 August 2006
+
+ECHO extern DRIVER %1driver; >> LINKAGE.H
+ECHO mail_link (&%1driver); /* link in the %1 driver */ >> LINKAGE.C
diff --git a/imap/src/osdep/dos/dummy.h b/imap/src/osdep/dos/dummy.h
new file mode 100644
index 00000000..32650e06
--- /dev/null
+++ b/imap/src/osdep/dos/dummy.h
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Dummy 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: 9 May 1991
+ * Last Edited: 30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+ unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+ unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
diff --git a/imap/src/osdep/dos/dummydos.c b/imap/src/osdep/dos/dummydos.c
new file mode 100644
index 00000000..4bf147b8
--- /dev/null
+++ b/imap/src/osdep/dos/dummydos.c
@@ -0,0 +1,689 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Dummy routines for DOS
+ *
+ * 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: 24 May 1993
+ * Last Edited: 30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mail.h"
+#include "osdep.h"
+#include <sys\stat.h>
+#include <dos.h>
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+ long level);
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+ long attributes,char *contents);
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long dummy_badname (char *tmp,char *s);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+ "dummy", /* driver name */
+ DR_LOCAL|DR_MAIL, /* driver flags */
+ (DRIVER *) NIL, /* next driver */
+ dummy_valid, /* mailbox is valid for us */
+ dummy_parameters, /* manipulate parameters */
+ dummy_scan, /* scan mailboxes */
+ dummy_list, /* list mailboxes */
+ dummy_lsub, /* list subscribed mailboxes */
+ dummy_subscribe, /* subscribe to mailbox */
+ NIL, /* unsubscribe from mailbox */
+ dummy_create, /* create mailbox */
+ dummy_delete, /* delete mailbox */
+ dummy_rename, /* rename mailbox */
+ mail_status_default, /* status of mailbox */
+ dummy_open, /* open mailbox */
+ dummy_close, /* close mailbox */
+ NIL, /* fetch message "fast" attributes */
+ NIL, /* fetch message flags */
+ NIL, /* fetch overview */
+ NIL, /* fetch message structure */
+ NIL, /* fetch header */
+ NIL, /* fetch text */
+ NIL, /* fetch message data */
+ NIL, /* unique identifier */
+ NIL, /* message number from UID */
+ NIL, /* modify flags */
+ NIL, /* per-message modify flags */
+ NIL, /* search for message based on criteria */
+ NIL, /* sort messages */
+ NIL, /* thread messages */
+ dummy_ping, /* ping mailbox to see if still alive */
+ dummy_check, /* check for new messages */
+ dummy_expunge, /* expunge deleted messages */
+ dummy_copy, /* copy messages to another mailbox */
+ dummy_append, /* append string message to mailbox */
+ NIL /* garbage collect stream */
+};
+
+
+ /* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+ /* driver parameters */
+static char *file_extension = NIL;
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+ char *s,tmp[MAILTMPLEN];
+ struct stat sbuf;
+ /* must be valid local mailbox */
+ return (name && *name && (*name != '{') &&
+ (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ?
+ &dummydriver : NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+ void *ret = NIL;
+ switch ((int) function) {
+ case SET_EXTENSION:
+ if (file_extension) fs_give ((void **) &file_extension);
+ if (*(char *) value) file_extension = cpystr ((char *) value);
+ case GET_EXTENSION:
+ ret = (void *) file_extension;
+ }
+ return ret;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ * string to scan
+ */
+
+#define LISTTMPLEN 128
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+ char *s,test[LISTTMPLEN],file[LISTTMPLEN];
+ long i = 0;
+ if (!pat || !*pat) { /* empty pattern? */
+ if (dummy_canonicalize (test,ref,"*")) {
+ /* tie off name at root */
+ if (s = strchr (test,'\\')) *++s = '\0';
+ else test[0] = '\0';
+ dummy_listed (stream,'\\',test,LATT_NOINFERIORS,NIL);
+ }
+ }
+ /* get canonical form of name */
+ else if (dummy_canonicalize (test,ref,pat)) {
+ /* found any wildcards? */
+ if (s = strpbrk (test,"%*")) {
+ /* yes, copy name up to that point */
+ strncpy (file,test,(size_t) (i = s - test));
+ file[i] = '\0'; /* tie off */
+ }
+ else strcpy (file,test); /* use just that name then */
+ /* find directory name */
+ if (s = strrchr (file,'\\')) {
+ *++s = '\0'; /* found, tie off at that point */
+ s = file;
+ }
+ /* silly case */
+ else if (file[0] == '#') s = file;
+ /* do the work */
+ dummy_list_work (stream,s,test,contents,0);
+ if (pmatch ("INBOX",test)) /* always an INBOX */
+ dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
+ }
+}
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+ dummy_scan (stream,ref,pat,NIL);
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ * pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+ void *sdb = NIL;
+ char *s,*t,test[MAILTMPLEN];
+ int showuppers = pat[strlen (pat) - 1] == '%';
+ /* get canonical form of name */
+ if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
+ if (*s != '{') {
+ if (pmatch_full (s,test,'\\')) {
+ if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
+ else mm_lsub (stream,'\\',s,NIL);
+ }
+ else while (showuppers && (t = strrchr (s,'\\'))) {
+ *t = '\0'; /* tie off the name */
+ if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
+ }
+ }
+ while (s = sm_read (&sdb)); /* until no more subscriptions */
+}
+
+
+/* Dummy subscribe to mailbox
+ * Accepts: mail stream
+ * mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+ char *s,tmp[MAILTMPLEN];
+ struct stat sbuf;
+ /* must be valid local mailbox */
+ if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
+ ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
+ sprintf (tmp,"Can't subscribe %s: not a mailbox",mailbox);
+ mm_log (tmp,ERROR);
+ return NIL;
+}
+
+/* Dummy list mailboxes worker routine
+ * Accepts: mail stream
+ * directory name to search
+ * search pattern
+ * string to scan
+ * search level
+ */
+
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+ long level)
+{
+ struct find_t f;
+ struct stat sbuf;
+ char *s,tmp[LISTTMPLEN],tmpx[LISTTMPLEN];
+ char *base = (dir && (dir[0] == '\\')) ? NIL : myhomedir ();
+ /* build name */
+ if (base) sprintf (tmpx,"%s\\",base);
+ else tmpx[0] = '\0';
+ if (dir) strcat (tmpx,dir);
+ /* punt if bogus name */
+ if (!mailboxfile (tmp,tmpx)) return;
+ /* make directory wildcard */
+ strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*." : "\\*.");
+ strcat (tmp,file_extension ? file_extension : "*");
+ /* do nothing if can't open directory */
+ if (!_dos_findfirst (tmp,_A_NORMAL|_A_SUBDIR,&f)) {
+ /* list it if at top-level */
+ if (!level && dir && pmatch_full (dir,pat,'\\'))
+ dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
+ /* scan directory */
+ if (tmpx[strlen (tmpx) - 1] == '\\') do if (*f.name != '.') {
+ if (base) sprintf (tmpx,"%s\\",base);
+ else tmpx[0] = '\0';
+ if (dir) sprintf (tmpx + strlen (tmpx),"%s%s",dir,f.name);
+ else strcat (tmpx,f.name);
+ if (mailboxfile (tmp,tmpx) && !stat (tmp,&sbuf)) {
+ /* suppress extension */
+ if (file_extension && (s = strchr (f.name,'.'))) *s = '\0';
+ /* now make name we'd return */
+ if (dir) sprintf (tmp,"%s%s",dir,f.name);
+ else strcpy (tmp,f.name);
+ /* only interested in file type */
+ switch (sbuf.st_mode & S_IFMT) {
+ case S_IFDIR: /* directory? */
+ if (pmatch_full (tmp,pat,'\\')) {
+ dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents);
+ strcat (tmp,"\\"); /* set up for dmatch call */
+ }
+ /* try again with trailing / */
+ else if (pmatch_full (strcat (tmp,"\\"),pat,'\\'))
+ dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents);
+ if (dmatch (tmp,pat,'\\') &&
+ (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+ dummy_list_work (stream,tmp,pat,contents,level+1);
+ break;
+ case S_IFREG: /* ordinary name */
+ if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
+ dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
+ break;
+ }
+ }
+ }
+ while (!_dos_findnext (&f));
+ }
+}
+
+/* Mailbox found
+ * Accepts: hierarchy delimiter
+ * mailbox name
+ * attributes
+ * contents to search before calling mm_list()
+ * Returns: T, always
+ */
+
+#define BUFSIZE MAILTMPLEN
+
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+ long attributes,char *contents)
+{
+ struct stat sbuf;
+ int fd;
+ size_t csiz,ssiz,bsiz;
+ char *buf,tmp[MAILTMPLEN];
+ if (contents) { /* want to search contents? */
+ /* forget it if can't select or open */
+ if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
+ !mailboxfile (tmp,name) || stat (tmp,&sbuf) || (csiz > sbuf.st_size) ||
+ ((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T;
+ /* get buffer including slop */
+ buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
+ memset (buf,'\0',ssiz); /* no slop area the first time */
+ while (sbuf.st_size) { /* until end of file */
+ read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
+ if (search ((unsigned char *) buf,bsiz+ssiz,
+ (unsigned char *) contents,csiz)) break;
+ memcpy (buf,buf+BUFSIZE,ssiz);
+ sbuf.st_size -= bsiz; /* note that we read that much */
+ }
+ fs_give ((void **) &buf); /* flush buffer */
+ close (fd); /* finished with file */
+ if (!sbuf.st_size) return T;/* not found */
+ }
+ /* notify main program */
+ mm_list (stream,delimiter,name,attributes);
+ return T;
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ * mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+ char tmp[MAILTMPLEN];
+ return (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox)) ?
+ dummy_create_path (stream,tmp,NIL) : dummy_badname (tmp,mailbox);
+}
+
+
+/* Dummy create path
+ * Accepts: mail stream
+ * path name to create
+ * directory mode
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
+{
+ struct stat sbuf;
+ char c,*s,tmp[MAILTMPLEN];
+ int fd;
+ long ret = NIL;
+ char *t = strrchr (path,'\\');
+ char *pt = (path[1] == ':') ? path + 2 : path;
+ int wantdir = t && !t[1];
+ if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */
+ /* found superior to this name? */
+ if ((s = strrchr (pt,'\\')) && (s != pt)) {
+ strncpy (tmp,path,(size_t) (s - path));
+ tmp[s - path] = '\0'; /* make directory name for stat */
+ c = *++s; /* tie off in case need to recurse */
+ *s = '\0';
+ /* name doesn't exist, create it */
+ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+ !dummy_create_path (stream,path,dirmode)) return NIL;
+ *s = c; /* restore full name */
+ }
+ if (wantdir) { /* want to create directory? */
+ ret = !mkdir (path);
+ *t = '\\'; /* restore directory delimiter */
+ }
+ /* create file */
+ else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
+ ret = !close (fd); /* close file */
+ if (!ret) { /* error? */
+ sprintf (tmp,"Can't create mailbox node %s: %s",path,strerror (errno));
+ mm_log (tmp,ERROR);
+ }
+ return ret; /* return status */
+}
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ * mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+ struct stat sbuf;
+ char *s,tmp[MAILTMPLEN];
+ if (!mailboxfile (tmp,mailbox)) return dummy_badname (tmp,mailbox);
+ /* no trailing \ */
+ if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
+ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
+ rmdir (tmp) : unlink (tmp)) {
+ sprintf (tmp,"Can't delete mailbox %s: %s",mailbox,strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ return T; /* return success */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ * old mailbox name
+ * new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+ struct stat sbuf;
+ char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN];
+ /* make file name */
+ if (!mailboxfile (file,old)) return dummy_badname (tmp,old);
+ /* no trailing \ allowed */
+ if (!(s = mailboxfile (tmp,newname)) || ((s = strrchr (s,'\\')) && !s[1]))
+ return dummy_badname (tmp,newname);
+ if (s) { /* found superior to destination name? */
+ c = *++s; /* remember first character of inferior */
+ *s = '\0'; /* tie off to get just superior */
+ /* name doesn't exist, create it */
+ if ((stat (file,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+ !dummy_create (stream,file)) return NIL;
+ *s = c; /* restore full name */
+ }
+ if (rename (file,tmp)) {
+ sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,newname,
+ strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ return LONGT; /* return success */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+ char tmp[MAILTMPLEN];
+ struct stat sbuf;
+ int fd = -1;
+ /* OP_PROTOTYPE call or silence */
+ if (!stream || stream->silent) return NIL;
+ if (!mailboxfile (tmp,stream->mailbox))
+ sprintf (tmp,"Can't open this name: %.80s",stream->mailbox);
+ else if (compare_cstring (stream->mailbox,"INBOX") &&
+ ((fd = open (tmp,O_RDONLY,NIL)) < 0))
+ sprintf (tmp,"%s: %s",strerror (errno),stream->mailbox);
+ else {
+ if (fd >= 0) { /* if got a file */
+ fstat (fd,&sbuf); /* sniff at its size */
+ close (fd);
+ if (sbuf.st_size) sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
+ else fd = -1; /* a-OK */
+ }
+ if (fd < 0) { /* no file, right? */
+ if (!stream->silent) { /* only if silence not requested */
+ /* say there are 0 messages */
+ mail_exists (stream,(long) 0);
+ mail_recent (stream,(long) 0);
+ stream->uid_validity = time (0);
+ }
+ stream->inbox = T; /* note that it's an INBOX */
+ return stream; /* return success */
+ }
+ }
+ mm_log (tmp,stream->silent ? WARN: ERROR);
+ return NIL; /* always fails */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ * options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+ /* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+ MAILSTREAM *test;
+ /* time to do another test? */
+ if (time (0) >= ((time_t) (stream->gensym + 30))) {
+ /* has mailbox format changed? */
+ if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
+ (test->dtb != stream->dtb) &&
+ (test = mail_open (NIL,stream->mailbox,NIL))) {
+ /* preserve some resources */
+ test->original_mailbox = stream->original_mailbox;
+ stream->original_mailbox = NIL;
+ test->sparep = stream->sparep;
+ stream->sparep = NIL;
+ test->sequence = stream->sequence;
+ mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
+ memcpy (fs_get (sizeof (MAILSTREAM)),stream,
+ sizeof (MAILSTREAM)));
+ /* swap the streams */
+ memcpy (stream,test,sizeof (MAILSTREAM));
+ fs_give ((void **) &test);/* flush test now that copied */
+ /* make sure application knows */
+ mail_exists (stream,stream->recent = stream->nmsgs);
+ }
+ /* still hasn't changed */
+ else stream->gensym = time (0);
+ }
+ return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+ dummy_ping (stream); /* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ * sequence to expunge if non-NIL
+ * expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+ return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ * sequence
+ * destination mailbox
+ * options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+ if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+ mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+ return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ * destination mailbox
+ * append callback function
+ * data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+ struct stat sbuf;
+ int fd = -1;
+ int e;
+ char tmp[MAILTMPLEN];
+ MAILSTREAM *ts = default_proto (T);
+ if (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox) &&
+ ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
+ if ((e = errno) == ENOENT) /* failed, was it no such file? */
+ mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+ (long) NIL);
+ sprintf (tmp,"%s: %s",strerror (e),mailbox);
+ mm_log (tmp,ERROR); /* pass up error */
+ return NIL; /* always fails */
+ }
+ if (fd >= 0) { /* found file? */
+ fstat (fd,&sbuf); /* get its size */
+ close (fd); /* toss out the fd */
+ if (sbuf.st_size) ts = NIL; /* non-empty file? */
+ }
+ if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
+ sprintf (tmp,"Indeterminate mailbox format: %s",mailbox);
+ mm_log (tmp,ERROR);
+ return NIL;
+}
+
+/* Return bad file name error message
+ * Accepts: temporary buffer
+ * file name
+ * Returns: long NIL always
+ */
+
+long dummy_badname (char *tmp,char *s)
+{
+ sprintf (tmp,"Invalid mailbox name: %s",s);
+ mm_log (tmp,ERROR);
+ return (long) NIL;
+}
+
+
+/* Dummy canonicalize name
+ * Accepts: buffer to write name
+ * reference
+ * pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long dummy_canonicalize (char *tmp,char *ref,char *pat)
+{
+ unsigned long i;
+ char *s,dev[4];
+ /* initially no device */
+ dev[0] = dev[1] = dev[2] = dev[3] = '\0';
+ if (ref) switch (*ref) { /* preliminary reference check */
+ case '{': /* remote names not allowed */
+ return NIL; /* disallowed */
+ case '\0': /* empty reference string */
+ break;
+ default: /* all other names */
+ if (ref[1] == ':') { /* start with device name? */
+ dev[0] = *ref++; dev[1] = *ref++;
+ }
+ break;
+ }
+ if (pat[1] == ':') { /* device name in pattern? */
+ dev[0] = *pat++; dev[1] = *pat++;
+ ref = NIL; /* ignore reference */
+ }
+ switch (*pat) {
+ case '#': /* namespace names */
+ if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
+ else return NIL; /* unknown namespace */
+ break;
+ case '{': /* remote names not allowed */
+ return NIL;
+ case '\\': /* rooted name */
+ ref = NIL; /* ignore reference */
+ break;
+ }
+ /* make sure device names are rooted */
+ if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
+ /* build name */
+ sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
+ ucase (tmp); /* force upper case */
+ /* count wildcards */
+ for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+ if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */
+ MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+ return NIL;
+ }
+ return T;
+}
diff --git a/imap/src/osdep/dos/env_dos.c b/imap/src/osdep/dos/env_dos.c
new file mode 100644
index 00000000..152dd322
--- /dev/null
+++ b/imap/src/osdep/dos/env_dos.c
@@ -0,0 +1,300 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: DOS environment 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: 1 August 1988
+ * Last Edited: 30 August 2006
+ */
+
+
+static char *myLocalHost = NIL; /* local host name */
+static char *myClientAddr = NIL;/* client host address */
+static char *myClientHost = NIL;/* client host name */
+static char *myServerAddr = NIL;/* server host address */
+static char *myServerHost = NIL;/* server host name */
+static char *myHomeDir = NIL; /* home directory name */
+static char *myNewsrc = NIL; /* newsrc file name */
+static long list_max_level = 5; /* maximum level of list recursion */
+static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
+ /* home namespace */
+static NAMESPACE nshome = {"",'\\',NIL,NIL};
+ /* namespace list */
+static NAMESPACE *nslist[3] = {&nshome,NIL,NIL};
+
+#include "write.c" /* include safe writing routines */
+#include "pmatch.c" /* include wildcard pattern matcher */
+
+
+/* Dummy definitions to prevent errors */
+
+#define server_login(user,pass,authuser,argc,argv) NIL
+#define authserver_login(user,authuser,argc,argv) NIL
+#define myusername() ""
+#define MD5ENABLE "\\.nosuch.."
+
+
+/* Get all authenticators */
+
+#include "auths.c"
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+ void *ret = NIL;
+ switch ((int) function) {
+ case GET_NAMESPACE:
+ ret = (void *) nslist;
+ break;
+ case SET_HOMEDIR:
+ myHomeDir = cpystr ((char *) value);
+ case GET_HOMEDIR:
+ ret = (void *) myHomeDir;
+ break;
+ case SET_LOCALHOST:
+ myLocalHost = cpystr ((char *) value);
+ case GET_LOCALHOST:
+ ret = (void *) myLocalHost;
+ break;
+ case SET_NEWSRC:
+ if (myNewsrc) fs_give ((void **) &myNewsrc);
+ myNewsrc = cpystr ((char *) value);
+ case GET_NEWSRC:
+ if (!myNewsrc) { /* set news file name if not defined */
+ char tmp[MAILTMPLEN];
+ sprintf (tmp,"%s\\NEWSRC",myhomedir ());
+ myNewsrc = cpystr (tmp);
+ }
+ ret = (void *) myNewsrc;
+ break;
+ case SET_LISTMAXLEVEL:
+ list_max_level = (long) value;
+ case GET_LISTMAXLEVEL:
+ ret = (void *) list_max_level;
+ break;
+ case SET_DISABLE822TZTEXT:
+ no822tztext = value ? T : NIL;
+ case GET_DISABLE822TZTEXT:
+ ret = (void *) (no822tztext ? VOIDT : NIL);
+ break;
+ }
+ return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ * optional format of day-of-week prefix
+ * format of date and time
+ * flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+ time_t tn = time (0);
+ struct tm *t = gmtime (&tn);
+ int zone = t->tm_hour * 60 + t->tm_min;
+ int julian = t->tm_yday;
+ t = localtime (&tn); /* get local time now */
+ /* minus UTC minutes since midnight */
+ zone = t->tm_hour * 60 + t->tm_min - zone;
+ /* julian can be one of:
+ * 36x local time is December 31, UTC is January 1, offset -24 hours
+ * 1 local time is 1 day ahead of UTC, offset +24 hours
+ * 0 local time is same day as UTC, no offset
+ * -1 local time is 1 day behind UTC, offset -24 hours
+ * -36x local time is January 1, UTC is December 31, offset +24 hours
+ */
+ if (julian = t->tm_yday -julian)
+ zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+ if (prefix) { /* want day of week? */
+ sprintf (date,prefix,days[t->tm_wday]);
+ date += strlen (date); /* make next sprintf append */
+ }
+ /* output the date */
+ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+ t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+ if (suffix) { /* append timezone suffix if desired */
+ tzset (); /* get timezone from TZ environment stuff */
+ sprintf (date + strlen (date)," (%.50s)",
+ tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]);
+ }
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+ do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+ no822tztext ? NIL : T);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+ do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+ int i;
+ char *s;
+ if (!myHomeDir) { /* get home directory name if not yet known */
+ i = strlen (myHomeDir = cpystr ((s = getenv ("HOME")) ? s : ""));
+ if (i && ((myHomeDir[i-1] == '\\') || (myHomeDir[i-1]=='/')))
+ myHomeDir[i-1] = '\0'; /* tie off trailing directory delimiter */
+ }
+ return myHomeDir;
+}
+
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ * mailbox name
+ * Returns: file name
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+ char *s;
+ char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL);
+ /* forbid extraneous extensions */
+ if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) &&
+ ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) ||
+ strchr (s+1,'.'))) return NIL;
+ /* absolute path name? */
+ if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name);
+ else sprintf (dst,"%s\\%s",myhomedir (),name);
+ if (ext) sprintf (dst + strlen (dst),".%s",ext);
+ return ucase (dst);
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+ extern MAILSTREAM DEFAULTPROTO;
+ return &DEFAULTPROTO; /* return default driver's prototype */
+}
+
+/* Global data */
+
+static unsigned rndm = 0; /* initial `random' number */
+
+
+/* Return random number
+ */
+
+long random ()
+{
+ if (!rndm) srand (rndm = (unsigned) time (0L));
+ return (long) rand ();
+}
+
+/* Default mailgets routine on DOS
+ * Accepts: readin function pointer
+ * stream to use
+ * number of bytes
+ * identifier data
+ * Returns: string read in, truncated if necessary
+ *
+ * This is a sample mailgets routine. It simply truncates any data larger
+ * than 63K. On most systems, you generally don't use a mailgets
+ * routine at all, but on DOS it's required to prevent the application from
+ * crashing.
+ */
+
+static char *dos_gets_buf = NIL;
+
+char *dos_default_gets (readfn_t f,void *stream,unsigned long size,
+ GETS_DATA *md)
+{
+ readprogress_t *rp = mail_parameters (NIL,GET_READPROGRESS,NIL);
+ char *ret,tmp[MAILTMPLEN+1];
+ unsigned long i,j,dsc,rdi = 0;
+ unsigned long dos_max = 63 * 1024;
+ if (!dos_gets_buf) /* one-time initialization */
+ dos_gets_buf = (char *) fs_get ((size_t) dos_max + 1);
+ ret = (md->flags & MG_COPY) ?
+ ((char *) fs_get ((size_t) size + 1)) : dos_gets_buf;
+ if (size > dos_max) {
+ sprintf (tmp,"Mailbox %s, %s %lu[%.80s], %lu octets truncated to %ld",
+ md->stream->mailbox,(md->flags & MG_UID) ? "UID" : "#",
+ md->msgno,md->what,size,(long) dos_max);
+ mm_log (tmp,WARN); /* warn user */
+ dsc = size - dos_max; /* number of bytes to discard */
+ size = dos_max; /* maximum length string we can read */
+ }
+ else dsc = 0; /* nothing to discard */
+ dos_gets_buf[size] = '\0'; /* tie off string */
+ if (rp) for (i = size; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
+ (*f) (stream,j,ret + rdi);
+ (*rp) (md,rdi += j);
+ }
+ else (*f) (stream,size,dos_gets_buf);
+ /* toss out everything after that */
+ for (i = dsc; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
+ (*f) (stream,j,tmp);
+ if (rp) (*rp) (md,rdi += j);
+ }
+ return ret;
+}
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ * message
+ * parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ * options
+ * facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
diff --git a/imap/src/osdep/dos/env_dos.h b/imap/src/osdep/dos/env_dos.h
new file mode 100644
index 00000000..bb0e8c0a
--- /dev/null
+++ b/imap/src/osdep/dos/env_dos.h
@@ -0,0 +1,68 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: DOS environment 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: 1 August 1988
+ * Last Edited: 30 August 2006
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/MAILBOX.LST",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/MAILBOX.TMP",myhomedir ())
+
+#define L_SET SEEK_SET
+
+/* Function prototypes */
+
+#include "env.h"
+
+char *dos_default_gets (readfn_t f,void *stream,unsigned long size,
+ GETS_DATA *md);
+long safe_write (int fd,char *buf,long nbytes);
+long random ();
+#if _MSC_VER < 700
+#define getpid random
+#endif
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL (2<<3) /* mail system */
+#define LOG_DAEMON (3<<3) /* system daemons */
+#define LOG_AUTH (4<<3) /* security/authorization messages */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but signification condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+#define LOG_PID 0x01 /* log the pid with each message */
+#define LOG_CONS 0x02 /* log on the console if errors in sending */
+#define LOG_ODELAY 0x04 /* delay open until syslog() is called */
+#define LOG_NDELAY 0x08 /* don't delay open */
+#define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
diff --git a/imap/src/osdep/dos/fdstring.c b/imap/src/osdep/dos/fdstring.c
new file mode 100644
index 00000000..7a491f7d
--- /dev/null
+++ b/imap/src/osdep/dos/fdstring.c
@@ -0,0 +1,99 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: File descriptor string 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: 15 April 1997
+ * Last Edited: 4 April 2007
+ */
+
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* String driver for fd stringstructs */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size);
+static char fd_string_next (STRING *s);
+static void fd_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER fd_string = {
+ fd_string_init, /* initialize string structure */
+ fd_string_next, /* get next byte in string structure */
+ fd_string_setpos /* set position in string structure */
+};
+
+
+/* Initialize string structure for fd stringstruct
+ * Accepts: string structure
+ * pointer to string
+ * size of string
+ */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size)
+{
+ FDDATA *d = (FDDATA *) data;
+ /* note fd */
+ s->data = (void *) (unsigned long) d->fd;
+ s->data1 = d->pos; /* note file offset */
+ s->size = size; /* note size */
+ s->curpos = s->chunk = d->chunk;
+ s->chunksize = (unsigned long) d->chunksize;
+ s->offset = 0; /* initial position */
+ /* and size of data */
+ s->cursize = min (s->chunksize,size);
+ /* move to that position in the file */
+ lseek (d->fd,d->pos,L_SET);
+ read (d->fd,s->chunk,(size_t) s->cursize);
+}
+
+/* Get next character from fd stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char fd_string_next (STRING *s)
+{
+ char c = *s->curpos++; /* get next byte */
+ SETPOS (s,GETPOS (s)); /* move to next chunk */
+ return c; /* return the byte */
+}
+
+
+/* Set string pointer position for fd stringstruct
+ * Accepts: string structure
+ * new position
+ */
+
+static void fd_string_setpos (STRING *s,unsigned long i)
+{
+ if (i > s->size) i = s->size; /* don't permit setting beyond EOF */
+ s->offset = i; /* set new offset */
+ s->curpos = s->chunk; /* reset position */
+ /* set size of data */
+ if (s->cursize = min (s->chunksize,SIZE (s))) {
+ /* move to that position in the file */
+ lseek ((long) s->data,s->data1 + s->offset,L_SET);
+ read ((long) s->data,s->curpos,(size_t) s->cursize);
+ }
+}
diff --git a/imap/src/osdep/dos/fdstring.h b/imap/src/osdep/dos/fdstring.h
new file mode 100644
index 00000000..d0a021bf
--- /dev/null
+++ b/imap/src/osdep/dos/fdstring.h
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: File descriptor string 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: 15 April 1997
+ * Last Edited: 30 August 2006
+ */
+
+/* Driver-dependent data passed to init method */
+
+typedef struct fd_data {
+ int fd; /* file descriptor */
+ unsigned long pos; /* initial position */
+ char *chunk; /* I/O buffer chunk */
+ unsigned long chunksize; /* I/O buffer chunk length */
+} FDDATA;
+
+
+extern STRINGDRIVER fd_string;
diff --git a/imap/src/osdep/dos/fs_dos.c b/imap/src/osdep/dos/fs_dos.c
new file mode 100644
index 00000000..03908328
--- /dev/null
+++ b/imap/src/osdep/dos/fs_dos.c
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Free storage management 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: 1 August 1988
+ * Last Edited: 30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+ void *block = malloc (size ? size : (size_t) 1);
+ if (!block) fatal ("Out of memory");
+ return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ * new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+ if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+ fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+ free (*block);
+ *block = NIL;
+}
diff --git a/imap/src/osdep/dos/ftl_dos.c b/imap/src/osdep/dos/ftl_dos.c
new file mode 100644
index 00000000..9e65ef55
--- /dev/null
+++ b/imap/src/osdep/dos/ftl_dos.c
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: DOS/VMS/TOPS-20 crash management 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: 1 August 1988
+ * Last Edited: 30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+ mm_fatal (string); /* pass up the string */
+ abort (); /* die horribly */
+}
diff --git a/imap/src/osdep/dos/makefile b/imap/src/osdep/dos/makefile
new file mode 100644
index 00000000..40cf2276
--- /dev/null
+++ b/imap/src/osdep/dos/makefile
@@ -0,0 +1,98 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+#
+# ========================================================================
+
+
+# Program: Portable C client makefile -- MS-DOS version
+#
+# 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: 11 May 1989
+# Last Edited: 23 May 2007
+
+
+OS = wsk
+EXTRAAUTHENTICATORS=
+DEFAULTAUTHENTICATORS= ext md5 pla log
+EXTRADRIVERS =
+DRIVERS = imap nntp pop3 mtx bezerk
+DEFAULTDRIVER = mtx
+CFLAGS= -AL /DCHUNKSIZE=4096 -nologo $(EXTRACFLAGS)
+CC = cl
+
+all: mtest.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_$(OS).h
+ copy os_$(OS).h osdep.h
+ drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+ mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
+ ECHO #define DEFAULTPROTO $(DEFAULTDRIVER)proto >> LINKAGE.H
+ ECHO if (!mail_parameters (NIL,GET_GETS)) >> LINKAGE.C
+ ECHO mail_parameters (NIL,SET_GETS,(void *) dos_default_gets); >> LINKAGE.C
+ ECHO mail_versioncheck (CCLIENTVERSION); >> LINKAGE.C
+
+mtest.obj: mail.h smtp.h misc.h osdep.h mtest.c
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_$(OS).obj: mail.h osdep.h env_dos.h fs.h ftl.h nl.h tcp.h \
+ os_$(OS).c fs_dos.c ftl_dos.c nl_dos.c env_dos.c pmatch.c write.c
+
+mtxdos.obj: mail.h misc.h osdep.h mtxdos.c
+
+bezrkdos.obj: mail.h misc.h osdep.h bezrkdos.c
+
+dummydos.obj: mail.h dummy.h misc.h osdep.h dummydos.c
+
+cclient.lib: mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+ imap4r1.obj nntp.obj pop3.obj smtp.obj os_$(OS).obj \
+ mtxdos.obj bezrkdos.obj dummydos.obj
+ erase cclient.lib
+ lib cclient +mail+misc+fdstring+flstring+netmsg+newsrc+rfc822+smanager+utf8+utf8aux+imap4r1+nntp+pop3+smtp+os_$(OS)+mtxdos+bezrkdos+dummydos;
+
+mtest.exe: cclient.lib mtest.obj
+ mtest$(OS)
diff --git a/imap/src/osdep/dos/mkautaux.bat b/imap/src/osdep/dos/mkautaux.bat
new file mode 100644
index 00000000..5d24d83b
--- /dev/null
+++ b/imap/src/osdep/dos/mkautaux.bat
@@ -0,0 +1,29 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Authenticator Linkage Generator auxillary for DOS
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 7 December 1995
+REM Last Edited:30 August 2006
+
+ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
+ECHO auth_link (&auth_%1); /* link in the %1 authenticator */ >> LINKAGE.C
+ECHO #include "auth_%1.c" >> AUTHS.C
diff --git a/imap/src/osdep/dos/mkauths.bat b/imap/src/osdep/dos/mkauths.bat
new file mode 100644
index 00000000..d8c5e360
--- /dev/null
+++ b/imap/src/osdep/dos/mkauths.bat
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Authenticator Linkage Generator for DOS and Windows
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 6 December 1995
+REM Last Edited:30 August 2006
+
+REM Erase old authenticators list
+IF EXIST AUTHS.C DEL AUTHS.C
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
+
+EXIT 0
diff --git a/imap/src/osdep/dos/mtestdbw.bat b/imap/src/osdep/dos/mtestdbw.bat
new file mode 100644
index 00000000..95452a01
--- /dev/null
+++ b/imap/src/osdep/dos/mtestdbw.bat
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Portable C client makefile -- MS-DOS B&W link
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llbwtcp.lib llibce.lib
diff --git a/imap/src/osdep/dos/mtestdnf.bat b/imap/src/osdep/dos/mtestdnf.bat
new file mode 100644
index 00000000..451bdda3
--- /dev/null
+++ b/imap/src/osdep/dos/mtestdnf.bat
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Portable C client makefile -- MS-DOS PC-NFS link
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib ltklib.lib
diff --git a/imap/src/osdep/dos/mtestdnv.bat b/imap/src/osdep/dos/mtestdnv.bat
new file mode 100644
index 00000000..2b444e18
--- /dev/null
+++ b/imap/src/osdep/dos/mtestdnv.bat
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Portable C client makefile -- MS-DOS Novell link
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llibsock.lib
diff --git a/imap/src/osdep/dos/mtestdpc.bat b/imap/src/osdep/dos/mtestdpc.bat
new file mode 100644
index 00000000..ca131181
--- /dev/null
+++ b/imap/src/osdep/dos/mtestdpc.bat
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Portable C client makefile -- MS-DOS PC/TCP link
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib lsocket.lib lnetlib.lib lpc.lib lconfig.lib llibce.lib;
diff --git a/imap/src/osdep/dos/mtestdwa.bat b/imap/src/osdep/dos/mtestdwa.bat
new file mode 100644
index 00000000..3d26146f
--- /dev/null
+++ b/imap/src/osdep/dos/mtestdwa.bat
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Portable C client makefile -- MS-DOS Waterloo link
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib wattcplg.lib
diff --git a/imap/src/osdep/dos/mtestwsk.bat b/imap/src/osdep/dos/mtestwsk.bat
new file mode 100644
index 00000000..5d8922e3
--- /dev/null
+++ b/imap/src/osdep/dos/mtestwsk.bat
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM
+REM ========================================================================
+
+REM Program: Portable C client makefile -- MS-DOS Winsock link
+REM
+REM Author: Mark Crispin
+REM Networks and Distributed Computing
+REM Computing & Communications
+REM University of Washington
+REM Administration Building, AG-44
+REM Seattle, WA 98195
+REM Internet: MRC@CAC.Washington.EDU
+REM
+REM Date: 26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOD:llibce mtest.obj,mtest.exe,,cclient.lib winsock.lib llibcewq.lib libw.lib, mtest
diff --git a/imap/src/osdep/dos/mtxdos.c b/imap/src/osdep/dos/mtxdos.c
new file mode 100644
index 00000000..ad969267
--- /dev/null
+++ b/imap/src/osdep/dos/mtxdos.c
@@ -0,0 +1,875 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: MTX mail 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: 24 June 1992
+ * Last Edited: 30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys\stat.h>
+#include <dos.h>
+#include "rfc822.h"
+#include "dummy.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* MTX I/O stream local data */
+
+typedef struct mtx_local {
+ int fd; /* file descriptor for I/O */
+ off_t filesize; /* file size parsed */
+ unsigned char *buf; /* temporary buffer */
+} MTXLOCAL;
+
+
+/* Drive-dependent data passed to init method */
+
+typedef struct mtx_data {
+ int fd; /* file data */
+ unsigned long pos; /* initial position */
+} MTXDATA;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MTXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mtx_valid (char *name);
+long mtx_isvalid (char *name,char *tmp);
+void *mtx_parameters (long function,void *value);
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mtx_create (MAILSTREAM *stream,char *mailbox);
+long mtx_delete (MAILSTREAM *stream,char *mailbox);
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *mtx_open (MAILSTREAM *stream);
+void mtx_close (MAILSTREAM *stream,long options);
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *length,long flags);
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mtx_ping (MAILSTREAM *stream);
+void mtx_check (MAILSTREAM *stream);
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+char *mtx_file (char *dst,char *name);
+long mtx_badname (char *tmp,char *s);
+long mtx_parse (MAILSTREAM *stream);
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno);
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *size);
+
+/* MTX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mtxdriver = {
+ "mtx", /* driver name */
+ /* driver flags */
+ DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY,
+ (DRIVER *) NIL, /* next driver */
+ mtx_valid, /* mailbox is valid for us */
+ mtx_parameters, /* manipulate parameters */
+ mtx_scan, /* scan mailboxes */
+ mtx_list, /* list mailboxes */
+ mtx_lsub, /* list subscribed mailboxes */
+ NIL, /* subscribe to mailbox */
+ NIL, /* unsubscribe from mailbox */
+ mtx_create, /* create mailbox */
+ mtx_delete, /* delete mailbox */
+ mtx_rename, /* rename mailbox */
+ mail_status_default, /* status of mailbox */
+ mtx_open, /* open mailbox */
+ mtx_close, /* close mailbox */
+ NIL, /* fetch message "fast" attributes */
+ NIL, /* fetch message flags */
+ NIL, /* fetch overview */
+ NIL, /* fetch message envelopes */
+ mtx_header, /* fetch message header */
+ mtx_text, /* fetch message body */
+ NIL, /* fetch partial message text */
+ NIL, /* unique identifier */
+ NIL, /* message number */
+ NIL, /* modify flags */
+ mtx_flagmsg, /* per-message modify flags */
+ NIL, /* search for message based on criteria */
+ NIL, /* sort messages */
+ NIL, /* thread messages */
+ mtx_ping, /* ping mailbox to see if still alive */
+ mtx_check, /* check for new messages */
+ mtx_expunge, /* expunge deleted messages */
+ mtx_copy, /* copy messages to another mailbox */
+ mtx_append, /* append string message to mailbox */
+ NIL /* garbage collect stream */
+};
+
+ /* prototype stream */
+MAILSTREAM mtxproto = {&mtxdriver};
+
+/* MTX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mtx_valid (char *name)
+{
+ char tmp[MAILTMPLEN];
+ return mtx_isvalid (name,tmp) ? &mtxdriver : (DRIVER *) NIL;
+}
+
+
+/* MTX mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+long mtx_isvalid (char *name,char *tmp)
+{
+ int fd;
+ long ret = NIL;
+ char *s;
+ struct stat sbuf;
+ errno = EINVAL; /* assume invalid argument */
+ /* if file, get its status */
+ if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) {
+ if (!sbuf.st_size)errno = 0;/* empty file */
+ else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) {
+ memset (tmp,'\0',MAILTMPLEN);
+ if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
+ (s[1] == '\012')) { /* valid format? */
+ *s = '\0'; /* tie off header */
+ /* must begin with dd-mmm-yy" */
+ ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+ (tmp[1] == '-' && tmp[5] == '-')) &&
+ (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+ }
+ else errno = -1; /* bogus format */
+ close (fd); /* close the file */
+ }
+ }
+ /* in case INBOX but not mtx format */
+ else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) &&
+ ((name[1] == 'N') || (name[1] == 'n')) &&
+ ((name[2] == 'B') || (name[2] == 'b')) &&
+ ((name[3] == 'O') || (name[3] == 'o')) &&
+ ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1;
+ return ret; /* return what we should */
+}
+
+
+/* MTX manipulate driver parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mtx_parameters (long function,void *value)
+{
+ return NIL;
+}
+
+/* MTX mail scan mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ * string to scan
+ */
+
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+ if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MTX mail list mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ */
+
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+ if (stream) dummy_list (stream,ref,pat);
+}
+
+
+/* MTX mail list subscribed mailboxes
+ * Accepts: mail stream
+ * reference
+ * pattern to search
+ */
+
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+ if (stream) dummy_lsub (stream,ref,pat);
+}
+
+/* MTX mail create mailbox
+ * Accepts: MAIL stream
+ * mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_create (MAILSTREAM *stream,char *mailbox)
+{
+ return dummy_create (stream,mailbox);
+}
+
+
+/* MTX mail delete mailbox
+ * Accepts: MAIL stream
+ * mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_delete (MAILSTREAM *stream,char *mailbox)
+{
+ return dummy_delete (stream,mailbox);
+}
+
+
+/* MTX mail rename mailbox
+ * Accepts: MAIL stream
+ * old mailbox name
+ * new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+ return dummy_rename (stream,old,newname);
+}
+
+/* MTX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mtx_open (MAILSTREAM *stream)
+{
+ long i;
+ int fd;
+ char *s;
+ char tmp[MAILTMPLEN];
+ /* return prototype for OP_PROTOTYPE call */
+ if (!stream) return &mtxproto;
+ if (stream->local) fatal ("mtx recycle stream");
+ if (!mailboxfile (tmp,stream->mailbox))
+ return (MAILSTREAM *) mtx_badname (tmp,stream->mailbox);
+ /* open, possibly creating INBOX */
+ if (((fd = open (tmp,O_BINARY|(stream->rdonly ? O_RDONLY:O_RDWR),NIL)) < 0)&&
+ (compare_cstring (stream->mailbox,"INBOX") ||
+ ((fd = open (tmp,O_BINARY|O_RDWR|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))<0))){
+ sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ stream->local = fs_get (sizeof (MTXLOCAL));
+ /* canonicalize the stream mailbox name */
+ fs_give ((void **) &stream->mailbox);
+ if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0';
+ stream->mailbox = cpystr (tmp);
+ LOCAL->fd = fd; /* note the file */
+ LOCAL->filesize = 0; /* initialize parsed file size */
+ LOCAL->buf = NIL; /* initially no local buffer */
+ stream->sequence++; /* bump sequence number */
+ stream->uid_validity = time (0);
+ /* parse mailbox */
+ stream->nmsgs = stream->recent = 0;
+ if (!mtx_ping (stream)) return NIL;
+ if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL);
+ stream->perm_seen = stream->perm_deleted =
+ stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+ stream->rdonly ? NIL : T;
+ stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+ return stream; /* return stream to caller */
+}
+
+/* MTX mail close
+ * Accepts: MAIL stream
+ * close options
+ */
+
+void mtx_close (MAILSTREAM *stream,long options)
+{
+ if (stream && LOCAL) { /* only if a file is open */
+ int silent = stream->silent;
+ stream->silent = T;
+ if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
+ close (LOCAL->fd); /* close the local file */
+ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+ /* nuke the local data */
+ fs_give ((void **) &stream->local);
+ stream->dtb = NIL; /* log out the DTB */
+ }
+}
+
+/* MTX mail fetch message header
+ * Accepts: MAIL stream
+ * message # to fetch
+ * pointer to returned header text length
+ * option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+ long flags)
+{
+ *length = 0; /* default to empty */
+ if (flags & FT_UID) return "";/* UID call "impossible" */
+ /* get to header position */
+ lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
+ /* is buffer big enough? */
+ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+ LOCAL->buf = (char *) fs_get ((size_t) *length + 1);
+ LOCAL->buf[*length] = '\0'; /* tie off string */
+ /* slurp the data */
+ read (LOCAL->fd,LOCAL->buf,(size_t) *length);
+ return LOCAL->buf;
+}
+
+
+/* MTX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ * message # to fetch
+ * pointer to returned header text length
+ * option flags
+ * Returns: T, always
+ */
+
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+ MESSAGECACHE *elt;
+ FDDATA d;
+ unsigned long hdrsize,hdrpos;
+ /* UID call "impossible" */
+ if (flags & FT_UID) return NIL;
+ elt = mail_elt (stream,msgno);/* if message not seen */
+ if (elt->seen && !(flags & FT_PEEK)) {
+ elt->seen = T; /* mark message as seen */
+ /* recalculate status */
+ mtx_update_status (stream,msgno);
+ mm_flags (stream,msgno);
+ }
+ /* get location of text data */
+ hdrpos = mtx_hdrpos (stream,msgno,&hdrsize);
+ d.fd = LOCAL->fd; /* set initial stringstruct */
+ d.pos = hdrpos + hdrsize;
+ /* flush old buffer */
+ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+ d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE);
+ INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize);
+ return T; /* success */
+}
+
+/* MTX mail per-message modify flags
+ * Accepts: MAIL stream
+ * message cache element
+ */
+
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+ /* recalculate status */
+ mtx_update_status (stream,elt->msgno);
+}
+
+
+/* MTX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mtx_ping (MAILSTREAM *stream)
+{
+ /* punt if stream no longer alive */
+ if (!(stream && LOCAL)) return NIL;
+ /* parse mailbox, punt if parse dies */
+ return (mtx_parse (stream)) ? T : NIL;
+}
+
+
+/* MTX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mtx_check (MAILSTREAM *stream)
+{
+ unsigned long i = 1;
+ if (mtx_ping (stream)) { /* ping mailbox */
+ /* get new message status */
+ while (i <= stream->nmsgs) mail_elt (stream,i++);
+ mm_log ("Check completed",(long) NIL);
+ }
+}
+
+/* MTX mail expunge mailbox
+ * Accepts: MAIL stream
+ * sequence to expunge if non-NIL
+ * expunge options
+ * Returns: T, always
+ */
+
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+ long ret;
+ unsigned long i = 1;
+ unsigned long j,k,m,recent;
+ unsigned long n = 0;
+ unsigned long delta = 0;
+ MESSAGECACHE *elt;
+ char tmp[MAILTMPLEN];
+ if (!(ret = (sequence ? ((options & EX_UID) ?
+ mail_uid_sequence (stream,sequence) :
+ mail_sequence (stream,sequence)) : LONGT) &&
+ mtx_ping (stream))); /* parse sequence if given, ping stream */
+ else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
+ else {
+ mm_critical (stream); /* go critical */
+ recent = stream->recent; /* get recent now that pinged */
+ while (i <= stream->nmsgs) {/* for each message */
+ elt = mail_elt (stream,i);/* get cache element */
+ /* number of bytes to smash or preserve */
+ k = elt->private.special.text.size + elt->rfc822_size;
+ /* if need to expunge this message */
+ if (elt->deleted && (sequence ? elt->sequence : T)) {
+ /* if recent, note one less recent message */
+ if (elt->recent) --recent;
+ delta += k; /* number of bytes to delete */
+ /* notify upper levels */
+ mail_expunged (stream,i);
+ n++; /* count up one more deleted message */
+ }
+ else if (i++ && delta) { /* preserved message */
+ /* first byte to preserve */
+ j = elt->private.special.offset;
+ do { /* read from source position */
+ m = min (k,(unsigned long) MAILTMPLEN);
+ lseek (LOCAL->fd,j,SEEK_SET);
+ read (LOCAL->fd,tmp,(size_t) m);
+ /* write to destination position */
+ lseek (LOCAL->fd,j - delta,SEEK_SET);
+ write (LOCAL->fd,tmp,(size_t) m);
+ j += m; /* next chunk, perhaps */
+ } while (k -= m); /* until done */
+ elt->private.special.offset -= delta;
+ }
+ }
+ if (n) { /* truncate file after last message */
+ chsize (LOCAL->fd,LOCAL->filesize -= delta);
+ sprintf (tmp,"Expunged %ld messages",n);
+ mm_log (tmp,(long) NIL); /* output the news */
+ }
+ else mm_log ("No messages deleted, so no update needed",(long) NIL);
+ mm_nocritical (stream); /* release critical */
+ /* notify upper level of new mailbox size */
+ mail_exists (stream,stream->nmsgs);
+ mail_recent (stream,recent);
+ }
+ return ret;
+}
+
+/* MTX mail copy message(s)
+ * Accepts: MAIL stream
+ * sequence
+ * destination mailbox
+ * copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+ char tmp[MAILTMPLEN];
+ struct stat sbuf;
+ MESSAGECACHE *elt;
+ unsigned long i,j,k;
+ long ret = LONGT;
+ int fd;
+ mailproxycopy_t pc =
+ (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+ if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+ mail_sequence (stream,sequence))) return NIL;
+ if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
+ case ENOENT: /* no such file? */
+ mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+ (long) NIL);
+ return NIL;
+ case 0: /* merely empty file? */
+ break;
+ case EINVAL: /* name is bogus */
+ if (pc) return (*pc) (stream,sequence,mailbox,options);
+ return mtx_badname (tmp,mailbox);
+ default: /* file exists, but not valid format */
+ if (pc) return (*pc) (stream,sequence,mailbox,options);
+ sprintf (tmp,"Not a MTX-format mailbox: %s",mailbox);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ /* open the destination */
+ if (!mailboxfile (tmp,mailbox) ||
+ (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+ S_IREAD|S_IWRITE)) < 0) {
+ sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+
+ mm_critical (stream); /* go critical */
+ fstat (fd,&sbuf); /* get current file size */
+ /* for each requested message */
+ for (i = 1; ret && (i <= stream->nmsgs); i++)
+ if ((elt = mail_elt (stream,i))->sequence) {
+ lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET);
+ /* number of bytes to copy */
+ k = elt->private.special.text.size + elt->rfc822_size;
+ do { /* read from source position */
+ j = min (k,(long) MAILTMPLEN);
+ read (LOCAL->fd,tmp,(size_t) j);
+ if (write (fd,tmp,(size_t) j) < 0) {
+ sprintf (tmp,"Unable to write message: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ chsize (fd,sbuf.st_size);
+ j = k;
+ ret = NIL; /* note error */
+ break;
+ }
+ } while (k -= j); /* until done */
+ }
+ close (fd); /* close the file */
+ mm_nocritical (stream); /* release critical */
+ /* delete all requested messages */
+ if (ret && (options & CP_MOVE)) for (i = 1; i <= stream->nmsgs; i++)
+ if ((elt = mail_elt (stream,i))->sequence) {
+ elt->deleted = T; /* mark message deleted */
+ /* recalculate status */
+ mtx_update_status (stream,i);
+ }
+ if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+ mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+ return ret;
+}
+
+/* MTX mail append message from stringstruct
+ * Accepts: MAIL stream
+ * destination mailbox
+ * append callback
+ * data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+ struct stat sbuf;
+ int fd,ld,c;
+ char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN];
+ FILE *df;
+ MESSAGECACHE elt;
+ long f;
+ unsigned long i,uf;
+ STRING *message;
+ long ret = LONGT;
+ /* default stream to prototype */
+ if (!stream) stream = &mtxproto;
+ /* make sure valid mailbox */
+ if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
+ case ENOENT: /* no such file? */
+ if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
+ ((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
+ ((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
+ ((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
+ ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5])
+ dummy_create (NIL,"INBOX.MTX");
+ else {
+ mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+ return NIL;
+ }
+ /* falls through */
+ case 0: /* merely empty file? */
+ break;
+ case EINVAL:
+ return mtx_badname (tmp,mailbox);
+ default:
+ sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ /* get first message */
+ if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+ /* open destination mailbox */
+ if (!mailboxfile (file,mailbox) ||
+ ((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+ S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) {
+ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ mm_critical (stream); /* go critical */
+ fstat (fd,&sbuf); /* get current file size */
+
+ errno = 0;
+ do { /* parse flags */
+ if (!SIZE (message)) { /* guard against zero-length */
+ mm_log ("Append of zero-length message",ERROR);
+ ret = NIL;
+ break;
+ }
+ f = mail_parse_flags (stream,flags,&i);
+ /* reverse bits (dontcha wish we had CIRC?) */
+ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+ if (date) { /* parse date if given */
+ if (!mail_parse_date (&elt,date)) {
+ sprintf (tmp,"Bad date in append: %.80s",date);
+ mm_log (tmp,ERROR);
+ ret = NIL; /* mark failure */
+ break;
+ }
+ mail_date (tmp,&elt); /* write preseved date */
+ }
+ else internal_date (tmp); /* get current date in IMAP format */
+ /* write header */
+ if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
+ (unsigned long) f) < 0) ret = NIL;
+ else { /* write message */
+ if (i) do c = 0xff & SNX (message);
+ while ((putc (c,df) != EOF) && --i);
+ /* get next message */
+ if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+ }
+ } while (ret && message);
+ /* revert file if failure */
+ if (!ret || (fflush (df) == EOF)) {
+ chsize (fd,sbuf.st_size); /* revert file */
+ close (fd); /* make sure fclose() doesn't corrupt us */
+ if (errno) {
+ sprintf (tmp,"Message append failed: %s",strerror (errno));
+ mm_log (tmp,ERROR);
+ }
+ ret = NIL;
+ }
+ fclose (df); /* close the file */
+ mm_nocritical (stream); /* release critical */
+ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+ mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+ WARN);
+ return ret;
+}
+
+
+/* Return bad file name error message
+ * Accepts: temporary buffer
+ * file name
+ * Returns: long NIL always
+ */
+
+long mtx_badname (char *tmp,char *s)
+{
+ sprintf (tmp,"Invalid mailbox name: %s",s);
+ mm_log (tmp,ERROR);
+ return (long) NIL;
+}
+
+/* Parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ * NIL if failure, stream aborted
+ */
+
+long mtx_parse (MAILSTREAM *stream)
+{
+ struct stat sbuf;
+ MESSAGECACHE *elt = NIL;
+ unsigned char *s,*t,*x,lbuf[65];
+ char tmp[MAILTMPLEN];
+ long i;
+ long curpos = LOCAL->filesize;
+ long nmsgs = stream->nmsgs;
+ long recent = stream->recent;
+ fstat (LOCAL->fd,&sbuf); /* get status */
+ if (sbuf.st_size < curpos) { /* sanity check */
+ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+ mm_log (tmp,ERROR);
+ mtx_close (stream,NIL);
+ return NIL;
+ }
+ /* while there is stuff to parse */
+ while (i = sbuf.st_size - curpos) {
+ /* get to that position in the file */
+ lseek (LOCAL->fd,curpos,SEEK_SET);
+ if ((i = read (LOCAL->fd,lbuf,64)) <= 0) {
+ sprintf (tmp,"Unable to read internal header at %ld, size = %ld: %s",
+ curpos,sbuf.st_size,i ? strerror (errno) : "no data read");
+ mm_log (tmp,ERROR);
+ mtx_close (stream,NIL);
+ return NIL;
+ }
+ lbuf[i] = '\0'; /* tie off buffer just in case */
+ if (!((s = strchr (lbuf,'\015')) && (s[1] == '\012'))) {
+ sprintf (tmp,"Unable to find end of line at %ld in %ld bytes, text: %s",
+ curpos,i,(char *) lbuf);
+ mm_log (tmp,ERROR);
+ mtx_close (stream,NIL);
+ return NIL;
+ }
+ *s = '\0'; /* tie off header line */
+ i = (s + 2) - lbuf; /* note start of text offset */
+ if (!((s = strchr (lbuf,',')) && (t = strchr (s+1,';')))) {
+ sprintf (tmp,"Unable to parse internal header at %ld: %s",curpos,
+ (char *) lbuf);
+ mm_log (tmp,ERROR);
+ mtx_close (stream,NIL);
+ return NIL;
+ }
+
+ *s++ = '\0'; *t++ = '\0'; /* tie off fields */
+ /* intantiate an elt for this message */
+ (elt = mail_elt (stream,++nmsgs))->valid = T;
+ elt->private.uid = ++stream->uid_last;
+ /* note file offset of header */
+ elt->private.special.offset = curpos;
+ /* as well as offset from header of message */
+ elt->private.special.text.size = i;
+ /* header size not known yet */
+ elt->private.msg.header.text.size = 0;
+ /* parse the header components */
+ if (!(mail_parse_date (elt,lbuf) &&
+ (elt->rfc822_size = strtol (x = s,(char **) &s,10)) && (!(s && *s))&&
+ isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+ isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+ isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+ isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])) {
+ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+ curpos,(char *) lbuf,(char *) x,(char *) t);
+ mtx_close (stream,NIL);
+ return NIL;
+ }
+ /* update current position to next header */
+ curpos += i + elt->rfc822_size;
+ /* calculate system flags */
+ if ((i = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+ if (i & fDELETED) elt->deleted = T;
+ if (i & fFLAGGED) elt->flagged = T;
+ if (i & fANSWERED) elt->answered = T;
+ if (i & fDRAFT) elt->draft = T;
+ if (curpos > sbuf.st_size) {
+ sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+ elt->private.special.offset,curpos,sbuf.st_size);
+ mm_log (tmp,ERROR);
+ mtx_close (stream,NIL);
+ return NIL;
+ }
+ }
+ /* update parsed file size */
+ LOCAL->filesize = sbuf.st_size;
+ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */
+ mail_recent (stream,recent); /* and of change in recent messages */
+ return T; /* return the winnage */
+}
+
+/* Update status string
+ * Accepts: MAIL stream
+ * message number
+ */
+
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno)
+{
+ char tmp[MAILTMPLEN];
+ MESSAGECACHE *elt = mail_elt (stream,msgno);
+ unsigned long j,k = 0;
+ /* not if readonly you don't */
+ if (stream->rdonly || !elt->valid) return;
+ j = elt->user_flags; /* get user flags */
+ /* reverse bits (dontcha wish we had CIRC?) */
+ while (j) k |= 1 << 29 - find_rightmost_bit (&j);
+ sprintf (tmp,"%010lo%02o",k, /* print new flag string */
+ fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+ (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+ (fDRAFT * elt->draft));
+ /* get to that place in the file */
+ lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+ elt->private.special.text.size - 14,SEEK_SET);
+ write (LOCAL->fd,tmp,12); /* write new flags */
+}
+
+/* MTX locate header for a message
+ * Accepts: MAIL stream
+ * message number
+ * pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+ unsigned long *size)
+{
+ unsigned long siz;
+ size_t i = 0;
+ int q = 0;
+ char *s,tmp[MAILTMPLEN];
+ MESSAGECACHE *elt = mail_elt (stream,msgno);
+ long pos = elt->private.special.offset + elt->private.special.text.size;
+ /* is header size known? */
+ if (!(*size = elt->private.msg.header.text.size)) {
+ /* get to header position */
+ lseek (LOCAL->fd,pos,SEEK_SET);
+ /* search message for CRLF CRLF */
+ for (siz = 1; siz <= elt->rfc822_size; siz++) {
+ if (!i && /* buffer empty? */
+ (read (LOCAL->fd,s = tmp,
+ i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0))
+ return pos;
+ else i--;
+ switch (q) { /* sniff at buffer */
+ case 0: /* first character */
+ q = (*s++ == '\015') ? 1 : 0;
+ break;
+ case 1: /* second character */
+ q = (*s++ == '\012') ? 2 : 0;
+ break;
+ case 2: /* third character */
+ q = (*s++ == '\015') ? 3 : 0;
+ break;
+ case 3: /* fourth character */
+ if (*s++ == '\012') { /* have the sequence? */
+ /* yes, note for later */
+ elt->private.msg.header.text.size = (*size = siz);
+ return pos; /* return to caller */
+ }
+ q = 0; /* lost... */
+ break;
+ }
+ }
+ }
+ return pos; /* have position */
+}
diff --git a/imap/src/osdep/dos/nl_dos.c b/imap/src/osdep/dos/nl_dos.c
new file mode 100644
index 00000000..47cb7f0a
--- /dev/null
+++ b/imap/src/osdep/dos/nl_dos.c
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Windows/TOPS-20 newline 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: 1 August 1988
+ * Last Edited: 30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ * pointer to size of destination string buffer
+ * source string
+ * length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+ unsigned char *src,unsigned long srcl)
+{
+ /* flush destination buffer if too small */
+ if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
+ if (!*dst) { /* make a new buffer if needed */
+ *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
+ if (dstl) *dstl = srcl; /* return new buffer length to main program */
+ }
+ /* copy strings */
+ if (srcl) memcpy (*dst,src,(size_t) srcl);
+ *(*dst + srcl) = '\0'; /* tie off destination */
+ return srcl; /* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+ return SIZE (s); /* no-brainer on DOS! */
+}
diff --git a/imap/src/osdep/dos/os_dbw.c b/imap/src/osdep/dos/os_dbw.c
new file mode 100644
index 00000000..e28e1ab0
--- /dev/null
+++ b/imap/src/osdep/dos/os_dbw.c
@@ -0,0 +1,91 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- MS-DOS (B&W) version
+ *
+ * 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h" /* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include "misc.h"
+#include "stdlib.h"
+#include "bwtcp.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#define read soread
+#define write sowrite
+#define close soclose
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+ char *s;
+ if (!myLocalHost) { /* known yet? */
+ /* get local host name from DISPLAY env var */
+ if (!((s = getenv ("DISPLAY")) || (s = getenv ("display")))) {
+ mm_log ("Environment variable 'DISPLAY' is not set", ERROR);
+ s = "random-pc";
+ }
+ myLocalHost = cpystr (s);
+ }
+ return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ * socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ * else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+ char *s = *host; /* in case of error */
+ sin->sin_addr.s_addr = rhost (host);
+ if (sin->sin_addr.s_addr == -1) {
+ *host = s; /* error, restore old host name */
+ return NIL;
+ }
+ *host = cpystr (*host); /* make permanent copy of name */
+ return T; /* success */
+}
diff --git a/imap/src/osdep/dos/os_dbw.h b/imap/src/osdep/dos/os_dbw.h
new file mode 100644
index 00000000..f22cae6f
--- /dev/null
+++ b/imap/src/osdep/dos/os_dbw.h
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- DOS (B&W/Novell) version
+ *
+ * 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: 11 May 1989
+ * Last Edited: 30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
diff --git a/imap/src/osdep/dos/os_dnf.c b/imap/src/osdep/dos/os_dnf.c
new file mode 100644
index 00000000..dcc3ea64
--- /dev/null
+++ b/imap/src/osdep/dos/os_dnf.c
@@ -0,0 +1,95 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- MS-DOS (PC-NFS) version
+ *
+ * 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h" /* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include <sys\nfs_time.h>
+#include <sys\tk_types.h>
+#include <sys\socket.h>
+#include <netinet\in.h>
+#include <tk_errno.h>
+#include <sys\uio.h>
+#include <netdb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+ if (!myLocalHost) { /* known yet? */
+ char *s,tmp[MAILTMPLEN];
+ unsigned long myip;
+ /* see if known host name */
+ if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp;
+ /* no, try host address */
+ else if (get_myipaddr ((char *) &myip))
+ sprintf (s = tmp,"[%s]",inet_ntoa (myip));
+ else s = "random-pc"; /* say what? */
+ myLocalHost = cpystr (s); /* record for subsequent use */
+ }
+ return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ * socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ * else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+ long ret = -1;
+ char tmp[MAILTMPLEN];
+ struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
+ if (!hn) return NIL; /* got a host name? */
+ *host = cpystr (hn->h_name); /* set official name */
+ /* copy host addresses */
+ memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
+ return T;
+}
diff --git a/imap/src/osdep/dos/os_dnf.h b/imap/src/osdep/dos/os_dnf.h
new file mode 100644
index 00000000..3a832217
--- /dev/null
+++ b/imap/src/osdep/dos/os_dnf.h
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- DOS (PC-NFS) version
+ *
+ * Author: Mike Seibel from Novell version by Mark Crispin
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MikeS@CAC.Washington.EDU
+ *
+ * Date: 11 May 1989
+ * Last Edited: 30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <tklib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
diff --git a/imap/src/osdep/dos/os_dnv.c b/imap/src/osdep/dos/os_dnv.c
new file mode 100644
index 00000000..e0341764
--- /dev/null
+++ b/imap/src/osdep/dos/os_dnv.c
@@ -0,0 +1,95 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- MS-DOS (Novell) version
+ *
+ * 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h" /* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include <sys\socket.h>
+#include <netinet\in.h>
+#include <netdb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#define read soread
+#define write sowrite
+#define close soclose
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+ if (!myLocalHost) { /* known yet? */
+ char *s,tmp[MAILTMPLEN];
+ struct hostent *he;
+ struct in_addr in;
+ /* could we get local id? */
+ if ((in.s_addr = getmyipaddr ()) != -1) {
+ if (he = gethostbyaddr ((char *) &in.s_addr,4,PF_INET)) s = he->h_name;
+ else sprintf (s = tmp,"[%s]",inet_ntoa (in));
+ }
+ else s = "random-pc"; /* say what? */
+ myLocalHost = cpystr (s); /* record for subsequent use */
+ }
+ return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ * socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ * else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+ char *s = *host; /* in case of error */
+ sin->sin_addr.s_addr = rhost (host);
+ if (sin->sin_addr.s_addr == -1) {
+ *host = s; /* error, restore old host name */
+ return NIL;
+ }
+ *host = cpystr (*host); /* make permanent copy of name */
+ return T; /* success */
+}
diff --git a/imap/src/osdep/dos/os_dnv.h b/imap/src/osdep/dos/os_dnv.h
new file mode 100644
index 00000000..f22cae6f
--- /dev/null
+++ b/imap/src/osdep/dos/os_dnv.h
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- DOS (B&W/Novell) version
+ *
+ * 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: 11 May 1989
+ * Last Edited: 30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
diff --git a/imap/src/osdep/dos/os_dpc.c b/imap/src/osdep/dos/os_dpc.c
new file mode 100644
index 00000000..eece19d7
--- /dev/null
+++ b/imap/src/osdep/dos/os_dpc.c
@@ -0,0 +1,102 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- MS-DOS (PC/TCP) version
+ *
+ * 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h" /* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include <4bsddefs.h>
+#include <sys\socket.h>
+#include <errno.h>
+#include <arpa\inet.h>
+#include <netinet\in.h>
+#include <netdb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+ if (!myLocalHost) { /* known yet */
+ char *s,tmp[MAILTMPLEN];
+ long myip;
+ /* see if known host name */
+ if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp;
+ /* no, try IP address */
+ else if (myip = gethostid ()) {
+ struct in_addr in;
+ in.s_addr = myip;
+ sprintf (s = tmp,"[%s]",inet_ntoa (in));
+ }
+ /* older kernel, look harder. */
+ else if (getconf ("ifcust","ip-address",tmp+1,MAILTMPLEN-2)) {
+ *(s = tmp) = '['; /* wrap the brackets around it */
+ strcat (tmp,"]");
+ }
+ else s = "random-pc"; /* say what? */
+ myLocalHost = cpystr (s); /* record for subsequent use */
+ }
+ return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ * socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ * else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+ long ret = -1;
+ char tmp[MAILTMPLEN];
+ struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
+ if (!hn) return NIL; /* got a host name? */
+ *host = cpystr (hn->h_name); /* set official name */
+ /* copy host addresses */
+ memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
+ return T;
+}
diff --git a/imap/src/osdep/dos/os_dpc.h b/imap/src/osdep/dos/os_dpc.h
new file mode 100644
index 00000000..5de3e637
--- /dev/null
+++ b/imap/src/osdep/dos/os_dpc.h
@@ -0,0 +1,41 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- DOS (PC/TCP) version
+ *
+ * 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: 11 May 1989
+ * Last Edited: 30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
diff --git a/imap/src/osdep/dos/os_dwa.c b/imap/src/osdep/dos/os_dwa.c
new file mode 100644
index 00000000..36e5b147
--- /dev/null
+++ b/imap/src/osdep/dos/os_dwa.c
@@ -0,0 +1,72 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- DOS (Waterloo) version
+ *
+ * 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+#include <tcp.h> /* must be before TCPSTREAM definition */
+#include "tcp_dwa.h" /* must be before osdep include our tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include "misc.h"
+
+/* Undo compatibility definition */
+
+#undef tcp_open
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#include "tcp_dwa.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+ if (!myLocalHost) {
+ char *s,hname[32],tmp[MAILTMPLEN];
+ long myip;
+
+ if (!sock_initted++) sock_init();
+ tcp_cbrk (0x01); /* turn off ctrl-break catching */
+ /*
+ * haven't discovered a way to find out the local host's
+ * name with wattcp yet.
+ */
+ if (myip = gethostid ()) sprintf (s = tmp,"[%s]",inet_ntoa (hname,myip));
+ else s = "random-pc";
+ myLocalHost = cpystr (s);
+ }
+ return myLocalHost;
+}
diff --git a/imap/src/osdep/dos/os_dwa.h b/imap/src/osdep/dos/os_dwa.h
new file mode 100644
index 00000000..f70fa31b
--- /dev/null
+++ b/imap/src/osdep/dos/os_dwa.h
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- DOS (Waterloo) version
+ *
+ * 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: 11 May 1989
+ * Last Edited: 30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define tcp_open TCP_open
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
diff --git a/imap/src/osdep/dos/os_wsk.c b/imap/src/osdep/dos/os_wsk.c
new file mode 100644
index 00000000..8627ef89
--- /dev/null
+++ b/imap/src/osdep/dos/os_wsk.c
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- Winsock version
+ *
+ * Author: Mike Seibel from Unix version by Mark Crispin
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MikeS@CAC.Washington.EDU
+ *
+ * Date: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+#include "tcp_wsk.h" /* must be before osdep includes tcp.h */
+#undef ERROR /* quell conflicting def warning */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#include "tcp_wsk.c"
diff --git a/imap/src/osdep/dos/os_wsk.h b/imap/src/osdep/dos/os_wsk.h
new file mode 100644
index 00000000..10213cef
--- /dev/null
+++ b/imap/src/osdep/dos/os_wsk.h
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Operating-system dependent routines -- 16-bit Winsock version
+ *
+ * Author: Mike Seibel from Novell version by Mark Crispin
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MikeS@CAC.Washington.EDU
+ *
+ * Date: 11 May 1989
+ * Last Edited: 30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+#define WSA_VERSION ((1 << 8) | 1)
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+
+#undef noErr
+#undef MAC
diff --git a/imap/src/osdep/dos/pmatch.c b/imap/src/osdep/dos/pmatch.c
new file mode 100644
index 00000000..95a0bb86
--- /dev/null
+++ b/imap/src/osdep/dos/pmatch.c
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: IMAP Wildcard Matching Routines (case-independent)
+ *
+ * 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: 15 June 2000
+ * Last Edited: 30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ * pattern string
+ * delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+ switch (*pat) {
+ case '%': /* non-recursive */
+ /* % at end, OK if no inferiors */
+ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+ /* scan remainder of string until delimiter */
+ do if (pmatch_full (s,pat+1,delim)) return T;
+ while ((*s != delim) && *s++);
+ break;
+ case '*': /* match 0 or more characters */
+ if (!pat[1]) return T; /* * at end, unconditional match */
+ /* scan remainder of string */
+ do if (pmatch_full (s,pat+1,delim)) return T;
+ while (*s++);
+ break;
+ case '\0': /* end of pattern */
+ return *s ? NIL : T; /* success if also end of base */
+ default: /* match this character */
+ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+ }
+ return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ * pattern string
+ * delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+ switch (*pat) {
+ case '%': /* non-recursive */
+ if (!*s) return T; /* end of base means have a subset match */
+ if (!*++pat) return NIL; /* % at end, no inferiors permitted */
+ /* scan remainder of string until delimiter */
+ do if (dmatch (s,pat,delim)) return T;
+ while ((*s != delim) && *s++);
+ if (*s && !s[1]) return T; /* ends with delimiter, must be subset */
+ return dmatch (s,pat,delim);/* do new scan */
+ case '*': /* match 0 or more characters */
+ return T; /* unconditional match */
+ case '\0': /* end of pattern */
+ break;
+ default: /* match this character */
+ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+ /* end of base, return if at delimiter */
+ else if (*pat == delim) return T;
+ break;
+ }
+ return NIL;
+}
diff --git a/imap/src/osdep/dos/tcp_dos.c b/imap/src/osdep/dos/tcp_dos.c
new file mode 100644
index 00000000..062f260c
--- /dev/null
+++ b/imap/src/osdep/dos/tcp_dos.c
@@ -0,0 +1,434 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: MS-DOS TCP/IP 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: 11 April 1989
+ * Last Edited: 13 January 2008
+ */
+
+static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */
+static long ttmo_read = 0; /* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+ long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+ void *ret = NIL;
+ switch ((int) function) {
+ case SET_TIMEOUT:
+ tmoh = (tcptimeout_t) value;
+ case GET_TIMEOUT:
+ ret = (void *) tmoh;
+ break;
+ case SET_READTIMEOUT:
+ ttmo_read = (long) value;
+ case GET_READTIMEOUT:
+ ret = (void *) ttmo_read;
+ break;
+ case SET_WRITETIMEOUT:
+ ttmo_write = (long) value;
+ case GET_WRITETIMEOUT:
+ ret = (void *) ttmo_write;
+ break;
+ }
+ return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ * contact service name
+ * contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+ TCPSTREAM *stream = NIL;
+ struct sockaddr_in sin;
+ int sock;
+ char *s,tmp[MAILTMPLEN];
+ port &= 0xffff; /* erase flags */
+ /* The domain literal form is used (rather than simply the dotted decimal
+ as with other Unix programs) because it has to be a valid "host name"
+ in mailsystem terminology. */
+ sin.sin_family = AF_INET; /* family is always Internet */
+ /* look like domain literal? */
+ if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+ strcpy (tmp,host+1); /* yes, copy number part */
+ tmp[strlen (tmp)-1] = '\0';
+ if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
+ sprintf (tmp,"Bad format domain-literal: %.80s",host);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ }
+ /* look up host name */
+ else if (!lookuphost (&host,&sin)) {
+ sprintf (tmp,"Host not found: %s",host);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+
+ /* copy port number in network format */
+ if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
+ /* get a TCP stream */
+ if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
+ sprintf (tmp,"Unable to create TCP socket (%d)",errno);
+ mm_log (tmp,ERROR);
+ fs_give ((void **) &host);
+ return NIL;
+ }
+#if 0
+ /* needed? */
+ else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
+ sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
+ sock,FD_SETSIZE);
+ close (sock);
+ errno = ENOBUFS; /* just in case */
+ return NIL;
+ }
+#endif
+ /* open connection */
+ if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
+ switch (errno) { /* analyze error */
+ case ECONNREFUSED:
+ s = "Refused";
+ break;
+ case ENOBUFS:
+ s = "Insufficient system resources";
+ break;
+ case ETIMEDOUT:
+ s = "Timed out";
+ break;
+ default:
+ s = "Unknown error";
+ break;
+ }
+ sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
+ mm_log (tmp,ERROR);
+ close (sock);
+ fs_give ((void **) &host);
+ return NIL;
+ }
+ /* create TCP/IP stream */
+ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+ stream->host = host; /* official host name */
+ stream->localhost = cpystr (mylocalhost ());
+ stream->port = port; /* port number */
+ stream->tcps = sock; /* init socket */
+ stream->ictr = 0; /* init input counter */
+ return stream; /* return success */
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ * service name
+ * returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+ return NIL; /* always NIL on DOS */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+ unsigned long n,contd;
+ char *ret = tcp_getline_work (stream,&n,&contd);
+ if (ret && contd) { /* got a line needing continuation? */
+ STRINGLIST *stl = mail_newstringlist ();
+ STRINGLIST *stc = stl;
+ do { /* collect additional lines */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ stc = stc->next = mail_newstringlist ();
+ ret = tcp_getline_work (stream,&n,&contd);
+ } while (ret && contd);
+ if (ret) { /* stash final part of line on list */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ /* determine how large a buffer we need */
+ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+ ret = fs_get (n + 1); /* copy parts into buffer */
+ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+ memcpy (ret + n,stc->text.data,stc->text.size);
+ ret[n] = '\0';
+ }
+ mail_free_stringlist (&stl);/* either way, done with list */
+ }
+ return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ * pointer to return size
+ * pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+ long *contd)
+{
+ unsigned long n;
+ char *s,*ret,c,d;
+ *contd = NIL; /* assume no continuation */
+ /* make sure have data */
+ if (!tcp_getdata (stream)) return NIL;
+ for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+ d = *stream->iptr++; /* slurp another character */
+ if ((c == '\015') && (d == '\012')) {
+ ret = (char *) fs_get (n--);
+ memcpy (ret,s,*size = n); /* copy into a free storage string */
+ ret[n] = '\0'; /* tie off string with null */
+ return ret;
+ }
+ }
+ /* copy partial string from buffer */
+ memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+ /* get more data from the net */
+ if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+ /* special case of newline broken by buffer */
+ else if ((c == '\015') && (*stream->iptr == '\012')) {
+ stream->iptr++; /* eat the line feed */
+ stream->ictr--;
+ ret[*size = --n] = '\0'; /* tie off string with null */
+ }
+ else *contd = LONGT; /* continuation needed */
+ return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ * size in bytes
+ * buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+ unsigned long n;
+ char *bufptr = buffer;
+ while (size > 0) { /* until request satisfied */
+ if (!tcp_getdata (stream)) return NIL;
+ n = min (size,stream->ictr);/* number of bytes to transfer */
+ /* do the copy */
+ memcpy (bufptr,stream->iptr,n);
+ bufptr += n; /* update pointer */
+ stream->iptr +=n;
+ size -= n; /* update # of bytes to do */
+ stream->ictr -=n;
+ }
+ bufptr[0] = '\0'; /* tie off string */
+ return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+ int i;
+ fd_set fds,efds;
+ struct timeval tmo;
+ time_t t = time (0);
+ if (stream->tcps < 0) return NIL;
+ while (stream->ictr < 1) { /* if nothing in the buffer */
+ time_t tl = time (0); /* start of request */
+ tmo.tv_sec = ttmo_read; /* read timeout */
+ tmo.tv_usec = 0;
+ FD_ZERO (&fds); /* initialize selection vector */
+ FD_ZERO (&efds); /* handle errors too */
+ FD_SET (stream->tcps,&fds);/* set bit in selection vector */
+ FD_SET(stream->tcps,&efds);/* set bit in error selection vector */
+ errno = NIL; /* block and read */
+ while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0)
+ && (errno == EINTR));
+ if (!i) { /* timeout? */
+ time_t tc = time (0);
+ if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+ else return tcp_abort (stream);
+ }
+ else if (i < 0) return tcp_abort (stream);
+ while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
+ (errno == EINTR));
+ if (i < 1) return tcp_abort (stream);
+ stream->iptr = stream->ibuf;/* point at TCP buffer */
+ stream->ictr = i; /* set new byte count */
+ }
+ return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ * string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+ return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ * string pointer
+ * byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+ int i;
+ fd_set fds;
+ struct timeval tmo;
+ time_t t = time (0);
+ if (stream->tcps < 0) return NIL;
+ while (size > 0) { /* until request satisfied */
+ time_t tl = time (0); /* start of request */
+ tmo.tv_sec = ttmo_write; /* write timeout */
+ tmo.tv_usec = 0;
+ FD_ZERO (&fds); /* initialize selection vector */
+ FD_SET (stream->tcps,&fds);/* set bit in selection vector */
+ errno = NIL; /* block and write */
+ while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
+ && (errno == EINTR));
+ if (!i) { /* timeout? */
+ time_t tc = time (0);
+ if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+ else return tcp_abort (stream);
+ }
+ else if (i < 0) return tcp_abort (stream);
+ while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR));
+ if (i < 0) return tcp_abort (stream);
+ size -= i; /* how much we sent */
+ string += i;
+ }
+ return T; /* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+ tcp_abort (stream); /* nuke the socket */
+ /* flush host names */
+ fs_give ((void **) &stream->host);
+ fs_give ((void **) &stream->localhost);
+ fs_give ((void **) &stream); /* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+ if (stream->tcps >= 0) close (stream->tcps);
+ stream->tcps = -1;
+ return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+ return stream->host; /* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+ return stream->host; /* all we can do for now */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+ return stream->port; /* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+ return stream->localhost; /* return local host name */
+}
+
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+ return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+ return "UNKNOWN";
+}
diff --git a/imap/src/osdep/dos/tcp_dos.h b/imap/src/osdep/dos/tcp_dos.h
new file mode 100644
index 00000000..2933a5ff
--- /dev/null
+++ b/imap/src/osdep/dos/tcp_dos.h
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: OS2 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+ char *host; /* host name */
+ unsigned long port; /* port number */
+ char *localhost; /* local host name */
+ int tcps; /* tcp socket */
+ long ictr; /* input counter */
+ char *iptr; /* input pointer */
+ char ibuf[BUFLEN]; /* input buffer */
+};
+
+
+/* Local function prototypes */
+
+long lookuphost (char **host,struct sockaddr_in *sin);
+long tcp_abort (TCPSTREAM *stream);
diff --git a/imap/src/osdep/dos/tcp_dwa.c b/imap/src/osdep/dos/tcp_dwa.c
new file mode 100644
index 00000000..4275f27c
--- /dev/null
+++ b/imap/src/osdep/dos/tcp_dwa.c
@@ -0,0 +1,344 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Waterloo DOS TCP/IP 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: 11 April 1989
+ * Last Edited: 13 January 2008
+ */
+
+
+/* Global data */
+
+short sock_initted = 0; /* global so others using net can see it */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+ long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+ return NIL;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ * contact service name
+ * contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *TCP_open (char *host,char *service,unsigned long port)
+{
+ TCPSTREAM *stream = NIL;
+ tcp_Socket *sock;
+ char *s,tmp[MAILTMPLEN];
+ unsigned long adr,i,j,k,l;
+ port &= 0xffff; /* erase flags */
+ /* initialize if first time here */
+ if (!sock_initted++) sock_init();
+ /* The domain literal form is used (rather than simply the dotted decimal
+ as with other Unix programs) because it has to be a valid "host name"
+ in mailsystem terminology. */
+ /* look like domain literal? */
+ if (host[0] == '[' && host[strlen (host)-1] == ']') {
+ if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
+ ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+ ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+ ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s)
+ adr = (i << 24) + (j << 16) + (k << 8) + l;
+ else {
+ sprintf (tmp,"Bad format domain-literal: %.80s",host);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ }
+ else { /* lookup host name */
+ if (!(adr = resolve (host))) {
+ sprintf (tmp,"Host not found: %s",host);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ }
+
+ /* OK to instantiate socket now */
+ sock = (tcp_Socket *) fs_get (sizeof (tcp_Socket));
+ /* open connection */
+ if (!tcp_open (sock,(word) 0,adr,(word) port,NULL)) {
+ sprintf (tmp,"Can't connect to %.80s,%ld",host,port);
+ mm_log (tmp,ERROR);
+ fs_give ((void **) &sock);
+ return NIL;
+ }
+ /* create TCP/IP stream */
+ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+ stream->host = cpystr (host); /* official host name */
+ stream->localhost = cpystr (mylocalhost ());
+ stream->port = port; /* port number */
+ stream->tcps = sock; /* init socket */
+ stream->ictr = 0; /* init input counter */
+ return stream; /* return success */
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ * service name
+ * returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+ return NIL; /* always NIL on DOS */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+ unsigned long n,contd;
+ char *ret = tcp_getline_work (stream,&n,&contd);
+ if (ret && contd) { /* got a line needing continuation? */
+ STRINGLIST *stl = mail_newstringlist ();
+ STRINGLIST *stc = stl;
+ do { /* collect additional lines */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ stc = stc->next = mail_newstringlist ();
+ ret = tcp_getline_work (stream,&n,&contd);
+ } while (ret && contd);
+ if (ret) { /* stash final part of line on list */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ /* determine how large a buffer we need */
+ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+ ret = fs_get (n + 1); /* copy parts into buffer */
+ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+ memcpy (ret + n,stc->text.data,stc->text.size);
+ ret[n] = '\0';
+ }
+ mail_free_stringlist (&stl);/* either way, done with list */
+ }
+ return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ * pointer to return size
+ * pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+ long *contd)
+{
+ unsigned long n;
+ char *s,*ret,c,d;
+ *contd = NIL; /* assume no continuation */
+ /* make sure have data */
+ if (!tcp_getdata (stream)) return NIL;
+ for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+ d = *stream->iptr++; /* slurp another character */
+ if ((c == '\015') && (d == '\012')) {
+ ret = (char *) fs_get (n--);
+ memcpy (ret,s,*size = n); /* copy into a free storage string */
+ ret[n] = '\0'; /* tie off string with null */
+ return ret;
+ }
+ }
+ /* copy partial string from buffer */
+ memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+ /* get more data from the net */
+ if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+ /* special case of newline broken by buffer */
+ else if ((c == '\015') && (*stream->iptr == '\012')) {
+ stream->iptr++; /* eat the line feed */
+ stream->ictr--;
+ ret[*size = --n] = '\0'; /* tie off string with null */
+ }
+ else *contd = LONGT; /* continuation needed */
+ return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ * size in bytes
+ * buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+ unsigned long n;
+ char *bufptr = buffer;
+ while (size > 0) { /* until request satisfied */
+ if (!tcp_getdata (stream)) return NIL;
+ n = min (size,stream->ictr);/* number of bytes to transfer */
+ /* do the copy */
+ memcpy (bufptr,stream->iptr,(size_t) n);
+ bufptr += n; /* update pointer */
+ stream->iptr +=n;
+ size -= n; /* update # of bytes to do */
+ stream->ictr -=n;
+ }
+ bufptr[0] = '\0'; /* tie off string */
+ return T;
+}
+
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+ int status;
+ if (!stream->tcps) return NIL;/* no-no nuked socket */
+ while (stream->ictr < 1) { /* if buffer empty, block for input and read */
+ if (!_ip_delay1 (stream->tcps,600,NULL,&status))
+ stream->ictr = sock_fastread (stream->tcps,
+ stream->iptr = stream->ibuf,BUFLEN);
+ else if (status == 1) { /* nuke the socket if closed */
+ sock_close (stream->tcps);
+ fs_give ((void **) &stream->tcps);
+ return NIL;
+ }
+ }
+ return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+ /* output the cruft */
+ sock_puts (stream->tcps,string);
+ return T; /* all done */
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ * string pointer
+ * byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+ sock_write (stream->tcps,string,(int) size);
+ return T;
+}
+
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+ if (stream->tcps){ /* nuke the socket */
+ sock_close (stream->tcps);
+ _ip_delay2 (stream->tcps,0,NULL,NULL);
+ }
+ fs_give ((void **) &stream->tcps);
+ /* flush host names */
+ fs_give ((void **) &stream->host);
+ fs_give ((void **) &stream->localhost);
+ fs_give ((void **) &stream); /* flush the stream */
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+ return stream->host; /* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+ return stream->host; /* return host name */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+ return stream->port; /* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+ return stream->localhost; /* return local host name */
+}
+
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+ return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+ return "UNKNOWN";
+}
diff --git a/imap/src/osdep/dos/tcp_dwa.h b/imap/src/osdep/dos/tcp_dwa.h
new file mode 100644
index 00000000..360eea85
--- /dev/null
+++ b/imap/src/osdep/dos/tcp_dwa.h
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Waterloo DOS TCP/IP 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: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+ char *host; /* host name */
+ unsigned long port; /* port number */
+ char *localhost; /* local host name */
+ tcp_Socket *tcps; /* tcp socket */
+ long ictr; /* input counter */
+ char *iptr; /* input pointer */
+ char ibuf[BUFLEN]; /* input buffer */
+};
diff --git a/imap/src/osdep/dos/tcp_wsk.c b/imap/src/osdep/dos/tcp_wsk.c
new file mode 100644
index 00000000..90e206a9
--- /dev/null
+++ b/imap/src/osdep/dos/tcp_wsk.c
@@ -0,0 +1,818 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Winsock TCP/IP routines
+ *
+ * Author: Mark Crispin from Mike Seibel's Winsock code
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MRC@CAC.Washington.EDU
+ *
+ * Date: 11 April 1989
+ * Last Edited: 13 January 2008
+ */
+
+
+#define TCPMAXSEND 32768
+
+/* Private functions */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
+ unsigned long port);
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+ long *contd);
+long tcp_abort (TCPSTREAM *stream);
+long tcp_close_socket (SOCKET *sock);
+char *tcp_name (struct sockaddr_in *sin,long flag);
+char *tcp_name_valid (char *s);
+
+
+/* Private data */
+
+int wsa_initted = 0; /* init ? */
+static int wsa_sock_open = 0; /* keep track of open sockets */
+static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */
+static long ttmo_read = 0; /* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+static long allowreversedns = T;/* allow reverse DNS lookup */
+static long tcpdebug = NIL; /* extra TCP debugging telemetry */
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ * function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+ void *ret = NIL;
+ switch ((int) function) {
+ case SET_TIMEOUT:
+ tmoh = (tcptimeout_t) value;
+ case GET_TIMEOUT:
+ ret = (void *) tmoh;
+ break;
+ case SET_READTIMEOUT:
+ ttmo_read = (long) value;
+ case GET_READTIMEOUT:
+ ret = (void *) ttmo_read;
+ break;
+ case SET_WRITETIMEOUT:
+ ttmo_write = (long) value;
+ case GET_WRITETIMEOUT:
+ ret = (void *) ttmo_write;
+ break;
+ case SET_ALLOWREVERSEDNS:
+ allowreversedns = (long) value;
+ case GET_ALLOWREVERSEDNS:
+ ret = (void *) allowreversedns;
+ break;
+ case SET_TCPDEBUG:
+ tcpdebug = (long) value;
+ case GET_TCPDEBUG:
+ ret = (void *) tcpdebug;
+ break;
+ }
+ return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ * contact service name
+ * contact port number and optional silent flag
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+ TCPSTREAM *stream = NIL;
+ int i;
+ SOCKET sock = INVALID_SOCKET;
+ int silent = (port & NET_SILENT) ? T : NIL;
+ char *s;
+ struct sockaddr_in sin;
+ struct hostent *he;
+ char hostname[MAILTMPLEN];
+ char tmp[MAILTMPLEN];
+ struct servent *sv = NIL;
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ if (!wsa_initted++) { /* init Windows Sockets */
+ WSADATA wsock;
+ if (i = (int) WSAStartup (WSA_VERSION,&wsock)) {
+ wsa_initted = 0; /* in case we try again */
+ sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ }
+ port &= 0xffff; /* erase flags */
+ /* lookup service */
+ if (service && (sv = getservbyname (service,"tcp")))
+ port = ntohs (sin.sin_port = sv->s_port);
+ /* copy port number in network format */
+ else sin.sin_port = htons ((u_short) port);
+ /* The domain literal form is used (rather than simply the dotted decimal
+ as with other Windows programs) because it has to be a valid "host name"
+ in mailsystem terminology. */
+ sin.sin_family = AF_INET; /* family is always Internet */
+ /* look like domain literal? */
+ if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+ strcpy (tmp,host+1); /* yes, copy number part */
+ tmp[strlen (tmp)-1] = '\0';
+ if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
+ sprintf (tmp,"Bad format domain-literal: %.80s",host);
+ mm_log (tmp,ERROR);
+ return NIL;
+ }
+ else {
+ sin.sin_family = AF_INET; /* family is always Internet */
+ strcpy (hostname,host);
+ (*bn) (BLOCK_TCPOPEN,NIL);
+ sock = tcp_socket_open (&sin,tmp,hostname,port);
+ (*bn) (BLOCK_NONE,NIL);
+ }
+ }
+
+ else { /* lookup host name */
+ if (tcpdebug) {
+ sprintf (tmp,"DNS resolution %.80s",host);
+ mm_log (tmp,TCPDEBUG);
+ }
+ (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
+ if (!(he = gethostbyname (lcase (strcpy (tmp,host)))))
+ sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
+ (*bn) (BLOCK_NONE,NIL);
+ if (he) { /* DNS resolution won? */
+ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
+ /* copy address type */
+ sin.sin_family = he->h_addrtype;
+ /* copy host name */
+ strcpy (hostname,he->h_name);
+ wsa_sock_open++; /* prevent tcp_close_socket() from freeing in
+ loop */
+ for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) {
+ if (i && !silent) mm_log (tmp,WARN);
+ memcpy (&sin.sin_addr,s,he->h_length);
+ (*bn) (BLOCK_TCPOPEN,NIL);
+ sock = tcp_socket_open (&sin,tmp,hostname,port);
+ (*bn) (BLOCK_NONE,NIL);
+ }
+ wsa_sock_open--; /* undo protection */
+ }
+ }
+ if (sock == INVALID_SOCKET) { /* error? */
+ if (!silent) mm_log (tmp,ERROR);
+ tcp_close_socket (&sock); /* do possible cleanup action */
+ }
+ else { /* got a socket, create TCP/IP stream */
+ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+ sizeof (TCPSTREAM));
+ stream->port = port; /* port number */
+ /* init socket */
+ stream->tcpsi = stream->tcpso = sock;
+ stream->ictr = 0; /* init input counter */
+ /* copy official host name */
+ stream->host = cpystr (hostname);
+ if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
+ }
+ return stream; /* return success */
+}
+
+/* Open a TCP socket
+ * Accepts: Internet socket address block
+ * scratch buffer
+ * host name for error message
+ * port number for error message
+ * Returns: socket if success, else -1 with error string in scratch buffer
+ */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
+ unsigned long port)
+{
+ int sock;
+ char *s;
+ sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
+ mm_log (tmp,NIL);
+ /* get a TCP stream */
+ if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
+ sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
+ return -1;
+ }
+ wsa_sock_open++; /* count this socket as open */
+ /* open connection */
+ if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) ==
+ SOCKET_ERROR) {
+ switch (WSAGetLastError ()){/* analyze error */
+ case WSAECONNREFUSED:
+ s = "Refused";
+ break;
+ case WSAENOBUFS:
+ s = "Insufficient system resources";
+ break;
+ case WSAETIMEDOUT:
+ s = "Timed out";
+ break;
+ case WSAEHOSTUNREACH:
+ s = "Host unreachable";
+ break;
+ default:
+ s = "Unknown error";
+ break;
+ }
+ sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s,
+ WSAGetLastError ());
+ tcp_close_socket (&sock); /* flush socket */
+ sock = INVALID_SOCKET;
+ }
+ return sock; /* return the socket */
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ * service name
+ * returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+ return NIL; /* always NIL on Windows */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+ unsigned long n,contd;
+ char *ret = tcp_getline_work (stream,&n,&contd);
+ if (ret && contd) { /* got a line needing continuation? */
+ STRINGLIST *stl = mail_newstringlist ();
+ STRINGLIST *stc = stl;
+ do { /* collect additional lines */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ stc = stc->next = mail_newstringlist ();
+ ret = tcp_getline_work (stream,&n,&contd);
+ } while (ret && contd);
+ if (ret) { /* stash final part of line on list */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ /* determine how large a buffer we need */
+ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+ ret = fs_get (n + 1); /* copy parts into buffer */
+ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+ memcpy (ret + n,stc->text.data,stc->text.size);
+ ret[n] = '\0';
+ }
+ mail_free_stringlist (&stl);/* either way, done with list */
+ }
+ return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ * pointer to return size
+ * pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+ long *contd)
+{
+ unsigned long n;
+ char *s,*ret,c,d;
+ *contd = NIL; /* assume no continuation */
+ /* make sure have data */
+ if (!tcp_getdata (stream)) return NIL;
+ for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+ d = *stream->iptr++; /* slurp another character */
+ if ((c == '\015') && (d == '\012')) {
+ ret = (char *) fs_get (n--);
+ memcpy (ret,s,*size = n); /* copy into a free storage string */
+ ret[n] = '\0'; /* tie off string with null */
+ return ret;
+ }
+ }
+ /* copy partial string from buffer */
+ memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+ /* get more data from the net */
+ if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+ /* special case of newline broken by buffer */
+ else if ((c == '\015') && (*stream->iptr == '\012')) {
+ stream->iptr++; /* eat the line feed */
+ stream->ictr--;
+ ret[*size = --n] = '\0'; /* tie off string with null */
+ }
+ else *contd = LONGT; /* continuation needed */
+ return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ * size in bytes
+ * buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
+{
+ unsigned long n;
+ /* make sure socket still alive */
+ if (stream->tcpsi == INVALID_SOCKET) return NIL;
+ /* can transfer bytes from buffer? */
+ if (n = min (size,stream->ictr)) {
+ memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */
+ s += n; /* update pointer */
+ stream->iptr +=n;
+ size -= n; /* update # of bytes to do */
+ stream->ictr -=n;
+ }
+ if (size) {
+ int i;
+ fd_set fds;
+ struct timeval tmo;
+ time_t tc,t = time (0);
+ blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ (*bn) (BLOCK_TCPREAD,NIL);
+ while (size > 0) { /* until request satisfied */
+ time_t tl = time (0);
+ if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
+ FD_ZERO (&fds); /* initialize selection vector */
+ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+ tmo.tv_sec = ttmo_read;
+ tmo.tv_usec = 0;
+ /* block and read */
+ switch ((stream->tcpsi == stream->tcpso) ?
+ select (stream->tcpsi+1,&fds,0,0,
+ ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
+ case SOCKET_ERROR: /* error */
+ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+ break;
+ case 0: /* timeout */
+ tc = time (0);
+ if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+ return tcp_abort (stream);
+ default:
+ if (stream->tcpsi == stream->tcpso)
+ while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) ==
+ SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
+ else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) <
+ 0) && (errno == EINTR));
+ switch (i) {
+ case SOCKET_ERROR: /* error */
+ case 0: /* no data read */
+ return tcp_abort (stream);
+ default:
+ s += i; /* point at new place to write */
+ size -= i; /* reduce byte count */
+ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+ }
+ }
+ }
+ (*bn) (BLOCK_NONE,NIL);
+ }
+ *s = '\0'; /* tie off string */
+ return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+ struct timeval tmo;
+ int i;
+ fd_set fds;
+ time_t tc,t = time (0);
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ FD_ZERO (&fds); /* initialize selection vector */
+ if (stream->tcpsi == INVALID_SOCKET) return NIL;
+ (*bn) (BLOCK_TCPREAD,NIL);
+ tmo.tv_sec = ttmo_read;
+ tmo.tv_usec = 0;
+ while (stream->ictr < 1) { /* if nothing in the buffer */
+ time_t tl = time (0);
+ if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
+ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+ /* block and read */
+ switch ((stream->tcpsi == stream->tcpso) ?
+ select (stream->tcpsi+1,&fds,0,0,
+ ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
+ case SOCKET_ERROR: /* error */
+ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+ break;
+ case 0: /* timeout */
+ tc = time (0);
+ if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+ return tcp_abort (stream);
+ default:
+ if (stream->tcpsi == stream->tcpso)
+ while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
+ SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
+ else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+ (errno == EINTR));
+ switch (i) {
+ case SOCKET_ERROR: /* error */
+ case 0: /* no data read */
+ return tcp_abort (stream);
+ default:
+ stream->ictr = i; /* set new byte count */
+ /* point at TCP buffer */
+ stream->iptr = stream->ibuf;
+ if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+ }
+ }
+ }
+ (*bn) (BLOCK_NONE,NIL);
+ return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ * string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+ return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ * string pointer
+ * byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+ int i;
+ struct timeval tmo;
+ fd_set fds;
+ time_t tc,t = time (0);
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ tmo.tv_sec = ttmo_write;
+ tmo.tv_usec = 0;
+ FD_ZERO (&fds); /* initialize selection vector */
+ if (stream->tcpso == INVALID_SOCKET) return NIL;
+ (*bn) (BLOCK_TCPWRITE,NIL);
+ while (size > 0) { /* until request satisfied */
+ time_t tl = time (0);
+ if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
+ FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
+ /* block and write */
+ switch ((stream->tcpsi == stream->tcpso) ?
+ select (stream->tcpso+1,NULL,&fds,NULL,
+ tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) {
+ case SOCKET_ERROR: /* error */
+ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+ break;
+ case 0: /* timeout */
+ tc = time (0);
+ if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+ return tcp_abort (stream);
+ default:
+ if (stream->tcpsi == stream->tcpso)
+ while (((i = send (stream->tcpso,string,
+ (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) &&
+ (WSAGetLastError () == WSAEINTR));
+ else while (((i = write (stream->tcpso,string,
+ min (size,TCPMAXSEND))) < 0) &&
+ (errno == EINTR));
+ if (i == SOCKET_ERROR) return tcp_abort (stream);
+ size -= i; /* count this size */
+ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+ string += i;
+ }
+ }
+ (*bn) (BLOCK_NONE,NIL);
+ return T; /* all done */
+}
+
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+ tcp_abort (stream); /* nuke the sockets */
+ /* flush host names */
+ if (stream->host) fs_give ((void **) &stream->host);
+ if (stream->remotehost) fs_give ((void **) &stream->remotehost);
+ if (stream->localhost) fs_give ((void **) &stream->localhost);
+ fs_give ((void **) &stream); /* flush the stream */
+}
+
+
+/* TCP/IP abort sockets
+ * Accepts: TCP/IP stream
+ * Returns: NIL, always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+ if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
+ else stream->tcpso = INVALID_SOCKET;
+ return tcp_close_socket (&stream->tcpsi);
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: WinSock socket
+ * Returns: NIL, always
+ */
+
+long tcp_close_socket (SOCKET *sock)
+{
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ /* something to close? */
+ if (sock && (*sock != INVALID_SOCKET)) {
+ (*bn) (BLOCK_TCPCLOSE,NIL);
+ closesocket (*sock); /* WinSock socket close */
+ *sock = INVALID_SOCKET;
+ (*bn) (BLOCK_NONE,NIL);
+ wsa_sock_open--; /* drop this socket */
+ }
+ /* no more open streams? */
+ if (wsa_initted && !wsa_sock_open) {
+ mm_log ("Winsock cleanup",NIL);
+ wsa_initted = 0; /* no more sockets, so... */
+ WSACleanup (); /* free up resources until needed */
+ }
+ return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+ return stream->host; /* use tcp_remotehost() if want guarantees */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+ if (!stream->remotehost) {
+ struct sockaddr_in sin;
+ int sinlen = sizeof (struct sockaddr_in);
+ stream->remotehost = /* get socket's peer name */
+ ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
+ SOCKET_ERROR) || (sinlen <= 0)) ?
+ cpystr (stream->host) : tcp_name (&sin,NIL);
+ }
+ return stream->remotehost;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+ return stream->port; /* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+ if (!stream->localhost) {
+ struct sockaddr_in sin;
+ int sinlen = sizeof (struct sockaddr_in);
+ stream->localhost = /* get socket's name */
+ ((stream->port & 0xffff000) ||
+ ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
+ SOCKET_ERROR) || (sinlen <= 0))) ?
+ cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
+ }
+ return stream->localhost; /* return local host name */
+}
+
+/* TCP/IP get client host address (server calls only)
+ * Returns: client host address
+ */
+
+char *tcp_clientaddr ()
+{
+ if (!myClientAddr) {
+ struct sockaddr_in sin;
+ int sinlen = sizeof (struct sockaddr_in);
+ myClientAddr = /* get stdin's peer name */
+ ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+ (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
+ }
+ return myClientAddr;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+ if (!myClientHost) {
+ struct sockaddr_in sin;
+ int sinlen = sizeof (struct sockaddr_in);
+ myClientHost = /* get stdin's peer name */
+ ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+ (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T);
+ }
+ return myClientHost;
+}
+
+/* TCP/IP get server host address (server calls only)
+ * Returns: server host address
+ */
+
+char *tcp_serveraddr ()
+{
+ if (!myServerAddr) {
+ struct sockaddr_in sin;
+ int sinlen = sizeof (struct sockaddr_in);
+ myServerAddr = /* get stdin's peer name */
+ ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+ (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
+ }
+ return myServerAddr;
+}
+
+
+/* TCP/IP get server host name (server calls only)
+ * Returns: server host name
+ */
+
+static long myServerPort = -1;
+
+char *tcp_serverhost ()
+{
+ if (!myServerHost) {
+ struct sockaddr_in sin;
+ int sinlen = sizeof (struct sockaddr_in);
+ if (!wsa_initted++) { /* init Windows Sockets */
+ WSADATA wsock;
+ if (WSAStartup (WSA_VERSION,&wsock)) {
+ wsa_initted = 0;
+ return "random-pc"; /* try again later? */
+ }
+ }
+ /* get stdin's name */
+ if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+ (sinlen <= 0)) myServerHost = cpystr (mylocalhost ());
+ else {
+ myServerHost = tcp_name (&sin,NIL);
+ myServerPort = ntohs (sin.sin_port);
+ }
+ }
+ return myServerHost;
+}
+
+
+/* TCP/IP get server port number (server calls only)
+ * Returns: server port number
+ */
+
+long tcp_serverport ()
+{
+ if (!myServerHost) tcp_serverhost ();
+ return myServerPort;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+ char *ret,host[MAILTMPLEN];
+ struct hostent *he;
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ /* look like domain literal? */
+ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+ (*bn) (BLOCK_DNSLOOKUP,NIL);
+ if (tcpdebug) {
+ sprintf (host,"DNS canonicalization %.80s",name);
+ mm_log (host,TCPDEBUG);
+ }
+ /* note that NT requires lowercase! */
+ ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name;
+ (*bn) (BLOCK_NONE,NIL);
+ if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
+ return ret;
+}
+
+
+/* TCP/IP return name from socket
+ * Accepts: socket
+ * verbose flag
+ * Returns: cpystr name
+ */
+
+char *tcp_name (struct sockaddr_in *sin,long flag)
+{
+ char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
+ sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
+ if (allowreversedns) {
+ struct hostent *he;
+ blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
+ void *data;
+ if (tcpdebug) {
+ sprintf (tmp,"Reverse DNS resolution %s",adr);
+ mm_log (tmp,TCPDEBUG);
+ }
+ (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+ data = (*bn) (BLOCK_SENSITIVE,NIL);
+ /* translate address to name */
+ if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
+ sizeof (struct in_addr),
+ sin->sin_family)) ?
+ (char *) he->h_name : NIL)) {
+ /* produce verbose form if needed */
+ if (flag) sprintf (ret = tmp,"%s %s",t,adr);
+ else ret = t;
+ }
+ (*bn) (BLOCK_NONSENSITIVE,data);
+ (*bn) (BLOCK_NONE,NIL); /* alarms OK now */
+ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
+ }
+ return cpystr (ret);
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+ if (!myLocalHost) {
+ char tmp[MAILTMPLEN];
+ if (!wsa_initted++) { /* init Windows Sockets */
+ WSADATA wsock;
+ if (WSAStartup (WSA_VERSION,&wsock)) {
+ wsa_initted = 0;
+ return "random-pc"; /* try again later? */
+ }
+ }
+ myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
+ "random-pc" : tcp_canonical (tmp));
+ }
+ return myLocalHost;
+}
+
+
+/* Validate name
+ * Accepts: domain name
+ * Returns: T if valid, NIL otherwise
+ */
+
+char *tcp_name_valid (char *s)
+{
+ int c;
+ char *ret,*tail;
+ /* must be non-empty and not too long */
+ if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
+ /* must be alnum, dot, or hyphen */
+ while ((c = *s++) && (s <= tail) &&
+ (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+ ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
+ if (c) ret = NIL;
+ }
+ return ret;
+}
diff --git a/imap/src/osdep/dos/tcp_wsk.h b/imap/src/osdep/dos/tcp_wsk.h
new file mode 100644
index 00000000..6e8f9af7
--- /dev/null
+++ b/imap/src/osdep/dos/tcp_wsk.h
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Winsock TCP/IP routines
+ *
+ * Author: Mike Seibel from Unix version by Mark Crispin
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MRC@CAC.Washington.EDU
+ *
+ * Date: 11 April 1989
+ * Last Edited: 30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 16384 /* 32768 causes stdin read() to barf */
+
+#include <windows.h>
+#define _INC_WINDOWS
+#include <winsock.h>
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+ char *host; /* host name */
+ char *remotehost; /* remote host name */
+ unsigned long port; /* port number */
+ char *localhost; /* local host name */
+ SOCKET tcpsi; /* tcp socket */
+ SOCKET tcpso; /* tcp socket */
+ long ictr; /* input counter */
+ char *iptr; /* input pointer */
+ char ibuf[BUFLEN]; /* input buffer */
+};
diff --git a/imap/src/osdep/dos/write.c b/imap/src/osdep/dos/write.c
new file mode 100644
index 00000000..c7854815
--- /dev/null
+++ b/imap/src/osdep/dos/write.c
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Write data, treating partial writes as an error
+ *
+ * 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: 26 May 1995
+ * Last Edited: 30 August 2006
+ */
+
+/* The whole purpose of this unfortunate routine is to deal with DOS and
+ * certain cretinous versions of UNIX which decided that the "bytes actually
+ * written" return value from write() gave them license to use that for things
+ * that are really errors, such as disk quota exceeded, maximum file size
+ * exceeded, disk full, etc.
+ *
+ * BSD won't screw us this way on the local filesystem, but who knows what
+ * some NFS-mounted filesystem will do.
+ */
+
+#undef write
+
+/* Write data to file
+ * Accepts: file descriptor
+ * I/O vector structure
+ * number of vectors in structure
+ * Returns: number of bytes written if successful, -1 if failure
+ */
+
+long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
+
+long safe_write (int fd,char *buf,long nbytes)
+{
+ long i,j;
+ if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
+ while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
+ (errno == EINTR));
+ if (j < 0) return j;
+ }
+ return nbytes;
+}