You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by do...@apache.org on 2013/08/22 17:29:58 UTC
svn commit: r1516486 [3/4] - in /james/hupa/trunk: ./ client/
client/src/main/java/org/apache/hupa/
client/src/main/java/org/apache/hupa/client/
client/src/main/java/org/apache/hupa/client/activity/
client/src/main/java/org/apache/hupa/client/ioc/ clie...
Added: james/hupa/trunk/mock/src/main/resources/mime/12.msg
URL: http://svn.apache.org/viewvc/james/hupa/trunk/mock/src/main/resources/mime/12.msg?rev=1516486&view=auto
==============================================================================
--- james/hupa/trunk/mock/src/main/resources/mime/12.msg (added)
+++ james/hupa/trunk/mock/src/main/resources/mime/12.msg Thu Aug 22 15:29:57 2013
@@ -0,0 +1,57 @@
+Delivered-To: mcdodot@gmail.com
+Received: by 10.60.131.212 with SMTP id oo20csp73659oeb;
+ Mon, 10 Jun 2013 08:49:12 -0700 (PDT)
+X-Received: by 10.205.22.196 with SMTP id qx4mr1610488bkb.57.1370879351744;
+ Mon, 10 Jun 2013 08:49:11 -0700 (PDT)
+Return-Path: <ec...@gmail.com>
+Received: from mail-bk0-x22a.google.com (mail-bk0-x22a.google.com [2a00:1450:4008:c01::22a])
+ by mx.google.com with ESMTPS id t2si950481bkh.191.2013.06.10.08.49.11
+ for <mc...@gmail.com>
+ (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
+ Mon, 10 Jun 2013 08:49:11 -0700 (PDT)
+Received-SPF: pass (google.com: domain of echowdx@gmail.com designates 2a00:1450:4008:c01::22a as permitted sender) client-ip=2a00:1450:4008:c01::22a;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of echowdx@gmail.com designates 2a00:1450:4008:c01::22a as permitted sender) smtp.mail=echowdx@gmail.com;
+ dkim=pass header.i=@gmail.com
+Received: by mail-bk0-x22a.google.com with SMTP id jk13so3448363bkc.1
+ for <mc...@gmail.com>; Mon, 10 Jun 2013 08:49:11 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=gmail.com; s=20120113;
+ h=message-id:date:from:user-agent:mime-version:to:subject
+ :x-chiaramail-content-pointer:x-chiaramail-content-key2
+ :x-chiaramail-content-server-name:x-chiaramail-content-server-port
+ :content-type:content-transfer-encoding;
+ bh=40fimkYYpXaLiVIKuTv2tLgUPaqUGA1DOkoRGdypt/8=;
+ b=vvOKuDgFhW7lhslsd+p1zFzCgGsB1q+Nz/VX94yvOzYNgzK+ztjWuRXqhxInvKB/6A
+ KULfTqxc6eCGaOwQe2jfzcCnE9NqbqNyqWdrKGtcYo/kC3cmSM+vPiVVwin4Ocib+tZk
+ gLRThq7wglPAniM9+y0MEtXWU2C0PRWCKM/keEZloAJrL9x3RR/5vQ3Cn8oVyI5yg328
+ sFIUYa2UvKJ+3rb3I/XCoqaDu26+A2wDiemzPMXUP3p3rTawvt/Bmg8SsxuzCo5zi8vf
+ oUsbFJWM9wPxCW53BBKQXNJ8yIPh+MD76ymg6bGuKHkSilqfTQk1NCr8QbFdO/FaeAba
+ Ad5g==
+X-Received: by 10.204.74.138 with SMTP id u10mr1617410bkj.113.1370879351096;
+ Mon, 10 Jun 2013 08:49:11 -0700 (PDT)
+Return-Path: <ec...@gmail.com>
+Received: from [10.20.0.2] ([69.85.95.7])
+ by mx.google.com with ESMTPSA id jm15sm4132474bkb.13.2013.06.10.08.49.08
+ for <multiple recipients>
+ (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
+ Mon, 10 Jun 2013 08:49:10 -0700 (PDT)
+Message-ID: <51...@gmail.com>
+Date: Mon, 10 Jun 2013 23:49:05 +0800
+From: dongxu <ec...@gmail.com>
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:17.0) Gecko/20130509 Thunderbird/17.0.6
+MIME-Version: 1.0
+To: Manuel Carrasco <mc...@gmail.com>
+Subject: Test with bcc without content inside
+X-ChiaraMail-Content-Pointer: 72
+X-ChiaraMail-Content-Key2: 98333074730306711837946622793808
+X-ChiaraMail-Content-Server-Name: www.chiaramail.com
+X-ChiaraMail-Content-Server-Port: 443
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+
+This message was sent using ECS technology
+(http://en.wikipedia.org/wiki/Envelope-content_splitting), but your mail
+client does not support ECS. Please download and install the appropriate
+ECS-enabling software for your mail client
+(http://www.chiaramail.com/download_extension.html) to read this message.
Added: james/hupa/trunk/mock/src/main/resources/mime/13.msg
URL: http://svn.apache.org/viewvc/james/hupa/trunk/mock/src/main/resources/mime/13.msg?rev=1516486&view=auto
==============================================================================
--- james/hupa/trunk/mock/src/main/resources/mime/13.msg (added)
+++ james/hupa/trunk/mock/src/main/resources/mime/13.msg Thu Aug 22 15:29:57 2013
@@ -0,0 +1,43 @@
+Return-Path: <mc...@gmail.com>
+Received: from [192.168.1.35] (239.Red-79-148-67.dynamicIP.rima-tde.net. [79.148.67.239])
+ by mx.google.com with ESMTPSA id l7sm2877195wiw.4.1969.12.31.16.00.00
+ (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
+ Thu, 15 Aug 2013 06:08:16 -0700 (PDT)
+Message-ID: <52...@gmail.com>
+Date: Thu, 15 Aug 2013 15:08:07 +0200
+From: Manuel Carrasco <mc...@gmail.com>
+User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130803 Thunderbird/17.0.8
+MIME-Version: 1.0
+To: mcdodot@gmail.com
+Subject: ECS unencripted attachment
+X-ChiaraMail-Content-Pointer: 16 24
+X-ChiaraMail-Content-Server-Name: www.chiaramail.com
+X-ChiaraMail-Content-Server-Port: 443
+Content-Type: multipart/mixed;
+ boundary="------------020706090302030909010608"
+
+This is a multi-part message in MIME format.
+--------------020706090302030909010608
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+
+This message was sent using ECS technology
+(http://en.wikipedia.org/wiki/Envelope-content_splitting), but your mail
+client does not support ECS. Please download and install the appropriate
+ECS-enabling software for your mail client
+(http://www.chiaramail.com/download_extension.html) to read this message.
+
+--------------020706090302030909010608
+Content-Type: application/pdf;
+ name="TRATAMIENTOS TERMAEUROPA 2013.pdf"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="TRATAMIENTOS TERMAEUROPA 2013.pdf"
+
+VGhpcyBtZXNzYWdlIHdhcyBzZW50IHVzaW5nIEVDUyB0ZWNobm9sb2d5IChodHRwOi8vZW4u
+d2lraXBlZGlhLm9yZy93aWtpL0VudmVsb3BlLWNvbnRlbnRfc3BsaXR0aW5nKSwgYnV0IHlv
+dXIgbWFpbCBjbGllbnQgZG9lcyBub3Qgc3VwcG9ydCBFQ1MuIFBsZWFzZSBkb3dubG9hZCBh
+bmQgaW5zdGFsbCB0aGUgYXBwcm9wcmlhdGUgRUNTLWVuYWJsaW5nIHNvZnR3YXJlIGZvciB5
+b3VyIG1haWwgY2xpZW50IChodHRwOi8vd3d3LmNoaWFyYW1haWwuY29tL2Rvd25sb2FkX2V4
+dGVuc2lvbi5odG1sKSB0byByZWFkIHRoaXMgbWVzc2FnZS4=
+--------------020706090302030909010608--
Modified: james/hupa/trunk/pom.xml
URL: http://svn.apache.org/viewvc/james/hupa/trunk/pom.xml?rev=1516486&r1=1516485&r2=1516486&view=diff
==============================================================================
--- james/hupa/trunk/pom.xml (original)
+++ james/hupa/trunk/pom.xml Thu Aug 22 15:29:57 2013
@@ -27,7 +27,7 @@
</parent>
<groupId>org.apache.james.hupa</groupId>
<artifactId>hupa-parent</artifactId>
- <version>0.0.5-SNAPSHOT</version>
+ <version>0.0.3-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Apache James Hupa Parent</name>
<description>Hupa is a GWT based Webmail</description>
Modified: james/hupa/trunk/server/pom.xml
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/pom.xml?rev=1516486&r1=1516485&r2=1516486&view=diff
==============================================================================
--- james/hupa/trunk/server/pom.xml (original)
+++ james/hupa/trunk/server/pom.xml Thu Aug 22 15:29:57 2013
@@ -1,135 +1,145 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.james.hupa</groupId>
- <artifactId>hupa-parent</artifactId>
- <version>0.0.5-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
- <artifactId>hupa-server</artifactId>
- <packaging>jar</packaging>
- <name>Apache James Hupa Server</name>
- <description>Servercode implementation to access IMAP Mailbox</description>
- <dependencies>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>hupa-mock</artifactId>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>hupa-shared</artifactId>
- </dependency>
- <dependency>
- <groupId>javax.inject</groupId>
- <artifactId>javax.inject</artifactId>
- </dependency>
- <dependency>
- <groupId>aopalliance</groupId>
- <artifactId>aopalliance</artifactId>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <exclusions>
- <exclusion>
- <groupId>logkit</groupId>
- <artifactId>logkit</artifactId>
- </exclusion>
- <exclusion>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- </dependency>
- <dependency>
- <groupId>com.googlecode.gwtupload</groupId>
- <artifactId>gwtupload</artifactId>
- </dependency>
- <dependency>
- <groupId>commons-fileupload</groupId>
- <artifactId>commons-fileupload</artifactId>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.code.guice</groupId>
- <artifactId>guice</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.code.guice</groupId>
- <artifactId>guice-assistedinject</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.code.guice</groupId>
- <artifactId>guice-servlet</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.gwt</groupId>
- <artifactId>gwt-user</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.gwt</groupId>
- <artifactId>gwt-servlet</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>com.google.gwt</groupId>
- <artifactId>gwt-dev</artifactId>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <outputDirectory>war/WEB-INF/classes</outputDirectory>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-war-plugin</artifactId>
- <configuration>
- <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
- <webResources>
- <resource>
- <directory>war</directory>
- <excludes>
- <exclude>**/hupa/*</exclude>
- </excludes>
- </resource>
- </webResources>
- <warName>${project.name}</warName>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.james.hupa</groupId>
+ <artifactId>hupa-parent</artifactId>
+ <version>0.0.3-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <artifactId>hupa-server</artifactId>
+ <packaging>jar</packaging>
+ <name>Apache James Hupa Server</name>
+ <description>Servercode implementation to access IMAP Mailbox</description>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hupa-mock</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hupa-shared</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>aopalliance</groupId>
+ <artifactId>aopalliance</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>logkit</groupId>
+ <artifactId>logkit</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.googlecode.gwtupload</groupId>
+ <artifactId>gwtupload</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-fileupload</groupId>
+ <artifactId>commons-fileupload</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.guice</groupId>
+ <artifactId>guice</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.guice</groupId>
+ <artifactId>guice-assistedinject</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.guice</groupId>
+ <artifactId>guice-servlet</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.gwt</groupId>
+ <artifactId>gwt-user</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.gwt</groupId>
+ <artifactId>gwt-servlet</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.gwt</groupId>
+ <artifactId>gwt-dev</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!-- ECS specific stuff
+ ECS encryption needs oracle crypto extension to work
+ http://www.oracle.com/technetwork/es/java/javase/downloads/jce-6-download-429243.html
+ http://www.oracle.com/technetwork/es/java/javase/downloads/jce-7-download-432124.html
+ -->
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-ext-jdk14</artifactId>
+ <version>1.49</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <outputDirectory>war/WEB-INF/classes</outputDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+ <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
+ <webResources>
+ <resource>
+ <directory>war</directory>
+ <excludes>
+ <exclude>**/hupa/*</exclude>
+ </excludes>
+ </resource>
+ </webResources>
+ <warName>${project.name}</warName>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
Added: james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Account.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Account.java?rev=1516486&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Account.java (added)
+++ james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Account.java Thu Aug 22 15:29:57 2013
@@ -0,0 +1,47 @@
+package com.chiaramail.hupa.helper;
+
+import java.util.Date;
+
+public class Account {
+
+ public static final int LICENSE_UNKNOWN = 0;
+ public static final int LICENSE_ACTIVE = 1;
+ public static final int LICENSE_EXPIRED = 2;
+
+ private int license = LICENSE_UNKNOWN;
+ private long time = System.currentTimeMillis() + (24*60*60*1000);
+ public String email;
+ public String password;
+ public String name;
+ public String serverName = "www.chiaramail.com";
+ public String serverPort = "443";
+
+ public String getEmail() {
+ return email;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setLicenseStatus(int licenseActive) {
+ license = licenseActive;
+ }
+ public int getLicenseStatus() {
+ return license;
+ }
+ public void setLicenseCheckDate(long time) {
+ this.time = time;
+ }
+ public int getLicenseCheckDate() {
+ return (int)time;
+ }
+ public String getPassword() {
+ return password;
+ }
+ public String getContentServerName() {
+ return serverName;
+ }
+ public String getContentServerPort() {
+ return serverPort;
+ }
+
+}
Added: james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Utility.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Utility.java?rev=1516486&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Utility.java (added)
+++ james/hupa/trunk/server/src/main/java/com/chiaramail/hupa/helper/Utility.java Thu Aug 22 15:29:57 2013
@@ -0,0 +1,1476 @@
+package com.chiaramail.hupa.helper;
+
+ import static com.chiaramail.hupa.helper.Account.LICENSE_ACTIVE;
+import static com.chiaramail.hupa.helper.Account.LICENSE_EXPIRED;
+import static com.chiaramail.hupa.helper.Account.LICENSE_UNKNOWN;
+
+import java.awt.Cursor;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import javax.mail.Address;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.net.ssl.HttpsURLConnection;
+
+import org.apache.commons.codec.binary.Base64;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class Utility {
+ /**
+ * Regular expression that represents characters we won't allow in file
+ * names.
+ *
+ * <p>
+ * Allowed are:
+ * <ul>
+ * <li>word characters (letters, digits, and underscores): {@code \w}</li>
+ * <li>spaces: {@code " "}</li>
+ * <li>special characters: {@code !}, {@code #}, {@code $}, {@code %},
+ * {@code &}, {@code '}, {@code (}, {@code )}, {@code -}, {@code @},
+ * {@code ^}, {@code `}, <code>{</code>, <code>}</code>, {@code ~}, {@code .}, {@code ,}</li>
+ * </ul>
+ * </p>
+ *
+ * @see #sanitizeFilename(String)
+ */
+ private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
+
+ /**
+ * Invalid characters in a file name are replaced by this character.
+ *
+ * @see #sanitizeFilename(String)
+ */
+ private static final String REPLACEMENT_CHARACTER = "_";
+
+ // \u00A0 (non-breaking space) happens to be used by French MUA
+
+ // Note: no longer using the ^ beginning character combined with (...)+
+ // repetition matching as we might want to strip ML tags. Ex:
+ // Re: [foo] Re: RE : [foo] blah blah blah
+ private static final Pattern RESPONSE_PATTERN = Pattern.compile(
+ "((Re|Fw|Fwd|Aw|R\\u00E9f\\.)(\\[\\d+\\])?[\\u00A0 ]?: *)+",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Mailing-list tag pattern to match strings like "[foobar] "
+ */
+ private static final Pattern TAG_PATTERN = Pattern.compile(
+ "\\[[-_a-z0-9]+\\] ", Pattern.CASE_INSENSITIVE);
+ public static final String CONTENT_SERVER_APP = "/DynamicContentServer/ContentServer";
+ public static final String RECEIVE_CONTENT = "RECEIVE CONTENT ";
+ public static final String UPDATE_CONTENT = "UPDATE CONTENT ";
+ public static final String FETCH_CONTENT = "FETCH CONTENT ";
+ public static final String DELETE_CONTENT = "DELETE CONTENT ";
+ public static final String DELETE_DATA = "DELETE DATA ";
+ public static final String REMOVE_RECIPIENT = "REMOVE RECIPIENT ";
+ public static final String GET_DATA = "GET DATA ";
+ public static final String USER_REGISTERED = "USER REGISTERED ";
+ public static final String SERVER_LICENSED = "SERVER LICENSED ";
+ // private static final int MAX_SIZE = 32768;
+ // private static final int MAX_SIZE = 7844;
+ // private static final int MAX_SIZE = 128;
+ private static final int MAX_SIZE = 76;
+ private static final int DECODED_SIZE = 57;
+ private static final int NEXT_DAY = 24 * 60 * 60 * 1000; // Number of msec
+ // in a day
+
+ public static final String BLANK = " ";
+ public static final String CONTENT_SERVER_NAME = "X-ChiaraMail-Content-Server-Name";
+ public static final String CONTENT_SERVER_PORT = "X-ChiaraMail-Content-Server-Port";
+ public static final String CONTENT_POINTER = "X-ChiaraMail-Content-Pointer";
+ public static final String ENCRYPTION_KEY = "X-ChiaraMail-Content-Key2";
+ public static final String CONTENT_DURATION = "X-ChiaraMail-Content-Duration";
+ public static final String DEFAULT_CONTENT_SERVER_NAME = "www.chiaramail.com";
+ public static final String DEFAULT_CONTENT_SERVER_PORT = "443";
+
+ public static final String GREEN = "#00a000";
+ public static final String RED = "#ff0000";
+ public static final String BLACK = "#000000";
+
+ public static Vector ValidECSMessages = new Vector();
+ public static Vector BogusECSMessages = new Vector();
+
+ public static boolean arrayContains(Object[] a, Object o) {
+ for (Object element : a) {
+ if (element.equals(o)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean arrayContainsAny(Object[] a, Object... o) {
+ for (Object element : a) {
+ if (arrayContains(o, element)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Combines the given array of Objects into a single String using each
+ * Object's toString() method and the separator character between each part.
+ *
+ * @param parts
+ * @param separator
+ * @return new String
+ */
+ public static String combine(Object[] parts, char separator) {
+ if (parts == null) {
+ return null;
+ } else if (parts.length == 0) {
+ return "";
+ } else if (parts.length == 1) {
+ return parts[0].toString();
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(parts[0]);
+ for (int i = 1; i < parts.length; ++i) {
+ sb.append(separator);
+ sb.append(parts[i]);
+ }
+ return sb.toString();
+ }
+
+ public static String base64Decode(String encoded) {
+ if (encoded == null) {
+ return null;
+ }
+ byte[] decoded = new Base64().decode(encoded.getBytes());
+ return new String(decoded);
+ }
+
+ public static byte[] base64DecodeToBytes(String encoded) {
+ if (encoded == null) {
+ return null;
+ }
+ byte[] decoded = new Base64().decode(encoded.getBytes());
+ return decoded;
+ }
+
+ public static String base64Encode(String s) {
+ if (s == null) {
+ return s;
+ }
+ byte[] encoded = new Base64().encode(s.getBytes());
+ return new String(encoded);
+ }
+
+ public static boolean domainFieldValid(String s) {
+ if (s != null) {
+ if (s.matches("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)*[a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?$")
+ && s.length() <= 253) {
+ return true;
+ }
+ if (s.matches("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final Pattern ATOM = Pattern
+ .compile("^(?:[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]|\\s)+$");
+
+ /**
+ * Quote a string, if necessary, based upon the definition of an "atom," as
+ * defined by RFC2822 (http://tools.ietf.org/html/rfc2822#section-3.2.4).
+ * Strings that consist purely of atoms are left unquoted; anything else is
+ * returned as a quoted string.
+ *
+ * @param text
+ * String to quote.
+ * @return Possibly quoted string.
+ */
+ public static String quoteAtoms(final String text) {
+ if (ATOM.matcher(text).matches()) {
+ return text;
+ } else {
+ return quoteString(text);
+ }
+ }
+
+ /**
+ * Ensures that the given string starts and ends with the double quote
+ * character. The string is not modified in any way except to add the double
+ * quote character to start and end if it's not already there. sample ->
+ * "sample" "sample" -> "sample" ""sample"" -> "sample"
+ * "sample"" -> "sample" sa"mp"le -> "sa"mp"le" "sa"mp"le" -> "sa"mp"le"
+ * (empty string) -> "" " -> ""
+ *
+ * @param s
+ * @return
+ */
+ public static String quoteString(String s) {
+ if (s == null) {
+ return null;
+ }
+ if (!s.matches("^\".*\"$")) {
+ return "\"" + s + "\"";
+ } else {
+ return s;
+ }
+ }
+
+ /**
+ * A fast version of URLDecoder.decode() that works only with UTF-8 and does
+ * only two allocations. This version is around 3x as fast as the standard
+ * one and I'm using it hundreds of times in places that slow down the UI,
+ * so it helps.
+ */
+ public static String fastUrlDecode(String s) {
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ byte ch;
+ int length = 0;
+ for (int i = 0, count = bytes.length; i < count; i++) {
+ ch = bytes[i];
+ if (ch == '%') {
+ int h = (bytes[i + 1] - '0');
+ int l = (bytes[i + 2] - '0');
+ if (h > 9) {
+ h -= 7;
+ }
+ if (l > 9) {
+ l -= 7;
+ }
+ bytes[length] = (byte) ((h << 4) | l);
+ i += 2;
+ } else if (ch == '+') {
+ bytes[length] = ' ';
+ } else {
+ bytes[length] = bytes[i];
+ }
+ length++;
+ }
+ return new String(bytes, 0, length, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ return null;
+ }
+ }
+
+ /**
+ * <p>
+ * Wraps a multiline string of text, identifying words by <code>' '</code>.
+ * </p>
+ *
+ * <p>
+ * New lines will be separated by the system property line separator. Very
+ * long words, such as URLs will <i>not</i> be wrapped.
+ * </p>
+ *
+ * <p>
+ * Leading spaces on a new line are stripped. Trailing spaces are not
+ * stripped.
+ * </p>
+ *
+ * <pre>
+ * WordUtils.wrap(null, *) = null
+ * WordUtils.wrap("", *) = ""
+ * </pre>
+ *
+ * Adapted from the Apache Commons Lang library.
+ * http://svn.apache.org/viewvc/commons/proper/lang
+ * /trunk/src/main/java/org/apache/commons/lang3/text/WordUtils.java SVN
+ * Revision 925967, Mon Mar 22 06:16:49 2010 UTC
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * @param str
+ * the String to be word wrapped, may be null
+ * @param wrapLength
+ * the column to wrap the words at, less than 1 is treated as 1
+ * @return a line with newlines inserted, <code>null</code> if null input
+ */
+ private static final String NEWLINE_REGEX = "(?:\\r?\\n)";
+
+ public static String wrap(String str, int wrapLength) {
+ StringBuilder result = new StringBuilder();
+ for (String piece : str.split(NEWLINE_REGEX)) {
+ result.append(wrap(piece, wrapLength, null, false));
+ result.append("\n");
+ }
+ return result.toString();
+ }
+
+ /**
+ * <p>
+ * Wraps a single line of text, identifying words by <code>' '</code>.
+ * </p>
+ *
+ * <p>
+ * Leading spaces on a new line are stripped. Trailing spaces are not
+ * stripped.
+ * </p>
+ *
+ * <pre>
+ * WordUtils.wrap(null, *, *, *) = null
+ * WordUtils.wrap("", *, *, *) = ""
+ * </pre>
+ *
+ * This is from the Apache Commons Lang library.
+ * http://svn.apache.org/viewvc/commons/proper/lang
+ * /trunk/src/main/java/org/apache/commons/lang3/text/WordUtils.java SVN
+ * Revision 925967, Mon Mar 22 06:16:49 2010 UTC
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * @param str
+ * the String to be word wrapped, may be null
+ * @param wrapLength
+ * the column to wrap the words at, less than 1 is treated as 1
+ * @param newLineStr
+ * the string to insert for a new line, <code>null</code> uses
+ * the system property line separator
+ * @param wrapLongWords
+ * true if long words (such as URLs) should be wrapped
+ * @return a line with newlines inserted, <code>null</code> if null input
+ */
+ public static String wrap(String str, int wrapLength, String newLineStr,
+ boolean wrapLongWords) {
+ if (str == null) {
+ return null;
+ }
+ if (newLineStr == null) {
+ newLineStr = "\n";
+ }
+ if (wrapLength < 1) {
+ wrapLength = 1;
+ }
+ int inputLineLength = str.length();
+ int offset = 0;
+ StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32);
+
+ while ((inputLineLength - offset) > wrapLength) {
+ if (str.charAt(offset) == ' ') {
+ offset++;
+ continue;
+ }
+ int spaceToWrapAt = str.lastIndexOf(' ', wrapLength + offset);
+
+ if (spaceToWrapAt >= offset) {
+ // normal case
+ wrappedLine.append(str.substring(offset, spaceToWrapAt));
+ wrappedLine.append(newLineStr);
+ offset = spaceToWrapAt + 1;
+ } else {
+ // really long word or URL
+ if (wrapLongWords) {
+ // wrap really long word one line at a time
+ wrappedLine.append(str.substring(offset, wrapLength
+ + offset));
+ wrappedLine.append(newLineStr);
+ offset += wrapLength;
+ } else {
+ // do not wrap really long word, just extend beyond limit
+ spaceToWrapAt = str.indexOf(' ', wrapLength + offset);
+ if (spaceToWrapAt >= 0) {
+ wrappedLine
+ .append(str.substring(offset, spaceToWrapAt));
+ wrappedLine.append(newLineStr);
+ offset = spaceToWrapAt + 1;
+ } else {
+ wrappedLine.append(str.substring(offset));
+ offset = inputLineLength;
+ }
+ }
+ }
+ }
+
+ // Whatever is left in line is short enough to just pass through
+ wrappedLine.append(str.substring(offset));
+
+ return wrappedLine.toString();
+ }
+
+ /**
+ * Extract the 'original' subject value, by ignoring leading
+ * response/forward marker and '[XX]' formatted tags (as many mailing-list
+ * softwares do).
+ *
+ * <p>
+ * Result is also trimmed.
+ * </p>
+ *
+ * @param subject
+ * Never <code>null</code>.
+ * @return Never <code>null</code>.
+ */
+ public static String stripSubject(final String subject) {
+ int lastPrefix = 0;
+
+ final Matcher tagMatcher = TAG_PATTERN.matcher(subject);
+ String tag = null;
+ // whether tag stripping logic should be active
+ boolean tagPresent = false;
+ // whether the last action stripped a tag
+ boolean tagStripped = false;
+ if (tagMatcher.find(0)) {
+ tagPresent = true;
+ if (tagMatcher.start() == 0) {
+ // found at beginning of subject, considering it an actual tag
+ tag = tagMatcher.group();
+
+ // now need to find response marker after that tag
+ lastPrefix = tagMatcher.end();
+ tagStripped = true;
+ }
+ }
+
+ final Matcher matcher = RESPONSE_PATTERN.matcher(subject);
+
+ // while:
+ // - lastPrefix is within the bounds
+ // - response marker found at lastPrefix position
+ // (to make sure we don't catch response markers that are part of
+ // the actual subject)
+
+ while (lastPrefix < subject.length() - 1
+ && matcher.find(lastPrefix)
+ && matcher.start() == lastPrefix
+ && (!tagPresent || tag == null || subject.regionMatches(
+ matcher.end(), tag, 0, tag.length()))) {
+ lastPrefix = matcher.end();
+
+ if (tagPresent) {
+ tagStripped = false;
+ if (tag == null) {
+ // attempt to find tag
+ if (tagMatcher.start() == lastPrefix) {
+ tag = tagMatcher.group();
+ lastPrefix += tag.length();
+ tagStripped = true;
+ }
+ } else if (lastPrefix < subject.length() - 1
+ && subject.startsWith(tag, lastPrefix)) {
+ // Re: [foo] Re: [foo] blah blah blah
+ // ^ ^
+ // ^ ^
+ // ^ new position
+ // ^
+ // initial position
+ lastPrefix += tag.length();
+ tagStripped = true;
+ }
+ }
+ }
+ // Null pointer check is to make the static analysis component of
+ // Eclipse happy.
+ if (tagStripped && (tag != null)) {
+ // restore the last tag
+ lastPrefix -= tag.length();
+ }
+ if (lastPrefix > -1 && lastPrefix < subject.length() - 1) {
+ return subject.substring(lastPrefix).trim();
+ } else {
+ return subject.trim();
+ }
+ }
+
+ /**
+ * @param parentDir
+ * @param name
+ * Never <code>null</code>.
+ */
+ public static void touchFile(final File parentDir, final String name) {
+ final File file = new File(parentDir, name);
+ try {
+ if (!file.exists()) {
+ file.createNewFile();
+ } else {
+ file.setLastModified(System.currentTimeMillis());
+ }
+ } catch (Exception e) {
+ System.out.println("Unable to touch file: "
+ + file.getAbsolutePath() + " " + e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a unique file in the given directory by appending a hyphen and a
+ * number to the given filename.
+ *
+ * @param directory
+ * @param filename
+ * @return
+ */
+ public static File createUniqueFile(File directory, String filename) {
+ File file = new File(directory, filename);
+ if (!file.exists()) {
+ return file;
+ }
+ // Get the extension of the file, if any.
+ int index = filename.lastIndexOf('.');
+ String format;
+ if (index != -1) {
+ String name = filename.substring(0, index);
+ String extension = filename.substring(index);
+ format = name + "-%d" + extension;
+ } else {
+ format = filename + "-%d";
+ }
+ for (int i = 2; i < Integer.MAX_VALUE; i++) {
+ file = new File(directory, String.format(format, i));
+ if (!file.exists()) {
+ return file;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param from
+ * @param to
+ * @return
+ */
+ public static boolean move(final File from, final File to) {
+ if (to.exists()) {
+ to.delete();
+ }
+ to.getParentFile().mkdirs();
+
+ try {
+ FileInputStream in = new FileInputStream(from);
+ try {
+ FileOutputStream out = new FileOutputStream(to);
+ try {
+ byte[] buffer = new byte[1024];
+ int count = -1;
+ while ((count = in.read(buffer)) > 0) {
+ out.write(buffer, 0, count);
+ }
+ } finally {
+ out.close();
+ }
+ } finally {
+ try {
+ in.close();
+ } catch (Throwable ignore) {
+ }
+ }
+ from.delete();
+ return true;
+ } catch (Exception e) {
+ System.out.println("cannot move " + from.getAbsolutePath() + " to "
+ + to.getAbsolutePath() + " " + e.getMessage());
+ return false;
+ }
+
+ }
+
+ /**
+ * @param fromDir
+ * @param toDir
+ */
+ public static void moveRecursive(final File fromDir, final File toDir) {
+ if (!fromDir.exists()) {
+ return;
+ }
+ if (!fromDir.isDirectory()) {
+ if (toDir.exists()) {
+ if (!toDir.delete()) {
+ System.out
+ .println("cannot delete already existing file/directory "
+ + toDir.getAbsolutePath());
+ }
+ }
+ if (!fromDir.renameTo(toDir)) {
+ System.out.println("cannot rename " + fromDir.getAbsolutePath()
+ + " to " + toDir.getAbsolutePath()
+ + " - moving instead");
+ move(fromDir, toDir);
+ }
+ return;
+ }
+ if (!toDir.exists() || !toDir.isDirectory()) {
+ if (toDir.exists()) {
+ toDir.delete();
+ }
+ if (!toDir.mkdirs()) {
+ System.out.println("cannot create directory "
+ + toDir.getAbsolutePath());
+ }
+ }
+ File[] files = fromDir.listFiles();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ moveRecursive(file, new File(toDir, file.getName()));
+ file.delete();
+ } else {
+ File target = new File(toDir, file.getName());
+ if (!file.renameTo(target)) {
+ System.out.println("cannot rename "
+ + file.getAbsolutePath() + " to "
+ + target.getAbsolutePath() + " - moving instead");
+ move(file, target);
+ }
+ }
+ }
+ if (!fromDir.delete()) {
+ System.out.println("cannot delete " + fromDir.getAbsolutePath());
+ }
+ }
+
+ private static final String IMG_SRC_REGEX = "(?is:<img[^>]+src\\s*=\\s*['\"]?([a-z]+)\\:)";
+ private static final Pattern IMG_PATTERN = Pattern.compile(IMG_SRC_REGEX);
+
+ /**
+ * Figure out if this part has images. TODO: should only return true if
+ * we're an html part
+ *
+ * @param message
+ * Content to evaluate
+ * @return True if it has external images; false otherwise.
+ */
+ public static boolean hasExternalImages(final String message) {
+ Matcher imgMatches = IMG_PATTERN.matcher(message);
+ while (imgMatches.find()) {
+ if (!imgMatches.group(1).equals("content")) {
+ System.out.println("External images found");
+ return true;
+ }
+ }
+ System.out.println("No external images.");
+ return false;
+ }
+
+ /**
+ * Unconditionally close a Cursor. Equivalent to {@link Cursor#close()}, if
+ * cursor is non-null. This is typically used in finally blocks.
+ *
+ * @param cursor
+ * cursor to close
+ */
+ public static void closeQuietly(final Cursor cursor) {
+ if (cursor != null) {
+ // cursor.close();
+ }
+ }
+
+ private static class BlockData {
+ int blockSize;
+ int bytesRead;
+ String msgBlock;
+ String msgChunk;
+ }
+
+ private static BlockData getNextBlock(BufferedReader rdr, char[] buf)
+ throws IOException {
+ BlockData blockData = new BlockData();
+ String msgChunk = "";
+ String msgBlock = "";
+ int blockSize = 0, bytesRead = 0;
+
+ while (blockSize < MAX_SIZE) {
+ bytesRead = rdr.read(buf, 0, MAX_SIZE - bytesRead);
+ if (bytesRead == -1)
+ return null;
+ msgChunk = new String(buf, 0, bytesRead);
+ msgBlock += msgChunk;
+ blockSize += bytesRead;
+ }
+ blockData.blockSize = blockSize;
+ blockData.bytesRead = bytesRead;
+ blockData.msgBlock = msgBlock;
+ blockData.msgChunk = msgChunk;
+ return blockData;
+ }
+
+ public static String fetchBodyContent(Message message, Account account,
+ String[] contentPointers, String contentServerName,
+ String contentServerPort, String encryptionKey) {
+ try {
+ String from = message.getFrom()[0].toString().replaceFirst("^.*<(.*)>.*$", "$1");
+ String[] reply = doFetchContent(account,
+ from + BLANK
+ + contentPointers[0], "https://"
+ + contentServerName + ":" + contentServerPort,
+ account.getEmail(),
+ base64Encode(account.getPassword()),
+ false, null,
+ null);
+ if (reply[0].equals("3")) {
+ // Indicate to MessageList to set message Subject field color to
+ // green in the message list.
+ if (!ValidECSMessages
+ .contains(message.getHeader("Message-ID")[0]))
+ ValidECSMessages
+ .addElement(message.getHeader("Message-ID")[0]);
+ String[] encryptionHeader = message.getHeader(ENCRYPTION_KEY);
+ if (encryptionHeader != null) {
+ return new String(decrypt(encryptionKey.getBytes(),
+ base64DecodeToBytes(reply[1].substring(reply[1]
+ .toUpperCase().indexOf("CONTENT = ")
+ + "CONTENT = ".length()))));
+ }
+ return base64Decode(reply[1].substring(reply[1].toUpperCase()
+ .indexOf("CONTENT = ") + "CONTENT = ".length()));
+ } else {
+ // Indicate to MessageList to set message Subject field color to
+ // red in the message list; the fetch had problems, so this
+ // message may be bogus. Better safe than sorry.
+ if (!BogusECSMessages
+ .contains(message.getHeader("Message-ID")[0]))
+ BogusECSMessages
+ .addElement(message.getHeader("Message-ID")[0]);
+ // Toast.makeText(getContext(),
+ // getContext().getString(R.string.message_read_error_fetching_content)
+ // + reply[1], Toast.LENGTH_LONG).show();
+ return null;
+ }
+ } catch (Exception e) {
+ System.out.println("Exception when fetching message content: "
+ + " " + e.getMessage());
+ e.printStackTrace();
+ // Toast.makeText(this.getContext(),
+ // getContext().getString(R.string.message_fetch_exception) + e,
+ // Toast.LENGTH_LONG).show();
+ return null;
+ }
+ }
+
+ /****************************************************************************/
+ /* The askServer() method sends an HTTP request to a server. */
+ /****************************************************************************/
+ public static String[] askServer(String url_str, String command,
+ String email_addr, String password, boolean isAttachment,
+ String filename, String key) throws Exception {
+
+// System.out.println("AskServer: " + url_str + " cmd:" + command + " email:" + email_addr + " pass:" + password + " att:" + isAttachment + " file:" + filename + " key:" + key);
+ String tmp = "", parms;
+
+ HttpURLConnection connection;
+
+ InputStream is;
+
+ BufferedWriter writer;
+
+ BufferedReader rdr;
+
+ String[] srvr_rsp = null;
+
+ URL url;
+
+ int index;
+
+ srvr_rsp = new String[2];
+
+ try {
+ url = new URL(url_str);
+ if (command.startsWith(SERVER_LICENSED)) {
+ // Since the request isn't going to the ChiaraMail content
+ // server, make sure the private server has an active license.
+ connection = (HttpsURLConnection) new URL("https://"
+ + DEFAULT_CONTENT_SERVER_NAME + ":"
+ + DEFAULT_CONTENT_SERVER_PORT + CONTENT_SERVER_APP)
+ .openConnection();
+ connection.setDoOutput(true);
+ writer = new BufferedWriter(new OutputStreamWriter(
+ connection.getOutputStream()));
+ writer.write("email_addr="
+ + URLEncoder.encode(email_addr, "UTF-8")
+ + "&"
+ + "passwd="
+ + URLEncoder.encode(password, "UTF-8")
+ + "&"
+ + "cmd="
+ + SERVER_LICENSED
+ + "&"
+ + "parms="
+ + URLEncoder.encode(
+ url_str.substring(0,
+ url_str.indexOf(CONTENT_SERVER_APP)),
+ "UTF-8"));
+ writer.close();
+ is = connection.getInputStream();
+
+ rdr = new BufferedReader(new InputStreamReader(is));
+ tmp = rdr.readLine();
+ if ((index = tmp.indexOf(BLANK)) != -1) {
+ srvr_rsp[0] = tmp.substring(0, tmp.indexOf(BLANK));
+ srvr_rsp[1] = tmp.substring(tmp.indexOf(BLANK) + 1);
+ } else {
+ srvr_rsp[0] = tmp;
+ srvr_rsp[1] = "";
+ }
+ rdr.close();
+ is.close();
+ return srvr_rsp;
+ // if (!srvr_rsp[0].equals("10")) return srvr_rsp;
+ }
+
+ if (url_str.startsWith("https")) {
+ connection = (HttpsURLConnection) url.openConnection();
+ } else {
+ connection = (HttpURLConnection) url.openConnection();
+ }
+ connection.setDoOutput(true);
+
+ index = command.indexOf(BLANK);
+ tmp = "";
+ tmp += command.substring(0, index + 1);
+ command = command.substring(index).trim();
+ index = command.indexOf(BLANK);
+ if (index == -1) {
+ tmp += command;
+ parms = "";
+ } else {
+ tmp += command.substring(0, index);
+ parms = command.substring(index).trim();
+ }
+ writer = new BufferedWriter(new OutputStreamWriter(
+ connection.getOutputStream()));
+ writer.write("email_addr=" + URLEncoder.encode(email_addr, "UTF-8")
+ + "&" + "passwd=" + URLEncoder.encode(password, "UTF-8")
+ + "&" + "cmd=" + tmp + "&" + "parms="
+ + URLEncoder.encode(parms, "UTF-8"));
+ writer.close();
+
+ is = connection.getInputStream();
+ rdr = new BufferedReader(new InputStreamReader(is));
+
+ if (isAttachment) {
+ char[] buf = new char[MAX_SIZE + 29]; // Include room for
+ // response from content
+ // server plus 76 bytes of
+ // Base64 encoded content
+ byte[] blockArray = new byte[16 * DECODED_SIZE];
+ byte[] decodedChunk;
+ int bytesRead = 0;
+ int totalBlockLen = 0;
+ String msgBlock = "";
+
+ File file = new File(System.getProperty("java.io.tmpdir") + File.separatorChar + filename);
+ if (file.exists())
+ file.delete();
+
+ System.out.println("Creating attachment file: " + file.getAbsolutePath());
+
+ RandomAccessFile attachmentFile = new RandomAccessFile(file,
+ "rw");
+ bytesRead = rdr.read(buf);
+ /**
+ * if (bytesRead < MAX_SIZE + 29) { // Should never happen
+ * attachmentFile.close(); rdr.close(); is.close(); return null;
+ * }
+ **/
+ String tmp2 = new String(buf, 0, 29);
+ if (!tmp2.startsWith("3 ")) {
+ tmp = new String(buf, 0, buf.length);
+ if ((index = tmp.indexOf(BLANK)) != -1) {
+ srvr_rsp[0] = tmp.substring(0, tmp.indexOf(BLANK));
+ srvr_rsp[1] = tmp.substring(tmp.indexOf(BLANK) + 1);
+ } else {
+ srvr_rsp[0] = tmp;
+ srvr_rsp[1] = "";
+ }
+ return srvr_rsp;
+ }
+ int startContentIndex = tmp2.toUpperCase()
+ .indexOf("CONTENT = ") + "CONTENT = ".length();
+ tmp = tmp2.substring(0, startContentIndex);
+ if (tmp.startsWith("3 ")) {
+ msgBlock = new String(buf).substring(startContentIndex);
+ decodedChunk = base64DecodeToBytes(msgBlock);
+ if (key != null) {
+ for (int i = 0; i < decodedChunk.length; i++) {
+ blockArray[i] = decodedChunk[i];
+ }
+ totalBlockLen = decodedChunk.length;
+ } else {
+ attachmentFile.write(decodedChunk);
+ }
+ buf = new char[MAX_SIZE];
+ bytesRead = 0;
+ while (bytesRead >= 0) {
+ if (key != null) {
+ /*
+ * The following code reads 76-byte data blocks from
+ * the content server, decodes them and concatenates
+ * them into a block whose lengths is divisible by
+ * 16, which is needed for decryption. Then result
+ * is decrypted prior to saving to disk.
+ */
+ do {
+ BlockData blockData = getNextBlock(rdr, buf);
+ if (blockData != null) {
+ bytesRead = blockData.bytesRead;
+ decodedChunk = base64DecodeToBytes(blockData.msgBlock);
+ for (int i = 0; i < decodedChunk.length; i++) {
+ blockArray[i + totalBlockLen] = decodedChunk[i];
+ }
+ totalBlockLen += decodedChunk.length;
+ if (totalBlockLen % 16 == 0)
+ break; // Read the next block from the
+ // server
+ } else { // EOF, bytesRead == -1
+ bytesRead = -1;
+ break;
+ }
+ } while (totalBlockLen % 16 != 0);
+ if (totalBlockLen == 0)
+ break;
+ byte[] tmpArray = decrypt(key.getBytes(),
+ blockArray);
+ blockArray = Arrays.copyOf(tmpArray, totalBlockLen);
+
+ attachmentFile.write(blockArray);
+ blockArray = new byte[16 * DECODED_SIZE];
+ totalBlockLen = 0;
+ } else {
+ BlockData blockData = getNextBlock(rdr, buf);
+ if (blockData == null)
+ break;
+ bytesRead = blockData.bytesRead;
+ decodedChunk = base64DecodeToBytes(blockData.msgBlock);
+ attachmentFile.write(decodedChunk);
+ }
+ }
+ }
+ attachmentFile.close();
+ } else {
+ tmp = rdr.readLine();
+ }
+
+ rdr.close();
+ is.close();
+
+ if ((index = tmp.indexOf(BLANK)) != -1) {
+ srvr_rsp[0] = tmp.substring(0, tmp.indexOf(BLANK));
+ srvr_rsp[1] = tmp.substring(tmp.indexOf(BLANK) + 1);
+ } else {
+ srvr_rsp[0] = tmp;
+ srvr_rsp[1] = "";
+ }
+ } catch (MalformedURLException e) {
+ srvr_rsp[0] = "-1";
+ srvr_rsp[1] = e.getMessage();
+ System.out
+ .println("MalformedURLException when sending content to server: "
+ + " " + e.getMessage());
+ e.printStackTrace();
+ } catch (IOException e) {
+ srvr_rsp[0] = "-1";
+ srvr_rsp[1] = e.getMessage();
+ System.out.println("IOException when sending content to server: "
+ + " " + e.getMessage());
+ e.printStackTrace();
+ }
+ return srvr_rsp;
+ }
+
+ /****************************************************************************/
+ /* The registerServlet() method sends an HTTP request to the Register */
+ /* servlet. */
+ /****************************************************************************/
+ public static void registerServlet(Account account, String addr)
+ throws Exception {
+ HttpURLConnection connection;
+
+ BufferedWriter writer;
+
+ URL url;
+
+ try {
+ url = new URL("https://www.chiaramail.com/Register");
+ connection = (HttpsURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ writer = new BufferedWriter(new OutputStreamWriter(
+ connection.getOutputStream()));
+ writer.write("email_addr="
+ + URLEncoder.encode(account.getEmail(), "UTF-8") + "&addr="
+ + URLEncoder.encode("!FGw38;_&hIoPDC6887", "UTF-8")
+ + "&username="
+ + URLEncoder.encode(account.getName(), "UTF-8") + "&city="
+ + "&zipcode=00000" + "&country="
+ + URLEncoder.encode("United States of America", "UTF-8"));
+ writer.close();
+
+ connection.getResponseCode();
+ } catch (MalformedURLException e) {
+ System.out
+ .println("MalformedURLException when sending registration request to server: "
+ + " " + e.getMessage());
+ } catch (IOException e) {
+ System.out
+ .println("IOException when sending registration request to server: "
+ + " " + e.getMessage());
+ }
+
+ return;
+ }
+
+ /****************************************************************************/
+ /* doUpdateContent() sends updated content to the ContentServer. */
+ /****************************************************************************/
+ public static String[] doUpdateContent(String parms, String url_str,
+ String email_addr, String password) throws Exception {
+ String[] rsp;
+
+ rsp = askServer(url_str + CONTENT_SERVER_APP, UPDATE_CONTENT + parms,
+ email_addr, password, false, null, null);
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* doFetchContent() fetches content from the ContentServer. */
+ /****************************************************************************/
+ public static String[] doFetchContent(Account account, String parms,
+ String url_str, String email_addr, String password,
+ boolean isAttachment, String filename, String encryption_key)
+ throws Exception {
+ String[] rsp;
+
+ if (!url_str.toLowerCase().startsWith(
+ "https://" + DEFAULT_CONTENT_SERVER_NAME + ":"
+ + DEFAULT_CONTENT_SERVER_PORT)
+ && (account.getLicenseStatus() == LICENSE_UNKNOWN || account
+ .getLicenseCheckDate() + NEXT_DAY < getCurrentDate())) {
+ rsp = askServer(url_str + CONTENT_SERVER_APP, SERVER_LICENSED
+ + parms, email_addr, password, false, null, null);
+ if (rsp[0].equals("10")) {
+ account.setLicenseStatus(LICENSE_ACTIVE);
+ account.setLicenseCheckDate(new Date().getTime());
+ rsp = askServer(url_str + CONTENT_SERVER_APP, FETCH_CONTENT
+ + parms, email_addr, password, isAttachment, filename,
+ encryption_key);
+ } else {
+ account.setLicenseStatus(LICENSE_EXPIRED);
+ }
+ } else {
+ rsp = askServer(url_str + CONTENT_SERVER_APP,
+ FETCH_CONTENT + parms, email_addr, password, isAttachment,
+ filename, encryption_key);
+ }
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* doReceiveContent() requests the ContentServer to store content. */
+ /****************************************************************************/
+ public static String[] doReceiveContent(Account account, String parms,
+ String url_str, String email_addr, String password)
+ throws Exception {
+ String[] rsp;
+
+ if (!url_str.toLowerCase().startsWith(
+ "https://" + DEFAULT_CONTENT_SERVER_NAME + ":"
+ + DEFAULT_CONTENT_SERVER_PORT)
+ && (account.getLicenseStatus() == LICENSE_UNKNOWN || account
+ .getLicenseCheckDate() + NEXT_DAY < getCurrentDate())) {
+ rsp = askServer(url_str + CONTENT_SERVER_APP, SERVER_LICENSED
+ + parms, email_addr, password, false, null, null);
+ if (rsp[0].equals("10")) {
+ account.setLicenseStatus(LICENSE_ACTIVE);
+ account.setLicenseCheckDate(new Date().getTime());
+ rsp = askServer(url_str + CONTENT_SERVER_APP, RECEIVE_CONTENT
+ + parms, email_addr, password, false, null, null);
+ } else {
+ account.setLicenseStatus(LICENSE_EXPIRED);
+ }
+ } else {
+ rsp = askServer(url_str + CONTENT_SERVER_APP, RECEIVE_CONTENT
+ + parms, email_addr, password, false, null, null);
+ }
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* doRemoveRecipient() requests the ContentServer to remove the recipient */
+ /* from the access list of the named message. */
+ /****************************************************************************/
+ public static String[] doRemoveRecipient(String parms, String url_str,
+ String email_addr, String password) throws Exception {
+ String[] rsp;
+
+ rsp = askServer(url_str + CONTENT_SERVER_APP, REMOVE_RECIPIENT + parms,
+ email_addr, password, false, null, null);
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* doDeleteContent() requests the ContentServer to delete content and */
+ /* content pointer entries in the content_indexes database table. */
+ /****************************************************************************/
+ public static String[] doDeleteContent(String parms, String url_str,
+ String email_addr, String password) throws Exception {
+ String[] rsp;
+
+ rsp = askServer(url_str + CONTENT_SERVER_APP, DELETE_CONTENT + parms,
+ email_addr, password, false, null, null);
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* doDeleteData() requests the ContentServer to delete content only. */
+ /****************************************************************************/
+ public static String[] doDeleteData(String parms, String url_str,
+ String email_addr, String password) throws Exception {
+ String[] rsp;
+
+ rsp = askServer(url_str + CONTENT_SERVER_APP, DELETE_DATA + parms,
+ email_addr, password, false, null, null);
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* doGetData() requests the ContentServer to return the amount of space */
+ /* the user has left. */
+ /****************************************************************************/
+ public static String[] doGetData(String url_str, String email_addr,
+ String password) throws Exception {
+ String[] rsp;
+
+ rsp = askServer(url_str + CONTENT_SERVER_APP, GET_DATA, email_addr,
+ password, false, null, null);
+
+ return rsp;
+ }
+
+ /****************************************************************************/
+ /* isUserRegistered() requests the ContentServer to report if the given */
+ /* account exists. */
+ /****************************************************************************/
+ public static String isUserRegistered(Account account, String address) {
+ try {
+ String[] reply = askServer(
+ "https://" + account.getContentServerName() + ":"
+ + account.getContentServerPort()
+ + CONTENT_SERVER_APP, USER_REGISTERED + address,
+ account.getEmail(),
+ base64Encode(account.getPassword()), false,
+ null, null);
+ if (reply[0].equals("7")) {
+ String rsp = reply[1].substring(reply[1].lastIndexOf("= ") + 2);
+ return rsp.substring(0, rsp.length() - 1);
+ } else {
+ System.out.println(reply[1]);
+ return "";
+ }
+ } catch (Exception e) {
+ System.out
+ .println("Exception when fetching content server response: "
+ + " " + e.getMessage());
+ return "";
+ }
+ }
+
+ /****************************************************************************/
+ /* doRegisterUser() registers the user for content service. */
+ /****************************************************************************/
+ public static void doRegisterUser(Account account, String addr)
+ throws Exception {
+ String[] rsp;
+
+ registerServlet(account, addr);
+
+ return;
+ }
+
+ /****************************************************************************/
+ /* getCurrentDate() fetches the current date and is used when validating */
+ /* licenses. */
+ /****************************************************************************/
+ private static long getCurrentDate() {
+ Date date = new Date();
+ return date.getTime();
+ }
+
+ /**
+ * Replace characters we don't allow in file names with a replacement
+ * character.
+ *
+ * @param filename
+ * The original file name.
+ *
+ * @return The sanitized file name containing only allowed characters.
+ */
+ public static String sanitizeFilename(String filename) {
+ return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
+ }
+
+ /**
+ * Check to see if we have network connectivity.
+ *
+ * @param app
+ * Current application (Hint: see if your base class has a
+ * getApplication() method.)
+ * @return true if we have connectivity, false otherwise.
+ */
+ public static boolean hasConnectivity(final Object app) {
+ return true;
+ }
+
+ private static final Pattern MESSAGE_ID = Pattern.compile("<" + "(?:"
+ + "[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+"
+ + "(?:\\.[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+)*" + "|"
+ + "\"(?:[^\\\\\"]|\\\\.)*\"" + ")" + "@" + "(?:"
+ + "[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+"
+ + "(?:\\.[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+)*" + "|"
+ + "\\[(?:[^\\\\\\]]|\\\\.)*\\]" + ")" + ">");
+
+ public static List<String> extractMessageIds(final String text) {
+ List<String> messageIds = new ArrayList<String>();
+ Matcher matcher = MESSAGE_ID.matcher(text);
+
+ int start = 0;
+ while (matcher.find(start)) {
+ String messageId = text.substring(matcher.start(), matcher.end());
+ messageIds.add(messageId);
+ start = matcher.end();
+ }
+
+ return messageIds;
+ }
+
+ public static String extractMessageId(final String text) {
+ Matcher matcher = MESSAGE_ID.matcher(text);
+
+ if (matcher.find()) {
+ return text.substring(matcher.start(), matcher.end());
+ }
+
+ return null;
+ }
+
+ public static String[] copyOf(String[] original, int newLength) {
+ return Arrays.copyOf(original, newLength);
+ }
+
+ public static String extractAddresses(Address[] toAddrs, Address[] ccAddrs,
+ Address[] bccAddrs) {
+ String tmp = "", tmp1 = "", tmp2 = "", tmp3 = "";
+
+ StringTokenizer st;
+
+ for (int i = 0; i < toAddrs.length; i++) {
+ st = new StringTokenizer(toAddrs[i].toString(), " ,");
+ for (int j = 0; st.hasMoreTokens(); j++) {
+ tmp1 += st.nextToken() + ",";
+ }
+ }
+
+ for (int i = 0; i < ccAddrs.length; i++) {
+ st = new StringTokenizer(ccAddrs[i].toString(), " ,");
+
+ for (int j = 0; st.hasMoreTokens(); j++) {
+ tmp2 += st.nextToken() + ",";
+ }
+ }
+
+ for (int i = 0; i < bccAddrs.length; i++) {
+ st = new StringTokenizer(bccAddrs[i].toString(), " ,");
+
+ while (st.hasMoreTokens()) {
+ tmp3 += st.nextToken() + ",";
+ }
+ }
+ if (tmp1.length() > 0) {
+ tmp += tmp1;
+ if (tmp2.length() > 0) {
+ tmp += "," + tmp2;
+ if (tmp3.length() > 0) {
+ tmp += "," + tmp3;
+ return tmp;
+ }
+ return tmp;
+ } else {
+ if (tmp3.length() > 0) {
+ tmp += "," + tmp3;
+ return tmp;
+ }
+ return tmp;
+ }
+ } else {
+ if (tmp2.length() > 0) {
+ tmp += tmp2;
+ if (tmp3.length() > 0) {
+ tmp += "," + tmp3;
+ return tmp;
+ }
+ return tmp;
+ } else {
+ if (tmp3.length() > 0) {
+ return tmp3;
+ }
+ }
+ }
+ return tmp;
+ }
+
+ public static String generateEncryptionKey() {
+ Random random = new Random();
+ return (String.valueOf(random.nextLong()) + "01234567890123456789012345678901")
+ .substring(0, 32); // Pad out to 32 bytes
+ }
+
+ public static byte[] doFinal(int mode, byte[] key, byte[] data) throws Exception {
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
+ Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
+ try {
+ cipher.init(mode, skeySpec);
+ } catch (Exception e) {
+ System.err.println("Error initializing Cipher: " + e.getMessage());
+ System.err.println("Your java version is : " + System.getProperty("java.version") + " installed in: " + System.getProperty("java.home"));
+ System.err.println("If you are using sun/oracle version, be sure you have installed 'Java Cryptography Extension (JCE)'");
+ throw e;
+ }
+ return cipher.doFinal(data);
+ }
+
+ public static String encrypt(byte[] raw, byte[] clear) throws Exception {
+ return new String(Base64.encodeBase64(doFinal(Cipher.ENCRYPT_MODE, raw, clear)));
+ }
+
+ public static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
+ return doFinal(Cipher.DECRYPT_MODE, raw, encrypted);
+ }
+
+ // MCM
+ public static int getSpinnerIndex() {
+ return -1;
+ }
+
+ public static boolean validateHeaders(Message message) {
+ String contentServerName[] = null;
+ String contentServerPort[] = null;
+ String contentPointers[] = null;
+
+ int port = 0, pointer = 0;
+
+ try {
+ if ((contentServerName = message.getHeader(CONTENT_SERVER_NAME)) == null
+ || (contentServerPort = message
+ .getHeader(CONTENT_SERVER_PORT)) == null
+ || (contentPointers = message.getHeader(CONTENT_POINTER)) == null)
+ return false;
+
+ if (contentServerName.length == 0) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_missing_content_server_name),
+ // Toast.LENGTH_LONG).show();
+ return false;
+ }
+
+ if (contentServerPort.length == 0) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_missing_content_server_port),
+ // Toast.LENGTH_LONG).show();
+ return false;
+ } else {
+ try {
+ port = Integer.parseInt(contentServerPort[0]);
+ } catch (Exception e) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_bogus_content_server_port)
+ // + port, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ if (port < 0) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_rangerr_content_server_port)
+ // + contentServerPort, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ }
+
+ if (contentPointers.length == 0) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_missing_content_pointers),
+ // Toast.LENGTH_LONG).show();
+ return false;
+ } else {
+ StringTokenizer st = new StringTokenizer(contentPointers[0]);
+ for (; st.hasMoreTokens();) {
+ try {
+ pointer = Integer.parseInt(st.nextToken());
+ } catch (Exception e) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_bogus_content_pointer)
+ // + pointer, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ if (pointer < 0 || pointer % 8 != 0) {
+ // Toast.makeText(this.getContext(),
+ // this.getContext().getString(R.string.message_compose_error_bogus_content_pointer)
+ // + pointer, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ }
+ }
+ } catch (MessagingException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public static long getCurrentFreeMemoryBytes() {
+ long heapSize = Runtime.getRuntime().totalMemory();
+ long heapRemaining = Runtime.getRuntime().freeMemory();
+ long nativeUsage = 0; // Debug.getNativeHeapAllocatedSize();
+
+ return Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining)
+ - nativeUsage;
+ }
+}
\ No newline at end of file
Modified: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/service/GetMessageDetailsServiceImpl.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/service/GetMessageDetailsServiceImpl.java?rev=1516486&r1=1516485&r2=1516486&view=diff
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/service/GetMessageDetailsServiceImpl.java (original)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/service/GetMessageDetailsServiceImpl.java Thu Aug 22 15:29:57 2013
@@ -54,11 +54,14 @@ import javax.mail.Flags.Flag;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Part;
import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
-import org.apache.hupa.server.utils.MessageUtils;
import org.apache.hupa.shared.data.GetMessageDetailsResultImpl;
import org.apache.hupa.shared.data.MailHeaderImpl;
+import org.apache.hupa.shared.data.MessageAttachmentImpl;
import org.apache.hupa.shared.data.MessageDetailsImpl;
import org.apache.hupa.shared.domain.GetMessageDetailsAction;
import org.apache.hupa.shared.domain.GetMessageDetailsResult;
@@ -115,12 +118,12 @@ public class GetMessageDetailsServiceImp
MessagingException, UnsupportedEncodingException {
MessageDetails mDetails = new MessageDetailsImpl();
- Object content = message.getContent();
+ Object con = message.getContent();
StringBuffer sbPlain = new StringBuffer();
ArrayList<MessageAttachment> attachmentList = new ArrayList<MessageAttachment>();
- boolean isHTML = MessageUtils.handleParts(message, content, sbPlain, attachmentList);
+ boolean isHTML = handleParts(message, con, sbPlain, attachmentList);
if (isHTML) {
mDetails.setText(filterHtmlDocument(sbPlain.toString(), folderName, uid));
@@ -130,14 +133,115 @@ public class GetMessageDetailsServiceImp
mDetails.setMessageAttachments(attachmentList);
- for (@SuppressWarnings("unchecked") Enumeration<Header> en = message.getAllHeaders(); en.hasMoreElements();) {
+ for (@SuppressWarnings("unchecked")
+ Enumeration<Header> en = message.getAllHeaders(); en.hasMoreElements();) {
Header header = en.nextElement();
mDetails.setMailHeader(new MailHeaderImpl(header.getName(), header.getValue()));
+// mDetails.addHeader(header.getName(), header.getValue());
}
return mDetails;
}
+ /**
+ * Handle the parts of the given message. The method will call itself
+ * recursively to handle all nested parts
+ *
+ * @param message the MimeMessage
+ * @param con the current processing Content
+ * @param sbPlain the StringBuffer to fill with text
+ * @param attachmentList ArrayList with attachments
+ * @throws UnsupportedEncodingException
+ * @throws MessagingException
+ * @throws IOException
+ */
+ protected boolean handleParts(MimeMessage message, Object con, StringBuffer sbPlain,
+ ArrayList<MessageAttachment> attachmentList) throws UnsupportedEncodingException, MessagingException,
+ IOException {
+ boolean isHTML = false;
+ if (con instanceof String) {
+ if (message.getContentType().toLowerCase().startsWith("text/html")) {
+ isHTML = true;
+ } else {
+ isHTML = false;
+ }
+ sbPlain.append((String) con);
+
+ } else if (con instanceof Multipart) {
+
+ Multipart mp = (Multipart) con;
+ String multipartContentType = mp.getContentType().toLowerCase();
+
+ String text = null;
+
+ if (multipartContentType.startsWith("multipart/alternative")) {
+ isHTML = handleMultiPartAlternative(mp, sbPlain);
+ } else {
+ for (int i = 0; i < mp.getCount(); i++) {
+ Part part = mp.getBodyPart(i);
+
+ String contentType = part.getContentType().toLowerCase();
+
+ Boolean bodyRead = sbPlain.length() > 0;
+
+ if (!bodyRead && contentType.startsWith("text/plain")) {
+ isHTML = false;
+ text = (String) part.getContent();
+ } else if (!bodyRead && contentType.startsWith("text/html")) {
+ isHTML = true;
+ text = (String) part.getContent();
+ } else if (!bodyRead && contentType.startsWith("message/rfc822")) {
+ // Extract the message and pass it
+ MimeMessage msg = (MimeMessage) part.getDataHandler().getContent();
+ isHTML = handleParts(msg, msg.getContent(), sbPlain, attachmentList);
+ } else {
+ if (part.getFileName() != null) {
+ // Inline images are not added to the attachment
+ // list
+ // TODO: improve the in-line images detection
+ if (part.getHeader("Content-ID") == null) {
+ MessageAttachment attachment = new MessageAttachmentImpl();
+ attachment.setName(MimeUtility.decodeText(part.getFileName()));
+ attachment.setContentType(part.getContentType());
+ attachment.setSize(part.getSize());
+ attachmentList.add(attachment);
+ }
+ } else {
+ isHTML = handleParts(message, part.getContent(), sbPlain, attachmentList);
+ }
+ }
+
+ }
+ if (text != null)
+ sbPlain.append(text);
+ }
+
+ }
+ return isHTML;
+ }
+
+ private boolean handleMultiPartAlternative(Multipart mp, StringBuffer sbPlain) throws MessagingException,
+ IOException {
+ String text = null;
+ boolean isHTML = false;
+ for (int i = 0; i < mp.getCount(); i++) {
+ Part part = mp.getBodyPart(i);
+
+ String contentType = part.getContentType().toLowerCase();
+
+ // we prefer html
+ if (text == null && contentType.startsWith("text/plain")) {
+ isHTML = false;
+ text = (String) part.getContent();
+ } else if (contentType.startsWith("text/html")) {
+ isHTML = true;
+ text = (String) part.getContent();
+ }
+ }
+ sbPlain.append(text);
+ return isHTML;
+ }
+
protected String txtDocumentToHtml(String txt, String folderName, long uuid) {
if (txt == null || txt.length() == 0)
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org