📄 nntp.c
字号:
(f = netmsg_slurp (LOCAL->nntpstream->netstream,&k,NIL))) { fread (LOCAL->over_fmt = (char *) fs_get ((size_t) k + 3), (size_t) 1,(size_t) k,f); LOCAL->over_fmt[k] = '\0'; fclose (f); /* flush temp file */ } if (nmsgs) { /* if any messages exist */ short silent = stream->silent; stream->silent = T; /* don't notify main program yet */ mail_exists (stream,nmsgs); /* silently set the cache to the guesstimate */ /* get UID/sequence map, nuke holes */ if (nntp_getmap (stream,mbx,i,j,rnmsgs,nmsgs,tmp)) { for (nmsgs = 0; /* calculate true count */ (s = net_getline (nstream->netstream)) && strcmp (s,"."); ) { if ((k = atol (s)) > j){/* discard too high article numbers */ sprintf (tmp,"NNTP SERVER BUG (out of range article ID): %lu > %lu", k,j); mm_notify (stream,tmp,NIL); stream->unhealthy = T; } else if (k >= i) { /* silently ignore too-low article numbers */ /* guard against server returning extra msgs */ if (nmsgs == stream->nmsgs) mail_exists (stream,nmsgs+1); /* create elt for this message, set UID */ mail_elt (stream,++nmsgs)->private.uid = k; } fs_give ((void **) &s); } if (s) fs_give ((void **) &s); } /* assume c-client/NNTP map is entire range */ else for (k = 1; k <= nmsgs; k++) mail_elt (stream,k)->private.uid = i++; stream->unhealthy = NIL; /* set healthy */ stream->nmsgs = 0; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ mail_exists (stream,nmsgs); /* notify upper level that messages exist */ /* read .newsrc entries */ mail_recent (stream,newsrc_read (mbx,stream)); } else { /* empty newsgroup or halfopen */ if (!(stream->silent || stream->halfopen)) { sprintf (tmp,"Newsgroup %s is empty",mbx); mm_log (tmp,WARN); } mail_exists (stream,(long) 0); mail_recent (stream,(long) 0); } return stream; /* return stream to caller */}/* NNTP close * Accepts: MAIL stream * option flags */void nntp_mclose (MAILSTREAM *stream,long options){ unsigned long i; MESSAGECACHE *elt; if (LOCAL) { /* only if a file is open */ nntp_check (stream); /* dump final checkpoint */ if (LOCAL->over_fmt) fs_give ((void **) &LOCAL->over_fmt); if (LOCAL->name) fs_give ((void **) &LOCAL->name); if (LOCAL->user) fs_give ((void **) &LOCAL->user); if (LOCAL->newsrc) fs_give ((void **) &LOCAL->newsrc); if (LOCAL->txt) fclose (LOCAL->txt); /* close NNTP connection */ if (LOCAL->nntpstream) nntp_close (LOCAL->nntpstream); for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->private.spare.ptr) fs_give ((void **) &elt->private.spare.ptr); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ }}/* NNTP fetch fast information * Accepts: MAIL stream * sequence * option flags * This is ugly and slow */void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags){ unsigned long i; MESSAGECACHE *elt; /* get sequence */ 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->valid = T) && !(elt->day && elt->rfc822_size)) { ENVELOPE **env = NIL; ENVELOPE *e = NIL; if (!stream->scache) env = &elt->private.msg.env; else if (stream->msgno == i) env = &stream->env; else env = &e; if (!*env || !elt->rfc822_size) { STRING bs; unsigned long hs; char *ht = (*stream->dtb->header) (stream,i,&hs,NIL); /* need to make an envelope? */ if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST, stream->dtb->flags); /* need message size too, ugh */ if (!elt->rfc822_size) { (*stream->dtb->text) (stream,i,&bs,FT_PEEK); elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs); } } /* if need date, have date in envelope? */ if (!elt->day && *env && (*env)->date) mail_parse_date (elt,(*env)->date); /* sigh, fill in bogus default */ if (!elt->day) elt->day = elt->month = 1; mail_free_envelope (&e); } }}/* NNTP fetch flags * Accepts: MAIL stream * sequence * option flags */void nntp_flags (MAILSTREAM *stream,char *sequence,long flags){ unsigned long i; if ((flags & FT_UID) ? /* validate all elts */ mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;}/* NNTP fetch overview * Accepts: MAIL stream, sequence bits set * overview return function * Returns: T if successful, NIL otherwise */long nntp_overview (MAILSTREAM *stream,overview_t ofn){ unsigned long i,j,k,uid; char c,*s,*t,*v,tmp[MAILTMPLEN]; MESSAGECACHE *elt; OVERVIEW ov; if (!LOCAL->nntpstream->netstream) return NIL; /* scan sequence to load cache */ for (i = 1; i <= stream->nmsgs; i++) /* have cached overview yet? */ if ((elt = mail_elt (stream,i))->sequence && !elt->private.spare.ptr) { for (j = i + 1; /* no, find end of cache gap range */ (j <= stream->nmsgs) && (elt = mail_elt (stream,j))->sequence && !elt->private.spare.ptr; j++); /* make NNTP range */ sprintf (tmp,(i == (j - 1)) ? "%lu" : "%lu-%lu",mail_uid (stream,i), mail_uid (stream,j - 1)); i = j; /* advance beyond gap */ /* ask server for overview data to cache */ if (nntp_over (stream,tmp)) { while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")) { /* death to embedded newlines */ for (t = v = s; c = *v++;) if ((c != '\012') && (c != '\015')) *t++ = c; *t++ = '\0'; /* tie off string in case it was shortened */ /* cache the overview if found its sequence */ if ((uid = atol (s)) && (k = mail_msgno (stream,uid)) && (t = strchr (s,'\t'))) { if ((elt = mail_elt (stream,k))->private.spare.ptr) fs_give ((void **) &elt->private.spare.ptr); elt->private.spare.ptr = cpystr (t + 1); } else { /* shouldn't happen, snarl if it does */ sprintf (tmp,"Server returned data for unknown UID %lu",uid); mm_notify (stream,tmp,WARN); stream->unhealthy = T; } /* flush the overview */ fs_give ((void **) &s); } stream->unhealthy = NIL;/* set healthy */ /* flush the terminating dot */ if (s) fs_give ((void **) &s); } else i = stream->nmsgs; /* OVER failed, punt cache load */ } /* now scan sequence to return overviews */ if (ofn) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { uid = mail_uid (stream,i);/* UID for this message */ /* parse cached overview */ if (nntp_parse_overview (&ov,s = (char *) elt->private.spare.ptr,elt)) (*ofn) (stream,uid,&ov,i); else { /* parse failed */ (*ofn) (stream,uid,NIL,i); if (s && *s) { /* unusable cached entry? */ sprintf (tmp,"Unable to parse overview for UID %lu: %.500s",uid,s); mm_notify (stream,tmp,WARN); stream->unhealthy = T; /* erase it from the cache */ fs_give ((void **) &s); } stream->unhealthy = NIL;/* set healthy */ /* insert empty cached text as necessary */ if (!s) elt->private.spare.ptr = cpystr (""); } /* clean up overview data */ if (ov.from) mail_free_address (&ov.from); if (ov.subject) fs_give ((void **) &ov.subject); } return T;}/* Send OVER to NNTP server * Accepts: mail stream * sequence to send * Returns: T if success and overviews will follow, else NIL */long nntp_over (MAILSTREAM *stream,char *sequence){ unsigned char *s; /* test for Netscape Collabra server */ if (EXTENSION.over && LOCAL->xover && nntp_send (LOCAL->nntpstream,"OVER","0") == NNTPOVER) { /* "Netscape-Collabra/3.52 03615 NNTP" responds to the OVER command with * a bogus "Subject:From:Date:Bytes:Lines" response followed by overviews * which lack the Message-ID and References:. This violates the draft * NNTP specification (draft-ietf-nntpext-base-18.txt as of this writing). * XOVER works fine. */ while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){ if (!isdigit (*s)) { /* is it that fetid piece of reptile dung? */ EXTENSION.over = NIL; /* sure smells like it */ mm_log ("Working around Netscape Collabra bug",WARN); } fs_give ((void **) &s); /* flush the overview */ } if (s) fs_give ((void **) &s); /* don't do this test again */ if (EXTENSION.over) LOCAL->xover = NIL; } if (EXTENSION.over) /* have OVER extension? */ return (nntp_send (LOCAL->nntpstream,"OVER",sequence) == NNTPOVER) ? LONGT : NIL; if (LOCAL->xover) /* try the experiment extension then */ switch ((int) nntp_send (LOCAL->nntpstream,"XOVER",sequence)) { case NNTPOVER: /* got an overview? */ return LONGT; case NNTPBADCMD: /* unknown command? */ LOCAL->xover = NIL; /* disable future XOVER attempts */ } return NIL;}/* Parse OVERVIEW struct from cached NNTP OVER response * Accepts: struct to load * cached OVER response * internaldate * Returns: T if success, NIL if fail */long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt){ char *t; /* nothing in overview yet */ memset ((void *) ov,0,sizeof (OVERVIEW)); /* no cached data */ if (!(text && *text)) return NIL; ov->subject = cpystr (text); /* make hackable copy of overview */ /* find end of Subject */ if (t = strchr (ov->subject,'\t')) { *t++ = '\0'; /* tie off Subject, point to From */ /* find end of From */ if (ov->date = strchr (t,'\t')) { *ov->date++ = '\0'; /* tie off From, point to Date */ /* load internaldate too */ if (!elt->day) mail_parse_date (elt,ov->date); /* parse From */ rfc822_parse_adrlist (&ov->from,t,BADHOST); /* find end of Date */ if (ov->message_id = strchr (ov->date,'\t')) { /* tie off Date, point to Message-ID */ *ov->message_id++ = '\0'; /* find end of Message-ID */ if (ov->references = strchr (ov->message_id,'\t')) { /* tie off Message-ID, point to References */ *ov->references++ = '\0'; /* fine end of References */ if (t = strchr (ov->references,'\t')) { *t++ = '\0'; /* tie off References, point to octet size */ /* parse size of message in octets */ ov->optional.octets = atol (t); /* find end of size */ if (t = strchr (t,'\t')) { /* parse size of message in lines */ ov->optional.lines = atol (++t); /* find Xref */ if (ov->optional.xref = strchr (t,'\t')) *ov->optional.xref++ = '\0'; } } } } } } return ov->references ? T : NIL;}/* NNTP fetch header as text * Accepts: mail stream * message number * pointer to return size * flags * Returns: header text */char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size, long flags){ char tmp[MAILTMPLEN]; MESSAGECACHE *elt; FILE *f; *size = 0; if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return ""; /* have header text? */ if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) { sprintf (tmp,"%lu",mail_uid (stream,msgno)); /* get header text */ switch (nntp_send (LOCAL->nntpstream,"HEAD",tmp)) { case NNTPHEAD: if (f = netmsg_slurp (LOCAL->nntpstream->netstream,size,NIL)) { fread (elt->private.msg.header.text.data = (unsigned char *) fs_get ((size_t) *size + 3), (size_t) 1,(size_t) *size,f); fclose (f); /* flush temp file */ /* tie off header with extra CRLF and NUL */ elt->private.msg.header.text.data[*size] = '\015'; elt->private.msg.header.text.data[++*size] = '\012'; elt->private.msg.header.text.data[++*size] = '\0'; elt->private.msg.header.text.size = *size; elt->valid = T; /* make elt valid now */ break; } /* fall into default case */ default: /* failed, mark as deleted and empty */ elt->valid = elt->deleted = T; case NNTPSOFTFATAL: /* don't mark deleted if stream dead */ *size = elt->private.msg.header.text.size = 0; break; } } /* just return size of text */ else *size = elt->private.msg.header.text.size; return elt->private.msg.header.text.data ? (char *) elt->private.msg.header.text.data : "";}/* NNTP fetch body * Accepts: mail stream * message number * pointer to stringstruct to initialize * flags * Returns: T if successful, else NIL */long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags){ char tmp[MAILTMPLEN]; MESSAGECACHE *elt; INIT (bs,mail_string,(void *) "",0); if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL; elt = mail_elt (stream,msgno); /* different message, flush cache */ if (LOCAL->txt && (LOCAL->msgno != msgno)) { fclose (LOCAL->txt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -