1.1 --- a/src/org/sonews/storage/DrupalMessage.java Wed Oct 19 21:40:51 2011 +0200
1.2 +++ b/src/org/sonews/storage/DrupalMessage.java Thu Oct 20 09:59:04 2011 +0200
1.3 @@ -18,6 +18,7 @@
1.4 package org.sonews.storage;
1.5
1.6 import java.io.BufferedReader;
1.7 +import java.io.ByteArrayInputStream;
1.8 import java.io.ByteArrayOutputStream;
1.9 import java.io.IOException;
1.10 import java.io.InputStream;
1.11 @@ -45,6 +46,7 @@
1.12 import javax.xml.transform.TransformerFactory;
1.13 import javax.xml.transform.stream.StreamResult;
1.14 import javax.xml.transform.stream.StreamSource;
1.15 +import org.sonews.daemon.NNTPConnection;
1.16 import org.sonews.util.io.Resource;
1.17
1.18 /**
1.19 @@ -66,6 +68,8 @@
1.20 private static final String XHTML_CONTENT_TYPE = "text/html; charset=" + CHARSET;
1.21 private static final String ZNAKČKA_KONCE_ŘÁDKU = "◆";
1.22 private String messageID;
1.23 + private Long parentID;
1.24 + private Long groupID;
1.25
1.26 /**
1.27 * Constructs MIME message from SQL result.
1.28 @@ -75,13 +79,14 @@
1.29 public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException {
1.30 super(Session.getDefaultInstance(System.getProperties()));
1.31
1.32 - addHeader("Message-id", constructMessageId(rs.getInt("id"), rs.getInt("group_id"), rs.getString("group_name"), myDomain));
1.33 + groupID = rs.getLong("group_id");
1.34 + addHeader("Message-id", constructMessageId(rs.getInt("id"), groupID, rs.getString("group_name"), myDomain));
1.35 addHeader("Newsgroups", rs.getString("group_name"));
1.36 setFrom(new InternetAddress(rs.getString("sender_email"), rs.getString("sender_name")));
1.37 setSubject(rs.getString("subject"));
1.38 setSentDate(new Date(rs.getLong("created")));
1.39
1.40 - int parentID = rs.getInt("parent_id");
1.41 + parentID = rs.getLong("parent_id");
1.42 if (parentID > 0) {
1.43 String parentMessageID = constructMessageId(parentID, rs.getInt("group_id"), rs.getString("group_name"), myDomain);
1.44 addHeader("In-Reply-To", parentMessageID);
1.45 @@ -116,6 +121,38 @@
1.46 }
1.47 }
1.48
1.49 + /**
1.50 + * Constructs MIME message from article posted by user.
1.51 + * @param article article that came through NNTP.
1.52 + * @throws MessagingException
1.53 + */
1.54 + public DrupalMessage(Article article) throws MessagingException {
1.55 + super(Session.getDefaultInstance(System.getProperties()), serializeArticle(article));
1.56 +
1.57 + String[] parentHeaders = getHeader("In-Reply-To");
1.58 + if (parentHeaders.length == 1) {
1.59 + String parentMessageID = parentHeaders[0];
1.60 + parentID = parseArticleID(parentMessageID);
1.61 + groupID = parseGroupID(parentMessageID);
1.62 + } else {
1.63 + throw new MessagingException("Message posted by user must have exactly one In-Reply-To header.");
1.64 + }
1.65 + }
1.66 +
1.67 + private static InputStream serializeArticle(Article a) {
1.68 + byte articleHeaders[] = a.getHeaderSource().getBytes();
1.69 + byte delimiter[] = (NNTPConnection.NEWLINE + NNTPConnection.NEWLINE).getBytes();
1.70 + byte body[] = a.getBody();
1.71 +
1.72 + byte message[] = new byte[articleHeaders.length + delimiter.length + body.length];
1.73 +
1.74 + System.arraycopy(articleHeaders, 0, message, 0, articleHeaders.length);
1.75 + System.arraycopy(delimiter, 0, message, articleHeaders.length, delimiter.length);
1.76 + System.arraycopy(body, 0, message, articleHeaders.length + delimiter.length, body.length);
1.77 +
1.78 + return new ByteArrayInputStream(message);
1.79 + }
1.80 +
1.81 private String readPlainText(ResultSet rs, String xhtmlText) {
1.82 try {
1.83 TransformerFactory tf = TransformerFactory.newInstance();
1.84 @@ -255,7 +292,7 @@
1.85 return výsledek.toString();
1.86 }
1.87
1.88 - private static String constructMessageId(int articleID, int groupID, String groupName, String domainName) {
1.89 + public static String constructMessageId(long articleID, long groupID, String groupName, String domainName) {
1.90 StringBuilder sb = new StringBuilder();
1.91 sb.append("<");
1.92 sb.append(articleID);
1.93 @@ -269,6 +306,54 @@
1.94 return sb.toString();
1.95 }
1.96
1.97 + /**
1.98 + * @return article ID of parent of this message | or null, if this is root article and not reply to another one
1.99 + */
1.100 + public Long getParentID() {
1.101 + return parentID;
1.102 + }
1.103 +
1.104 + /**
1.105 + * @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
1.106 + */
1.107 + public Long getGroupID() {
1.108 + return groupID;
1.109 + }
1.110 +
1.111 + /**
1.112 + *
1.113 + * @param messageID <{0}-{1}-{2}@domain.tld> where {0} is nntp_id and {1} is group_id and {2} is group_name
1.114 + * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid
1.115 + */
1.116 + private static String[] parseMessageID(String messageID) {
1.117 + if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) {
1.118 + return messageID.substring(1).split("@")[0].split("\\-");
1.119 + } else {
1.120 + return null;
1.121 + }
1.122 + }
1.123 +
1.124 + public static Long parseArticleID(String messageID) {
1.125 + String[] localPart = parseMessageID(messageID);
1.126 + if (localPart == null) {
1.127 + return null;
1.128 + } else {
1.129 + return Long.parseLong(localPart[0]);
1.130 + }
1.131 + }
1.132 +
1.133 + public static Long parseGroupID(String messageID) {
1.134 + String[] localPart = parseMessageID(messageID);
1.135 + if (localPart == null) {
1.136 + return null;
1.137 + } else {
1.138 + return Long.parseLong(localPart[1]);
1.139 + // If needed:
1.140 + // parseGroupName() will be same as this method, just with:
1.141 + // return localPart[2];
1.142 + }
1.143 + }
1.144 +
1.145 @Override
1.146 public void setHeader(String name, String value) throws MessagingException {
1.147 super.setHeader(name, value);