📄 mbxnt.c
字号:
/* ======================================================================== * 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: 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: 28 September 2007 *//* 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 "misc.h"#include "dummy.h"#include "fdstring.h"/* Build parameters */#define HDRSIZE 2048/* 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 */ 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 *file,int *ld,char *lock, long flags);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);long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);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]; int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL); if (fd < 0) return NIL; close (fd); /* don't need the fd now */ return &mbxdriver;}/* MBX mail test for valid mailbox * Accepts: returned stream with valid mailbox keywords * mailbox name * buffer to write file name * returned lock fd * returned lock name * RW flags or NIL for readonly * Returns: file descriptor if valid, NIL otherwise */#define MBXISVALIDNOUID 0x1 /* RW, don't do UID action */#define MBXISVALIDUID 0x2 /* RW, do UID action */int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock, long flags){ int fd,upd; int ret = -1; unsigned long i; long j,k; off_t pos; char c,*s,*t,hdr[HDRSIZE]; struct stat sbuf; struct utimbuf times; int error = EINVAL; /* assume invalid argument */ if (ld) *ld = -1; /* initially no lock */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) { error = -1; /* assume bogus format */ if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) || /* locked, set byte 0 to "*", read rest */ ((j < 0) && (lseek (fd,1,L_SET) == 1) && (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (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 (c = 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 = fd; /* mbx format */ if (stream) { /* lock if making a mini-stream */ if (flock (fd,LOCK_SH) || (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1; /* reread data now that locked */ else if (lseek (fd,0,L_SET) || (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1; else { *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0, sizeof (MAILSTREAM)); hdr[15] = '\0'; /* tie off UIDVALIDITY */ (*stream)->uid_validity = strtoul (hdr+7,NIL,16); hdr[15] = c; /* now get UIDLAST */ (*stream)->uid_last = strtoul (hdr+15,NIL,16); /* parse user flags */ for (i = 0, s = hdr + 25; (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); } /* make sure have true UIDLAST */ if (flags & MBXISVALIDUID) { for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size; pos += (j + k)) { /* read header for this message */ lseek (fd,pos,L_SET); if ((j = read (fd,hdr,64)) >= 0) { hdr[j] = '\0'; if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) { *s = '\0'; k = s + 2 - hdr; if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) && (*s == ';') && (s = strchr (s+1,'-'))) { /* get UID if there is any */ i = strtoul (++s,&t,16); if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) { if (!i) { lseek (fd,pos + s - hdr,L_SET); sprintf (hdr,"%08lx",++(*stream)->uid_last); write (fd,hdr,8); upd = T; } continue; } } } ret = -1; /* error, give up */ *stream = mail_close (*stream); pos = sbuf.st_size + 1; j = k = 0; } } if (upd) { /* need to update hdr with new UIDLAST? */ lseek (fd,15,L_SET); sprintf (hdr,"%08lx",(*stream)->uid_last); write (fd,hdr,8); } } } } } if (ret != fd) close (fd); /* close the file */ else lseek (fd,0,L_SET); /* else rewind to start */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } /* in case INBOX but not mbx format */ else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX")) error = -1; if ((ret < 0) && ld && (*ld >= 0)) { unlockfd (*ld,lock); *ld = -1; } errno = error; /* return as last error */ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -