Article(javax.mail.Message) now has a safe method to read the byte body from the given message object (fixes #16).
1.1 --- a/AUTHORS Wed May 12 11:18:02 2010 +0200
1.2 +++ b/AUTHORS Sun Aug 29 17:03:21 2010 +0200
1.3 @@ -7,9 +7,13 @@
1.4
1.5 sonews News Server
1.6 -------------------
1.7 -Copyright (c) 2009 by Christian Lins <christian.lins@fh-osnabrueck.de>
1.8 +Copyright (c) 2009, 2010 by
1.9
1.10 -based partly upon
1.11 +Christian Lins <christian.lins@fh-osnabrueck.de>
1.12 +Bernd Eilers <bernd.eilers@sun.com>
1.13 +
1.14 +
1.15 +sonews based partly upon
1.16
1.17 Neat NNTP Daemon (n3tpd)
1.18 ------------------------
2.1 --- a/org/sonews/storage/Article.java Wed May 12 11:18:02 2010 +0200
2.2 +++ b/org/sonews/storage/Article.java Sun Aug 29 17:03:21 2010 +0200
2.3 @@ -21,8 +21,6 @@
2.4 import java.io.ByteArrayInputStream;
2.5 import java.io.ByteArrayOutputStream;
2.6 import java.io.IOException;
2.7 -import java.io.InputStream;
2.8 -import java.nio.charset.Charset;
2.9 import java.security.MessageDigest;
2.10 import java.security.NoSuchAlgorithmException;
2.11 import java.util.UUID;
2.12 @@ -32,10 +30,8 @@
2.13 import javax.mail.Header;
2.14 import javax.mail.Message;
2.15 import javax.mail.MessagingException;
2.16 -import javax.mail.Multipart;
2.17 import javax.mail.internet.InternetHeaders;
2.18 import org.sonews.config.Config;
2.19 -import org.sonews.util.Log;
2.20
2.21 /**
2.22 * Represents a newsgroup article.
2.23 @@ -97,7 +93,7 @@
2.24
2.25 /**
2.26 * Creates an Article instance using the data from the javax.mail.Message
2.27 - * object.
2.28 + * object. This constructor is called by the Mailinglist gateway.
2.29 * @see javax.mail.Message
2.30 * @param msg
2.31 * @throws IOException
2.32 @@ -113,61 +109,25 @@
2.33 final Header header = (Header)e.nextElement();
2.34 this.headers.addHeader(header.getName(), header.getValue());
2.35 }
2.36 -
2.37 - // The "content" of the message can be a String if it's a simple text/plain
2.38 - // message, a Multipart object or an InputStream if the content is unknown.
2.39 - final Object content = msg.getContent();
2.40 - if(content instanceof String)
2.41 - {
2.42 - this.body = ((String)content).getBytes(getBodyCharset());
2.43 - }
2.44 - else if(content instanceof Multipart) // probably subclass MimeMultipart
2.45 - {
2.46 - // We're are not interested in the different parts of the MultipartMessage,
2.47 - // so we simply read in all data which *can* be huge.
2.48 - InputStream in = msg.getInputStream();
2.49 - this.body = readContent(in);
2.50 - }
2.51 - else if(content instanceof InputStream)
2.52 - {
2.53 - // The message format is unknown to the Message class, but we can
2.54 - // simply read in the whole message data.
2.55 - this.body = readContent((InputStream)content);
2.56 - }
2.57 - else
2.58 - {
2.59 - // Unknown content is probably a malformed mail we should skip.
2.60 - // On the other hand we produce an inconsistent mail mirror, but no
2.61 - // mail system must transport invalid content.
2.62 - Log.get().severe("Skipping message due to unknown content. Throwing exception...");
2.63 - MessagingException ex = new MessagingException("Unknown content: " + content);
2.64 - Log.get().throwing("Article.java", "<init>", ex);
2.65 - throw ex;
2.66 - }
2.67 +
2.68 + // Reads the raw byte body using Message.writeTo(OutputStream out)
2.69 + this.body = readContent(msg);
2.70
2.71 // Validate headers
2.72 validateHeaders();
2.73 }
2.74
2.75 /**
2.76 - * Reads from the given InputString into a byte array.
2.77 - * TODO: Move this generalized method to org.sonews.util.io.Resource.
2.78 + * Reads from the given Message into a byte array.
2.79 * @param in
2.80 * @return
2.81 * @throws IOException
2.82 */
2.83 - private byte[] readContent(InputStream in)
2.84 - throws IOException
2.85 + private byte[] readContent(Message in)
2.86 + throws IOException, MessagingException
2.87 {
2.88 ByteArrayOutputStream out = new ByteArrayOutputStream();
2.89 -
2.90 - int b = in.read();
2.91 - while(b >= 0)
2.92 - {
2.93 - out.write(b);
2.94 - b = in.read();
2.95 - }
2.96 -
2.97 + in.writeTo(out);
2.98 return out.toByteArray();
2.99 }
2.100
2.101 @@ -226,51 +186,6 @@
2.102 {
2.103 return body;
2.104 }
2.105 -
2.106 - /**
2.107 - * @return Charset of the body text
2.108 - */
2.109 - private Charset getBodyCharset()
2.110 - {
2.111 - // We espect something like
2.112 - // Content-Type: text/plain; charset=ISO-8859-15
2.113 - String contentType = getHeader(Headers.CONTENT_TYPE)[0];
2.114 - int idxCharsetStart = contentType.indexOf("charset=") + "charset=".length();
2.115 - int idxCharsetEnd = contentType.indexOf(";", idxCharsetStart);
2.116 -
2.117 - String charsetName = "UTF-8";
2.118 - if(idxCharsetStart >= 0 && idxCharsetStart < contentType.length())
2.119 - {
2.120 - if(idxCharsetEnd < 0)
2.121 - {
2.122 - charsetName = contentType.substring(idxCharsetStart);
2.123 - }
2.124 - else
2.125 - {
2.126 - charsetName = contentType.substring(idxCharsetStart, idxCharsetEnd);
2.127 - }
2.128 - }
2.129 -
2.130 - // Sometimes there are '"' around the name
2.131 - if(charsetName.length() > 2 &&
2.132 - charsetName.charAt(0) == '"' && charsetName.endsWith("\""))
2.133 - {
2.134 - charsetName = charsetName.substring(1, charsetName.length() - 2);
2.135 - }
2.136 -
2.137 - // Create charset
2.138 - Charset charset = Charset.forName("UTF-8"); // This MUST be supported by JVM
2.139 - try
2.140 - {
2.141 - charset = Charset.forName(charsetName);
2.142 - }
2.143 - catch(Exception ex)
2.144 - {
2.145 - Log.get().severe(ex.getMessage());
2.146 - Log.get().severe("Article.getBodyCharset(): Unknown charset: " + charsetName);
2.147 - }
2.148 - return charset;
2.149 - }
2.150
2.151 /**
2.152 * @return Numerical IDs of the newsgroups this Article belongs to.