📄 nntp.c
字号:
/* * Program: Network News Transfer Protocol (NNTP) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 February 1992 * Last Edited: 15 September 2000 * * Copyright 2000 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notices appear in all copies and that both the * above copyright notices and this permission notice appear in supporting * documentation, and that the name of the University of Washington not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. This software is made * available "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */#include <ctype.h>#include <stdio.h>#include "mail.h"#include "osdep.h"#include "nntp.h"#include "rfc822.h"#include "misc.h"#include "newsrc.h"#include "netmsg.h"#include "flstring.h"#include "utf8.h"/* Driver dispatch used by MAIL */DRIVER nntpdriver = { "nntp", /* driver name */#ifdef INADEQUATE_MEMORY DR_LOWMEM |#endif /* driver flags */ DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_CRLF|DR_RECYCLE, (DRIVER *) NIL, /* next driver */ nntp_valid, /* mailbox is valid for us */ nntp_parameters, /* manipulate parameters */ nntp_scan, /* scan mailboxes */ nntp_list, /* find mailboxes */ nntp_lsub, /* find subscribed mailboxes */ nntp_subscribe, /* subscribe to mailbox */ nntp_unsubscribe, /* unsubscribe from mailbox */ nntp_create, /* create mailbox */ nntp_delete, /* delete mailbox */ nntp_rename, /* rename mailbox */ nntp_status, /* status of mailbox */ nntp_mopen, /* open mailbox */ nntp_mclose, /* close mailbox */ nntp_fetchfast, /* fetch message "fast" attributes */ nntp_flags, /* fetch message flags */ nntp_overview, /* fetch overview */ NIL, /* fetch message structure */ nntp_header, /* fetch message header */ nntp_text, /* fetch message text */ NIL, /* fetch message */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ nntp_flagmsg, /* per-message modify flags */ nntp_search, /* search for message based on criteria */ nntp_sort, /* sort messages */ nntp_thread, /* thread messages */ nntp_ping, /* ping mailbox to see if still alive */ nntp_check, /* check for new messages */ nntp_expunge, /* expunge deleted messages */ nntp_copy, /* copy messages to another mailbox */ nntp_append, /* append string message to mailbox */ NIL /* garbage collect stream */}; /* prototype stream */MAILSTREAM nntpproto = {&nntpdriver}; /* driver parameters */static long nntp_maxlogintrials = MAXLOGINTRIALS;static long nntp_port = 0;static long nntp_altport = 0;static char *nntp_altname = NIL;/* NNTP validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */DRIVER *nntp_valid (char *name){ char tmp[MAILTMPLEN]; return nntp_isvalid (name,tmp);}/* NNTP validate mailbox work routine * Accepts: mailbox name * buffer for returned mailbox name * Returns: our driver if name is valid, NIL otherwise */DRIVER *nntp_isvalid (char *name,char *mbx){ NETMBX mb; if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,nntpdriver.name)|| mb.authuser[0] || mb.anoflag || mb.secflag) return NIL; if (mb.mailbox[0] != '#') strcpy (mbx,mb.mailbox); /* namespace format name */ else if ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') && (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') && (mb.mailbox[5] == '.')) strcpy (mbx,mb.mailbox+6); else return NIL; /* bogus name */ return &nntpdriver;}/* News manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *nntp_parameters (long function,void *value){ switch ((int) function) { case SET_MAXLOGINTRIALS: nntp_maxlogintrials = (unsigned long) value; break; case GET_MAXLOGINTRIALS: value = (void *) nntp_maxlogintrials; break; case SET_NNTPPORT: nntp_port = (long) value; break; case GET_NNTPPORT: value = (void *) nntp_port; break; case SET_ALTNNTPPORT: nntp_altport = (long) value; break; case GET_ALTNNTPPORT: value = (void *) nntp_altport; break; case SET_ALTNNTPNAME: nntp_altname = (char *) value; break; case GET_ALTNNTPNAME: value = (void *) nntp_altname; break; case SET_NEWSRC: fatal ("SET_NEWSRC not permitted"); case GET_NEWSRC: if (value) value = (void *) ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->newsrc; break; default: value = NIL; /* error case */ break; } return value;}/* NNTP mail scan mailboxes for string * Accepts: mail stream * reference * pattern to search * string to scan */void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents){ char tmp[MAILTMPLEN]; if (nntp_canonicalize (ref,pat,tmp)) mm_log ("Scan not valid for NNTP mailboxes",ERROR);}/* NNTP list newsgroups * Accepts: mail stream * reference * pattern to search */void nntp_list (MAILSTREAM *stream,char *ref,char *pat){ MAILSTREAM *st = stream; char *s,*t,*lcl,pattern[MAILTMPLEN],name[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; if (!pat || !*pat) { if (nntp_canonicalize (ref,"*",pattern)) { /* tie off name at root */ if ((s = strchr (pattern,'}')) && (s = strchr (s+1,'.'))) *++s = '\0'; else pattern[0] = '\0'; mm_list (stream,'.',pattern,NIL); } } /* ask server for open newsgroups */ else if (nntp_canonicalize (ref,pat,pattern) && ((stream && LOCAL && LOCAL->nntpstream) || (stream = mail_open (NIL,pattern,OP_HALFOPEN))) && ((nntp_send (LOCAL->nntpstream,"LIST","ACTIVE") == NNTPGLIST) || (nntp_send (LOCAL->nntpstream,"LIST",NIL) == NNTPGLIST))) { /* namespace format name? */ if (*(lcl = strchr (strcpy (name,pattern),'}') + 1) == '#') lcl += 6; /* process data until we see final dot */ while (s = net_getline (LOCAL->nntpstream->netstream)) { if ((*s == '.') && !s[1]){/* end of text */ fs_give ((void **) &s); break; } if (t = strchr (s,' ')) { /* tie off after newsgroup name */ *t = '\0'; strcpy (lcl,s); /* make full form of name */ /* report if match */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL); else while (showuppers && (t = strrchr (lcl,'.'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,LATT_NOSELECT); } } fs_give ((void **) &s); /* clean up */ } if (stream != st) mail_close (stream); }}/* NNTP list subscribed newsgroups * Accepts: mail stream * reference * pattern to search */void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat){ void *sdb = NIL; char *s,mbx[MAILTMPLEN]; /* return data from newsrc */ if (nntp_canonicalize (ref,pat,mbx)) 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 * Returns: T on success, NIL on failure */long nntp_canonicalize (char *ref,char *pat,char *pattern){ 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 */ return nntp_valid (pattern) ? T : 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; 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) && *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))) return NIL; /* can't reuse or make a new one */ if (nntp_send (LOCAL->nntpstream,"GROUP",name) == NNTPGOK) { status.flags = flags; /* status validity flags */ status.messages = strtoul (LOCAL->nntpstream->reply + 4,&s,10); i = strtoul (s,&s,10); status.uidnext = strtoul (s,NIL,10) + 1; /* initially empty */ status.recent = status.unseen = 0; /* don't bother if empty or don't want this */ if (status.messages && (flags & (SA_RECENT | SA_UNSEEN))) { if (state = newsrc_state (stream,name)) { /* in case have to do XHDR Date */ sprintf (tmp,"%lu-%lu",i,status.uidnext - 1); /* only bother if there appear to be holes */ if ((status.messages < (status.uidnext - i)) && ((nntp_send (LOCAL->nntpstream,"LISTGROUP",name) == NNTPGOK) || (nntp_send (LOCAL->nntpstream,"XHDR Date",tmp) == NNTPHEAD))) { while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")) { newsrc_check_uid (state,strtoul (s,NIL,10),&status.recent, &status.unseen); fs_give ((void **) &s); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -