📄 unix.c
字号:
/* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T;}/* UNIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */long unix_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) unix_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 if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); return NIL; } reparse = (sbuf.st_size != LOCAL->filesize); } /* parse if mailbox changed */ if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL); /* unlock mailbox */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* and stream */ MM_NOCRITICAL (stream); /* done with critical */ } } } return LOCAL ? LONGT : NIL; /* return if still alive */}/* UNIX mail check mailbox * Accepts: MAIL stream */void unix_check (MAILSTREAM *stream){ DOTLOCK lock; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,&lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) { if (!stream->silent) MM_LOG ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ }}/* UNIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */long unix_expunge (MAILSTREAM *stream,char *sequence,long options){ long ret; unsigned long i; DOTLOCK lock; char *msg = NIL; /* parse and lock mailbox */ if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,&lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ unix_unlock (LOCAL->fd,stream,&lock); msg = "No messages deleted, so no update needed"; } else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else unix_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); return ret;}/* UNIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */long unix_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); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; DRIVER *d; for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL); (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE)); d = d->next); /* see if mbox driver active */ if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) || unix_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); unix_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid UNIX-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 UNIX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; MM_CRITICAL (stream); /* go critical */ if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &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 = unix_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 = tstream ? /* write UIDPLUS data if have readwrite */ unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } 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 */ unix_unlock (fd,NIL,&lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL *local = (UNIXLOCAL *) 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;}/* UNIX 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 unix_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; if (!stream) { /* stream specified? */ stream = &unixproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!unix_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; } unix_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 UNIX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a UNIX-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 (!unix_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 */ /* close sniffing stream */ if (tstream != stream) tstream = mail_close (tstream); MM_CRITICAL (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -