chris@1: /*
chris@1:  *   SONEWS News Server
chris@1:  *   see AUTHORS for the list of contributors
chris@1:  *
chris@1:  *   This program is free software: you can redistribute it and/or modify
chris@1:  *   it under the terms of the GNU General Public License as published by
chris@1:  *   the Free Software Foundation, either version 3 of the License, or
chris@1:  *   (at your option) any later version.
chris@1:  *
chris@1:  *   This program is distributed in the hope that it will be useful,
chris@1:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
chris@1:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
chris@1:  *   GNU General Public License for more details.
chris@1:  *
chris@1:  *   You should have received a copy of the GNU General Public License
chris@1:  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
chris@1:  */
chris@1: package org.sonews.daemon.command;
chris@1: 
chris@1: import java.io.IOException;
chris@3: import org.sonews.storage.Article;
chris@1: import org.sonews.daemon.NNTPConnection;
cli@48: import org.sonews.storage.Group;
chris@3: import org.sonews.storage.StorageBackendException;
chris@1: 
chris@1: /**
chris@1:  * Class handling the ARTICLE, BODY and HEAD commands.
chris@1:  * @author Christian Lins
chris@1:  * @author Dennis Schwerdel
chris@1:  * @since n3tpd/0.1
chris@1:  */
cli@48: public class ArticleCommand implements Command {
chris@3: 
cli@37: 	@Override
cli@48: 	public String[] getSupportedCommandStrings() {
cli@48: 		return new String[]{"ARTICLE", "BODY", "HEAD"};
cli@37: 	}
chris@1: 
cli@37: 	@Override
cli@48: 	public boolean hasFinished() {
cli@37: 		return true;
cli@37: 	}
chris@1: 
cli@37: 	@Override
cli@48: 	public String impliedCapability() {
cli@37: 		return null;
cli@37: 	}
cli@20: 
cli@37: 	@Override
cli@48: 	public boolean isStateful() {
cli@37: 		return false;
cli@37: 	}
chris@3: 
cli@37: 	// TODO: Refactor this method to reduce its complexity!
cli@37: 	@Override
cli@37: 	public void processLine(NNTPConnection conn, final String line, byte[] raw)
cli@48: 			throws IOException {
cli@37: 		final String[] command = line.split(" ");
chris@1: 
cli@37: 		Article article = null;
cli@37: 		long artIndex = -1;
cli@37: 		if (command.length == 1) {
cli@37: 			article = conn.getCurrentArticle();
cli@37: 			if (article == null) {
cli@37: 				conn.println("420 no current article has been selected");
cli@37: 				return;
cli@37: 			}
cli@37: 		} else if (command[1].matches(NNTPConnection.MESSAGE_ID_PATTERN)) {
cli@37: 			// Message-ID
cli@37: 			article = Article.getByMessageID(command[1]);
cli@37: 			if (article == null) {
cli@37: 				conn.println("430 no such article found");
cli@37: 				return;
cli@37: 			}
cli@37: 		} else {
cli@37: 			// Message Number
cli@37: 			try {
cli@48: 				Group currentGroup = conn.getCurrentChannel();
cli@37: 				if (currentGroup == null) {
cli@37: 					conn.println("400 no group selected");
cli@37: 					return;
cli@37: 				}
chris@1: 
cli@37: 				artIndex = Long.parseLong(command[1]);
cli@37: 				article = currentGroup.getArticle(artIndex);
cli@37: 			} catch (NumberFormatException ex) {
cli@37: 				ex.printStackTrace();
cli@37: 			} catch (StorageBackendException ex) {
cli@37: 				ex.printStackTrace();
cli@37: 			}
cli@37: 
cli@37: 			if (article == null) {
cli@37: 				conn.println("423 no such article number in this group");
cli@37: 				return;
cli@37: 			}
cli@37: 			conn.setCurrentArticle(article);
cli@37: 		}
cli@37: 
cli@37: 		if (command[0].equalsIgnoreCase("ARTICLE")) {
cli@37: 			conn.println("220 " + artIndex + " " + article.getMessageID()
cli@48: 					+ " article retrieved - head and body follow");
cli@37: 			conn.println(article.getHeaderSource());
cli@37: 			conn.println("");
cli@37: 			conn.println(article.getBody());
cli@37: 			conn.println(".");
cli@37: 		} else if (command[0].equalsIgnoreCase("BODY")) {
cli@37: 			conn.println("222 " + artIndex + " " + article.getMessageID() + " body");
cli@37: 			conn.println(article.getBody());
cli@37: 			conn.println(".");
cli@37: 		} /*
cli@37: 		 * HEAD: This command is mandatory.
cli@37: 		 *
cli@37: 		 * Syntax
cli@37: 		 *    HEAD message-id
cli@37: 		 *    HEAD number
cli@37: 		 *    HEAD
cli@37: 		 *
cli@37: 		 * Responses
cli@37: 		 *
cli@37: 		 * First form (message-id specified)
cli@37: 		 *  221 0|n message-id    Headers follow (multi-line)
cli@37: 		 *  430                   No article with that message-id
cli@37: 		 *
cli@37: 		 * Second form (article number specified)
cli@37: 		 *  221 n message-id      Headers follow (multi-line)
cli@37: 		 *  412                   No newsgroup selected
cli@37: 		 *  423                   No article with that number
cli@37: 		 *
cli@37: 		 * Third form (current article number used)
cli@37: 		 *  221 n message-id      Headers follow (multi-line)
cli@37: 		 *  412                   No newsgroup selected
cli@37: 		 *  420                   Current article number is invalid
cli@37: 		 *
cli@37: 		 * Parameters
cli@37: 		 *  number        Requested article number
cli@37: 		 *  n             Returned article number
cli@37: 		 *  message-id    Article message-id
cli@37: 		 */ else if (command[0].equalsIgnoreCase("HEAD")) {
cli@37: 			conn.println("221 " + artIndex + " " + article.getMessageID()
cli@48: 					+ " Headers follow (multi-line)");
cli@37: 			conn.println(article.getHeaderSource());
cli@37: 			conn.println(".");
cli@37: 		}
cli@37: 	}
chris@1: }