src/org/sonews/storage/DrupalMessage.java
changeset 102 d843b4fee5dc
parent 100 08c9fb6fb017
child 103 a788bf0e1080
     1.1 --- a/src/org/sonews/storage/DrupalMessage.java	Wed Oct 19 17:23:53 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 &lt;{0}-{1}-{2}@domain.tld&gt; 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);