📄 mx.c
字号:
} /* note uncached */ LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ? elt->private.msg.header.text.size : 0) + (elt->private.msg.text.text.data ? elt->private.msg.text.text.size : 0)); mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS); if(elt->recent)--recent;/* if recent, note one less recent message */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else i++; /* otherwise try next message */ } if (n) { /* output the news if any expunged */ sprintf (LOCAL->buf,"Expunged %lu messages",n); MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); MM_NOCRITICAL (stream); /* release critical */ mx_unlockindex (stream); /* finished with index */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); } return ret;}/* MX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options){ FDDATA d; STRING st; MESSAGECACHE *elt; MAILSTREAM *astream; struct stat sbuf; int fd; unsigned long i,j,uid,uidv; char *t,tmp[MAILTMPLEN]; long ret; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mx_valid (mailbox)) switch (errno) { case NIL: /* no error in stat() */ if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: /* some stat() error */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } /* copy the messages */ if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))); /* acquire stream to append to */ else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { MM_LOG ("Can't open copy mailbox",ERROR); ret = NIL; } else { MM_CRITICAL (stream); /* go critical */ if (!(ret = mx_lockindex (astream))) MM_LOG ("Message copy failed: unable to lock index",ERROR); else { copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get size of message */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&st,fd_string,&d,sbuf.st_size); /* init flag string */ tmp[0] = tmp[1] = '\0'; if (j = elt->user_flags) do if (t = stream->user_flags[find_rightmost_bit (&j)]) strcat (strcat (tmp," "),t); while (j); if (elt->seen) strcat (tmp," \\Seen"); if (elt->deleted) strcat (tmp," \\Deleted"); if (elt->flagged) strcat (tmp," \\Flagged"); if (elt->answered) strcat (tmp," \\Answered"); if (elt->draft) strcat (tmp," \\Draft"); tmp[0] = '('; /* open list */ strcat (tmp,")"); /* close list */ if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) { /* add to source set if needed */ if (source) mail_append_set (source,mail_uid (stream,i)); /* delete if doing a move */ if (options & CP_MOVE) elt->deleted = T; } } } /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } mx_unlockindex (astream); /* unlock index */ } MM_NOCRITICAL (stream); mail_close (astream); /* finished with append stream */ } return ret; /* return success */}/* MX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data){ MESSAGECACHE elt; MAILSTREAM *astream; char *flags,*date,tmp[MAILTMPLEN]; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&mxproto); /* N.B.: can't use LOCAL->buf for tmp */ /* make sure valid mailbox */ if (!mx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { MM_LOG ("Can't open append mailbox",ERROR); return NIL; } MM_CRITICAL (astream); /* go critical */ /* lock the index */ if (!(ret = mx_lockindex (astream))) MM_LOG ("Message append failed: unable to lock index",ERROR); else { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; do { /* 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 ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&& MM_APPEND (af) (stream,data,&flags,&date,&message); } while (ret && message); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,astream->uid_validity,dst); else mail_free_searchset (&dst); mx_unlockindex (astream); /* unlock index */ } MM_NOCRITICAL (astream); /* release critical */ mail_close (astream); return ret;}/* MX 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 * Returns: T if success, NIL if failure */long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt, STRING *st,SEARCHSET *set){ char tmp[MAILTMPLEN]; int fd; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* make message file name */ sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last); if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't create append message: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } while (SIZE (st)) { /* copy the file */ if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) { unlink (tmp); /* delete file */ close (fd); /* close the file */ sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } SETPOS (st,GETPOS (st) + st->cursize); } close (fd); /* close the file */ if (elt) mx_setdate (tmp,elt);/* set file date */ /* swell the cache */ mail_exists (stream,++stream->nmsgs); /* copy flags */ mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid = stream->uid_last); if (f&fSEEN) elt->seen = T; if (f&fDELETED) elt->deleted = T; if (f&fFLAGGED) elt->flagged = T; if (f&fANSWERED) elt->answered = T; if (f&fDRAFT) elt->draft = T; elt->user_flags |= uf; return LONGT;}/* Internal routines *//* MX file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */int mx_select (struct direct *name){ char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T;}/* MX file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */int mx_numsort (const void *d1,const void *d2){ return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name);}/* MX mail build file name * Accepts: destination string * source * Returns: destination */char *mx_file (char *dst,char *name){ char *s; /* empty string if mailboxfile fails */ if (!mailboxfile (dst,name)) *dst = '\0'; /* driver-selected INBOX */ else if (!*dst) mailboxfile (dst,"~/INBOX"); /* tie off unnecessary trailing / */ else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0'; return dst;}/* MX read and lock index * Accepts: MAIL stream * Returns: T if success, NIL if failure */long mx_lockindex (MAILSTREAM *stream){ unsigned long uf,sf,uid; int k = 0; unsigned long msgno = 1; struct stat sbuf; char *s,*t,*idx,tmp[2*MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if ((LOCAL->fd < 0) && /* get index file, no-op if already have it */ (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME), O_RDWR|O_CREAT, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_EX); /* get exclusive lock */ (*bn) (BLOCK_NONE,NIL); fstat (LOCAL->fd,&sbuf); /* get size of index */ /* slurp index */ read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); idx[sbuf.st_size] = '\0'; /* tie off index */ /* parse index */ if (sbuf.st_size) while (s && *s) switch (*s) { case 'V': /* UID validity record */ stream->uid_validity = strtoul (s+1,&s,16); break; case 'L': /* UID last record */ stream->uid_last = strtoul (s+1,&s,16); break; case 'K': /* keyword */ /* find end of keyword */ if (s = strchr (t = ++s,'\n')) { *s++ = '\0'; /* tie off keyword */ /* copy keyword */ if ((k < NUSERFLAGS) && !stream->user_flags[k] && (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t); k++; /* one more keyword */ } break; case 'M': /* message status record */ uid = strtoul (s+1,&s,16);/* get UID for this message */ if (*s == ';') { /* get user flags */ uf = strtoul (s+1,&s,16); if (*s == '.') { /* get system flags */ sf = strtoul (s+1,&s,16); while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid)) msgno++; /* find message number for this UID */ if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) { (elt = mail_elt (stream,msgno))->valid = T; elt->user_flags=uf; /* set user and system flags in elt */ if (sf & fSEEN) elt->seen = T; if (sf & fDELETED) elt->deleted = T; if (sf & fFLAGGED) elt->flagged = T; if (sf & fANSWERED) elt->answered = T; if (sf & fDRAFT) elt->draft = T; } break; } } default: /* bad news */ sprintf (tmp,"Error in index: %.80s",s); MM_LOG (tmp,ERROR); *s = NIL; /* ignore remainder of index */ } else { /* new index */ stream->uid_validity = time (0); user_flags (stream); /* init stream with default user flags */ } fs_give ((void **) &idx); /* flush index */ } return (LOCAL->fd >= 0) ? T : NIL;}/* MX write and unlock index * Accepts: MAIL stream */#define MXIXBUFLEN 2048void mx_unlockindex (MAILSTREAM *stream){ unsigned long i,j; off_t size = 0; char *s,tmp[MXIXBUFLEN + 64]; MESSAGECACHE *elt; if (LOCAL->fd >= 0) { lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* write header */ sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]); /* write messages */ for (i = 1; i <= stream->nmsgs; i++) { /* filled buffer? */ if (((s += strlen (s)) - tmp) > MXIXBUFLEN) { write (LOCAL->fd,tmp,j = s - tmp); size += j; *(s = tmp) = '\0'; /* dump out and restart buffer */ } elt = mail_elt (stream,i); sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); } /* write tail end of buffer */ if ((s += strlen (s)) != tmp) { write (LOCAL->fd,tmp,j = s - tmp); size += j; } ftruncate (LOCAL->fd,size); flock (LOCAL->fd,LOCK_UN); /* unlock the index */ close (LOCAL->fd); /* finished with file */ LOCAL->fd = -1; /* no index now */ }}/* Set date for message * Accepts: file name * elt containing date */void mx_setdate (char *file,MESSAGECACHE *elt){ time_t tp[2]; tp[0] = time (0); /* atime is now */ tp[1] = mail_longdate (elt); /* modification time */ utime (file,tp); /* set the times */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -