📄 mx.c
字号:
/* MX mail rename mailbox * Accepts: MX mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */long mx_rename (MAILSTREAM *stream,char *old,char *newname){ char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; if (!mx_isvalid (old,tmp)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); /* new mailbox name must not be valid */ else if (mx_isvalid (newname,tmp)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); /* success if can rename the directory */ else { /* found superior to destination name? */ if (s = strrchr (mx_file (tmp1,newname),'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (mx_file (tmp,old),tmp1)) { /* recreate file if renamed INBOX */ if (!compare_cstring (old,"INBOX")) mx_create (NIL,"INBOX"); return T; } sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s", old,newname,strerror (errno)); } MM_LOG (tmp,ERROR); /* something failed */ return NIL;}/* MX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *mx_open (MAILSTREAM *stream){ char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mxproto); if (stream->local) fatal ("mx recycle stream"); stream->local = fs_get (sizeof (MXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); mx_file (tmp,stream->mailbox);/* get directory name */ LOCAL->dir = cpystr (tmp); /* copy directory name for later */ /* make temporary buffer */ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = MAXMESSAGESIZE) + 1); LOCAL->scantime = 0; /* not scanned yet */ LOCAL->fd = -1; /* no index yet */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mx_ping (stream) && !(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",(long) NIL); 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 */}/* MX mail close * Accepts: MAIL stream * close options */void mx_close (MAILSTREAM *stream,long options){ if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mx_expunge (stream); if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); /* free local scratch 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 */ stream->silent = silent; /* reset silent state */ }}/* MX mail fetch fast information * Accepts: MAIL stream * sequence * option flags */void mx_fast (MAILSTREAM *stream,char *sequence,long flags){ unsigned long i; MESSAGECACHE *elt; if (stream && LOCAL && ((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) mx_fast_work (stream,elt);}/* MX mail fetch fast information * Accepts: MAIL stream * message cache element * Returns: name of message file */char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt){ struct stat sbuf; struct tm *tm; /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); if (!elt->rfc822_size) { /* have size yet? */ stat (LOCAL->buf,&sbuf); /* get size of message */ /* make plausible IMAPish date string */ tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0; elt->rfc822_size = sbuf.st_size; } return LOCAL->buf; /* return file name */}/* MX 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 *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags){ unsigned long i; int fd; MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { mail_gc (stream,GC_TEXTS);/* just can't keep that much */ LOCAL->cachedtexts = 0; } if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return ""; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1); } /* slurp message */ read (fd,LOCAL->buf,elt->rfc822_size); /* tie off file */ LOCAL->buf[elt->rfc822_size] = '\0'; close (fd); /* flush message file */ /* find end of header */ if (elt->rfc822_size < 4) i = 0; else for (i = 4; (i < elt->rfc822_size) && !((LOCAL->buf[i - 4] == '\015') && (LOCAL->buf[i - 3] == '\012') && (LOCAL->buf[i - 2] == '\015') && (LOCAL->buf[i - 1] == '\012')); i++); /* copy header */ cpytxt (&elt->private.msg.header.text,LOCAL->buf,i); cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i); /* add to cached size */ LOCAL->cachedtexts += elt->rfc822_size; } *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data;}/* MX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno); /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { mx_header (stream,msgno,&i,flags); if (!elt->private.msg.text.text.data) return NIL; } /* mark as seen */ if (!(flags & FT_PEEK) && mx_lockindex (stream)) { elt->seen = T; mx_unlockindex (stream); MM_FLAGS (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T;}/* MX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags){ mx_unlockindex (stream); /* finished with index */}/* MX per-message modify flags * Accepts: MAIL stream * message cache element */void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt){ mx_lockindex (stream); /* lock index if not already locked */}/* MX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */long mx_ping (MAILSTREAM *stream){ MAILSTREAM *sysibx = NIL; MESSAGECACHE *elt,*selt; struct stat sbuf; char *s,tmp[MAILTMPLEN]; int fd; unsigned long i,j,r,old; long nmsgs = stream->nmsgs; long recent = stream->recent; int silent = stream->silent; if (stat (LOCAL->dir,&sbuf)) return NIL; stream->silent = T; /* don't pass up mm_exists() events yet */ if (sbuf.st_ctime != LOCAL->scantime) { struct direct **names = NIL; long nfiles = scandir (LOCAL->dir,&names,mx_select,mx_numsort); if (nfiles < 0) nfiles = 0; /* in case error */ old = stream->uid_last; /* note scanned now */ LOCAL->scantime = sbuf.st_ctime; /* scan directory */ for (i = 0; i < nfiles; ++i) { /* if newly seen, add to list */ if ((j = atoi (names[i]->d_name)) > old) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j; elt->valid = T; /* note valid flags */ if (old) { /* other than the first pass? */ elt->recent = T; /* yup, mark as recent */ recent++; /* bump recent count */ } } fs_give ((void **) &names[i]); } /* free directory */ if (s = (void *) names) fs_give ((void **) &s); } stream->nmsgs = nmsgs; /* don't upset mail_uid() */ /* if INBOX, snarf from system INBOX */ if (mx_lockindex (stream) && stream->inbox) { old = stream->uid_last; /* paranoia check */ if (!strcmp (sysinbox (),stream->mailbox)) { stream->silent = silent; return NIL; } MM_CRITICAL (stream); /* go critical */ stat (sysinbox (),&sbuf); /* see if anything there */ /* can get sysinbox mailbox? */ if (sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */ /* build file name we will use */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old); /* snarf message from Berkeley mailbox */ selt = mail_elt (sysibx,i); if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL, S_IREAD|S_IWRITE)) >= 0) && (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) && (write (fd,s,j) == j) && (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) && (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = /* create new elt, note its file number */ (elt = mail_elt (stream,nmsgs))->private.uid = old; recent++; /* bump recent count */ /* set up initial flags and date */ elt->valid = elt->recent = T; elt->seen = selt->seen; elt->deleted = selt->deleted; elt->flagged = selt->flagged; elt->answered = selt->answered; elt->draft = selt->draft; elt->day = selt->day;elt->month = selt->month;elt->year = selt->year; elt->hours = selt->hours;elt->minutes = selt->minutes; elt->seconds = selt->seconds; elt->zhours = selt->zhours; elt->zminutes = selt->zminutes; elt->zoccident = selt->zoccident; mx_setdate (LOCAL->buf,elt); } else { /* failed to snarf */ if (fd) { /* did it ever get opened? */ close (fd); /* close descriptor */ unlink (LOCAL->buf);/* flush this file */ } stream->silent = silent; return NIL; /* note that something is badly wrong */ } sprintf (tmp,"%lu",i); /* delete it from the sysinbox */ mail_flag (sysibx,tmp,"\\Deleted",ST_SET); } stat (LOCAL->dir,&sbuf); /* update scan time */ LOCAL->scantime = sbuf.st_ctime; mail_expunge (sysibx); /* now expunge all those messages */ } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ } mx_unlockindex (stream); /* done with index */ stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of mailbox size */ mail_recent (stream,recent); return T; /* return that we are alive */}/* MX mail check mailbox * Accepts: MAIL stream */void mx_check (MAILSTREAM *stream){ if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL);}/* MX mail expunge mailbox * Accepts: MAIL stream */void mx_expunge (MAILSTREAM *stream){ MESSAGECACHE *elt; unsigned long i = 1; unsigned long n = 0; unsigned long recent = stream->recent; if (mx_lockindex (stream)) { /* lock the index */ MM_CRITICAL (stream); /* go critical */ while (i <= stream->nmsgs) {/* for each message */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -