1.1 --- a/src/org/sonews/storage/impl/DrupalDatabase.java Tue Oct 11 01:17:30 2011 +0200
1.2 +++ b/src/org/sonews/storage/impl/DrupalDatabase.java Tue Oct 11 16:17:51 2011 +0200
1.3 @@ -26,10 +26,13 @@
1.4 import java.sql.Statement;
1.5 import java.util.ArrayList;
1.6 import java.util.Collections;
1.7 +import java.util.Date;
1.8 import java.util.List;
1.9 import java.util.logging.Level;
1.10 import java.util.logging.Logger;
1.11 +import javax.mail.internet.MailDateFormat;
1.12 import javax.mail.internet.MimeUtility;
1.13 +import org.apache.commons.codec.net.BCodec;
1.14 import org.apache.commons.codec.net.QuotedPrintableCodec;
1.15 import org.sonews.config.Config;
1.16 import org.sonews.feed.Subscription;
1.17 @@ -47,12 +50,15 @@
1.18 public class DrupalDatabase implements Storage {
1.19
1.20 private static final Logger log = Logger.getLogger(DrupalDatabase.class.getName());
1.21 + public static final String CHARSET = "UTF-8";
1.22 public static final String CRLF = "\r\n";
1.23 public static final int MAX_RESTARTS = 2;
1.24 /** How many times the database connection was reinitialized */
1.25 protected int restarts = 0;
1.26 protected Connection conn = null;
1.27 - private QuotedPrintableCodec qpc = new QuotedPrintableCodec("UTF-8");
1.28 + private QuotedPrintableCodec qpc = new QuotedPrintableCodec(CHARSET);
1.29 + // TODO: správná doména
1.30 + private String myDomain = "kinderporno.cz";
1.31
1.32 public DrupalDatabase() throws StorageBackendException {
1.33 connectDatabase();
1.34 @@ -102,12 +108,12 @@
1.35
1.36 /**
1.37 *
1.38 - * @param messageID {0}-{1}-{2}@domain.tld where {0} is nntp_id and {1} is group_id and {2} is group_name
1.39 + * @param messageID <{0}-{1}-{2}@domain.tld> where {0} is nntp_id and {1} is group_id and {2} is group_name
1.40 * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid
1.41 */
1.42 private static String[] parseMessageID(String messageID) {
1.43 - if (messageID.matches("[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+")) {
1.44 - return messageID.split("@")[0].split("\\-");
1.45 + if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) {
1.46 + return messageID.substring(1).split("@")[0].split("\\-");
1.47 } else {
1.48 return null;
1.49 }
1.50 @@ -140,33 +146,57 @@
1.51 }
1.52 }
1.53
1.54 - private static String constructHeaders(ResultSet rs) throws SQLException, UnsupportedEncodingException {
1.55 + private static String constructMessageId(int articleID, int groupID, String groupName, String domainName) {
1.56 + StringBuilder sb = new StringBuilder();
1.57 + sb.append("<");
1.58 + sb.append(articleID);
1.59 + sb.append("-");
1.60 + sb.append(groupID);
1.61 + sb.append("-");
1.62 + sb.append(groupName);
1.63 + sb.append("@");
1.64 + sb.append(domainName);
1.65 + sb.append(">");
1.66 + return sb.toString();
1.67 + }
1.68 +
1.69 + /**
1.70 + *
1.71 + * @param sb header list to be appended with new header. List must be terminated by line end.
1.72 + * @param key header name (without : and space)
1.73 + * @param value header value
1.74 + * @param encode true if value should be encoded/escaped before appending
1.75 + * @throws UnsupportedEncodingException
1.76 + */
1.77 + private static void addHeader(StringBuilder sb, String key, String value, boolean encode) throws UnsupportedEncodingException {
1.78 + sb.append(key);
1.79 + sb.append(": ");
1.80 + if (encode) {
1.81 + sb.append(MimeUtility.encodeWord(value));
1.82 + } else {
1.83 + sb.append(value);
1.84 + }
1.85 + sb.append(CRLF);
1.86 + }
1.87 +
1.88 + private String constructHeaders(ResultSet rs) throws SQLException, UnsupportedEncodingException {
1.89 StringBuilder sb = new StringBuilder();
1.90
1.91 - sb.append("Message-id: <");
1.92 - sb.append(rs.getInt("id"));
1.93 - sb.append("-");
1.94 - sb.append(rs.getInt("group_id"));
1.95 - sb.append("-");
1.96 - sb.append(rs.getString("group_name"));
1.97 - sb.append("@");
1.98 - sb.append("nntp.kinderporno.cz>");
1.99 - sb.append(CRLF);
1.100 + addHeader(sb, "Message-id", constructMessageId(rs.getInt("id"), rs.getInt("group_id"), rs.getString("group_name"), myDomain), false);
1.101 + addHeader(sb, "From", MimeUtility.encodeWord(rs.getString("sender_name")) + " <>", false);
1.102 + addHeader(sb, "Subject", rs.getString("subject"), true);
1.103 + /** TODO: správný formát data: */
1.104 + addHeader(sb, "Date", MailDateFormat.getInstance().format(new Date(rs.getLong("created") * 1000)), false);
1.105 + addHeader(sb, "Content-Type", "text/html; charset=" + CHARSET, false);
1.106 + addHeader(sb, "Content-Transfer-Encoding", "quoted-printable", false);
1.107 + //addHeader(sb, "Content-Transfer-Encoding", "base64", false);
1.108
1.109 - sb.append("From: ");
1.110 - sb.append(MimeUtility.encodeWord(rs.getString("sender_name")));
1.111 - sb.append(" <>");
1.112 - sb.append(CRLF);
1.113 -
1.114 - sb.append("Subject: ");
1.115 - sb.append(MimeUtility.encodeWord(rs.getString("subject")));
1.116 - sb.append(CRLF);
1.117 -
1.118 -
1.119 - sb.append("Content-Type: text/html; charset=UTF-8");
1.120 - sb.append(CRLF);
1.121 - sb.append("Content-Transfer-Encoding: quoted-printable");
1.122 - sb.append(CRLF);
1.123 + Integer parentID = rs.getInt("parent_id");
1.124 + if (parentID != null && parentID > 0) {
1.125 + String parentMessageID = constructMessageId(parentID, rs.getInt("group_id"), rs.getString("group_name"), myDomain);
1.126 + addHeader(sb, "In-Reply-To", parentMessageID, false);
1.127 + addHeader(sb, "References", parentMessageID, false);
1.128 + }
1.129
1.130 return sb.toString();
1.131 }
1.132 @@ -243,7 +273,10 @@
1.133
1.134 if (rs.next()) {
1.135 String headers = constructHeaders(rs);
1.136 + // TODO: fold?
1.137 + BCodec bc = new BCodec(CHARSET);
1.138 byte[] body = qpc.encode(rs.getString("text")).getBytes();
1.139 + //byte[] body = bc.encode(rs.getString("text")).getBytes();
1.140
1.141 return new Article(headers, body);
1.142 } else {
1.143 @@ -261,7 +294,8 @@
1.144 PreparedStatement ps = null;
1.145 ResultSet rs = null;
1.146 try {
1.147 - ps = conn.prepareStatement("SELECT * FROM nntp_article WHERE group_id = ? AND id >= ? AND id <= ?");
1.148 + // TODO: je nutné řazení?
1.149 + ps = conn.prepareStatement("SELECT * FROM nntp_article WHERE group_id = ? AND id >= ? AND id <= ? ORDER BY id");
1.150 ps.setLong(1, group.getInternalID());
1.151 ps.setLong(2, first);
1.152 ps.setLong(3, last);