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 +}