src/org/sonews/storage/DrupalMessage.java
changeset 72 aae4b4688700
child 74 e1244384cc6f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/org/sonews/storage/DrupalMessage.java	Wed Oct 12 00:11:25 2011 +0200
     1.3 @@ -0,0 +1,193 @@
     1.4 +/*
     1.5 + *   SONEWS News Server
     1.6 + *   see AUTHORS for the list of contributors
     1.7 + *
     1.8 + *   This program is free software: you can redistribute it and/or modify
     1.9 + *   it under the terms of the GNU General Public License as published by
    1.10 + *   the Free Software Foundation, either version 3 of the License, or
    1.11 + *   (at your option) any later version.
    1.12 + *
    1.13 + *   This program is distributed in the hope that it will be useful,
    1.14 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.16 + *   GNU General Public License for more details.
    1.17 + *
    1.18 + *   You should have received a copy of the GNU General Public License
    1.19 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    1.20 + */
    1.21 +package org.sonews.storage;
    1.22 +
    1.23 +import java.io.ByteArrayOutputStream;
    1.24 +import java.io.IOException;
    1.25 +import java.io.UnsupportedEncodingException;
    1.26 +import java.sql.ResultSet;
    1.27 +import java.sql.SQLException;
    1.28 +import java.util.ArrayList;
    1.29 +import java.util.Date;
    1.30 +import java.util.Enumeration;
    1.31 +import javax.mail.Header;
    1.32 +import javax.mail.MessagingException;
    1.33 +import javax.mail.Multipart;
    1.34 +import javax.mail.Session;
    1.35 +import javax.mail.internet.InternetAddress;
    1.36 +import javax.mail.internet.MimeBodyPart;
    1.37 +import javax.mail.internet.MimeMessage;
    1.38 +import javax.mail.internet.MimeMultipart;
    1.39 +
    1.40 +/**
    1.41 + * This is MimeMessage which enables custom Message-ID header
    1.42 + * (this header will not be overwritten by the default one like in MimeMessage).
    1.43 + * 
    1.44 + * Also add header and body separate serialization.
    1.45 + * 
    1.46 + * And can be deserialized from SQL ResultSet
    1.47 + * 
    1.48 + * @author František Kučera (frantovo.cz)
    1.49 + */
    1.50 +public class DrupalMessage extends MimeMessage {
    1.51 +
    1.52 +	private static final String MESSAGE_ID_HEADER = "Message-ID";
    1.53 +	private static final String CRLF = "\r\n";
    1.54 +	public static final String CHARSET = "UTF-8";
    1.55 +	private static final String XHTML_CONTENT_TYPE = "text/html; charset=" + CHARSET;
    1.56 +	private String messageID;
    1.57 +
    1.58 +	/**
    1.59 +	 * Constructs MIME message from SQL result.
    1.60 +	 * @param rs ResultSet containing message data. No {@link ResultSet#next()} will be called, just values from current row will be read.
    1.61 +	 * @param constructBody true if whole message should be constructed | false if we need only message headers (body will be dummy).
    1.62 +	 */
    1.63 +	public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException {
    1.64 +		super(Session.getDefaultInstance(System.getProperties()));
    1.65 +
    1.66 +		addHeader("Message-id", constructMessageId(rs.getInt("id"), rs.getInt("group_id"), rs.getString("group_name"), myDomain));
    1.67 +		addHeader("Newsgroups", rs.getString("group_name"));
    1.68 +		setFrom(new InternetAddress("anonym@example.com", rs.getString("sender_name")));
    1.69 +		setSubject(rs.getString("subject"));
    1.70 +		setSentDate(new Date(rs.getLong("created")));
    1.71 +		
    1.72 +		Integer parentID = rs.getInt("parent_id");
    1.73 +		if (parentID != null && parentID > 0) {
    1.74 +			String parentMessageID = constructMessageId(parentID, rs.getInt("group_id"), rs.getString("group_name"), myDomain);
    1.75 +			addHeader("In-Reply-To", parentMessageID);
    1.76 +			addHeader("References", parentMessageID);
    1.77 +		}
    1.78 +
    1.79 +		if (constructBody) {
    1.80 +			Multipart multipart = new MimeMultipart("alternative");
    1.81 +			setContent(multipart);
    1.82 +
    1.83 +			/** TODO: Plain text part */
    1.84 +			MimeBodyPart textPart = new MimeBodyPart();
    1.85 +			multipart.addBodyPart(textPart);
    1.86 +			textPart.setText(readPlainText(rs));
    1.87 +
    1.88 +			/** TODO: XHTML part */
    1.89 +			MimeBodyPart htmlPart = new MimeBodyPart();
    1.90 +			multipart.addBodyPart(htmlPart);
    1.91 +			htmlPart.setContent(readXhtmlText(rs), XHTML_CONTENT_TYPE);
    1.92 +		} else {
    1.93 +			setText("");
    1.94 +		}
    1.95 +	}
    1.96 +
    1.97 +	private String readPlainText(ResultSet rs) {
    1.98 +		/**
    1.99 +		 * TODO: převést na prostý text
   1.100 +		 */
   1.101 +		return "TODO: obyčejný text";
   1.102 +	}
   1.103 +
   1.104 +	private String readXhtmlText(ResultSet rs) {
   1.105 +		/**
   1.106 +		 * TODO: převést na XHTML
   1.107 +		 */
   1.108 +		return "<html><body>TODO: tady bude nějaký <strong>(X)HTML</strong></body></html>";
   1.109 +	}
   1.110 +
   1.111 +	private static String constructMessageId(int articleID, int groupID, String groupName, String domainName) {
   1.112 +		StringBuilder sb = new StringBuilder();
   1.113 +		sb.append("<");
   1.114 +		sb.append(articleID);
   1.115 +		sb.append("-");
   1.116 +		sb.append(groupID);
   1.117 +		sb.append("-");
   1.118 +		sb.append(groupName);
   1.119 +		sb.append("@");
   1.120 +		sb.append(domainName);
   1.121 +		sb.append(">");
   1.122 +		return sb.toString();
   1.123 +	}
   1.124 +
   1.125 +	@Override
   1.126 +	public void setHeader(String name, String value) throws MessagingException {
   1.127 +		super.setHeader(name, value);
   1.128 +
   1.129 +		if (MESSAGE_ID_HEADER.equalsIgnoreCase(name)) {
   1.130 +			messageID = value;
   1.131 +		}
   1.132 +	}
   1.133 +
   1.134 +	@Override
   1.135 +	public final void addHeader(String name, String value) throws MessagingException {
   1.136 +		super.addHeader(name, value);
   1.137 +
   1.138 +		if (MESSAGE_ID_HEADER.equalsIgnoreCase(name)) {
   1.139 +			messageID = value;
   1.140 +		}
   1.141 +	}
   1.142 +
   1.143 +	@Override
   1.144 +	public void removeHeader(String name) throws MessagingException {
   1.145 +		super.removeHeader(name);
   1.146 +
   1.147 +		if (MESSAGE_ID_HEADER.equalsIgnoreCase(name)) {
   1.148 +			messageID = null;
   1.149 +		}
   1.150 +	}
   1.151 +
   1.152 +	public void setMessageID(String messageID) {
   1.153 +		this.messageID = messageID;
   1.154 +	}
   1.155 +
   1.156 +	@Override
   1.157 +	protected void updateMessageID() throws MessagingException {
   1.158 +		if (messageID == null) {
   1.159 +			super.updateMessageID();
   1.160 +		} else {
   1.161 +			setHeader(MESSAGE_ID_HEADER, messageID);
   1.162 +		}
   1.163 +	}
   1.164 +
   1.165 +	/**
   1.166 +	 * Call {@link #saveChanges()} before this method, if you want all headers including such ones like:
   1.167 +	 * 
   1.168 +	 * <pre>MIME-Version: 1.0
   1.169 +	 *Content-Type: multipart/alternative;</pre>
   1.170 +	 * 
   1.171 +	 * @return serialized headers
   1.172 +	 * @throws MessagingException if getAllHeaders() fails
   1.173 +	 */
   1.174 +	public String getHeaders() throws MessagingException {
   1.175 +		StringBuilder sb = new StringBuilder();
   1.176 +		for (Enumeration eh = getAllHeaderLines(); eh.hasMoreElements();) {
   1.177 +			sb.append(eh.nextElement());
   1.178 +			sb.append(CRLF);
   1.179 +		}
   1.180 +		return sb.toString();
   1.181 +	}
   1.182 +
   1.183 +	public byte[] getBody() throws IOException, MessagingException {
   1.184 +		saveChanges();
   1.185 +
   1.186 +		ArrayList<String> skipHeaders = new ArrayList<String>();
   1.187 +		for (Enumeration eh = getAllHeaders(); eh.hasMoreElements();) {
   1.188 +			Header h = (Header) eh.nextElement();
   1.189 +			skipHeaders.add(h.getName());
   1.190 +		}
   1.191 +
   1.192 +		ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
   1.193 +		writeTo(baos, skipHeaders.toArray(new String[skipHeaders.size()]));
   1.194 +		return baos.toByteArray();
   1.195 +	}
   1.196 +}