⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nntpstore.java

📁 java 开发的一个电子邮局,挺实用的
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -