diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /imap/src/osdep/dos | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'imap/src/osdep/dos')
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; +} |