src/org/sonews/storage/DrupalMessage.java
author František Kučera <franta-hg@frantovo.cz>
Wed Oct 12 00:11:25 2011 +0200 (2011-10-12)
changeset 72 aae4b4688700
child 74 e1244384cc6f
permissions -rw-r--r--
Drupal: zprávy jsou multipart/alternative – jak prostý text, tak XHTML. TODO: filtry prostého textu a XHTML
zatím se do všech zpráv vkládá stejný vycpávkový text.
     1 /*
     2  *   SONEWS News Server
     3  *   see AUTHORS for the list of contributors
     4  *
     5  *   This program is free software: you can redistribute it and/or modify
     6  *   it under the terms of the GNU General Public License as published by
     7  *   the Free Software Foundation, either version 3 of the License, or
     8  *   (at your option) any later version.
     9  *
    10  *   This program is distributed in the hope that it will be useful,
    11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  *   GNU General Public License for more details.
    14  *
    15  *   You should have received a copy of the GNU General Public License
    16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  */
    18 package org.sonews.storage;
    19 
    20 import java.io.ByteArrayOutputStream;
    21 import java.io.IOException;
    22 import java.io.UnsupportedEncodingException;
    23 import java.sql.ResultSet;
    24 import java.sql.SQLException;
    25 import java.util.ArrayList;
    26 import java.util.Date;
    27 import java.util.Enumeration;
    28 import javax.mail.Header;
    29 import javax.mail.MessagingException;
    30 import javax.mail.Multipart;
    31 import javax.mail.Session;
    32 import javax.mail.internet.InternetAddress;
    33 import javax.mail.internet.MimeBodyPart;
    34 import javax.mail.internet.MimeMessage;
    35 import javax.mail.internet.MimeMultipart;
    36 
    37 /**
    38  * This is MimeMessage which enables custom Message-ID header
    39  * (this header will not be overwritten by the default one like in MimeMessage).
    40  * 
    41  * Also add header and body separate serialization.
    42  * 
    43  * And can be deserialized from SQL ResultSet
    44  * 
    45  * @author František Kučera (frantovo.cz)
    46  */
    47 public class DrupalMessage extends MimeMessage {
    48 
    49 	private static final String MESSAGE_ID_HEADER = "Message-ID";
    50 	private static final String CRLF = "\r\n";
    51 	public static final String CHARSET = "UTF-8";
    52 	private static final String XHTML_CONTENT_TYPE = "text/html; charset=" + CHARSET;
    53 	private String messageID;
    54 
    55 	/**
    56 	 * Constructs MIME message from SQL result.
    57 	 * @param rs ResultSet containing message data. No {@link ResultSet#next()} will be called, just values from current row will be read.
    58 	 * @param constructBody true if whole message should be constructed | false if we need only message headers (body will be dummy).
    59 	 */
    60 	public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException {
    61 		super(Session.getDefaultInstance(System.getProperties()));
    62 
    63 		addHeader("Message-id", constructMessageId(rs.getInt("id"), rs.getInt("group_id"), rs.getString("group_name"), myDomain));
    64 		addHeader("Newsgroups", rs.getString("group_name"));
    65 		setFrom(new InternetAddress("anonym@example.com", rs.getString("sender_name")));
    66 		setSubject(rs.getString("subject"));
    67 		setSentDate(new Date(rs.getLong("created")));
    68 		
    69 		Integer parentID = rs.getInt("parent_id");
    70 		if (parentID != null && parentID > 0) {
    71 			String parentMessageID = constructMessageId(parentID, rs.getInt("group_id"), rs.getString("group_name"), myDomain);
    72 			addHeader("In-Reply-To", parentMessageID);
    73 			addHeader("References", parentMessageID);
    74 		}
    75 
    76 		if (constructBody) {
    77 			Multipart multipart = new MimeMultipart("alternative");
    78 			setContent(multipart);
    79 
    80 			/** TODO: Plain text part */
    81 			MimeBodyPart textPart = new MimeBodyPart();
    82 			multipart.addBodyPart(textPart);
    83 			textPart.setText(readPlainText(rs));
    84 
    85 			/** TODO: XHTML part */
    86 			MimeBodyPart htmlPart = new MimeBodyPart();
    87 			multipart.addBodyPart(htmlPart);
    88 			htmlPart.setContent(readXhtmlText(rs), XHTML_CONTENT_TYPE);
    89 		} else {
    90 			setText("");
    91 		}
    92 	}
    93 
    94 	private String readPlainText(ResultSet rs) {
    95 		/**
    96 		 * TODO: převést na prostý text
    97 		 */
    98 		return "TODO: obyčejný text";
    99 	}
   100 
   101 	private String readXhtmlText(ResultSet rs) {
   102 		/**
   103 		 * TODO: převést na XHTML
   104 		 */
   105 		return "<html><body>TODO: tady bude nějaký <strong>(X)HTML</strong></body></html>";
   106 	}
   107 
   108 	private static String constructMessageId(int articleID, int groupID, String groupName, String domainName) {
   109 		StringBuilder sb = new StringBuilder();
   110 		sb.append("<");
   111 		sb.append(articleID);
   112 		sb.append("-");
   113 		sb.append(groupID);
   114 		sb.append("-");
   115 		sb.append(groupName);
   116 		sb.append("@");
   117 		sb.append(domainName);
   118 		sb.append(">");
   119 		return sb.toString();
   120 	}
   121 
   122 	@Override
   123 	public void setHeader(String name, String value) throws MessagingException {
   124 		super.setHeader(name, value);
   125 
   126 		if (MESSAGE_ID_HEADER.equalsIgnoreCase(name)) {
   127 			messageID = value;
   128 		}
   129 	}
   130 
   131 	@Override
   132 	public final void addHeader(String name, String value) throws MessagingException {
   133 		super.addHeader(name, value);
   134 
   135 		if (MESSAGE_ID_HEADER.equalsIgnoreCase(name)) {
   136 			messageID = value;
   137 		}
   138 	}
   139 
   140 	@Override
   141 	public void removeHeader(String name) throws MessagingException {
   142 		super.removeHeader(name);
   143 
   144 		if (MESSAGE_ID_HEADER.equalsIgnoreCase(name)) {
   145 			messageID = null;
   146 		}
   147 	}
   148 
   149 	public void setMessageID(String messageID) {
   150 		this.messageID = messageID;
   151 	}
   152 
   153 	@Override
   154 	protected void updateMessageID() throws MessagingException {
   155 		if (messageID == null) {
   156 			super.updateMessageID();
   157 		} else {
   158 			setHeader(MESSAGE_ID_HEADER, messageID);
   159 		}
   160 	}
   161 
   162 	/**
   163 	 * Call {@link #saveChanges()} before this method, if you want all headers including such ones like:
   164 	 * 
   165 	 * <pre>MIME-Version: 1.0
   166 	 *Content-Type: multipart/alternative;</pre>
   167 	 * 
   168 	 * @return serialized headers
   169 	 * @throws MessagingException if getAllHeaders() fails
   170 	 */
   171 	public String getHeaders() throws MessagingException {
   172 		StringBuilder sb = new StringBuilder();
   173 		for (Enumeration eh = getAllHeaderLines(); eh.hasMoreElements();) {
   174 			sb.append(eh.nextElement());
   175 			sb.append(CRLF);
   176 		}
   177 		return sb.toString();
   178 	}
   179 
   180 	public byte[] getBody() throws IOException, MessagingException {
   181 		saveChanges();
   182 
   183 		ArrayList<String> skipHeaders = new ArrayList<String>();
   184 		for (Enumeration eh = getAllHeaders(); eh.hasMoreElements();) {
   185 			Header h = (Header) eh.nextElement();
   186 			skipHeaders.add(h.getName());
   187 		}
   188 
   189 		ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
   190 		writeTo(baos, skipHeaders.toArray(new String[skipHeaders.size()]));
   191 		return baos.toByteArray();
   192 	}
   193 }