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: }