📄 mbxnt.c
字号:
if (k & fDRAFT) elt->draft = T; t[8] = '\0'; /* get user flags value */ elt->user_flags = strtoul (t,NIL,16); /* UID already assigned? */ if (!(elt->private.uid = m) || !(k & fOLD)) { elt->recent = T; /* no, mark as recent */ ++recent; /* count up a new recent message */ dirty = T; /* and must rewrite header */ /* assign new UID */ if (!elt->private.uid) elt->private.uid = ++stream->uid_last; mbx_update_status (stream,elt->msgno,NIL); } /* update last parsed UID */ lastuid = elt->private.uid; } curpos += i + j; /* update position */ } if (dirty && !stream->rdonly){/* update header */ mbx_update_header (stream); fsync (LOCAL->fd); /* make sure all the UID updates take */ } /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */}/* MBX get cache element with status updating from file * Accepts: MAIL stream * message number * expunge OK flag * Returns: cache element */MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok){ MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; /* get new flags */ if (mbx_read_flags (stream,elt) && expok) { mail_expunged (stream,elt->msgno); return NIL; /* return this message was expunged */ } if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt;}/* MBX read flags from file * Accepts: MAIL stream * cache element * Returns: non-NIL if message expunged */unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt){ unsigned long i; struct stat sbuf; fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } LOCAL->buf[13] = '\0'; /* tie off buffer */ /* calculate system flags */ i = strtoul (LOCAL->buf+9,NIL,16); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->expunged |= i & fEXPUNGED ? T : NIL; LOCAL->buf[9] = '\0'; /* tie off flags */ /* get user flags value */ elt->user_flags = strtoul (LOCAL->buf+1,NIL,16); elt->valid = T; /* have valid flags now */ return i & fEXPUNGED;}/* MBX update header * Accepts: MAIL stream */#define NTKLUDGEOFFSET 7void mbx_update_header (MAILSTREAM *stream){ int i; char *s = LOCAL->buf; memset (s,'\0',HDRSIZE); /* initialize header */ sprintf (s,"*mbx*\015\012%08lx%08lx\015\012", stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]); LOCAL->ffuserflag = i; /* first free user flag */ /* can we create more user flags? */ stream->kwd_create = (i < NUSERFLAGS) ? T : NIL; /* write reserved lines */ while (i++ < NUSERFLAGS) strcat (s,"\015\012"); while (T) { /* rewind file */ lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET); /* write new header */ if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET, HDRSIZE - NTKLUDGEOFFSET) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); }}/* MBX update status string * Accepts: MAIL stream * message number * flags */void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags){ struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); /* readonly */ if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt); else { /* readwrite */ fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } /* print new flag string */ sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned) (((elt->deleted && flags) ? fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + fOLD),elt->private.uid); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 23,L_SET); /* write new flags and UID */ if (write (LOCAL->fd,LOCAL->buf,21) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } }}/* MBX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * pointer to possible returned header * Returns: position of header in file */#define HDRBUFLEN 16384 /* good enough for most headers */#define SLOP 4 /* CR LF CR LF */unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr){ unsigned long siz,done; long i; unsigned char *s,*t,*te; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; if (hdr) *hdr = NIL; /* assume no header returned */ /* is header size known? */ if (*size = elt->private.msg.header.text.size) return ret; /* paranoia check */ if (LOCAL->buflen < (HDRBUFLEN + SLOP)) fatal ("LOCAL->buf smaller than HDRBUFLEN"); lseek (LOCAL->fd,ret,L_SET); /* get to header position */ /* read HDRBUFLEN chunks with 4 byte slop */ for (done = siz = 0, s = LOCAL->buf; (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) && (read (LOCAL->fd,s,i) == i); done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) { te = (t = s + i) - 12; /* calculate end of fast scan */ /* fast scan for CR */ for (s = LOCAL->buf; s < te;) if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } for (te = t - 3; (s < te);) /* final character-at-a-time scan */ if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } if (i <= SLOP) break; /* end of data */ /* slide over last 4 bytes */ memmove (LOCAL->buf,t - SLOP,SLOP); hdr = NIL; /* can't return header this way */ } /* not found: header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; if (hdr) *hdr = LOCAL->buf; /* possibly return header too */ return ret;}/* MBX mail rewrite mailbox * Accepts: MAIL stream * pointer to return reclaimed size * flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence) * Returns: number of expunged messages */unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags){ struct utimbuf times; struct stat sbuf; off_t pos,ppos; int ld; unsigned long i,j,k,m,delta; unsigned long n = *reclaimed = 0; unsigned long recent = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; /* get parse/append permission */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) { mm_log ("Unable to lock expunge mailbox",ERROR); return 0; } fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime && !LOCAL->flagcheck && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; if (!mbx_parse (stream)) { /* make sure see any newly-arrived messages */ unlockfd (ld,lock); /* failed?? */ return 0; } if (LOCAL->flagcheck) { /* sweep flags if need flagcheck */ LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL); LOCAL->flagcheck = NIL; } /* get exclusive access */ if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { mm_critical (stream); /* go critical */ for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) { /* note if message not at predicted location */ if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) { ppos = elt->private.special.offset; *reclaimed += m; /* note reclaimed message space */ delta += m; /* and as expunge delta */ } /* number of bytes to smash or preserve */ ppos += (k = elt->private.special.text.size + elt->rfc822_size); /* if need to expunge this message*/ if (flags && elt->deleted && ((flags > 0) || elt->sequence)) { delta += k; /* number of bytes to delete */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else { /* preserved message */ i++; /* count this message */ if (elt->recent) ++recent; if (delta) { /* moved, note first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages yet */ else pos = elt->private.special.offset + k; } } /* deltaed file size match position? */ if (m = (LOCAL->filesize -= delta) - pos) { *reclaimed += m; /* probably an fEXPUNGED msg */ LOCAL->filesize = pos; /* set correct size */ } /* truncate file after last message */ ftruncate (LOCAL->fd,LOCAL->filesize); fsync (LOCAL->fd); /* force disk update */ mm_nocritical (stream); /* release critical */ flock (LOCAL->fd,LOCK_SH); /* allow sharers again */ } else { /* can't get exclusive */ flock (LOCAL->fd,LOCK_SH); /* recover previous shared mailbox lock */ /* do hide-expunge when shared */ if (flags) for (i = 1; i <= stream->nmsgs; ) { if (elt = mbx_elt (stream,i,T)) { /* make the message invisible */ if (elt->deleted && ((flags > 0) || elt->sequence)) { mbx_update_status (stream,elt->msgno,LONGT); /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else { i++; /* preserved message */ if (elt->recent) ++recent; } } else n++; /* count up one more expunged message */ } fsync (LOCAL->fd); /* force disk update */ } fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); unlockfd (ld,lock); /* release exclusive parse/append permission */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); return n; /* return number of expunged messages */}/* MBX mail lock for flag updating * Accepts: stream * Returns: T if successful, NIL if failure */long mbx_flaglock (MAILSTREAM *stream){ struct stat sbuf; unsigned long i; int ld; char lock[MAILTMPLEN]; /* no-op if readonly or already locked */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) { /* lock now */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL; if (!LOCAL->flagcheck) { /* don't do this if flagcheck already needed */ if (LOCAL->filetime) { /* know previous time? */ fstat (LOCAL->fd,&sbuf);/* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } if (!mbx_parse (stream)) {/* parse mailbox */ unlockfd (ld,lock); /* shouldn't happen */ return NIL; } if (LOCAL->flagcheck) /* invalidate cache if flagcheck */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL; } LOCAL->ld = ld; /* copy to stream for subsequent calls */ memcpy (LOCAL->lock,lock,MAILTMPLEN); } return LONGT;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -