📄 mmdf.c
字号:
elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t <= tl; t++) if ((*t != '\r') || (t[1] != '\n')) *s++ = *t; /* adjust length */ LOCAL->buf[*length = s - LOCAL->buf - 1] = '\0'; } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ } *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT); return LOCAL->buf; /* return processed copy */}/* MMDF mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; MM_FLAGS (stream,msgno); } s = mmdf_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */}/* MMDF mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags){ FDDATA d; STRING bs; unsigned char *s,*t,*tl,tmp[CHUNK]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t <= tl; t++) if ((*t != '\r') || (t[1] != '\n')) *s++ = *t; /* adjust length */ LOCAL->buf[*length = s - LOCAL->buf - 1] = '\0'; return LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNK; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (CHR (&bs)) { case '\r': /* carriage return seen */ *s++ = SNX (&bs); /* copy it and any succeeding LF */ if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs); break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = SNX (&bs); /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data;}/* MMDF per-message modify flag * Accepts: MAIL stream * message cache element */void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt){ /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T;}/* MMDF mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */long mmdf_ping (MAILSTREAM *stream){ DOTLOCK lock; struct stat sbuf; long reparse; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) mmdf_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* see if need to reparse */ if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else stat (stream->mailbox,&sbuf); reparse = (sbuf.st_size != LOCAL->filesize); } /* parse if mailbox changed */ if (reparse && mmdf_parse (stream,&lock,LOCK_SH)) { /* unlock mailbox */ mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* and stream */ /* done with critical */ MM_NOCRITICAL (stream); } } } return LOCAL ? LONGT : NIL; /* return if still alive */}/* MMDF mail check mailbox * Accepts: MAIL stream */void mmdf_check (MAILSTREAM *stream){ DOTLOCK lock; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && mmdf_parse (stream,&lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock)) { if (!stream->silent) MM_LOG ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ }}/* MMDF mail expunge mailbox * Accepts: MAIL stream */void mmdf_expunge (MAILSTREAM *stream){ unsigned long i; DOTLOCK lock; char *msg = NIL; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && mmdf_parse (stream,&lock,LOCK_EX)) { /* count expunged messages if not dirty */ if (!LOCAL->dirty) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; if (!LOCAL->dirty) { /* not dirty and no expunged messages */ mmdf_unlock (LOCAL->fd,stream,&lock); msg = "No messages deleted, so no update needed"; } else if (mmdf_rewrite (stream,&i,&lock)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ if (msg && !stream->silent) MM_LOG (msg,NIL); } else if (!stream->silent) MM_LOG ("Expunge ignored on readonly mailbox",WARN);}/* MMDF mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options){ struct stat sbuf; int fd; char *s,file[MAILTMPLEN]; DOTLOCK lock; time_t tp[2]; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure valid mailbox */ if (!mmdf_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) { if (pc) return (*pc) (stream,sequence,mailbox,options); mmdf_create (NIL,"INBOX");/* create empty INBOX */ break; } MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } LOCAL->buf[0] = '\0'; MM_CRITICAL (stream); /* go critical */ if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND|O_CREAT, S_IREAD|S_IWRITE,&lock,LOCK_EX)) < 0) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); /* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL; else { /* internal header succeeded */ s = mmdf_header (stream,i,&j,FT_INTERNAL); /* header size, sans trailing newline */ if (j && (s[j - 2] == '\n')) j--; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = mmdf_text_work (stream,elt,&j,FT_INTERNAL); if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0)) ret = NIL; } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } tp[1] = time (0); /* set mtime to now */ if (ret) tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ else tp[0] = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; utime (file,tp); /* set the times */ mmdf_unlock (fd,NIL,&lock); /* unlock and close mailbox */ MM_NOCRITICAL (stream); /* release critical */ /* log the error */ if (!ret) MM_LOG (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; return ret;}/* MMDF mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */#define BUFLEN 8*MAILTMPLENlong mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data){ struct stat sbuf; int fd; unsigned long i,j; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; time_t tp[2]; FILE *sf,*df; MESSAGECACHE elt; DOTLOCK lock; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) { /* stream specified? */ stream = &mmdfproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); stream->kwd_create = T; /* allow new flags */ } /* make sure valid mailbox */ if (!mmdf_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) { mmdf_create (NIL,"INBOX");/* create empty INBOX */ break; } MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -