chris@0: /*
chris@0: * StarOffice News Server
chris@0: * see AUTHORS for the list of contributors
chris@0: *
chris@0: * This program is free software: you can redistribute it and/or modify
chris@0: * it under the terms of the GNU General Public License as published by
chris@0: * the Free Software Foundation, either version 3 of the License, or
chris@0: * (at your option) any later version.
chris@0: *
chris@0: * This program is distributed in the hope that it will be useful,
chris@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of
chris@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
chris@0: * GNU General Public License for more details.
chris@0: *
chris@0: * You should have received a copy of the GNU General Public License
chris@0: * along with this program. If not, see .
chris@0: */
chris@0:
chris@0: package com.so.news.storage;
chris@0:
chris@0: import java.sql.ResultSet;
chris@0: import java.sql.SQLException;
chris@0: import java.util.Date;
chris@0: import java.util.HashMap;
chris@0: import java.util.Map;
chris@0: import java.util.Map.Entry;
chris@0: import java.util.UUID;
chris@0:
chris@0: import com.so.news.Config;
chris@0: import com.so.news.Debug;
chris@0:
chris@0: /**
chris@0: * Represents a newsgroup article.
chris@0: * @author Christian Lins
chris@0: * @author Denis Schwerdel
chris@0: */
chris@0: public class Article
chris@0: {
chris@0: /**
chris@0: * Loads the Article identified by the given ID from the Database.
chris@0: * @param messageID
chris@0: * @return null if Article is not found or if an error occurred.
chris@0: */
chris@0: public static Article getByMessageID(String messageID)
chris@0: {
chris@0: try
chris@0: {
chris@0: return Database.getInstance().getArticle(messageID);
chris@0: }
chris@0: catch(SQLException ex)
chris@0: {
chris@0: ex.printStackTrace(Debug.getInstance().getStream());
chris@0: return null;
chris@0: }
chris@0: }
chris@0:
chris@0: public static Article getByNumberInGroup(Group group, int number)
chris@0: throws SQLException
chris@0: {
chris@0: long gid = group.getID();
chris@0: return Database.getInstance().getArticle(gid, number); // Is number her correct?
chris@0: }
chris@0:
chris@0: private String body = "";
chris@0: private long groupID = -1;
chris@0: private Map header = new HashMap();
chris@0: private int numberInGroup = -1;
chris@0: private String msgID = null;
chris@0:
chris@0: /**
chris@0: * Default constructor.
chris@0: */
chris@0: public Article()
chris@0: {
chris@0: }
chris@0:
chris@0: /**
chris@0: * Creates a new Article object using the date from the given
chris@0: * ResultSet. It is expected that ResultSet.next() was already
chris@0: * called by the Database class.
chris@0: * This construction has only package visibility.
chris@0: * @param rs
chris@0: */
chris@0: Article(ResultSet rs)
chris@0: throws SQLException
chris@0: {
chris@0: this.body = rs.getString("body");
chris@0: this.msgID = rs.getString("message_id");
chris@0:
chris@0: // Parse the header
chris@0: parseHeader(rs.getString("header"));
chris@0: }
chris@0:
chris@0: /**
chris@0: * Parses the header fields and puts them into a map for faster access.
chris@0: * TODO: There could be fields that go over more than one line, some
chris@0: * bad clients do create them.
chris@0: * @param hsrc
chris@0: */
chris@0: private void parseHeader(String hsrc)
chris@0: {
chris@0: String[] lines = hsrc.split("\n");
chris@0:
chris@0: for(String line : lines)
chris@0: {
chris@0: String[] kv = line.split(":");
chris@0: if(kv.length < 2)
chris@0: {
chris@0: Debug.getInstance().log("Invalid header field: " + line);
chris@0: continue;
chris@0: }
chris@0: else
chris@0: {
chris@0: // Set value in the header hash map
chris@0: String value = kv[1];
chris@0: for(int n = 2; n < kv.length; n++)
chris@0: value += ":" + kv[n];
chris@0: this.header.put(kv[0], value);
chris@0: }
chris@0: }
chris@0: }
chris@0:
chris@0: /**
chris@0: * Returnes the next Article in the group of this Article.
chris@0: * @return
chris@0: */
chris@0: public Article nextArticleInGroup()
chris@0: {
chris@0: return null;
chris@0: }
chris@0:
chris@0: /**
chris@0: * Returns the previous Article in the group of this Article.
chris@0: * @return
chris@0: */
chris@0: public Article prevArticleInGroup()
chris@0: {
chris@0: return null;
chris@0: }
chris@0:
chris@0: /**
chris@0: * Generates a message id for this article and sets it into
chris@0: * the header HashMap.
chris@0: */
chris@0: private String generateMessageID()
chris@0: {
chris@0: this.msgID = "<" + UUID.randomUUID() + "@"
chris@0: + Config.getInstance().get("n3tpd.hostname", "localhost") + ">";
chris@0:
chris@0: this.header.put("Message-ID", msgID);
chris@0:
chris@0: return msgID;
chris@0: }
chris@0:
chris@0: /**
chris@0: * Tries to delete this article.
chris@0: * @return false if the article could not be deleted, otherwise true
chris@0: */
chris@0: public boolean delete()
chris@0: {
chris@0: return false;
chris@0: }
chris@0:
chris@0: /**
chris@0: * Checks if all necessary header fields are within this header.
chris@0: */
chris@0: private void validateHeader()
chris@0: {
chris@0: // Forces a MessageID creation if not existing
chris@0: getMessageID();
chris@0:
chris@0: // Check if the references are correct...
chris@0: String rep = header.get("In-Reply-To");
chris@0: if(rep == null) // Some clients use only references instead of In-Reply-To
chris@0: return; //rep = header.get("References");
chris@0:
chris@0: String ref = getMessageID();
chris@0:
chris@0: if(rep != null && !rep.equals(""))
chris@0: {
chris@0: Article art = null; //TODO // getByMessageID(rep, articleDir);
chris@0: if(art != null)
chris@0: {
chris@0: ref = art.header.get("References") + " " + rep;
chris@0: }
chris@0: }
chris@0: header.put("References", ref);
chris@0: }
chris@0:
chris@0: /**
chris@0: * Returns the body string.
chris@0: */
chris@0: public String getBody()
chris@0: {
chris@0: return body;
chris@0: }
chris@0:
chris@0: /**
chris@0: * @return Numerical ID of the associated Group.
chris@0: */
chris@0: long getGroupID()
chris@0: {
chris@0: if(groupID == -1) // If the GroupID was not determined yet
chris@0: {
chris@0: // Determining GroupID
chris@0: String newsgroups = this.header.get("Newsgroups");
chris@0: if(newsgroups != null)
chris@0: {
chris@0: String[] newsgroup = newsgroups.split(",");
chris@0: // Crossposting is not supported
chris@0: try
chris@0: {
chris@0: Group group;
chris@0: if(newsgroup.length > 0)
chris@0: group = Database.getInstance().getGroup(newsgroup[0].trim());
chris@0: else
chris@0: group = Database.getInstance().getGroup(newsgroups.trim());
chris@0: // TODO: What to do if Group does not exist?
chris@0: this.groupID = group.getID();
chris@0: }
chris@0: catch(SQLException ex)
chris@0: {
chris@0: ex.printStackTrace(Debug.getInstance().getStream());
chris@0: System.err.println(ex.getLocalizedMessage());
chris@0: }
chris@0: }
chris@0: else
chris@0: System.err.println("Should never happen: Article::getGroupID");
chris@0: }
chris@0: return this.groupID;
chris@0: }
chris@0:
chris@0: public void setBody(String body)
chris@0: {
chris@0: this.body = body;
chris@0: }
chris@0:
chris@0: public int getNumberInGroup()
chris@0: {
chris@0: return this.numberInGroup;
chris@0: }
chris@0:
chris@0: public void setHeader(HashMap header)
chris@0: {
chris@0: this.header = header;
chris@0: }
chris@0:
chris@0: public void setNumberInGroup(int id)
chris@0: {
chris@0: this.numberInGroup = id;
chris@0: }
chris@0:
chris@0: public String getMessageID()
chris@0: {
chris@0: if(msgID == null)
chris@0: msgID = generateMessageID();
chris@0: return msgID;
chris@0: }
chris@0:
chris@0: /**
chris@0: * @return Header source code of this Article.
chris@0: */
chris@0: public String getHeaderSource()
chris@0: {
chris@0: StringBuffer buf = new StringBuffer();
chris@0:
chris@0: for(Entry entry : this.header.entrySet())
chris@0: {
chris@0: buf.append(entry.getKey());
chris@0: buf.append(":");
chris@0: buf.append(entry.getValue());
chris@0: buf.append("\n");
chris@0: }
chris@0:
chris@0: return buf.toString();
chris@0: }
chris@0:
chris@0: public Map getHeader()
chris@0: {
chris@0: return this.header;
chris@0: }
chris@0:
chris@0: public Date getDate()
chris@0: {
chris@0: try
chris@0: {
chris@0: String date = this.header.get("Date");
chris@0: return new Date(Date.parse(date));
chris@0: }
chris@0: catch(Exception e)
chris@0: {
chris@0: e.printStackTrace(Debug.getInstance().getStream());
chris@0: return null;
chris@0: }
chris@0: }
chris@0:
chris@0: public void setDate(Date date)
chris@0: {
chris@0: this.header.put("Date", date.toString());
chris@0: }
chris@0:
chris@0: @Override
chris@0: public String toString()
chris@0: {
chris@0: return getMessageID();
chris@0: }
chris@0: }