📄 mmdf.c
字号:
} if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } 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 */ if (tstream) { /* update last UID if we can */ MMDFLOCAL *local = (MMDFLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* 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; MM_NOCRITICAL (stream); /* release critical */ 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; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; time_t tp[2]; FILE *sf,*df; MESSAGECACHE elt; DOTLOCK lock; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; /* 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]); } if (!mmdf_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } mmdf_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; 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); MM_LOG (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR); else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } /* get next message */ else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ if (tstream != stream) tstream = mail_close (tstream); MM_CRITICAL (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); tp[1] = time (0); /* set mtime to now */ /* write all messages */ if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); MM_LOG (buf,ERROR); ftruncate (fd,sbuf.st_size); tp[0] = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; ret = NIL; /* return error */ } else tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ utime (file,tp); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); mmdf_unlock (fd,NIL,&lock); /* unlock and close mailbox */ fclose (df); if (tstream) { /* update last UID if we can */ MMDFLOCAL *local = (MMDFLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } MM_NOCRITICAL (stream); /* release critical */ return ret;}/* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg){ unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata, note date ends with NL */ if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (putc ('\n',sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing newline and return */ return (putc ('\n',sf) == EOF) ? NIL : T;}/* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set){ int c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(), mylocalhost(),x) < 0) || (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun"); i -= j; /* number of bytes left */ /* squish out ^A and CRs (note copies NUL) */ for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp)); if (!j) continue; /* do nothing if line emptied */ /* start of line? */ if ((c == '\n')) switch (tmp[0]) { case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; break; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } /* make sure read entire msg & wrote trailer */ if (i || (fputs (mmdfhdr,df) == EOF)) return NIL; /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T;}/* Internal routines *//* MMDF mail abort stream * Accepts: MAIL stream */void mmdf_abort (MAILSTREAM *stream){ if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -