📄 mh.c
字号:
cp = curdir + strlen (curdir);/* end of directory name */ np = name + strlen (name); /* end of MH name */ if (dp = opendir (curdir)) { /* open directory */ while (d = readdir (dp)) /* scan, ignore . and numeric names */ if ((d->d_name[0] != '.') && !mh_select (d)) { strcpy (cp,d->d_name); /* make directory name */ if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { strcpy (np,d->d_name);/* make mh name of directory name */ /* yes, an MH name if full match */ if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL); /* check if should recurse */ if (dmatch (name,pat,'/') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) mh_list_work (stream,name+4,pat,level+1); } } closedir (dp); /* all done, flush directory */ }}/* MH mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */long mh_subscribe (MAILSTREAM *stream,char *mailbox){ return sm_subscribe (mailbox);}/* MH mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */long mh_unsubscribe (MAILSTREAM *stream,char *mailbox){ return sm_unsubscribe (mailbox);}/* MH mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */long mh_create (MAILSTREAM *stream,char *mailbox){ char tmp[MAILTMPLEN]; if (!mh_namevalid (mailbox)) /* validate name */ sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox); /* must not already exist */ else if (mh_isvalid (mailbox,tmp,NIL)) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); else if (!mh_path (tmp)) return NIL; /* try to make it */ else if (!(mh_file (tmp,mailbox) && dummy_create_path (stream,strcat (tmp,"/"), get_dir_protection (mailbox)))) sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno)); else return LONGT; /* success */ mm_log (tmp,ERROR); return NIL;}/* MH mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */long mh_delete (MAILSTREAM *stream,char *mailbox){ DIR *dirp; struct direct *d; int i; char tmp[MAILTMPLEN]; /* is mailbox valid? */ if (!mh_isvalid (mailbox,tmp,NIL)) { sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); mm_log (tmp,ERROR); return NIL; } /* get name of directory */ i = strlen (mh_file (tmp,mailbox)); if (dirp = opendir (tmp)) { /* open directory */ tmp[i++] = '/'; /* now apply trailing delimiter */ /* massacre all mh owned files */ while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) { strcpy (tmp + i,d->d_name); unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ } /* try to remove the directory */ if (rmdir (mh_file (tmp,mailbox))) { sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno)); mm_log (tmp,WARN); } return T; /* return success */}/* MH mail rename mailbox * Accepts: MH mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */long mh_rename (MAILSTREAM *stream,char *old,char *newname){ char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; /* old mailbox name must be valid */ if (!mh_isvalid (old,tmp,NIL)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (!mh_namevalid (newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name", newname); /* new mailbox name must not be valid */ else if (mh_isvalid (newname,tmp,NIL)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); /* success if can rename the directory */ else { /* found superior to destination name? */ if (s = strrchr (mh_file (tmp1,newname),'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (mh_file (tmp,old),tmp1)) return T; sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s", old,newname,strerror (errno)); } mm_log (tmp,ERROR); /* something failed */ return NIL;}/* MH mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *mh_open (MAILSTREAM *stream){ char tmp[MAILTMPLEN]; if (!stream) return &mhproto; /* return prototype for OP_PROTOTYPE call */ if (stream->local) fatal ("mh recycle stream"); stream->local = fs_get (sizeof (MHLOCAL)); /* INBOXness is one of the following: * #mhinbox (case-independent) * #mh/inbox (mh is case-independent, inbox is case-dependent) * INBOX (case-independent */ stream->inbox = /* note if an INBOX or not */ (!compare_cstring (stream->mailbox,MHINBOX) || ((stream->mailbox[0] == '#') && ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) && ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) && (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) || !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL; mh_file (tmp,stream->mailbox);/* get directory name */ LOCAL->dir = cpystr (tmp); /* copy directory name for later */ LOCAL->scantime = 0; /* not scanned yet */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (!mh_ping (stream)) return NIL; if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",(long) NIL); return stream; /* return stream to caller */}/* MH mail close * Accepts: MAIL stream * close options */void mh_close (MAILSTREAM *stream,long options){ if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL); if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ stream->silent = silent; /* reset silent state */ }}/* MH mail fetch fast information * Accepts: MAIL stream * sequence * option flags */void mh_fast (MAILSTREAM *stream,char *sequence,long flags){ MESSAGECACHE *elt; unsigned long i; /* set up metadata for all messages */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL);}/* MH load message into cache * Accepts: MAIL stream * message # * option flags */void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags){ unsigned long i,j,nlseen; int fd; unsigned char c,*t; struct stat sbuf; MESSAGECACHE *elt; FDDATA d; STRING bs; elt = mail_elt (stream,msgno);/* get elt */ /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); /* anything we need not currently cached? */ if ((!elt->day || !elt->rfc822_size || ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) && ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file metadata */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&bs,fd_string,&d,sbuf.st_size); if (!elt->day) { /* set internaldate to file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } if (!elt->rfc822_size) { /* know message size yet? */ for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) { case '\015': /* unlikely carriage return */ if (!j || (CHR (&bs) != '\012')) { i++; /* ugh, raw CR */ nlseen = NIL; break; } SNX (&bs); /* eat the line feed, drop in */ --j; case '\012': /* line feed? */ i += 2; /* count a CRLF */ /* header size known yet? */ if (!elt->private.msg.header.text.size && nlseen) { /* note position in file */ elt->private.special.text.size = GETPOS (&bs); /* and CRLF-adjusted size */ elt->private.msg.header.text.size = i; } nlseen = T; /* note newline seen */ break; default: /* ordinary chararacter */ i++; nlseen = NIL; break; } SETPOS (&bs,0); /* restore old position */ elt->rfc822_size = i; /* note that we have size now */ /* header is entire message if no delimiter */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* text is remainder of message */ elt->private.msg.text.text.size = elt->rfc822_size - elt->private.msg.header.text.size; } /* need to load cache with message data? */ if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { /* just can't keep that much */ mail_gc (stream,GC_TEXTS); LOCAL->cachedtexts = 0; } if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) { t = elt->private.msg.header.text.data = (unsigned char *) fs_get (elt->private.msg.header.text.size + 1); LOCAL->cachedtexts += elt->private.msg.header.text.size; /* read in message header */ for (i = 0; i < elt->private.msg.header.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) { *t++ = SNX (&bs); i++; } break; case '\012': /* line feed? */ *t++ = '\015'; i++; default: *t++ = c; break; } *t = '\0'; /* tie off string */ if ((t - elt->private.msg.header.text.data) != elt->private.msg.header.text.size) fatal ("mh hdr size mismatch"); } if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) { t = elt->private.msg.text.text.data = (unsigned char *) fs_get (elt->private.msg.text.text.size + 1); SETPOS (&bs,elt->private.special.text.size); LOCAL->cachedtexts += elt->private.msg.text.text.size; /* read in message text */ for (i = 0; i < elt->private.msg.text.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) { *t++ = SNX (&bs); i++; } break; case '\012': /* line feed? */ *t++ = '\015'; i++; default: *t++ = c; break; } *t = '\0'; /* tie off string */ if ((t - elt->private.msg.text.text.data) != elt->private.msg.text.text.size) fatal ("mh txt size mismatch"); } } close (fd); /* flush message file */ }}/* MH mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags){ MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) mh_load_message (stream,msgno,MLM_HEADER); *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data;}/* MH mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get elt */ /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { mh_load_message (stream,msgno,MLM_TEXT); if (!elt->private.msg.text.text.data) return NIL; } if (!(flags & FT_PEEK)) { /* mark as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T;}/* MH mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */long mh_ping (MAILSTREAM *stream){ MAILSTREAM *sysibx = NIL; MESSAGECACHE *elt,*selt; struct stat sbuf; char *s,tmp[MAILTMPLEN]; int fd; unsigned long i,j,r; unsigned long old = stream->uid_last; long nmsgs = stream->nmsgs; long recent = stream->recent; int silent = stream->silent; if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */ if (stream->inbox && /* no, create if INBOX */ dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -