/*************** NNTP Java Class by Charles Bloom quite nice ***************/ import java.io.*; import java.net.*; import java.lang.*; class ArticleHeader { int number; String subject; String author; String date; int bytes,lines; int seqNum,seqTot; public void getSeq() /* from subject */ { int slashI,fdelimI,ldelimI,a,b; if ( (slashI = subject.lastIndexOf('/')) == -1 ) { seqNum=seqTot=0; return; } a = subject.lastIndexOf('(' /*)*/,slashI); b = subject.lastIndexOf('[',slashI); if ( a > b ) fdelimI = a; else fdelimI = b; if ( fdelimI == -1 ) { seqNum=seqTot=0; return; } a = subject.indexOf(/*(*/ ')',slashI); b = subject.indexOf(']',slashI); if ( a == -1 ) a = 999; if ( b == -1 ) b = 999; if ( a < b ) ldelimI = a; else ldelimI = b; if ( ldelimI == 999 ) { seqNum=seqTot=0; return; } try { seqNum = clib.atoi(subject.substring(fdelimI+1,slashI)); seqTot = clib.atoi(subject.substring(slashI+1,ldelimI)); } catch( NumberFormatException e ) { seqNum=seqTot=0; return; } } public String fileName() /* from subject */ { int dotidx,fspace,lspace; String fname; try { subject.replace('\t',' '); if ( (dotidx = subject.lastIndexOf(".jpg")) == -1 ) if ( (dotidx = subject.lastIndexOf('.')) == -1 ) dotidx = 0; if ( ! Character.isLetter( subject.charAt(dotidx+1) ) ) { int newdotidx; newdotidx = dotidx; while ( (newdotidx = subject.lastIndexOf('.',newdotidx-1)) != -1 ) { if ( Character.isLetter( subject.charAt(newdotidx+1) ) ) { dotidx = newdotidx; break; } } } if ( dotidx > 0 ) { fspace = subject.lastIndexOf(' ',dotidx) + 1; } else fspace = 0; if ( (lspace = subject.indexOf(' ',dotidx)) == -1 ) lspace = subject.length(); fname = subject.substring(fspace,lspace); while ( (lspace = fname.indexOf('(')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf(')')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('<')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('>')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('{')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('}')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('[')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf(']')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('/')) != -1 ) fname = fname.substring(0,lspace); while ( (lspace = fname.indexOf('\\')) != -1 ) fname = fname.substring(0,lspace); } catch ( StringIndexOutOfBoundsException e ) { return null; } return fname; }; }; class NNTP_Client { public SimpleClientConnection net; public long group_low=0,group_high=0; /* only valid right after goGroup */ boolean nntpConnected; DataInputStream nntp_in; PrintStream nntp_out; PrintStream log_out; String host,group_name; String saveUser,savePass; public boolean reset() throws IOException { ArticleHeader none = new ArticleHeader(); none.number = 0; return ( reset(none) ); }; public boolean reset(ArticleHeader last) throws IOException { disconnect(); NNTP_Connect(); if ( group_name != null ) { if ( ! goGroup(group_name) ) return(false); if ( ! goArticle(last.number) ) return(false); } return(true); }; /* these progress indicators should be in a seperate module so that they could be swapped out for GUI ones */ void progressUpdate(int cur,int tot) { System.err.print("nntp : " + cur + " / " + tot + "\r"); System.err.flush(); } void progressDone() { System.err.println(); } public byte[] getBody(ArticleHeader header) throws IOException { byte body[]; String instr; byte tbody[]; int curoff=0,lines=0,c; int linelen = 0; tbody = new byte[header.lines*80]; nntp_out.println("body"); instr = nntp_in.readLine(); log_out.println(instr); if ( instr.charAt(0) != '2' ) throw new IOException("nntp.getBody:no article body"); progressUpdate(lines,header.lines); for(;;) { if ( (c = nntp_in.read()) == -1 ) break; if ( linelen == 0 && c == '.' ) { if ( lines > 150 || lines >= header.lines ) break; /*** <> the problem is that the '.' seems to occur before the right # of lines have been seen. However, .'s may occur in the text! as in '....' ***/ } //debug: <> //log_out.write( c ); // debug: //System.err.print("nntp : " + lines + " lines " + curoff + " bytes " + linelen + " linelen\r"); System.err.flush(); linelen++; if ( c == '\n' ) { linelen = 0; lines++; if ( lines % 50 == 0 ) progressUpdate(lines,header.lines); } else if ( c <= 13 ) continue; tbody[curoff++] = (byte) c; } progressUpdate(lines,header.lines); progressDone(); // <> if ( c == -1 ) log_out.print("got -1 "); else if ( c == '.' ) log_out.print("got . "); else log_out.print("got bad "); log_out.println( nntp_in.readLine() ); /* '.' line */ log_out.println(" saw " + lines + " of " + header.lines + " sought; saw " + curoff + " bytes of " + header.bytes + " sought"); body = new byte[curoff]; System.arraycopy(tbody,0,body,0,curoff); return( body ); }; public ArticleHeader getHeader() throws IOException { boolean goterror; String instr,instrbase,curstr; ArticleHeader header = new ArticleHeader(); int next_pos; do { goterror = false; nntp_out.println("xover"); instr = nntp_in.readLine(); log_out.println(instr); if ( instr.charAt(0) != '2' ) throw new IOException("nntp.getHeader:no xover data"); instr = nntp_in.readLine(); log_out.println(instr); instrbase = instr; /* now process instr and fill in header */ /* article number */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); try { header.number = clib.atoi(curstr); } catch ( NumberFormatException e ) { goterror = true; } /* subject */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); header.subject = curstr; /* author */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); header.author = curstr; /* date */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); header.date = curstr; /* message-id */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); // ignore /* references */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); // ignore /* bytes */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); try { header.bytes = clib.atoi(curstr); } catch ( NumberFormatException e ) { goterror = true; } /* lines (last one) */ while( (next_pos = instr.indexOf('\t')) == -1 ) { instr = nntp_in.readLine(); log_out.println(instr); } curstr = instr.substring(0,next_pos); instr = instr.substring(next_pos + 1); try { header.lines = clib.atoi(curstr); } catch ( NumberFormatException e ) { goterror = true; } while(instr.length() == 0 || instr.charAt(0) != '.' ) log_out.println( instr = nntp_in.readLine() ); } while( goterror ); return(header); }; public boolean goArticle(int number) { String retStr; nntp_out.println("stat " + number); try { log_out.println( retStr = nntp_in.readLine() ); } catch ( IOException e ) { return(false); } // "423 Bad article number" = bad if ( retStr.charAt(0) != '2' ) return(false); return(true); }; public boolean goGroup(String in_group_name) { String reply; String[] replyToks; group_low = group_high = 0; group_name = in_group_name; nntp_out.println("group " + group_name); try { log_out.println( reply = nntp_in.readLine() ); } catch ( IOException e ) { return(false); } if ( reply.charAt(0) != '2' ) { log_out.println("NNTP_Client:Got:No such group"); return(false); } replyToks = clib.stringSpaceTok(reply); if ( replyToks.length < 5 ) { log_out.println("NNTP_Client:Got: less than 5 tokens in group header"); return(false); } group_low = clib.atol(replyToks[2]); group_high = clib.atol(replyToks[3]); return(true); }; /* next : returns false when no more messages */ public boolean next() throws IOException { String statstr; nntp_out.println("next"); // <> this should be more fail-safe do { statstr = nntp_in.readLine(); log_out.println("next:" + statstr); } while ( statstr.length() < 2 ); // "223 ... Article retrieved; request text separately." = good // "421 No next to retrieve." = bad // "423 Bad article number" = bad if ( statstr.charAt(0) != '2' ) return(false); return(true); }; public boolean isConnected() { return( nntpConnected ); }; public void disconnect() { if ( nntpConnected ) nntp_out.println("quit"); nntpConnected = false; net.disconnect(); }; public NNTP_Client(String in_host,PrintStream in_log_out,String user,String pass) throws IOException { host = in_host; log_out = in_log_out; group_name = null; nntpConnected = false; NNTP_Connect(user,pass); }; public NNTP_Client(String in_host,PrintStream in_log_out) throws IOException { host = in_host; log_out = in_log_out; group_name = null; nntpConnected = false; NNTP_Connect(); }; public void NNTP_Connect() throws IOException { NNTP_Connect(saveUser,savePass); }; public void NNTP_Connect(String user,String password) throws IOException { net = new SimpleClientConnection(host, 119); /* 119 is NNTP */ nntpConnected = net.isConnected(); if ( nntpConnected ) { nntp_in = net.inputStream(); nntp_out = net.outputStream(); } else { nntp_in = null; nntp_out= null; } /* init */ { String incoming = null; int ret; log_out.println("Waiting for '20'"); do { incoming = nntp_in.readLine(); log_out.println(incoming); } while ( incoming.indexOf("20") == -1 ); if ( incoming.indexOf("ready") == -1 ) { saveUser = user; savePass = password; nntp_out.println("AUTHINFO user " + user); incoming = nntp_in.readLine(); log_out.println("authinfo user : " + incoming); nntp_out.println("AUTHINFO pass " + password); incoming = nntp_in.readLine(); log_out.println("authinfo pass : " + incoming); } } }; };