You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Rory Winston <Ro...@telewest.co.uk> on 2003/05/22 12:53:39 UTC

[Net]Adding Authentication and XHDR to NNTP

Hi

Thanks for all the helpful comments on my first draft of getting
authentication into the NNTP classes. I have come up with a slightly revised
version. Along the way, I have also made a first pass at implementing the
XHDR command. It is not complete yet, but the reason I am posting it for
review is that I have some slight reservations about the way I have
implemented it - using one base method and passing nulls for unused
parameters. If anyone has any better suggestions they would be much
appreciated. 

Here are the diffs for the base NNTP classes:

Index: org/apache/commons/net/nntp/NNTP.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNT
P.java,v
retrieving revision 1.5
diff -b -B -r1.5 NNTP.java
929a930,964
> 	/***
> 	 * A convenience method to send the AUTHINFO USER and AUTHINFO PASS 
> 	 * command to the server, receive the replies, and return the reply
code.
> 	 * <p>
> 	 * @return The reply code received from the server.
> 	 * @exception NNTPConnectionClosedException
> 	 *      If the NNTP server prematurely closes the connection as a
result
> 	 *      of the client being idle or some other reason causing the
server
> 	 *      to send NNTP reply code 400.  This exception may be caught
either
> 	 *      as an IOException or independently as itself.
> 	 * @exception IOException  If an I/O error occurs while either
sending the
> 	 *      command or receiving the server reply.
> 	 ***/
>     public int authenticate(String username, String password) throws
IOException
>     {
> 		
> 		String authUserString = "USER " + username;
> 		
> 		int replyCode = sendCommand(NNTPCommand.AUTHINFO,
authUserString);
> 		
> 		 if(replyCode == NNTPReply.MORE_AUTHENTICATION_REQUIRED)
> 		{
> 			String authPassString = "PASS " + password;
> 			replyCode = sendCommand(NNTPCommand.AUTHINFO,
authPassString);
> 			
> 			if(replyCode == NNTPReply.AUTHENTICATION_ACCEPTED)
> 			{
> 				_isAllowedToPost = true;
> 				return replyCode;
> 			}
> 		}
> 		
> 		return replyCode;
>     
>     }
Index: org/apache/commons/net/nntp/NNTPClient.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNT
PClient.java,v
retrieving revision 1.4
diff -b -B -r1.4 NNTPClient.java
679a679,759
>    /***
>     * Implements the RFC 2980 XHDR command.
>     *
>     * see RFC 1036 for valid headers
>     */ 
>    public Reader retrieveHeaderRange(String header) 
>       throws IOException
>    {
>       Integer nullInt = null;
>       String nullString = null;
>       return __retrieveHeaders(header, nullString, nullInt, nullInt);   
>    }
> 
>    public Reader retrieveHeaderRange(String header, String messageId) 
>       throws IOException
>    {
>       Integer nullInt = null;
>       return __retrieveHeaders(header, messageId, nullInt, nullInt);
>    }    
> 
>    public Reader retrieveHeaderRange(String header, int articleNumber) 
>       throws IOException
>    {
>       String nullString = null;
>       Integer nullInt = null;
>       return __retrieveHeaders(header, nullString, new
Integer(articleNumber), nullInt);
>    }
> 
>    public Reader retrieveHeaderRange(String header, int lowArticleNumber,
int highArticleNumber) 
>       throws IOException
>    {
>       String nullString = null;
>       return __retrieveHeaders(header, nullString, new
Integer(lowArticleNumber), new Integer(highArticleNumber));
>    }
> 
>    /***
>     * Actual implementation of the XHDR command. Returns a
DotTerminatedMessageReader.
>     *
>     * <p>
>     * @param header the String representation of the header required (e.g.
"message-id")
>     *
>     * @param messageId the String representation of the message-id
>     *
>     * @param lowArticleNumber the lowest element in the range of article
numbers to retrieve from
>     * 
>     * @param highArticleNumber the highest element in the range of article
numbers to retrieve from
>     */
>    private Reader __retrieveHeaders(String header, String messageId,
Integer lowArticleNumber,  Integer highArticleNumber)
>       throws IOException
>    {
>       Reader reader;
> 
>       // messageId and articleNumber are mutually exclusive as per RFC
2980
>       if(messageId != null)
>       {
> 	 if(!NNTPReply.isPositiveCompletion(sendCommand(NNTPCommand.XHDR,
new String(header + " " + messageId))))
> 	    return null;
>       }
>       else
>       {
> 	 if(lowArticleNumber != null)
> 	 {
> 	    if(highArticleNumber == null)	// no range specified, just
an article number
> 	    {
>
if(!NNTPReply.isPositiveCompletion(sendCommand(NNTPCommand.XHDR, 
> 			   new String(header + " " +
lowArticleNumber.toString()))))
> 		  return null;				
> 	    }
> 	    else				// low and high elements
specified						
> 	    {
>
if(!NNTPReply.isPositiveCompletion(sendCommand(NNTPCommand.XHDR, 
> 			   new String(header + " " +
lowArticleNumber.toString() + "-" + highArticleNumber.toString()))))
> 		  return null;
> 	    }
> 
> 	 }// lowArticleNumber != null
> 
>       }// messageId != null
> 
>       return new DotTerminatedMessageReader(_reader_);
>    }
1139a1220,1229
>    /***
>     * 
>     * @param username
>     * @param password
>     * @return True if successful, false if not
>     */
>    public boolean login(String username, String password) throws
IOException
>    {
>       return NNTPReply.isPositiveCompletion(authenticate(username,
password));
>    }
Index: org/apache/commons/net/nntp/NNTPCommand.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNT
PCommand.java,v
retrieving revision 1.3
diff -b -B -r1.3 NNTPCommand.java
83a84,87
>     // Extended NNTP (RFC 2980) commands
>     public static final int AUTHINFO = 15;
>     public static final int XHDR = 16;
> 
91c95,96
<                                           "NEWGROUPS", "NEWNEWS", "NEXT",
"POST", "QUIT", "SLAVE", "STAT"
---
>                                           "NEWGROUPS", "NEWNEWS", "NEXT",
"POST", "QUIT", "SLAVE", "STAT",
>                                           "AUTHINFO", "XHDR"
Index: org/apache/commons/net/nntp/NNTPReply.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNT
PReply.java,v
retrieving revision 1.3
diff -b -B -r1.3 NNTPReply.java
87a88
>     public static final int CODE_281 = 281;
89a91
>     public static final int CODE_381 = 381;
102a105
>     public static final int CODE_482 = 482;
122a126
>     public static final int AUTHENTICATION_ACCEPTED = CODE_281;
124a129
>     public static final int MORE_AUTHENTICATION_REQUIRED = CODE_381;
137a143
>     public static final int AUTHENTICATION_REJECTED = CODE_482;


Here is the source code for an example program to test XHDR functionality:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Hashtable;

import org.apache.commons.net.io.DotTerminatedMessageReader;
import org.apache.commons.net.nntp.NNTPClient;
import org.apache.commons.net.nntp.NewsgroupInfo;

/***
 * This is an example program using the NNTP package to post an article
 * to the specified newsgroup(s).  It prompts you for header information and
 * a filename to post.
 * <p>
 ***/

public final class xhdr {

	private String _server;
	private NNTPClient _client;
	private NewsgroupInfo[] _list;
	private BufferedReader _stdin;

	public final static void main(String[] args) {
		xhdr x = new xhdr();
	}

	public xhdr() {
		_server = new String("news.blueyonder.co.uk");
		_client = new NNTPClient();
		_stdin = new BufferedReader(new
InputStreamReader(System.in));

		try {
			_client.connect(_server);
		} catch (Exception e) {
			System.err.println("Error connecting to server.");
			e.printStackTrace();
		}

		doXhdr();
	}

	public void doXhdr() {
		String groupName = new String("");
		Hashtable groups = new Hashtable();
		String lowArticle, highArticle;
		NewsgroupInfo theGroup;
		String header;
		DotTerminatedMessageReader reader = null;
		char[] buffer = new char[100];

		System.out.println("Retrieving newsgroups...");

		try {
			_list = _client.listNewsgroups();

			if (_list != null) {
				for (int i = 0; i < _list.length; ++i) {
	
//System.out.println(_list[i].getNewsgroup());
					groups.put(_list[i].getNewsgroup(),
_list[i]);
				}

			} else {
				System.err.println(
					"LIST failed with : " +
_client.getReplyString());
			}

			while(groupName.equals("")) 
			{
					System.out.println("Enter a
newsgroup name to query:");
					groupName = _stdin.readLine();
			}

			_client.selectNewsgroup(groupName);

		theGroup = (NewsgroupInfo)groups.get(groupName);

			System.out.println("Enter the required header
field.");
			System.out.println("Possible headers (as per RFC
1036) are:");
			System.out.println("From, Date, Newsgroups, Subject,
Message-ID,Path");

			header = _stdin.readLine();
			
			if(header.equals(""))
			{
				header = new String("Subject");
			}

			System.out.println("Enter an article  number between
" + theGroup.getFirstArticle() + " and " + theGroup.getLastArticle());
			System.out.println("Press Enter to automatically
choose the lowest article number available.");
			
			lowArticle = _stdin.readLine();
			
			if(lowArticle.equals(""))
			{
				lowArticle =
Integer.toString(theGroup.getFirstArticle());
			}
			
			System.out.println("Enter an article number higher
than " + lowArticle + " to retrieve a range of headers.");
			System.out.println("Enter a dash (-) to retrieve all
" + header + " headers following article number " + lowArticle);
			System.out.println("Leave input blank to retrieve
header for " + lowArticle + " only.");
			
			highArticle = _stdin.readLine();
			
			if(highArticle.equals("-"))
			{
				reader =
(DotTerminatedMessageReader)_client.retrieveHeaderRange(header,
Integer.parseInt(lowArticle), theGroup.getLastArticle());
			}
			else if (highArticle.equals(""))
			{
				reader =
(DotTerminatedMessageReader)_client.retrieveHeaderRange(header,
Integer.parseInt(lowArticle));
			}
			
			System.out.println("The server return code was: " +
_client.getReplyString()); 
			 
			 if(reader != null)
			 {
			 		StringBuffer sb = new
StringBuffer();
			 	  
			 	  // Issue a blocking read
			 	  // this is probably horribly inefficient
			 	  // any suggestions appreciated
			 	    int i = reader.read(buffer);

			 		while (i != -1) {
			 			for (int j = 0; j < i; j++)
{			 			
	
sb.append(buffer[j]);
			 			}
						i = reader.read(buffer);
			 		}
			 		
					 System.out.println(sb.toString());

					 System.out.flush();
					 
			 }
			 else
			 	System.err.println("reader is null.");
					
			} catch (Exception e) {
			e.printStackTrace();
		}

	}

}


Any suggestions, etc. much appreciated
Cheers
Rory

------------------------------------------------------------------------------
Live Life in Broadband
www.telewest.co.uk


The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material.
Statements and opinions expressed in this e-mail may not represent those of the company. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender immediately and delete the material from any computer.


==============================================================================


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org