📄 nntp.c
字号:
{ void *sdb = NIL; char *s,mbx[MAILTMPLEN]; /* return data from newsrc */ if (nntp_canonicalize (ref,pat,mbx,NIL)) newsrc_lsub (stream,mbx); if (*pat == '{') { /* if remote pattern, must be NNTP */ if (!nntp_valid (pat)) return; ref = NIL; /* good NNTP pattern, punt reference */ } /* if remote reference, must be valid NNTP */ if (ref && (*ref == '{') && !nntp_valid (ref)) return; /* kludgy application of reference */ if (ref && *ref) sprintf (mbx,"%s%s",ref,pat); else strcpy (mbx,pat); if (s = sm_read (&sdb)) do if (nntp_valid (s) && pmatch (s,mbx)) mm_lsub (stream,NIL,s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */}/* NNTP canonicalize newsgroup name * Accepts: reference * pattern * returned single pattern * returned wildmat pattern * Returns: T on success, NIL on failure */long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat){ char *s; DRIVER *ret; if (ref && *ref) { /* have a reference */ if (!nntp_valid (ref)) return NIL; strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (strchr (pattern,'}') + 1,pat); /* pattern starts, reference ends, with . */ else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ if ((ret = wildmat ? /* if valid and wildmat */ nntp_isvalid (pattern,wildmat) : nntp_valid (pattern)) && wildmat) { /* don't return wildmat if specials present */ if (strpbrk (wildmat,",?![\\]")) wildmat[0] = '\0'; /* replace all % with * */ for (s = wildmat; s = strchr (s,'%'); *s = '*'); } return ret ? LONGT : NIL;}/* NNTP subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */long nntp_subscribe (MAILSTREAM *stream,char *mailbox){ char mbx[MAILTMPLEN]; return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,':') : NIL;}/* NNTP unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox){ char mbx[MAILTMPLEN]; return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,'!') : NIL;}/* NNTP create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */long nntp_create (MAILSTREAM *stream,char *mailbox){ return NIL; /* never valid for NNTP */}/* NNTP delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */long nntp_delete (MAILSTREAM *stream,char *mailbox){ return NIL; /* never valid for NNTP */}/* NNTP rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */long nntp_rename (MAILSTREAM *stream,char *old,char *newname){ return NIL; /* never valid for NNTP */}/* NNTP status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */long nntp_status (MAILSTREAM *stream,char *mbx,long flags){ MAILSTATUS status; NETMBX mb; unsigned long i,j,k,rnmsgs; long ret = NIL; char *s,*name,*state,tmp[MAILTMPLEN]; char *old = (stream && !stream->halfopen) ? LOCAL->name : NIL; MAILSTREAM *tstream = NIL; if (!(mail_valid_net_parse (mbx,&mb) && !strcmp (mb.service,"nntp") && *mb.mailbox && ((mb.mailbox[0] != '#') || ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') && (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') && (mb.mailbox[5] == '.'))))) { sprintf (tmp,"Invalid NNTP name %s",mbx); mm_log (tmp,ERROR); return NIL; } /* note mailbox name */ name = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox; /* stream to reuse? */ if (!(stream && LOCAL->nntpstream && mail_usable_network_stream (stream,mbx)) && !(tstream = stream = mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT| ((flags & SA_MULNEWSRC) ? OP_MULNEWSRC : NIL)))) return NIL; /* can't reuse or make a new one */ if (nntp_send (LOCAL->nntpstream,"GROUP",name) == NNTPGOK) { status.flags = flags; /* status validity flags */ k = strtoul (LOCAL->nntpstream->reply + 4,&s,10); i = strtoul (s,&s,10); /* first assigned UID */ /* next UID to be assigned */ status.uidnext = (j = strtoul (s,NIL,10)) + 1; /* maximum number of messages */ rnmsgs = status.messages = (i | j) ? status.uidnext - i : 0; if (k > status.messages) { /* check for absurdity */ sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu", k,status.messages); mm_log (tmp,WARN); } /* restrict article range if needed */ if (nntp_range && (status.messages > nntp_range)) { i = status.uidnext - (status.messages = nntp_range); if (k > nntp_range) k = nntp_range; } /* initially zero */ status.recent = status.unseen = 0; if (!status.messages); /* empty case */ /* use server guesstimate in simple case */ else if (!(flags & (SA_RECENT | SA_UNSEEN))) status.messages = k; /* have newsrc state? */ else if (state = newsrc_state (stream,name)) { /* yes, get the UID/sequence map */ if (nntp_getmap (stream,name,i,status.uidnext - 1,rnmsgs, status.messages,tmp)) { /* calculate true count */ for (status.messages = 0; (s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,"."); ) { /* only count if in range */ if (((k = atol (s)) >= i) && (k < status.uidnext)) { newsrc_check_uid (state,k,&status.recent,&status.unseen); status.messages++; } fs_give ((void **) &s); } 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 get map * Accepts: stream * newsgroup name * first UID in map range * last UID in map range * reported total number of messages in newsgroup * calculated number of messages in range * temporary buffer * Returns: T on success, NIL on failure */long nntp_getmap (MAILSTREAM *stream,char *name, unsigned long first,unsigned long last, unsigned long rnmsgs,unsigned long nmsgs,char *tmp){ short trylistgroup = NIL; if (rnmsgs > (nmsgs * 8)) /* small subrange? */ trylistgroup = T; /* yes, can try LISTGROUP if [X]HDR fails */ else switch ((int) nntp_send (LOCAL->nntpstream,"LISTGROUP",name)) { case NNTPGOK: /* got data */ return LONGT; default: /* else give up if server claims LISTGROUP */ if (EXTENSION.listgroup) return NIL; } /* build range */ sprintf (tmp,"%lu-%lu",first,last); if (EXTENSION.hdr) /* have HDR extension? */ return (nntp_send (LOCAL->nntpstream,"HDR Date",tmp) == NNTPHEAD) ? LONGT : NIL; if (LOCAL->xhdr) /* try the experimental extension then */ switch ((int) nntp_send (LOCAL->nntpstream,"XHDR Date",tmp)) { case NNTPHEAD: /* got an overview? */ return LONGT; case NNTPBADCMD: /* unknown command? */ LOCAL->xhdr = NIL; /* disable future XHDR attempts */ } if (trylistgroup && /* no [X]HDR, maybe do LISTGROUP after all */ (nntp_send (LOCAL->nntpstream,"LISTGROUP",name) == NNTPGOK)) return LONGT; return NIL;}/* NNTP open * Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *nntp_mopen (MAILSTREAM *stream){ unsigned long i,j,k,nmsgs,rnmsgs; char *s,*mbx,tmp[MAILTMPLEN]; FILE *f; 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 */ nstream = LOCAL->nntpstream;/* remember NNTP protocol stream */ sprintf (tmp,"Reusing connection to %s",net_host (nstream->netstream)); if (!stream->silent) mm_log (tmp,(long) NIL); if (stream->rdonly) mb.readonlyflag = T; if (LOCAL->tlsflag) mb.tlsflag = T; if (LOCAL->tlssslv23) mb.tlssslv23 = T; if (LOCAL->notlsflag) mb.notlsflag = T; if (LOCAL->sslflag) mb.sslflag = T; if (LOCAL->novalidate) mb.novalidate = T; if (LOCAL->nntpstream->loser) mb.loser = T; if (stream->secure) mb.secflag = T; LOCAL->nntpstream = NIL; /* keep nntp_mclose() from punting it */ nntp_mclose (stream,NIL); /* do close action */ stream->dtb = &nntpdriver; /* reattach this driver */ } /* copy flags */ if (mb.dbgflag) stream->debug = T; if (mb.readonlyflag) stream->rdonly = T; if (mb.secflag) stream->secure = T; mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL; 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.tlsflag) strcat (tmp,"/tls"); if (mb.tlssslv23) strcat (tmp,"/tls-sslv23"); if (mb.notlsflag) strcat (tmp,"/notls"); if (mb.sslflag) strcat (tmp,"/ssl"); if (mb.novalidate) strcat (tmp,"/novalidate-cert"); if (mb.loser) strcat (tmp,"/loser"); if (mb.secflag) strcat (tmp,"/secure"); if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=\"%s\"",mb.user); hostlist[1] = NIL; if (!(nstream = nntp_open (hostlist,NOP_READONLY | (stream->debug ? NOP_DEBUG : NIL)))) return NIL; } /* always zero messages if halfopen */ if (stream->halfopen) i = j = k = rnmsgs = 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); rnmsgs = nmsgs = (i | j) ? 1 + j - i : 0; if (k > nmsgs) { /* check for absurdity */ sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu", k,nmsgs); mm_log (tmp,WARN); } /* restrict article range if needed */ if (nntp_range && (nmsgs > nntp_range)) i = 1 + j - (nmsgs = nntp_range); } else { /* no such newsgroup */ mm_log (nstream->reply,ERROR); nntp_close (nstream); /* punt stream */ return NIL; } /* instantiate local data */ stream->local = memset (fs_get (sizeof (NNTPLOCAL)),0,sizeof (NNTPLOCAL)); LOCAL->nntpstream = nstream; /* save state for future recycling */ if (mb.tlsflag) LOCAL->tlsflag = T; if (mb.tlssslv23) LOCAL->tlssslv23 = T; if (mb.notlsflag) LOCAL->notlsflag = T; if (mb.sslflag) LOCAL->sslflag = T; if (mb.novalidate) LOCAL->novalidate = T; if (mb.loser) LOCAL->nntpstream->loser = T; /* assume present until proven otherwise */ LOCAL->xhdr = LOCAL->xover = T; LOCAL->name = cpystr (mbx); /* copy newsgroup name */ 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,(long) mail_parameters (NIL,GET_NEWSRCCANONHOST,NIL) ? net_host (nstream->netstream) : mb.host)); LOCAL->newsrc = cpystr (nq ? (*nq) (stream,tmp,newsrc) : tmp); } 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",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (nstream->netstream) : mb.host, net_port (nstream->netstream)); if (LOCAL->tlsflag) strcat (tmp,"/tls"); if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23"); if (LOCAL->notlsflag) strcat (tmp,"/notls"); if (LOCAL->sslflag) strcat (tmp,"/ssl"); if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert"); if (LOCAL->nntpstream->loser) strcat (tmp,"/loser"); if (stream->secure) strcat (tmp,"/secure"); if (stream->rdonly) strcat (tmp,"/readonly"); 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 (EXTENSION.over && /* get overview format if have OVER */ (nntp_send (LOCAL->nntpstream,"LIST","OVERVIEW.FMT") == NNTPGLIST) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -