📄 mbxnt.c
字号:
* 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) || ((s = strrchr (tmp,'\\')) && !s[1])))) { 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 */ /* 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 (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 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,NIL,NIL); 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); /* 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 on success, NIL on failure */long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ FDDATA d; unsigned long i,j; 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) return NIL; /* mbx_flaglock() could have aborted */ /* find header position */ i = mbx_hdrpos (stream,msgno,&j,NIL); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return LONGT; /* success */}/* MBX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags * Unlocks flag lock */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,×); } if (LOCAL->ld >= 0) { /* unlock now */ 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 (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck || !stream->nmsgs) && ((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) { if (!LOCAL->flagcheck) ret = mbx_parse (stream); /* sweep mailbox for changed message status */ else if (ret = mbx_parse (stream)) { unsigned long recent = 0; LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ) if (elt = mbx_elt (stream,i,LOCAL->expok)) { if (elt->recent) ++recent; ++i; } mail_recent (stream,recent); LOCAL->flagcheck = NIL; /* got all the updates */ } 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 * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */long mbx_expunge (MAILSTREAM *stream,char *sequence,long options){ long ret; unsigned long nexp,reclaimed; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { 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,sequence ? -1 : 1)) { 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); } return ret;}/* MBX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -