diff -r 6fceb66e1ad7 -r 2fdc9cc89502 org/sonews/daemon/command/PostCommand.java --- a/org/sonews/daemon/command/PostCommand.java Fri Jun 26 16:48:50 2009 +0200 +++ b/org/sonews/daemon/command/PostCommand.java Wed Jul 22 14:04:05 2009 +0200 @@ -19,24 +19,26 @@ package org.sonews.daemon.command; import java.io.IOException; - import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.sql.SQLException; +import java.util.Arrays; import java.util.Locale; import javax.mail.MessagingException; import javax.mail.internet.AddressException; import javax.mail.internet.InternetHeaders; -import org.sonews.daemon.Config; +import org.sonews.config.Config; import org.sonews.util.Log; import org.sonews.mlgw.Dispatcher; -import org.sonews.daemon.storage.Article; -import org.sonews.daemon.storage.Database; -import org.sonews.daemon.storage.Group; +import org.sonews.storage.Article; +import org.sonews.storage.Group; import org.sonews.daemon.NNTPConnection; -import org.sonews.daemon.storage.Headers; +import org.sonews.storage.Headers; +import org.sonews.storage.StorageBackendException; +import org.sonews.storage.StorageManager; import org.sonews.feed.FeedManager; import org.sonews.util.Stats; @@ -47,7 +49,7 @@ * @author Christian Lins * @since sonews/0.5.0 */ -public class PostCommand extends AbstractCommand +public class PostCommand implements Command { private final Article article = new Article(); @@ -55,14 +57,15 @@ private long bodySize = 0; private InternetHeaders headers = null; private long maxBodySize = - Config.getInstance().get(Config.ARTICLE_MAXSIZE, 128) * 1024L; // Size in bytes + Config.inst().get(Config.ARTICLE_MAXSIZE, 128) * 1024L; // Size in bytes private PostState state = PostState.WaitForLineOne; - private final StringBuilder strBody = new StringBuilder(); - private final StringBuilder strHead = new StringBuilder(); - - public PostCommand(final NNTPConnection conn) + private final ByteArrayOutputStream bufBody = new ByteArrayOutputStream(); + private final StringBuilder strHead = new StringBuilder(); + + @Override + public String[] getSupportedCommandStrings() { - super(conn); + return new String[]{"POST"}; } @Override @@ -71,6 +74,12 @@ return this.state == PostState.Finished; } + @Override + public boolean isStateful() + { + return true; + } + /** * Process the given line String. line.trim() was called by NNTPConnection. * @param line @@ -78,8 +87,8 @@ * @throws java.sql.SQLException */ @Override // TODO: Refactor this method to reduce complexity! - public void processLine(String line) - throws IOException, SQLException + public void processLine(NNTPConnection conn, String line, byte[] raw) + throws IOException, StorageBackendException { switch(state) { @@ -87,12 +96,12 @@ { if(line.equalsIgnoreCase("POST")) { - printStatus(340, "send article to be posted. End with ."); + conn.println("340 send article to be posted. End with ."); state = PostState.ReadingHeaders; } else { - printStatus(500, "invalid command usage"); + conn.println("500 invalid command usage"); } break; } @@ -111,7 +120,7 @@ // Parse the header using the InternetHeader class from JavaMail API headers = new InternetHeaders( new ByteArrayInputStream(strHead.toString().trim() - .getBytes(connection.getCurrentCharset()))); + .getBytes(conn.getCurrentCharset()))); // add the header entries for the article article.setHeaders(headers); @@ -119,21 +128,21 @@ catch (MessagingException e) { e.printStackTrace(); - printStatus(500, "posting failed - invalid header"); + conn.println("500 posting failed - invalid header"); state = PostState.Finished; break; } // Change charset for reading body; // for multipart messages UTF-8 is returned - connection.setCurrentCharset(article.getBodyCharset()); + //conn.setCurrentCharset(article.getBodyCharset()); state = PostState.ReadingBody; if(".".equals(line)) { // Post an article without body - postArticle(article); + postArticle(conn, article); state = PostState.Finished; } } @@ -146,15 +155,16 @@ // Set some headers needed for Over command headers.setHeader(Headers.LINES, Integer.toString(lineCount)); headers.setHeader(Headers.BYTES, Long.toString(bodySize)); + + byte[] body = bufBody.toByteArray(); + if(body.length >= 2) + { + // Remove trailing CRLF + body = Arrays.copyOf(body, body.length - 2); + } + article.setBody(body); // set the article body - if(strBody.length() >= 2) - { - strBody.deleteCharAt(strBody.length() - 1); // Remove last newline - strBody.deleteCharAt(strBody.length() - 1); // Remove last CR - } - article.setBody(strBody.toString()); // set the article body - - postArticle(article); + postArticle(conn, article); state = PostState.Finished; } else @@ -163,19 +173,19 @@ lineCount++; // Add line to body buffer - strBody.append(line); - strBody.append(NNTPConnection.NEWLINE); + bufBody.write(raw, 0, raw.length); + bufBody.write(NNTPConnection.NEWLINE.getBytes()); if(bodySize > maxBodySize) { - printStatus(500, "article is too long"); + conn.println("500 article is too long"); state = PostState.Finished; break; } // Check if this message is a MIME-multipart message and needs a // charset change - try + /*try { line = line.toLowerCase(Locale.ENGLISH); if(line.startsWith(Headers.CONTENT_TYPE)) @@ -197,7 +207,7 @@ try { - connection.setCurrentCharset(Charset.forName(charsetName)); + conn.setCurrentCharset(Charset.forName(charsetName)); } catch(IllegalCharsetNameException ex) { @@ -213,12 +223,15 @@ catch(Exception ex) { ex.printStackTrace(); - } + }*/ } break; } default: + { + // Should never happen Log.msg("PostCommand::processLine(): already finished...", false); + } } } @@ -226,7 +239,7 @@ * Article is a control message and needs special handling. * @param article */ - private void controlMessage(Article article) + private void controlMessage(NNTPConnection conn, Article article) throws IOException { String[] ctrl = article.getHeader(Headers.CONTROL)[0].split(" "); @@ -234,52 +247,52 @@ { try { - Database.getInstance().delete(ctrl[1]); + StorageManager.current().delete(ctrl[1]); // Move cancel message to "control" group article.setHeader(Headers.NEWSGROUPS, "control"); - Database.getInstance().addArticle(article); - printStatus(240, "article cancelled"); + StorageManager.current().addArticle(article); + conn.println("240 article cancelled"); } - catch(SQLException ex) + catch(StorageBackendException ex) { Log.msg(ex, false); - printStatus(500, "internal server error"); + conn.println("500 internal server error"); } } else { - printStatus(441, "unknown Control header"); + conn.println("441 unknown control header"); } } - private void supersedeMessage(Article article) + private void supersedeMessage(NNTPConnection conn, Article article) throws IOException { try { String oldMsg = article.getHeader(Headers.SUPERSEDES)[0]; - Database.getInstance().delete(oldMsg); - Database.getInstance().addArticle(article); - printStatus(240, "article replaced"); + StorageManager.current().delete(oldMsg); + StorageManager.current().addArticle(article); + conn.println("240 article replaced"); } - catch(SQLException ex) + catch(StorageBackendException ex) { Log.msg(ex, false); - printStatus(500, "internal server error"); + conn.println("500 internal server error"); } } - private void postArticle(Article article) + private void postArticle(NNTPConnection conn, Article article) throws IOException { if(article.getHeader(Headers.CONTROL)[0].length() > 0) { - controlMessage(article); + controlMessage(conn, article); } else if(article.getHeader(Headers.SUPERSEDES)[0].length() > 0) { - supersedeMessage(article); + supersedeMessage(conn, article); } else // Post the article regularily { @@ -291,10 +304,10 @@ String[] groupnames = article.getHeader(Headers.NEWSGROUPS)[0].split(","); for(String groupname : groupnames) { - Group group = Database.getInstance().getGroup(groupname); - if(group != null) + Group group = StorageManager.current().getGroup(groupname); + if(group != null && !group.isDeleted()) { - if(group.isMailingList() && !connection.isLocalConnection()) + if(group.isMailingList() && !conn.isLocalConnection()) { // Send to mailing list; the Dispatcher writes // statistics to database @@ -304,9 +317,9 @@ else { // Store in database - if(!Database.getInstance().isArticleExisting(article.getMessageID())) + if(!StorageManager.current().isArticleExisting(article.getMessageID())) { - Database.getInstance().addArticle(article); + StorageManager.current().addArticle(article); // Log this posting to statistics Stats.getInstance().mailPosted( @@ -319,30 +332,30 @@ if(success) { - printStatus(240, "article posted ok"); + conn.println("240 article posted ok"); FeedManager.queueForPush(article); } else { - printStatus(441, "newsgroup not found"); + conn.println("441 newsgroup not found"); } } catch(AddressException ex) { Log.msg(ex.getMessage(), true); - printStatus(441, "invalid sender address"); + conn.println("441 invalid sender address"); } catch(MessagingException ex) { // A MessageException is thrown when the sender email address is // invalid or something is wrong with the SMTP server. System.err.println(ex.getLocalizedMessage()); - printStatus(441, ex.getClass().getCanonicalName() + ": " + ex.getLocalizedMessage()); + conn.println("441 " + ex.getClass().getCanonicalName() + ": " + ex.getLocalizedMessage()); } - catch(SQLException ex) + catch(StorageBackendException ex) { ex.printStackTrace(); - printStatus(500, "internal server error"); + conn.println("500 internal server error"); } } }