📄 nntp.c
字号:
if (s) fs_give ((void **) &s); } /* assume c-client/NNTP map is entire range */ else while (i < status.uidnext) newsrc_check_uid (state,i++,&status.recent,&status.unseen); fs_give ((void **) &state); } /* no .newsrc state, all messages new */ else status.recent = status.unseen = status.messages; } /* UID validity is a constant */ status.uidvalidity = stream->uid_validity; /* pass status to main program */ mm_status (stream,mbx,&status); ret = T; /* succes */ } /* flush temporary stream */ if (tstream) mail_close (tstream); /* else reopen old newsgroup */ else if (old && nntp_send (LOCAL->nntpstream,"GROUP",old) != NNTPGOK) { mm_log (LOCAL->nntpstream->reply,ERROR); stream->halfopen = T; /* go halfopen */ } return ret; /* success */}/* NNTP open * Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *nntp_mopen (MAILSTREAM *stream){ unsigned long i,j,k,nmsgs; char *s,*mbx,tmp[MAILTMPLEN]; NETMBX mb; char *newsrc = (char *) mail_parameters (NIL,GET_NEWSRC,NIL); newsrcquery_t nq = (newsrcquery_t) mail_parameters (NIL,GET_NEWSRCQUERY,NIL); SENDSTREAM *nstream = NIL; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &nntpproto; mail_valid_net_parse (stream->mailbox,&mb); /* note mailbox anme */ mbx = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox; if (LOCAL) { /* recycle stream */ sprintf (tmp,"Reusing connection to %s",LOCAL->host); if (!stream->silent) mm_log (tmp,(long) NIL); nstream = LOCAL->nntpstream; LOCAL->nntpstream = NIL; /* keep nntp_mclose() from punting it */ nntp_mclose (stream,NIL); /* do close action */ stream->dtb = &nntpdriver; /* reattach this driver */ } /* in case /debug switch given */ if (mb.dbgflag) stream->debug = T; mb.tryaltflag = stream->tryalt; if (!nstream) { /* open NNTP now if not already open */ char *hostlist[2]; hostlist[0] = strcpy (tmp,mb.host); if (mb.port || nntp_port) sprintf (tmp + strlen (tmp),":%lu",mb.port ? mb.port : nntp_port); if (mb.altflag) sprintf (tmp + strlen (tmp),"/%s",(char *) mail_parameters (NIL,GET_ALTDRIVERNAME,NIL)); if (mb.altopt) sprintf (tmp + strlen (tmp),"/%s",(char *) mail_parameters (NIL,GET_ALTOPTIONNAME,NIL)); if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=\"%s\"",mb.user); hostlist[1] = NIL; nstream = nntp_open (hostlist,OP_READONLY+(stream->debug ? OP_DEBUG:NIL)); } if (!nstream) return NIL; /* didn't get an NNTP session */ /* always zero messages if halfopen */ if (stream->halfopen) i = j = k = nmsgs = 0; /* otherwise open the newsgroup */ else if (nntp_send (nstream,"GROUP",mbx) == NNTPGOK) { k = strtoul (nstream->reply + 4,&s,10); i = strtoul (s,&s,10); stream->uid_last = j = strtoul (s,&s,10); nmsgs = (i | j) ? 1 + j - i : 0; } else { /* no such newsgroup */ mm_log (nstream->reply,ERROR); nntp_close (nstream); /* punt stream */ return NIL; } /* newsgroup open, instantiate local data */ stream->local = memset (fs_get (sizeof (NNTPLOCAL)),0,sizeof (NNTPLOCAL)); LOCAL->nntpstream = nstream; LOCAL->name = cpystr (mbx); /* copy newsgroup name */ /* copy host name */ LOCAL->host = cpystr (net_host (nstream->netstream)); if (stream->mulnewsrc) { /* want to use multiple .newsrc files? */ strcpy (tmp,newsrc); s = tmp + strlen (tmp); /* end of string */ *s++ = '-'; /* hyphen delimiter and host */ lcase (strcpy (s,LOCAL->host)); LOCAL->newsrc = cpystr (nq ? (*nq) (stream,tmp,newsrc) : newsrc); } else LOCAL->newsrc = cpystr (newsrc); if (mb.user[0]) LOCAL->user = cpystr (mb.user); stream->sequence++; /* bump sequence number */ stream->rdonly = stream->perm_deleted = T; /* UIDs are always valid */ stream->uid_validity = 0xbeefface; sprintf (tmp,"{%s:%lu/nntp",LOCAL->host,net_port (nstream->netstream)); if (mb.altflag) sprintf (tmp + strlen (tmp),"/%s",(char *) mail_parameters (NIL,GET_ALTDRIVERNAME,NIL)); if (mb.altopt) sprintf (tmp + strlen (tmp),"/%s",(char *) mail_parameters (NIL,GET_ALTOPTIONNAME,NIL)); if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",LOCAL->user); if (stream->halfopen) strcat (tmp,"}<no_mailbox>"); else sprintf (tmp + strlen (tmp),"}#news.%s",mbx); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); 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 */ sprintf (tmp,"%lu-%lu",i,j);/* in case have to do XHDR Date */ if ((k < nmsgs) && /* only bother if there appear to be holes */ ((nntp_send (nstream,"LISTGROUP",mbx) == NNTPGOK) || (nntp_send (nstream,"XHDR Date",tmp) == NNTPHEAD))) { nmsgs = 0; /* have holes, calculate true count */ while ((s = net_getline (nstream->netstream)) && strcmp (s,".")) { mail_elt (stream,++nmsgs)->private.uid = atol (s); 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->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->name) fs_give ((void **) &LOCAL->name); if (LOCAL->host) fs_give ((void **) &LOCAL->host); 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.data) fs_give ((void **) &elt->private.data); /* 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->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 * UID sequence (may be NIL for nntp_search() call) * overview return function * Returns: T if successful, NIL otherwise */long nntp_overview (MAILSTREAM *stream,char *sequence,overview_t ofn){ unsigned long i,j,k,uid; char c,*s,*t,*v,tmp[MAILTMPLEN]; MESSAGECACHE *elt; OVERVIEW ov; /* parse the sequence */ if (!sequence || mail_uid_sequence (stream,sequence)) { /* 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.data) { for (j = i + 1; /* no, find end of cache gap range */ (j <= stream->nmsgs) && (elt = mail_elt (stream,j))->sequence && !elt->private.data; 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_send (LOCAL->nntpstream,"XOVER",tmp) == NNTPOVER) { 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.data) fs_give ((void **) &elt->private.data); elt->private.data = (unsigned long) cpystr (t + 1); } else { /* shouldn't happen, snarl if it does */ sprintf (tmp,"Server returned data for unknown UID %lu",uid); mm_log (tmp,WARN); } /* flush the overview */ fs_give ((void **) &s); } /* flush the terminating dot */ if (s) fs_give ((void **) &s); } else i = stream->nmsgs; /* XOVER 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 for this message */ uid = mail_uid (stream,i); /* parse cached overview */ if (nntp_parse_overview (&ov,s = (char *) elt->private.data)) (*ofn) (stream,uid,&ov); else { /* parse failed */ (*ofn) (stream,uid,NIL); if (s && *s) { /* unusable cached entry? */ sprintf (tmp,"Unable to parse overview for UID %lu: %.500s",uid,s); mm_log (tmp,WARN); /* erase it from the cache */ fs_give ((void **) &s); } /* insert empty cached text as necessary */ if (!s) elt->private.data = (unsigned long) cpystr (""); } /* clean up overview data */ if (ov.from) mail_free_address (&ov.from); if (ov.subject) fs_give ((void **) &ov.subject); } } return T;}/* Parse OVERVIEW struct from cached NNTP XOVER response * Accepts: struct to load * cached XOVER response * Returns: T if success, NIL if fail */long nntp_parse_overview (OVERVIEW *ov,char *text){ 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 */ /* 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; 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 */ if ((nntp_send (LOCAL->nntpstream,"HEAD",tmp) == NNTPHEAD) && (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 */ } else { /* failed, mark as deleted and empty */ elt->valid = elt->deleted = T; *size = elt->private.msg.header.text.size = 0; } } /* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -