HSQLDB backend support completed, but untested.
3 * see AUTHORS for the list of contributors
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 package org.sonews.storage;
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.security.MessageDigest;
25 import java.security.NoSuchAlgorithmException;
26 import java.util.UUID;
27 import java.util.ArrayList;
28 import java.util.Enumeration;
29 import java.util.List;
30 import javax.mail.Header;
31 import javax.mail.Message;
32 import javax.mail.MessagingException;
33 import javax.mail.internet.InternetHeaders;
34 import org.sonews.config.Config;
37 * Represents a newsgroup article.
38 * @author Christian Lins
39 * @author Denis Schwerdel
42 public class Article extends ArticleHead
46 * Loads the Article identified by the given ID from the JDBCDatabase.
48 * @return null if Article is not found or if an error occurred.
50 public static Article getByMessageID(final String messageID)
53 return StorageManager.current().getArticle(messageID);
54 } catch (StorageBackendException ex) {
59 private byte[] body = new byte[0];
62 * Default constructor.
69 * Creates a new Article object using the date from the given
72 public Article(String headers, byte[] body)
78 this.headers = new InternetHeaders(
79 new ByteArrayInputStream(headers.getBytes()));
81 this.headerSrc = headers;
82 } catch (MessagingException ex) {
88 * Creates an Article instance using the data from the javax.mail.Message
89 * object. This constructor is called by the Mailinglist gateway.
90 * @see javax.mail.Message
93 * @throws MessagingException
95 public Article(final Message msg)
96 throws IOException, MessagingException
98 this.headers = new InternetHeaders();
100 for (Enumeration e = msg.getAllHeaders(); e.hasMoreElements();) {
101 final Header header = (Header) e.nextElement();
102 this.headers.addHeader(header.getName(), header.getValue());
105 // Reads the raw byte body using Message.writeTo(OutputStream out)
106 this.body = readContent(msg);
113 * Reads from the given Message into a byte array.
116 * @throws IOException
118 private byte[] readContent(Message in)
119 throws IOException, MessagingException
121 ByteArrayOutputStream out = new ByteArrayOutputStream();
123 return out.toByteArray();
127 * Removes the header identified by the given key.
130 public void removeHeader(final String headerKey)
132 this.headers.removeHeader(headerKey);
133 this.headerSrc = null;
137 * Generates a message id for this article and sets it into
138 * the header object. You have to update the JDBCDatabase manually to make this
140 * Note: a Message-ID should never be changed and only generated once.
142 private String generateMessageID()
147 md5 = MessageDigest.getInstance("MD5");
149 md5.update(getBody());
150 md5.update(getHeader(Headers.SUBJECT)[0].getBytes());
151 md5.update(getHeader(Headers.FROM)[0].getBytes());
152 byte[] result = md5.digest();
153 StringBuffer hexString = new StringBuffer();
154 for (int i = 0; i < result.length; i++) {
155 hexString.append(Integer.toHexString(0xFF & result[i]));
157 randomString = hexString.toString();
158 } catch (NoSuchAlgorithmException e) {
160 randomString = UUID.randomUUID().toString();
162 String msgID = "<" + randomString + "@"
163 + Config.inst().get(Config.HOSTNAME, "localhost") + ">";
165 this.headers.setHeader(Headers.MESSAGE_ID, msgID);
171 * Returns the body string.
173 public byte[] getBody()
179 * @return Numerical IDs of the newsgroups this Article belongs to.
181 public List<Group> getGroups()
183 String[] groupnames = getHeader(Headers.NEWSGROUPS)[0].split(",");
184 ArrayList<Group> groups = new ArrayList<Group>();
187 for (String newsgroup : groupnames) {
188 newsgroup = newsgroup.trim();
189 Group group = StorageManager.current().getGroup(newsgroup);
190 if (group != null && // If the server does not provide the group, ignore it
191 !groups.contains(group)) // Yes, there may be duplicates
196 } catch (StorageBackendException ex) {
197 ex.printStackTrace();
203 public void setBody(byte[] body)
210 * @param groupname Name(s) of newsgroups
212 public void setGroup(String groupname)
214 this.headers.setHeader(Headers.NEWSGROUPS, groupname);
218 * Returns the Message-ID of this Article. If the appropriate header
219 * is empty, a new Message-ID is created.
220 * @return Message-ID of this Article.
222 public String getMessageID()
224 String[] msgID = getHeader(Headers.MESSAGE_ID);
225 return msgID[0].equals("") ? generateMessageID() : msgID[0];
229 * @return String containing the Message-ID.
232 public String toString()
234 return getMessageID();