📄 mmdf.c
字号:
if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { /* error -1 for invalid format */ if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1; close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } return ret; /* return what we should */}/* MMDF mail test for valid mailbox * Accepts: file descriptor * scratch buffer * Returns: T if valid, NIL otherwise */long mmdf_isvalid_fd (int fd,char *tmp){ int ret = NIL; memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL; return ret; /* return what we should */}/* MMDF manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *mmdf_parameters (long function,void *value){ void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; } return ret;}/* MMDF mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents){ if (stream) dummy_scan (NIL,ref,pat,contents);}/* MMDF mail list mailboxes * Accepts: mail stream * reference * pattern to search */void mmdf_list (MAILSTREAM *stream,char *ref,char *pat){ if (stream) dummy_list (NIL,ref,pat);}/* MMDF mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat){ if (stream) dummy_lsub (NIL,ref,pat);}/* MMDF mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */long mmdf_create (MAILSTREAM *stream,char *mailbox){ char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int i,fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if dir-only or whiner */ if (((s = strrchr (s,'/')) && !s[1]) || mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T; else if ((fd = open (mbx,O_WRONLY, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti)); rfc822_date (s = tmp + strlen (tmp)); sprintf (s += strlen (s), /* write the pseudo-header */ "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti); for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i)) sprintf (s += strlen (s)," %s",default_user_flag (i)); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr); if (write (fd,tmp,strlen (tmp)) > 0) ret = T; else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL;}/* MMDF mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */long mmdf_delete (MAILSTREAM *stream,char *mailbox){ return mmdf_rename (stream,mailbox,NIL);}/* MMDF mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */long mmdf_rename (MAILSTREAM *stream,char *old,char *newname){ long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; DOTLOCK lockx; int fd,ld; long i; struct stat sbuf; MM_CRITICAL (stream); /* get the c-client lock */ 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); /* lock out other c-clients */ else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0) sprintf (tmp,"Mailbox %.80s is in use by another process",old); else { if ((fd = mmdf_lock (file,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (s,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) { mmdf_unlock (fd,NIL,&lockx); mmdf_unlock (ld,NIL,NIL); unlink (lock); MM_NOCRITICAL (stream); return ret; /* return success or failure */ } *s = c; /* restore full name */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ mmdf_unlock (fd,NIL,&lockx); } mmdf_unlock (ld,NIL,NIL); /* flush the lock */ unlink (lock); } MM_NOCRITICAL (stream); /* no longer critical */ if (!ret) MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success or failure */}/* MMDF mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */MAILSTREAM *mmdf_open (MAILSTREAM *stream){ long i; int fd; char tmp[MAILTMPLEN]; DOTLOCK lock; long retry; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mmdfproto); retry = stream->silent ? 1 : KODRETRY; if (stream->local) fatal ("mmdf recycle stream"); stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ /* make lock for read/write access */ if (!stream->rdonly) while (retry) { /* try to lock file */ if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) { /* suppressing kiss-of-death? */ if (stream->nokod) retry = 0; /* no, first time through? */ else if (retry-- == KODRETRY) { /* learned other guy's PID and can signal? */ if (i && !kill ((int) i,SIGUSR2)) { sprintf (tmp,"Trying to get mailbox lock from process %ld",i); MM_LOG (tmp,WARN); } else retry = 0; /* give up */ } if (!stream->silent) { /* nothing if silent stream */ if (retry) sleep (1); /* wait a second before trying again */ else MM_LOG ("Mailbox is open by another process, access is readonly", WARN); } } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); /* make sure mode OK (don't use fchmod()) */ chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL)); if (stream->silent) i = 0;/* silent streams won't accept KOD */ else { /* note our PID in the lock */ sprintf (tmp,"%d",getpid ()); write (fd,tmp,(i = strlen (tmp))+1); } ftruncate (fd,i); /* make sure tied off */ fsync (fd); /* make sure it's available */ retry = 0; /* no more need to try */ } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) { MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) mmdf_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (mmdf_parse (stream,&lock,LOCK_SH)) { mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; if (!stream->uid_nosticky) {/* users with lives get permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too! */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } } return stream; /* return stream alive to caller */}/* MMDF mail close * Accepts: MAIL stream * close options */void mmdf_close (MAILSTREAM *stream,long options){ int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) mmdf_check (stream); stream->silent = silent; /* restore old silence state */ mmdf_abort (stream); /* now punt the file and local data */}/* MMDF mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */static STRINGLIST *mmdf_hlines = NIL;char *mmdf_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags){ MESSAGECACHE *elt; unsigned char *s,*t,*tl; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!mmdf_hlines) { /* once only code */ STRINGLIST *lines = mmdf_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -