diff -r d54786065fa3 -r d843b4fee5dc src/org/sonews/storage/DrupalMessage.java --- a/src/org/sonews/storage/DrupalMessage.java Wed Oct 19 21:40:51 2011 +0200 +++ b/src/org/sonews/storage/DrupalMessage.java Thu Oct 20 09:59:04 2011 +0200 @@ -18,6 +18,7 @@ package org.sonews.storage; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -45,6 +46,7 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.sonews.daemon.NNTPConnection; import org.sonews.util.io.Resource; /** @@ -66,6 +68,8 @@ private static final String XHTML_CONTENT_TYPE = "text/html; charset=" + CHARSET; private static final String ZNAKČKA_KONCE_ŘÁDKU = "◆"; private String messageID; + private Long parentID; + private Long groupID; /** * Constructs MIME message from SQL result. @@ -75,13 +79,14 @@ public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException { super(Session.getDefaultInstance(System.getProperties())); - addHeader("Message-id", constructMessageId(rs.getInt("id"), rs.getInt("group_id"), rs.getString("group_name"), myDomain)); + groupID = rs.getLong("group_id"); + addHeader("Message-id", constructMessageId(rs.getInt("id"), groupID, rs.getString("group_name"), myDomain)); addHeader("Newsgroups", rs.getString("group_name")); setFrom(new InternetAddress(rs.getString("sender_email"), rs.getString("sender_name"))); setSubject(rs.getString("subject")); setSentDate(new Date(rs.getLong("created"))); - int parentID = rs.getInt("parent_id"); + parentID = rs.getLong("parent_id"); if (parentID > 0) { String parentMessageID = constructMessageId(parentID, rs.getInt("group_id"), rs.getString("group_name"), myDomain); addHeader("In-Reply-To", parentMessageID); @@ -116,6 +121,38 @@ } } + /** + * Constructs MIME message from article posted by user. + * @param article article that came through NNTP. + * @throws MessagingException + */ + public DrupalMessage(Article article) throws MessagingException { + super(Session.getDefaultInstance(System.getProperties()), serializeArticle(article)); + + String[] parentHeaders = getHeader("In-Reply-To"); + if (parentHeaders.length == 1) { + String parentMessageID = parentHeaders[0]; + parentID = parseArticleID(parentMessageID); + groupID = parseGroupID(parentMessageID); + } else { + throw new MessagingException("Message posted by user must have exactly one In-Reply-To header."); + } + } + + private static InputStream serializeArticle(Article a) { + byte articleHeaders[] = a.getHeaderSource().getBytes(); + byte delimiter[] = (NNTPConnection.NEWLINE + NNTPConnection.NEWLINE).getBytes(); + byte body[] = a.getBody(); + + byte message[] = new byte[articleHeaders.length + delimiter.length + body.length]; + + System.arraycopy(articleHeaders, 0, message, 0, articleHeaders.length); + System.arraycopy(delimiter, 0, message, articleHeaders.length, delimiter.length); + System.arraycopy(body, 0, message, articleHeaders.length + delimiter.length, body.length); + + return new ByteArrayInputStream(message); + } + private String readPlainText(ResultSet rs, String xhtmlText) { try { TransformerFactory tf = TransformerFactory.newInstance(); @@ -255,7 +292,7 @@ return výsledek.toString(); } - private static String constructMessageId(int articleID, int groupID, String groupName, String domainName) { + public static String constructMessageId(long articleID, long groupID, String groupName, String domainName) { StringBuilder sb = new StringBuilder(); sb.append("<"); sb.append(articleID); @@ -269,6 +306,54 @@ return sb.toString(); } + /** + * @return article ID of parent of this message | or null, if this is root article and not reply to another one + */ + public Long getParentID() { + return parentID; + } + + /** + * @return group ID of this message | or null, if this message is not reply to any other one – which is wrong because we have to know the group + */ + public Long getGroupID() { + return groupID; + } + + /** + * + * @param messageID <{0}-{1}-{2}@domain.tld> where {0} is nntp_id and {1} is group_id and {2} is group_name + * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid + */ + private static String[] parseMessageID(String messageID) { + if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) { + return messageID.substring(1).split("@")[0].split("\\-"); + } else { + return null; + } + } + + public static Long parseArticleID(String messageID) { + String[] localPart = parseMessageID(messageID); + if (localPart == null) { + return null; + } else { + return Long.parseLong(localPart[0]); + } + } + + public static Long parseGroupID(String messageID) { + String[] localPart = parseMessageID(messageID); + if (localPart == null) { + return null; + } else { + return Long.parseLong(localPart[1]); + // If needed: + // parseGroupName() will be same as this method, just with: + // return localPart[2]; + } + } + @Override public void setHeader(String name, String value) throws MessagingException { super.setHeader(name, value);