📄 nntpstore.java
字号:
/* * NNTPStore.java * Copyright (C) 1999 dog <dog@dog.net.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * You may retrieve the latest version of this library from * http://www.dog.net.uk/knife/ */package dog.mail.nntp;import java.io.*;import java.net.*;import java.util.*;import javax.mail.*;import javax.mail.event.*;import javax.mail.internet.*;import dog.mail.util.*;import dog.util.*;/** * The storage class implementing the NNTP Usenet news protocol. * * @author dog@dog.net.uk * @version 1.2 */public class NNTPStore extends Store implements StatusSource { /** * The default NNTP port. */ public static final int DEFAULT_PORT = 119; static int fetchsize = 1024; Socket socket; CRLFInputStream in; CRLFOutputStream out; String hostname; String response; static final int HELP = 100; static final int READY = 200; static final int READ_ONLY = 201; static final int STREAMING_OK = 203; static final int CLOSING = 205; static final int GROUP_SELECTED = 211; // or list of article numbers follows static final int LISTING = 215; // list of newsgroups follows static final int ARTICLE_RETRIEVED_BOTH = 220; static final int ARTICLE_RETRIEVED_HEAD = 221; // or header follows static final int ARTICLE_RETRIEVED_BODY = 222; static final int ARTICLE_RETRIEVED = 223; static final int LISTING_OVERVIEW = 224; static final int LISTING_ARTICLES = 230; // list of new articles by message-id follows static final int LISTING_NEW = 231; // list of new newsgroups follows static final int ARTICLE_POSTED = 240; // article posted ok static final int AUTHINFO_OK = 281; static final int SEND_ARTICLE = 340; // send article to be posted. End with <CR-LF>.<CR-LF> static final int SEND_AUTHINFOPASS = 381; // send password (response to user name) static final int SERVICE_DISCONTINUED = 400; static final int NO_SUCH_GROUP = 411; static final int NO_GROUP_SELECTED = 412; // no newsgroup has been selected static final int NO_ARTICLE_SELECTED = 420; // no current article has been selected static final int NO_SUCH_ARTICLE_IN_GROUP = 423; // no such article number in this group static final int NO_SUCH_ARTICLE = 430; // no such article found static final int POSTING_NOT_ALLOWED = 440; // posting not allowed static final int POSTING_FAILED = 441; // posting failed static final int COMMAND_NOT_RECOGNIZED = 500; static final int COMMAND_SYNTAX_ERROR = 501; static final int PERMISSION_DENIED = 502; static final int SERVER_ERROR = 503; boolean postingAllowed = false; Root root; Newsgroup current; Date lastNewGroup; Hashtable newsgroups = new Hashtable(); // hashtable of newsgroups by name Hashtable articles = new Hashtable(); // hashtable of articles by message-id Vector statusListeners = new Vector(); /** * Constructor. */ public NNTPStore(Session session, URLName urlname) { super(session, urlname); String ccs = session.getProperty("mail.nntp.fetchsize"); if (ccs!=null) try { fetchsize = Math.max(Integer.parseInt(ccs), 1024); } catch (NumberFormatException e) {} } /** * Connects to the NNTP server and authenticates with the specified parameters. */ protected boolean protocolConnect(String host, int port, String username, String password) throws MessagingException { if (port<0) port = DEFAULT_PORT; if (host==null) return false; try { boolean debug = session.getDebug(); hostname = host; if (debug) System.err.println("DEBUG: nntp: opening connection to "+hostname); socket = new Socket(host, port); in = new CRLFInputStream(new BufferedInputStream(socket.getInputStream()), fetchsize); out = new CRLFOutputStream(new BufferedOutputStream(socket.getOutputStream())); switch (getResponse()) { case READY: postingAllowed = true; case READ_ONLY: //StringTokenizer st = new StringTokenizer(response); //if (st.hasMoreTokens()) hostname = st.nextToken(); break; default: throw new MessagingException("unexpected server response: "+response); } send("MODE READER"); // newsreader extension switch (getResponse()) { case READY: postingAllowed = true; case READ_ONLY: break; } // NNTP basic authentication // introduced by Volker Schmidt <vs75@gmx.de> // NOTE: need to handle multiple varities of authentication (kerberos, etc) if (username!=null && password!=null) { send("AUTHINFO USER "+username); if (getResponse()!=SEND_AUTHINFOPASS) throw new AuthenticationFailedException(response); send("AUTHINFO PASS "+password); if (getResponse()!=AUTHINFO_OK) throw new AuthenticationFailedException(response); } // end authentication if (debug) System.err.println("DEBUG: nntp: connected to "+hostname+", posting is "+(postingAllowed ? "" : "not ")+"allowed"); addStore(this); readNewsrc(); return true; } catch(UnknownHostException e) { throw new MessagingException("unknown host", e); } catch(IOException e) { throw new MessagingException("I/O error", e); } } /** * Closes the connection. */ public synchronized void close() throws MessagingException { if (socket!=null) try { boolean debug = session.getDebug(); if (debug) System.err.println("DEBUG: nntp: closing connection to "+hostname); send("QUIT"); switch (getResponse()) { case CLOSING: break; case SERVER_ERROR: if (response.toLowerCase().indexOf("timeout")>-1) break; default: throw new MessagingException("unexpected server response: "+response); } removeStore(this); socket.close(); socket = null; if (debug) System.err.println("DEBUG: nntp: closed connection to "+hostname); } catch (IOException e) { // socket.close() seems to throw an exception! //throw new MessagingException("Close failed", e); } super.close(); } /** * Returns the hostname of the server. */ public String getHostName() { return hostname; } int getResponse() throws IOException { response = in.readLine(); boolean debug = session.getDebug(); if (debug) System.err.println("DEBUG: nntp: <"+response); if (response==null) response = SERVER_ERROR+" timeout"; try { int index = response.indexOf(' '); if (index>-1) { int code = Integer.parseInt(response.substring(0, index)); response = response.substring(index+1); return code; } else { int code = Integer.parseInt(response); return code; } } catch (StringIndexOutOfBoundsException e) { throw new ProtocolException("NNTP protocol exception: "+response); } catch (NumberFormatException e) { throw new ProtocolException("NNTP protocol exception: "+response); } } void send(String command) throws IOException { boolean debug = session.getDebug(); if (debug) System.err.println("DEBUG: nntp: >"+command); out.write(command.getBytes()); out.writeln(); out.flush(); } // Opens a newsgroup. synchronized void open(Newsgroup group) throws MessagingException { if (current!=null) { if (current.equals(group)) return; else close(current); } String name = group.getName(); try { send("GROUP "+name); int r = getResponse(); switch (r) { case GROUP_SELECTED: try { updateGroup(group, response); group.open = true; current = group; } catch (NumberFormatException e) { throw new MessagingException("NNTP protocol exception: "+response, e); } break; case NO_SUCH_GROUP: throw new MessagingException(response); case SERVER_ERROR: if (response.toLowerCase().indexOf("timeout")>-1) { close(); connect(); open(group); break; } default: throw new MessagingException("unexpected server response ("+r+"): "+response); } } catch (IOException e) { throw new MessagingException("I/O error", e); } } // Updates a newsgroup with the most recent article counts. void updateGroup(Newsgroup newsgroup, String response) throws IOException { try { StringTokenizer st = new StringTokenizer(response, " "); newsgroup.count = Integer.parseInt(st.nextToken()); newsgroup.first = Integer.parseInt(st.nextToken()); newsgroup.last = Integer.parseInt(st.nextToken()); boolean debug = session.getDebug(); if (debug) System.err.println("DEBUG: nntp: "+newsgroup.name+": "+newsgroup.count+" articles"); } catch (NumberFormatException e) { throw new ProtocolException("NNTP protocol exception"); } catch (NoSuchElementException e) { throw new ProtocolException("NNTP protocol exception"); } } // Closes a newsgroup. synchronized void close(Newsgroup group) throws MessagingException { if (current!=null && !current.equals(group)) close(current); group.open = false; } // Returns the (approximate) number of articles in a newsgroup. synchronized int getMessageCount(Newsgroup group) throws MessagingException { String name = group.getName(); try { send("GROUP "+name); switch (getResponse()) { case GROUP_SELECTED: try { updateGroup(group, response); current = group; return group.count; } catch(NumberFormatException e) { throw new MessagingException("NNTP protocol exception: "+response, e); } case NO_SUCH_GROUP: throw new MessagingException("No such group"); case SERVER_ERROR: if (response.toLowerCase().indexOf("timeout")>-1) { close(); connect(); return getMessageCount(group); } default: throw new MessagingException("unexpected server response: "+response); } } catch (IOException e) { throw new MessagingException("I/O error", e); } } // Returns the headers for an article. synchronized InternetHeaders getHeaders(Article article) throws MessagingException { new Throwable().printStackTrace(); String mid = article.messageId; if (mid==null) { Newsgroup group = (Newsgroup)article.getFolder(); if (!current.equals(group)) open(group); mid = Integer.toString(article.getMessageNumber()); } try { send("HEAD "+mid); switch (getResponse()) { case ARTICLE_RETRIEVED_HEAD: return new InternetHeaders(new MessageInputStream(in)); case NO_GROUP_SELECTED: throw new MessagingException("No group selected"); case NO_ARTICLE_SELECTED: throw new MessagingException("No article selected"); case NO_SUCH_ARTICLE_IN_GROUP: //throw new MessagingException("No such article in group"); return null; case NO_SUCH_ARTICLE: throw new MessagingException("No such article"); case SERVER_ERROR: if (response.toLowerCase().indexOf("timeout")>-1) { close(); connect(); return getHeaders(article); } default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -