mbxnt.c

来自「这是用C编写IMAP源代码」· C语言 代码 · 共 1,572 行 · 第 1/4 页

C
1,572
字号
/* * Program:	MBX 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:	3 October 1995 * Last Edited:	8 March 2005 *  * The IMAP toolkit provided in this Distribution is * Copyright 1988-2005 University of Washington. * The full text of our legal notices is contained in the file called * CPYRIGHT, included with this Distribution. *//*				FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */#include <stdio.h>#include <ctype.h>#include <errno.h>extern int errno;		/* just in case */#include "mail.h"#include "osdep.h"#include <fcntl.h>#include <time.h>#include <sys/stat.h>#include <sys/utime.h>#include "mbxnt.h"#include "misc.h"#include "dummy.h"/* MBX I/O stream local data */	typedef struct mbx_local {  unsigned int flagcheck: 1;	/* if ping should sweep for flags */  unsigned int expok: 1;	/* if expunging OK in ping */  unsigned int expunged : 1;	/* if one or more expunged messages */  int fd;			/* file descriptor for I/O */  int ld;			/* lock file descriptor */  int ffuserflag;		/* first free user flag */  off_t filesize;		/* file size parsed */  time_t filetime;		/* last file time */  time_t lastsnarf;		/* last snarf time */  unsigned char *buf;		/* temporary buffer */  unsigned long buflen;		/* current size of temporary buffer */  unsigned long uid;		/* current text uid */  SIZEDTEXT text;		/* current text */  char lock[MAILTMPLEN];	/* buffer to write lock name */} MBXLOCAL;/* Convenient access to local data */#define LOCAL ((MBXLOCAL *) stream->local)/* Function prototypes */DRIVER *mbx_valid (char *name);int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp);void *mbx_parameters (long function,void *value);void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);void mbx_list (MAILSTREAM *stream,char *ref,char *pat);void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);long mbx_create (MAILSTREAM *stream,char *mailbox);long mbx_delete (MAILSTREAM *stream,char *mailbox);long mbx_rename (MAILSTREAM *stream,char *old,char *newname);long mbx_status (MAILSTREAM *stream,char *mbx,long flags);MAILSTREAM *mbx_open (MAILSTREAM *stream);void mbx_close (MAILSTREAM *stream,long options);void mbx_abort (MAILSTREAM *stream);void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,		  long flags);long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);long mbx_ping (MAILSTREAM *stream);void mbx_check (MAILSTREAM *stream);void mbx_expunge (MAILSTREAM *stream);void mbx_snarf (MAILSTREAM *stream);long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);long mbx_parse (MAILSTREAM *stream);MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);void mbx_update_header (MAILSTREAM *stream);void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,			  unsigned long *size,char **hdr);unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,			   long flags);long mbx_flaglock (MAILSTREAM *stream);/* MBX mail routines *//* Driver dispatch used by MAIL */DRIVER mbxdriver = {  "mbx",			/* driver name */  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,				/* driver flags */  (DRIVER *) NIL,		/* next driver */  mbx_valid,			/* mailbox is valid for us */  mbx_parameters,		/* manipulate parameters */  mbx_scan,			/* scan mailboxes */  mbx_list,			/* list mailboxes */  mbx_lsub,			/* list subscribed mailboxes */  NIL,				/* subscribe to mailbox */  NIL,				/* unsubscribe from mailbox */  mbx_create,			/* create mailbox */  mbx_delete,			/* delete mailbox */  mbx_rename,			/* rename mailbox */  mail_status_default,		/* status of mailbox */  mbx_open,			/* open mailbox */  mbx_close,			/* close mailbox */  mbx_flags,			/* fetch message "fast" attributes */  mbx_flags,			/* fetch message flags */  NIL,				/* fetch overview */  NIL,				/* fetch message envelopes */  mbx_header,			/* fetch message header */  mbx_text,			/* fetch message body */  NIL,				/* fetch partial message text */  NIL,				/* unique identifier */  NIL,				/* message number */  mbx_flag,			/* modify flags */  mbx_flagmsg,			/* per-message modify flags */  NIL,				/* search for message based on criteria */  NIL,				/* sort messages */  NIL,				/* thread messages */  mbx_ping,			/* ping mailbox to see if still alive */  mbx_check,			/* check for new messages */  mbx_expunge,			/* expunge deleted messages */  mbx_copy,			/* copy messages to another mailbox */  mbx_append,			/* append string message to mailbox */  NIL				/* garbage collect stream */};				/* prototype stream */MAILSTREAM mbxproto = {&mbxdriver};/* MBX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */DRIVER *mbx_valid (char *name){  char tmp[MAILTMPLEN];  return mbx_isvalid (NIL,name,tmp) ? &mbxdriver : NIL;}/* MBX mail test for valid mailbox * Accepts: returned stream with valid mailbox keywords *	    mailbox name *	    scratch buffer * Returns: T if valid, NIL otherwise */int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp){  int fd;  int ret = NIL;  unsigned long i;  unsigned char *s,*t,hdr[HDRSIZE];  struct stat sbuf;  struct utimbuf times;  errno = EINVAL;		/* assume invalid argument */				/* if file, get its status */  if ((s = dummy_file (tmp,name)) && !stat (s,&sbuf) &&      ((sbuf.st_mode & S_IFMT) == S_IFREG) &&      ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) >= 0)) {    errno = -1;			/* bogus format */    if ((read (fd,hdr,HDRSIZE) == HDRSIZE) &&	(hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') &&	(hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') &&	(hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]) &&	isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) &&	isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) &&	isxdigit (hdr[15]) && isxdigit (hdr[16]) && isxdigit (hdr[17]) &&	isxdigit (hdr[18]) && isxdigit (hdr[19]) && isxdigit (hdr[20]) &&	isxdigit (hdr[21]) && isxdigit (hdr[22]) &&	(hdr[23] == '\015') && (hdr[24] == '\012')) {      ret = T;      if (stream) {		/* stream specified? */	*stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0,					 sizeof (MAILSTREAM));	for (i = 0, s = hdr + 25;	/* parse user flags */	     (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);	     i++, s = t + 2) {	  *t = '\0';		/* tie off flag */	  if (strlen (s) <= MAXUSERFLAG) (*stream)->user_flags[i] = cpystr (s);	}      }    }    close (fd);			/* close the file */				/* \Marked status? */    if (sbuf.st_ctime > sbuf.st_atime) {				/* preserve atime and mtime */      times.actime = sbuf.st_atime;      times.modtime = sbuf.st_mtime;      utime (tmp,&times);	/* set the times */    }  }				/* in case INBOX but not mbx format */  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;  return ret;			/* return what we should */}/* MBX manipulate driver parameters * Accepts: function code *	    function-dependent value * Returns: function-dependent return value */void *mbx_parameters (long function,void *value){  void *ret = NIL;  switch ((int) function) {  case SET_ONETIMEEXPUNGEATPING:    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;  case GET_ONETIMEEXPUNGEATPING:    if (value) ret = (void *)      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);    break;  }  return ret;}/* MBX mail scan mailboxes * Accepts: mail stream *	    reference *	    pattern to search *	    string to scan */void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents){  if (stream) dummy_scan (NIL,ref,pat,contents);}/* MBX mail list mailboxes * Accepts: mail stream *	    reference *	    pattern to search */void mbx_list (MAILSTREAM *stream,char *ref,char *pat){  if (stream) dummy_list (NIL,ref,pat);}/* MBX mail list subscribed mailboxes * Accepts: mail stream *	    reference *	    pattern to search */void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat){  if (stream) dummy_lsub (NIL,ref,pat);}/* MBX mail create mailbox * Accepts: MAIL stream *	    mailbox name to create * Returns: T on success, NIL on failure */long mbx_create (MAILSTREAM *stream,char *mailbox){  char *s,mbx[MAILTMPLEN],tmp[HDRSIZE];  long ret = NIL;  int i,fd;  if (!(s = dummy_file (mbx,mailbox))) {    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);    mm_log (mbx,ERROR);  }				/* create underlying file */  else if (dummy_create (stream,s)) {				/* done if made directory */    if ((s = strrchr (s,'\\')) && !s[1]) return T;    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));      mm_log (tmp,ERROR);      unlink (mbx);		/* delete the file */    }    else {      memset (tmp,'\0',HDRSIZE);/* initialize header */      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",	       (unsigned long) time (0));      for (i = 0; i < NUSERFLAGS; ++i)	sprintf (s += strlen (s),"%s\015\012",		 (stream && stream->user_flags[i]) ? stream->user_flags[i] :		 "");      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",		 mbx,strerror (errno));	mm_log (tmp,ERROR);	unlink (mbx);		/* delete the file */      }      else ret = T;		/* success */      close (fd);		/* close file */    }  }  return ret;}/* MBX mail delete mailbox * Accepts: MAIL stream *	    mailbox name to delete * Returns: T on success, NIL on failure */long mbx_delete (MAILSTREAM *stream,char *mailbox){  return mbx_rename (stream,mailbox,NIL);}/* MBX mail rename mailbox * Accepts: MAIL stream *	    old mailbox name *	    new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */long mbx_rename (MAILSTREAM *stream,char *old,char *newname){  long ret = LONGT;  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];  int fd,ld;  struct stat sbuf;  if (!dummy_file (file,old) ||      (newname && !((s = mailboxfile (tmp,newname)) && *s))) {    sprintf (tmp,newname ?	     "Can't rename mailbox %.80s to %.80s: invalid name" :	     "Can't delete mailbox %.80s: invalid name",	     old,newname);    mm_log (tmp,ERROR);    return NIL;  }  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));    mm_log (tmp,ERROR);    return NIL;  }				/* get parse/append permission */  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {    mm_log ("Unable to lock rename mailbox",ERROR);    return NIL;  }				/* lock out other users */  if (flock (fd,LOCK_EX|LOCK_NB)) {    close (fd);			/* couldn't lock, give up on it then */    sprintf (tmp,"Mailbox %.80s is in use by another process",old);    mm_log (tmp,ERROR);    unlockfd (ld,lock);		/* release exclusive parse/append permission */    return NIL;  }  if (newname) {		/* want rename? */				/* found superior to destination name? */    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&	((tmp[1] != ':') || (s != tmp + 2))) {      c = s[1];			/* remember character after delimiter */      *s = s[1] = '\0';		/* tie off name at delimiter */				/* name doesn't exist, create it */      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {	*s = '\\';		/* restore delimiter */	if (!dummy_create (stream,tmp)) ret = NIL;      }      else *s = '\\';		/* restore delimiter */      s[1] = c;			/* restore character after delimiter */    }    flock (fd,LOCK_UN);		/* release lock on the file */    close (fd);			/* pacify NTFS */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?