View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  package org.apache.james.transport.mailets;
20  
21  import org.apache.james.core.MailImpl;
22  import org.apache.james.test.mock.mailet.MockMailContext;
23  import org.apache.james.test.mock.mailet.MockMailetConfig;
24  import org.apache.mailet.Mail;
25  import org.apache.mailet.Mailet;
26  
27  import javax.mail.MessagingException;
28  import javax.mail.Session;
29  import javax.mail.internet.MimeMessage;
30  import javax.mail.internet.MimeUtility;
31  
32  import java.io.ByteArrayInputStream;
33  import java.io.ByteArrayOutputStream;
34  import java.io.IOException;
35  import java.io.UnsupportedEncodingException;
36  import java.util.Properties;
37  
38  import junit.framework.TestCase;
39  
40  /***
41   * Test encoding issues
42   * 
43   * This test should also be run with the following JVM options to be sure it tests:
44   * "-Dfile.encoding=ASCII -Dmail.mime.charset=ANSI_X3.4-1968"
45   */
46  public class AddFooterTest extends TestCase {
47  
48      public AddFooterTest(String arg0) throws UnsupportedEncodingException {
49          super(arg0);
50          
51          /*
52          
53          String encoding = (new InputStreamReader(System.in)).getEncoding();
54          System.out.println("System Encoding: "+encoding);
55          System.out.println("Default Java Charset:"+MimeUtility.getDefaultJavaCharset());
56          System.out.println("---------");
57          String a = "\u20AC\u00E0"; // euro char followed by an italian a with an accent System.out.println(debugString(a,"UTF-8"));
58          System.out.println(debugString(a,"UTF8"));
59          System.out.println(debugString(a,"UTF-16"));
60          System.out.println(debugString(a,"UNICODE"));
61          System.out.println(debugString(a,"ISO-8859-15"));
62          System.out.println(debugString(a,"ISO-8859-1"));
63          System.out.println(debugString(a,"CP1252"));
64          System.out.println(debugString(a,"ANSI_X3.4-1968"));
65           
66           */
67      }
68  
69      private final static char[] hexchars = { '0', '1', '2', '3', '4', '5', '6',
70              '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
71  
72      public String debugString(String a, String charset)
73              throws UnsupportedEncodingException {
74          byte[] bytes = a.getBytes(charset);
75          StringBuffer res = new StringBuffer();
76          for (int i = 0; i < bytes.length; i++) {
77              if (i > 0)
78                  res.append("-");
79              res.append(hexchars[((bytes[i] + 256) % 256) / 16]);
80              res.append(hexchars[((bytes[i] + 256) % 256) % 16]);
81          }
82          res.append(" (");
83          res.append(MimeUtility.mimeCharset(charset));
84          res.append(" / ");
85          res.append(MimeUtility.javaCharset(charset));
86          res.append(")");
87          return res.toString();
88      }
89  
90      /*
91       * Class under test for String getSubject()
92       */
93      public void testAddFooterTextPlain() throws MessagingException, IOException {
94  
95          // quoted printable mimemessage text/plain
96          String asciisource = "Subject: test\r\nContent-Type: text/plain; charset=ISO-8859-15\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and one\r\n";
97  
98          String iso885915qpheader = "------ my footer =E0/=A4 ------";
99          String footer = "------ my footer \u00E0/\u20AC ------";
100 
101         String res = processAddFooter(asciisource, footer);
102 
103         assertEquals(asciisource + iso885915qpheader, res);
104 
105     }
106 
107     public void testUnsupportedEncoding() throws MessagingException, IOException {
108 
109         // quoted printable mimemessage text/plain
110         String asciisource = "Subject: test\r\nContent-Type: text/plain; charset=UNSUPPORTED_ENCODING\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and one\r\n";
111 
112         String footer = "------ my footer \u00E0/\u20AC ------";
113 
114         try {
115             String res = processAddFooter(asciisource, footer);
116             assertEquals(asciisource, res);
117         } catch (Exception e) {
118             fail("should not throw an exception: "+e.getMessage());
119         }
120 
121 
122     }
123 
124     /*
125      * Test for      JAMES-443
126      * This should not add the header and should leave the multipart/mixed Content-Type intact
127      */
128     public void testAddFooterMimeNestedUnsupportedMultipart() throws MessagingException, IOException {
129 
130         // quoted printable mimemessage text/plain
131         String asciisource = "MIME-Version: 1.0\r\n"
132             +"Content-Type: multipart/mixed; boundary=\"===============0204599088==\"\r\n"
133                 +"\r\n"
134                 +"This is a cryptographically signed message in MIME format.\r\n"
135                 +"\r\n"
136                 +"--===============0204599088==\r\n"
137                 +"Content-Type: multipart/unsupported; boundary=\"------------ms050404020900070803030808\"\r\n"
138                 +"\r\n"
139                 +"--------------ms050404020900070803030808\r\n"
140                 +"Content-Type: text/plain; charset=ISO-8859-1\r\n"
141                 +"\r\n"
142                 +"test\r\n"
143                 +"\r\n"
144                 +"--------------ms050404020900070803030808--\r\n"
145                 +"\r\n"
146                 +"--===============0204599088==--\r\n";
147         // String asciisource = "Subject: test\r\nContent-Type: multipart/mixed; boundary=\"===============0204599088==\"\r\nMIME-Version: 1.0\r\n\r\nThis is a cryptographically signed message in MIME format.\r\n\r\n--===============0204599088==\r\nContent-Type: text/plain\r\n\r\ntest\r\n--===============0204599088==\r\nContent-Type: text/plain; charset=\"us-ascii\"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline\r\n\r\ntest\r\n--===============0204599088==--\r\n";
148 
149         String footer = "------ my footer \u00E0/\u20AC ------";
150 
151         String res = processAddFooter(asciisource, footer);
152 
153         assertEquals(asciisource, res);
154 
155     }
156     
157     /*
158      * Test for      JAMES-368
159      * AddFooter couldn't process mails which MimeType is multipart/related
160      */
161     public void testAddFooterMultipartRelated() throws MessagingException, IOException {
162 
163         // quoted printable mimemessage text/plain
164         String asciisource = "MIME-Version: 1.0\r\n"
165             +"Subject: test\r\n"
166             +"Content-Type: multipart/related;\r\n"
167             +"  boundary=\"------------050206010102010306090507\"\r\n"
168             +"\r\n"
169             +"--------------050206010102010306090507\r\n"
170             +"Content-Type: text/html; charset=ISO-8859-15\r\n"
171             +"Content-Transfer-Encoding: quoted-printable\r\n"
172             +"\r\n"
173             +"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n"
174             +"<html>\r\n"
175             +"<head>\r\n"
176             +"<meta content=3D\"text/html;charset=3DISO-8859-15\" http-equiv=3D\"Content-Typ=\r\n"
177             +"e\">\r\n"
178             +"</head>\r\n"
179             +"<body bgcolor=3D\"#ffffff\" text=3D\"#000000\">\r\n"
180             +"<br>\r\n"
181             +"<div class=3D\"moz-signature\">-- <br>\r\n"
182             +"<img src=3D\"cid:part1.02060605.123@zzz.com\" border=3D\"0\"></div>\r\n";
183         String asciifoot = "</body>\r\n"
184             +"</html>\r\n"
185             +"\r\n"
186             +"--------------050206010102010306090507\r\n"
187             +"Content-Type: image/gif\r\n"
188             +"Content-Transfer-Encoding: base64\r\n"
189             +"Content-ID: <part1.02060605.123@zzz.com>\r\n"
190             +"Content-Disposition: inline;\r\n"
191             +"\r\n"
192             +"YQ==\r\n"
193             +"--------------050206010102010306090507--\r\n";
194 
195         // String asciisource = "Subject: test\r\nContent-Type: multipart/mixed; boundary=\"===============0204599088==\"\r\nMIME-Version: 1.0\r\n\r\nThis is a cryptographically signed message in MIME format.\r\n\r\n--===============0204599088==\r\nContent-Type: text/plain\r\n\r\ntest\r\n--===============0204599088==\r\nContent-Type: text/plain; charset=\"us-ascii\"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline\r\n\r\ntest\r\n--===============0204599088==--\r\n";
196 
197         String footer = "------ my footer \u00E0/\u20AC ------";
198         String expectedFooter = "<br>------ my footer =E0/=A4 ------";
199 
200         String res = processAddFooter(asciisource+asciifoot, footer);
201 
202         assertEquals(asciisource+expectedFooter+asciifoot, res);
203 
204     }
205     
206     
207 
208     /*
209      * Class under test for String getSubject()
210      */
211     public void testAddFooterTextPlainISO8859() throws MessagingException, IOException {
212 
213         // quoted printable mimemessage text/plain
214         String asciisource = "Subject: test\r\nContent-Type: text/plain; charset=iso-8859-15\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and one =A4\r\n";
215 
216         String iso885915qpheader = "------ my footer =E0/=A4 ------";
217         String footer = "------ my footer \u00E0/\u20AC ------";
218 
219         String res = processAddFooter(asciisource, footer);
220 
221         assertEquals(asciisource + iso885915qpheader, res);
222 
223     }
224 
225     /*
226      * Class under test for String getSubject()
227      */
228     public void testAddFooterMultipartAlternative() throws MessagingException,
229             IOException {
230 
231         String sep = "--==--";
232         String head = "Subject: test\r\nContent-Type: multipart/alternative;\r\n    boundary=\""
233                 + sep
234                 + "\"\r\nMIME-Version: 1.0\r\n";
235         String content1 = "Content-Type: text/plain;\r\n    charset=\"ISO-8859-15\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and @=80";
236         String c2h = "Content-Type: text/html;\r\n    charset=\"CP1252\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n";
237         String c2pre = "<html><body>test =80 ss";
238         String c2post = "</body></html>";
239 
240         StringBuffer asciisource = new StringBuffer();
241         asciisource.append(head);
242         asciisource.append("\r\n--");
243         asciisource.append(sep);
244         asciisource.append("\r\n");
245         asciisource.append(content1);
246         asciisource.append("\r\n--");
247         asciisource.append(sep);
248         asciisource.append("\r\n");
249         asciisource.append(c2h);
250         asciisource.append(c2pre);
251         asciisource.append(c2post);
252         asciisource.append("\r\n--");
253         asciisource.append(sep);
254         asciisource.append("--\r\n");
255 
256         String iso885915qpheader = "------ my footer =E0/=A4 ------";
257         String cp1252qpfooter = "------ my footer =E0/=80 ------";
258         String footer = "------ my footer \u00E0/\u20AC ------";
259 
260         StringBuffer expected = new StringBuffer();
261         expected.append(head);
262         expected.append("\r\n--");
263         expected.append(sep);
264         expected.append("\r\n");
265         expected.append(content1);
266         expected.append("\r\n");
267         expected.append(iso885915qpheader);
268         expected.append("\r\n--");
269         expected.append(sep);
270         expected.append("\r\n");
271         expected.append(c2h);
272         expected.append(c2pre);
273         expected.append("<br>");
274         expected.append(cp1252qpfooter);
275         expected.append(c2post);
276         expected.append("\r\n--");
277         expected.append(sep);
278         expected.append("--\r\n");
279         
280         String res = processAddFooter(asciisource.toString(), footer);
281 
282         assertEquals(expected.toString(), res);
283 
284     }
285 
286     private String processAddFooter(String asciisource, String footer)
287             throws MessagingException, IOException {
288         Mailet mailet = new AddFooter();
289 
290         MockMailetConfig mci = new MockMailetConfig("Test",new MockMailContext());
291         mci.setProperty("text",footer);
292 
293         mailet.init(mci);
294 
295         Mail mail = new MailImpl(new MimeMessage(Session
296                 .getDefaultInstance(new Properties()),
297                 new ByteArrayInputStream(asciisource.getBytes())));
298 
299         mailet.service(mail);
300 
301         ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
302         mail.getMessage().writeTo(
303                 rawMessage,
304                 new String[] { "Bcc", "Content-Length", "Message-ID" });
305         String res = rawMessage.toString();
306         return res;
307     }
308 
309 }