mbxnt.c

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

C
1,572
字号
				/* rename the file */    if (ret && rename (file,tmp)) {      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,	       strerror (errno));      mm_log (tmp,ERROR);      ret = NIL;		/* set failure */    }  }  else {    flock (fd,LOCK_UN);		/* release lock on the file */    close (fd);			/* pacify NTFS */    if (unlink (file)) {      sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));      mm_log (tmp,ERROR);      ret = NIL;		/* set failure */    }  }  unlockfd (ld,lock);		/* release exclusive parse/append permission */				/* recreate file if renamed INBOX */  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");  return ret;			/* return success */}/* MBX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *mbx_open (MAILSTREAM *stream){  int fd,ld;  short silent;  char tmp[MAILTMPLEN];  if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */  if (stream->local) fatal ("mbx recycle stream");				/* canonicalize the mailbox name */  if (!dummy_file (tmp,stream->mailbox)) {    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);    mm_log (tmp,ERROR);  }  if (stream->rdonly ||      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));      mm_log (tmp,ERROR);      return NIL;    }    else if (!stream->rdonly) {	/* got it, but readonly */      mm_log ("Can't get write access to mailbox, access is readonly",WARN);      stream->rdonly = T;    }  }  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));  LOCAL->fd = fd;		/* bind the file */  LOCAL->ld = -1;		/* no flaglock */  LOCAL->buf = (char *) fs_get (MAXMESSAGESIZE + 1);  LOCAL->buflen = MAXMESSAGESIZE;  LOCAL->text.data = (unsigned char *)    fs_get ((LOCAL->text.size = MAXMESSAGESIZE) + 1);				/* note if an INBOX or not */  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");  fs_give ((void **) &stream->mailbox);  stream->mailbox = cpystr (tmp);				/* get parse/append permission */  if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) {    mm_log ("Unable to lock open mailbox",ERROR);    return NIL;  }  flock (LOCAL->fd,LOCK_SH);	/* lock the file */  unlockfd (ld,tmp);		/* release shared parse permission */  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */  LOCAL->filetime = 0;		/* time not set up yet */  LOCAL->expok = LOCAL->flagcheck = NIL;  stream->sequence++;		/* bump sequence number */				/* parse mailbox */  stream->nmsgs = stream->recent = 0;  silent = stream->silent;	/* defer events */  stream->silent = T;  if (mbx_ping (stream) && !stream->nmsgs)    mm_log ("Mailbox is empty",(long) NIL);  stream->silent = silent;	/* now notify upper level */  mail_exists (stream,stream->nmsgs);  mail_recent (stream,stream->recent);  if (!LOCAL) return NIL;	/* failure if stream died */  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;  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?    NIL : T;			/* can we create new user flags? */  return stream;		/* return stream to caller */}/* MBX mail close * Accepts: MAIL stream *	    close options */void mbx_close (MAILSTREAM *stream,long options){  if (stream && LOCAL) {	/* only if a file is open */    int silent = stream->silent;    stream->silent = T;		/* note this stream is dying */				/* do an expunge if requested */    if (options & CL_EXPUNGE) mbx_expunge (stream);    else {			/* otherwise do a checkpoint to purge */      LOCAL->expok = T;		/*  possible expunged messages */      mbx_ping (stream);    }    stream->silent = silent;	/* restore previous status */    mbx_abort (stream);  }}/* MBX mail abort stream * Accepts: MAIL stream */void mbx_abort (MAILSTREAM *stream){  if (stream && LOCAL) {	/* only if a file is open */    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */    close (LOCAL->fd);		/* close the local file */				/* free local text buffer */    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);				/* nuke the local data */    fs_give ((void **) &stream->local);    stream->dtb = NIL;		/* log out the DTB */  }}/* MBX mail fetch flags * Accepts: MAIL stream *	    sequence *	    option flags * Sniffs at file to see if some other process changed the flags */void mbx_flags (MAILSTREAM *stream,char *sequence,long flags){  MESSAGECACHE *elt;  unsigned long i;  if (mbx_ping (stream) && 	/* ping mailbox, get new status for messages */      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :       mail_sequence (stream,sequence)))    for (i = 1; i <= stream->nmsgs; i++)       if ((elt = mail_elt (stream,i))->sequence && !elt->valid)	mbx_elt (stream,i,NIL);}/* MBX 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 *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,		  long flags){  unsigned long i;  char *s;  *length = 0;			/* default to empty */  if (flags & FT_UID) return "";/* UID call "impossible" */				/* get header position, possibly header */  i = mbx_hdrpos (stream,msgno,length,&s);  if (!s) {			/* mbx_hdrpos() returned header? */    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */				/* is buffer big enough? */    if (*length > LOCAL->buflen) {      fs_give ((void **) &LOCAL->buf);      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);    }				/* slurp the data */    read (LOCAL->fd,s = LOCAL->buf,*length);  }  s[*length] = '\0';		/* tie off string */  return s;}/* MBX mail fetch message text (body only) * Accepts: MAIL stream *	    message # to fetch *	    pointer to returned header text length *	    option flags * Returns: T, always */long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){  unsigned long i,j;  char *s = LOCAL->text.data;  MESSAGECACHE *elt;				/* UID call "impossible" */  if (flags & FT_UID) return NIL;				/* get message status */  elt = mbx_elt (stream,msgno,NIL);				/* if message not seen */  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {    elt->seen = T;		/* mark message as seen */				/* recalculate status */    mbx_update_status (stream,msgno,NIL);    mm_flags (stream,msgno);				/* update flags */    mbx_flag (stream,NIL,NIL,NIL);  }  if (!LOCAL) i = 0;		/* mbx_flaglock() could have aborted */				/* in case previous text cached */  else if (elt->private.uid == LOCAL->uid)    i = elt->rfc822_size - elt->private.msg.header.text.size;  else {			/* not cached, cache it now */    LOCAL->uid = elt->private.uid;				/* find header position */    i = mbx_hdrpos (stream,msgno,&j,NIL);				/* go to text position */    lseek (LOCAL->fd,i + j,L_SET);				/* is buffer big enough? */    if ((i = elt->rfc822_size - j) > LOCAL->text.size) {      fs_give ((void **) &LOCAL->text.data);      LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = i) + 1);    }				/* slurp the data */    read (LOCAL->fd,s = LOCAL->text.data,i);    LOCAL->text.data[i] = '\0';	/* tie off string */  }  INIT (bs,mail_string,s,i);	/* set up stringstruct */  return T;			/* success */}/* MBX mail modify flags * Accepts: MAIL stream *	    sequence *	    flag(s) *	    option flags */void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags){  struct utimbuf times;  struct stat sbuf;				/* make sure the update takes */  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {    fsync (LOCAL->fd);    fstat (LOCAL->fd,&sbuf);	/* get current write time */    times.modtime = LOCAL->filetime = sbuf.st_mtime;				/* update header */    if ((LOCAL->ffuserflag < NUSERFLAGS) &&	stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream);    times.actime = time (0);	/* make sure read comes after all that */    utime (stream->mailbox,&times);    unlockfd (LOCAL->ld,LOCAL->lock);    LOCAL->ld = -1;  }}/* MBX mail per-message modify flags * Accepts: MAIL stream *	    message cache element */void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt){  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);}/* MBX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */long mbx_ping (MAILSTREAM *stream){  unsigned long i,pos;  long ret = NIL;  int ld;  char lock[MAILTMPLEN];  MESSAGECACHE *elt;  struct stat sbuf;  if (stream && LOCAL) {	/* only if stream already open */    ret = LONGT;		/* assume OK */    fstat (LOCAL->fd,&sbuf);	/* get current file poop */				/* allow expunge if permitted at ping */    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;				/* if external modification */    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))      LOCAL->flagcheck = T;	/* upgrade to flag checking */				/* new mail or flagcheck handling needed? */    if (((i = (sbuf.st_size - LOCAL->filesize)) || LOCAL->flagcheck ||	 !stream->nmsgs) &&	((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) {      if (LOCAL->flagcheck) {	/* sweep mailbox for changed message status */	if (ret = mbx_parse (stream)) {	  LOCAL->filetime = sbuf.st_mtime;	  for (i = 1; i <= stream->nmsgs; )	    if (mbx_elt (stream,i,LOCAL->expok)) ++i;	  LOCAL->flagcheck =NIL;/* got all the updates */	}      }      else if (i) ret = mbx_parse (stream);      unlockfd (ld,lock);	/* release shared parse/append permission */    }    if (ret) {			/* must still be alive */      if (!LOCAL->expunged)	/* look for holes if none known yet */	for (i = 1, pos = HDRSIZE;	     !LOCAL->expunged && (i <= stream->nmsgs);	     i++, pos += elt->private.special.text.size + elt->rfc822_size)	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)	    LOCAL->expunged = T;/* found a hole */				/* burp any holes */      if (LOCAL->expunged && !stream->rdonly) {	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");	if (i) {		/* any space reclaimed? */	  LOCAL->expunged = NIL;/* no more pending expunge */	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);	  mm_log (LOCAL->buf,(long) NIL);	}      }      LOCAL->expok = NIL;	/* no more expok */    }  }  return ret;			/* return result of the parse */}/* MBX mail check mailbox (reparses status too) * Accepts: MAIL stream */void mbx_check (MAILSTREAM *stream){  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */  if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL);}/* MBX mail expunge mailbox * Accepts: MAIL stream */void mbx_expunge (MAILSTREAM *stream){  unsigned long nexp,reclaimed;  if (!mbx_ping (stream));	/* do nothing if stream dead */  else if (stream->rdonly)	/* won't do on readonly files! */    mm_log ("Expunge ignored on readonly mailbox",WARN);				/* if expunged any messages */  else if (nexp = mbx_rewrite (stream,&reclaimed,T)) {    sprintf (LOCAL->buf,"Expunged %lu messages",nexp);    mm_log (LOCAL->buf,(long) NIL);  }  else if (reclaimed) {		/* or if any prior expunged space reclaimed */    sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);    mm_log (LOCAL->buf,(long) NIL);  }  else mm_log ("No messages deleted, so no update needed",(long) NIL);}/* MBX mail copy message(s) * Accepts: MAIL stream *	    sequence *	    destination mailbox *	    copy options * Returns: T if success, NIL if failed */long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options){  struct stat sbuf;  struct utimbuf times;  MESSAGECACHE *elt;  unsigned long i,j,k,m;  long ret = LONGT;  int fd,ld;  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];  mailproxycopy_t pc =    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);  MAILSTREAM *dstream = NIL;				/* make sure valid mailbox */  if (!mbx_isvalid (&dstream,mailbox,LOCAL->buf)) switch (errno) {  case ENOENT:			/* no such file? */    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);    return NIL;  case EINVAL:    if (pc) return (*pc) (stream,sequence,mailbox,options);    sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);    mm_log (LOCAL->buf,ERROR);    return NIL;  default:    if (pc) return (*pc) (stream,sequence,mailbox,options);

⌨️ 快捷键说明

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