📄 mix.c
字号:
break; MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); break; default: sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); break; } /* get first message */ if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) { MAILSTREAM *astream; FILE *idxf = NIL; FILE *msgf = NIL; FILE *statf = NIL; if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) && !astream->rdonly && (((MIXLOCAL *) astream->local)->expok = T) && (statf = mix_parse (astream,&idxf,LONGT,NIL))) ? LONGT : NIL) { int fd; unsigned long size,hdrsize; MESSAGECACHE elt; MIXLOCAL *local = (MIXLOCAL *) astream->local; unsigned long seq = mix_modseq (local->metaseq); /* make sure new modseq fits */ if (local->indexseq > seq) seq = local->indexseq + 1; if (local->statusseq > seq) seq = local->statusseq + 1; /* calculate size of per-message header */ sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0); hdrsize = strlen (local->buf); MM_CRITICAL (astream); /* go critical */ astream->silent = T; /* no events here */ /* open data file */ if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; while (ret && message) {/* while good to go and have messages */ errno = NIL; /* in case one of these causes failure */ /* guard against zero-length */ if (!(ret = SIZE (message))) MM_LOG ("Append of zero-length message",ERROR); else if (date && !(ret = mail_parse_date (&elt,date))) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { if (!date) { /* if date not specified, use now */ internal_date (tmp); mail_parse_date (&elt,tmp); } ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) && MM_APPEND (af) (stream,data,&flags,&date,&message); } } /* finish write if success */ if (ret && (ret = !fflush (msgf))) { fclose (msgf); /* all good, close the msg file now */ /* write new metadata, index, and status */ local->metaseq = local->indexseq = local->statusseq = seq; if ((ret = (mix_meta_update (astream) && mix_index_update (astream,idxf,LONGT) && mix_status_update (astream,statf,LONGT))) && au) { (*au) (mailbox,astream->uid_validity,dst); dst = NIL; /* don't free this set now */ } } else { /* failure */ if (errno) { /* output error message if system call error */ sprintf (tmp,"Message append failed: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } ftruncate (fd,size); /* revert all writes to file*/ close (fd); /* make sure that fclose doesn't corrupt us */ fclose (msgf); /* free the stdio resources */ } /* flush any set remaining */ mail_free_searchset (&dst); } else { /* message file open failed */ sprintf (tmp,"Error opening append message file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } MM_NOCRITICAL (astream); /* release critical */ } else MM_LOG ("Can't open append mailbox",ERROR); if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ if (astream) mail_close (astream); } return ret;}/* MIX mail append single message * Accepts: MAIL stream * flags for new message if non-NIL * elt with source date if non-NIL * stringstruct of message text * searchset to place UID * modseq of message * Returns: T if success, NIL if failure */long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt, STRING *msg,SEARCHSET *set,unsigned long seq){ MESSAGECACHE *elt; int c,cs; unsigned long i,j,k,uf,hoff; long sf; stream->kwd_create = NIL; /* don't copy unknown keywords */ sf = mail_parse_flags (stream,flags,&uf); /* swell the cache */ mail_exists (stream,++stream->nmsgs); /* assign new UID from metadata */ (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last; elt->private.mod = seq; /* set requested modseq in status */ elt->rfc822_size = SIZE (msg);/* copy message size and date to index */ elt->year = delt->year; elt->month = delt->month; elt->day = delt->day; elt->hours = delt->hours; elt->minutes = delt->minutes; elt->seconds = delt->seconds; elt->zoccident = delt->zoccident; elt->zhours = delt->zhours; elt->zminutes = delt->zminutes; /* * Do NOT set elt->valid here! mix_status_update() uses it to determine * whether a message should be marked as old. */ if (sf&fSEEN) elt->seen = T; /* copy flags to status */ if (sf&fDELETED) elt->deleted = T; if (sf&fFLAGGED) elt->flagged = T; if (sf&fANSWERED) elt->answered = T; if (sf&fDRAFT) elt->draft = T; elt->user_flags |= uf; /* message is in new message file */ elt->private.spare.data = LOCAL->newmsg; /* offset to message internal header */ elt->private.special.offset = ftell (f); /* build header for message */ fprintf (f,MSRFMT,MSGTOK,elt->private.uid, elt->year + BASEYEAR,elt->month,elt->day, elt->hours,elt->minutes,elt->seconds, elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes, elt->rfc822_size); /* offset to header from internal header */ elt->private.msg.header.offset = ftell (f) - elt->private.special.offset; for (cs = 0; SIZE (msg); ) { /* copy message */ if (elt->private.msg.header.text.size) { if (msg->cursize) /* blat entire chunk if have it */ for (j = msg->cursize; j; j -= k) if (!(k = fwrite (msg->curpos,1,j,f))) return NIL; SETPOS (msg,GETPOS (msg) + msg->cursize); } else { /* still searching for delimiter */ c = 0xff & SNX (msg); /* get source character */ if (putc (c,f) == EOF) return NIL; switch (cs) { /* decide what to do based on state */ case 0: /* previous char ordinary */ if (c == '\015') cs = 1;/* advance if CR */ break; case 1: /* previous CR, advance if LF */ cs = (c == '\012') ? 2 : 0; break; case 2: /* previous CRLF, advance if CR */ cs = (c == '\015') ? 3 : 0; break; case 3: /* previous CRLFCR, done if LF */ if (c == '\012') elt->private.msg.header.text.size = elt->rfc822_size - SIZE (msg); cs = 0; /* reset mechanism */ break; } } } /* if no delimiter, header is entire msg */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* add this message to set */ mail_append_set (set,elt->private.uid); return LONGT; /* success */}/* MIX mail read metadata, index, and status * Accepts: MAIL stream * returned index file * index file flags (non-NIL if want to add/remove messages) * status file flags (non-NIL if want to update elt->valid and old) * Returns: open status file, or NIL if failure * * Note that this routine can return an open index file even if it fails! */static char *shortmsg = "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)";FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags){ int fd; unsigned long i; char *s,*t; struct stat sbuf; FILE *statf = NIL; short metarepairneeded = 0; short indexrepairneeded = 0; short silent = stream->silent; *idxf = NIL; /* in case error */ /* readonly means no updates */ if (stream->rdonly) iflags = sflags = NIL; /* open index file */ if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0) MM_LOG ("Error opening mix index file",ERROR); /* acquire exclusive access and FILE */ else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) && !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) { MM_LOG ("Error obtaining stream on mix index file",ERROR); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } /* slurp metadata */ else if (s = mix_meta_slurp (stream,&i)) { unsigned long j = 0; /* non-zero if UIDVALIDITY/UIDLAST changed */ if (i != LOCAL->metaseq) { /* metadata changed? */ char *t,*k; LOCAL->metaseq = i; /* note new metadata sequence */ while (s && *s) { /* parse entire metadata file */ /* locate end of line */ if (s = strstr (t = s,"\015\012")) { *s = '\0'; /* tie off line */ s += 2; /* skip past CRLF */ switch (*t++) { /* parse line */ case 'V': /* UIDVALIDITY */ if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) { MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR); return NIL; /* give up */ } if (i != stream->uid_validity) j = stream->uid_validity = i; break; case 'L': /* new UIDLAST */ if (!isxdigit (*t)) { MM_LOG ("Error in mix metadata file UIDLAST record",ERROR); return NIL; /* give up */ } if ((i = strtoul (t,&t,16)) != stream->uid_last) j = stream->uid_last = i; break; case 'N': /* new message file */ if (!isxdigit (*t)) { MM_LOG ("Error in mix metadata file new msg record",ERROR); return NIL; /* give up */ } if ((i = strtoul (t,&t,16)) != stream->uid_last) LOCAL->newmsg = i; break; case 'K': /* new keyword list */ for (i = 0; t && *t && (i < NUSERFLAGS); ++i) { if (t = strchr (k = t,' ')) *t++ = '\0'; /* make sure keyword non-empty */ if (*k && (strlen (k) <= MAXUSERFLAG)) { /* in case value changes (shouldn't happen) */ if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){ char tmp[MAILTMPLEN]; sprintf (tmp,"flag rename old=%.80s new=%.80s", stream->user_flags[i],k); MM_LOG (tmp,WARN); fs_give ((void **) &stream->user_flags[i]); } if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k); } else break; /* empty keyword */ } if ((i < NUSERFLAGS) && stream->user_flags[i]) { MM_LOG ("Error in mix metadata file keyword record",ERROR); return NIL; /* give up */ } else if (i == NUSERFLAGS) stream->kwd_create = NIL; break; } } if (t && *t) { /* junk in line */ MM_LOG ("Error in mix metadata record",ERROR); return NIL; /* give up */ } } } /* get sequence */ if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) { MM_LOG ("Error in mix index file sequence record",ERROR); return NIL; /* give up */ } /* sequence changed from last time? */ else if (j || (i > LOCAL->indexseq)) { unsigned long uid,nmsgs,curfile,curfilesize,curpos; char *t,*msg,tmp[MAILTMPLEN]; /* start with no messages */ curfile = curfilesize = curpos = nmsgs = 0; /* update sequence iff expunging OK */ if (LOCAL->expok) LOCAL->indexseq = i; /* get first elt */ while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) && *s) switch (*s) { case ':': /* message record */ if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID"; else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) && ((t[14] == '+') || (t[14] == '-')) && isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) && isdigit (t[18]))) msg = "internaldate"; else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size"; else { unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) + ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR; unsigned int m = ((t[4] - '0') * 10) + t[5] - '0'; unsigned int d = ((t[6] - '0') * 10) + t[7] - '0'; unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0'; unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0'; unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0'; unsigned int z = (t[14] == '-') ? 1 : 0; unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0'; unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0'; unsigned long size = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long file = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long pos = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long hpos = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long hsiz = strtoul (s,&s,16); if (uid > stream->uid_last) { sprintf (tmp,"mix index invalid UID (%08lx < %08lx)", uid,stream->uid_last); if (stream->rdonly) { MM_LOG (tmp,ERROR); return NIL; } strcat (tmp,", repaired"); MM_LOG (tmp,WARN); stream->uid_last = uid; metarepairneeded = T; } /* ignore expansion values */ if (*s++ == ':') { MESSAGECACHE *elt; ++nmsgs; /* this is another mesage */ /* within current known range of messages? */ while (nmsgs <= stream->nmsgs) { /* yes, get corresponding elt */ elt = mail_elt (stream,nmsgs); /* existing message with matching data? */ if (uid == elt->private.uid) { /* beware of Dracula's resurrection */ if (elt->private.ghost) { sprintf (tmp,"mix index data unexpunged UID: %lx", uid); MM_LOG (tmp,ERROR); return NIL; } /* also of static data changing */ if ((size != elt->rfc822_size) || (file != elt->private.spare.data) || (pos != elt->private.special.offset) || (hpos != elt->private.msg.header.offset) || (hsiz != elt->private.msg.header.text.size) || (y != elt->year) || (m != elt->month) || (d != elt->day) || (hh != elt->hours) || (mm != elt->minutes) || (ss != elt->seconds) || (z != elt->zoccident) || (zh != elt->zhours) || (zm != elt->zminutes)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -