Merge heads.
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)
54 return StorageManager.current().getArticle(messageID);
56 catch(StorageBackendException ex)
63 private byte[] body = new byte[0];
66 * Default constructor.
73 * Creates a new Article object using the date from the given
76 public Article(String headers, byte[] body)
83 this.headers = new InternetHeaders(
84 new ByteArrayInputStream(headers.getBytes()));
86 this.headerSrc = headers;
88 catch(MessagingException ex)
95 * Creates an Article instance using the data from the javax.mail.Message
96 * object. This constructor is called by the Mailinglist gateway.
97 * @see javax.mail.Message
100 * @throws MessagingException
102 public Article(final Message msg)
103 throws IOException, MessagingException
105 this.headers = new InternetHeaders();
107 for(Enumeration e = msg.getAllHeaders() ; e.hasMoreElements();)
109 final Header header = (Header)e.nextElement();
110 this.headers.addHeader(header.getName(), header.getValue());
113 // Reads the raw byte body using Message.writeTo(OutputStream out)
114 this.body = readContent(msg);
121 * Reads from the given Message into a byte array.
124 * @throws IOException
126 private byte[] readContent(Message in)
127 throws IOException, MessagingException
129 ByteArrayOutputStream out = new ByteArrayOutputStream();
131 return out.toByteArray();
135 * Removes the header identified by the given key.
138 public void removeHeader(final String headerKey)
140 this.headers.removeHeader(headerKey);
141 this.headerSrc = null;
145 * Generates a message id for this article and sets it into
146 * the header object. You have to update the JDBCDatabase manually to make this
148 * Note: a Message-ID should never be changed and only generated once.
150 private String generateMessageID()
156 md5 = MessageDigest.getInstance("MD5");
158 md5.update(getBody());
159 md5.update(getHeader(Headers.SUBJECT)[0].getBytes());
160 md5.update(getHeader(Headers.FROM)[0].getBytes());
161 byte[] result = md5.digest();
162 StringBuffer hexString = new StringBuffer();
163 for (int i = 0; i < result.length; i++)
165 hexString.append(Integer.toHexString(0xFF & result[i]));
167 randomString = hexString.toString();
169 catch (NoSuchAlgorithmException e)
172 randomString = UUID.randomUUID().toString();
174 String msgID = "<" + randomString + "@"
175 + Config.inst().get(Config.HOSTNAME, "localhost") + ">";
177 this.headers.setHeader(Headers.MESSAGE_ID, msgID);
183 * Returns the body string.
185 public byte[] getBody()
191 * @return Numerical IDs of the newsgroups this Article belongs to.
193 public List<Group> getGroups()
195 String[] groupnames = getHeader(Headers.NEWSGROUPS)[0].split(",");
196 ArrayList<Group> groups = new ArrayList<Group>();
200 for(String newsgroup : groupnames)
202 newsgroup = newsgroup.trim();
203 Group group = StorageManager.current().getGroup(newsgroup);
204 if(group != null && // If the server does not provide the group, ignore it
205 !groups.contains(group)) // Yes, there may be duplicates
211 catch(StorageBackendException ex)
213 ex.printStackTrace();
219 public void setBody(byte[] body)
226 * @param groupname Name(s) of newsgroups
228 public void setGroup(String groupname)
230 this.headers.setHeader(Headers.NEWSGROUPS, groupname);
234 * Returns the Message-ID of this Article. If the appropriate header
235 * is empty, a new Message-ID is created.
236 * @return Message-ID of this Article.
238 public String getMessageID()
240 String[] msgID = getHeader(Headers.MESSAGE_ID);
241 return msgID[0].equals("") ? generateMessageID() : msgID[0];
245 * @return String containing the Message-ID.
248 public String toString()
250 return getMessageID();