KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > SnowMailClient > utils > MailMessageUtils


1 package SnowMailClient.utils;
2
3 import java.util.regex.Matcher JavaDoc;
4 import java.util.regex.Pattern JavaDoc;
5 import SnowMailClient.crypto.Utilities;
6 import snow.utils.storage.*;
7 import SnowMailClient.model.Header;
8 import SnowMailClient.model.Address;
9 import SnowMailClient.model.HeaderEntry;
10 import java.util.*;
11 import java.text.*;
12 import java.io.*;
13 import java.text.SimpleDateFormat JavaDoc;
14
15
16 public final class MailMessageUtils
17 {
18    private static final SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
19
20    // used when parsing
21
private static final SimpleDateFormat JavaDoc pdateFormat = new SimpleDateFormat JavaDoc("d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
22    private static final SimpleDateFormat JavaDoc pbadButFrequentDateFormat = new SimpleDateFormat JavaDoc("d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
23    private static final SimpleDateFormat JavaDoc pbadButFrequentDateFormat2 = new SimpleDateFormat JavaDoc("d MMM yyyy HH:mm:ss", Locale.ENGLISH);
24    private static final SimpleDateFormat JavaDoc pbadButFrequentDateFormat3 = new SimpleDateFormat JavaDoc("d MMM yyyy HH:mm Z", Locale.ENGLISH);
25    private static final SimpleDateFormat JavaDoc pbadButFrequentDateFormat4 = new SimpleDateFormat JavaDoc("MM.dd.yyyy HH:mm:ss", Locale.ENGLISH);
26
27     /** correct format
28          "14 Feb 2004 18:07:05 +0100"
29         sometimes encountered
30          "28 Dec 2003 11:05:44 -0000"
31          "16 Mar 2004 17:41:59 -00"
32          TODO#### '01 Jun 2004 21:39 -0700'
33          05 Jun 2004 1:10 -0700
34          // ONLY ONCE: Fri, 29 Oct 2004 08:47:14
35
36          Tuesday, 17 Jan 2006 09:35:04 +01:00 //bad : at the end
37          //Jan2006:
38
39          Cannot parse date from 'Fr, 24 Jun 2005 03:55:07'
40     */

41    public final static String JavaDoc msgDateFormat(Date date)
42    {
43      return dateFormat.format(date);
44    }
45
46    /** Sometimes encountered: %CURRENT_DATE_TIME
47
48    */

49    public final static Date parseDateFromString(String JavaDoc s) throws Exception JavaDoc
50    {
51      // remove the day name, if any (always , separated)
52
int posComa = s.indexOf(",");
53      if(posComa>=0)
54      {
55        s = s.substring(posComa+1).trim();
56      }
57
58      try
59      {
60        return pdateFormat.parse(s);
61      }
62      catch(Exception JavaDoc e1)
63      {
64        try
65        {
66          return pbadButFrequentDateFormat.parse(s);
67        }
68        catch(Exception JavaDoc e2) { }
69
70        try
71        {
72          return pbadButFrequentDateFormat2.parse(s);
73        }
74        catch(Exception JavaDoc e2) { }
75
76        try
77        {
78          return pbadButFrequentDateFormat3.parse(s);
79        }
80        catch(Exception JavaDoc e2) { }
81
82        try
83        {
84          return pbadButFrequentDateFormat4.parse(s);
85        }
86        catch(Exception JavaDoc e2) { }
87
88        try
89        {
90          return pdateFormat.parse(s+"00");
91        }
92        catch(Exception JavaDoc e3) { }
93
94
95
96        if(s.equalsIgnoreCase("%CURRENT_DATE_TIME")) return new Date();
97
98        if(s.endsWith(":00"))
99        {
100           // rare, but occurs, bad z (or correct seconds...)
101
return parseDateFromString(s.substring(0,s.length()-3));
102        }
103      }
104
105      throw new Exception JavaDoc("Cannot parse date from "+s);
106    }
107
108 /**
109  zmailer
110  Message-Id: <19980601143757Z2848-6117+4@nic.funet.fi>
111               YYYYMMDDhhmmssZnnnn-nnn+nn@hostname
112 */

113    public static String JavaDoc createMessageID(Address address)
114    {
115      int rand = (int)(Math.random()*1e8);
116      return "<"+rand+"."+address.getMailAddress()+">";
117
118      //return "<AAA"+rand+"BBB@62.65.146.182>";
119

120      //return "<EOECLIBDGGBLJBCOFBJLEEDPCAAA."+address.getMailAddress()+">";
121
//return "<EOECLIBDGGBLJBCOFBJLMEDPCAAA."+address.getMailAddress()+">";
122

123    }
124
125    public static final DecimalFormat formatSize0 = new DecimalFormat("0.0");
126    public static final DecimalFormat formatSize = new DecimalFormat("0");
127
128    public static String JavaDoc formatSize(long size)
129    {
130       if(size>3000000) return ""+formatSize.format(size/1000000.0) +" MB";
131       if(size>1000000) return ""+formatSize0.format(size/1000000.0) +" MB";
132       if(size>3000) return ""+formatSize.format(size/1000.0) +" kB";
133       if(size>1000) return ""+formatSize0.format(size/1000.0) +" kB";
134       return ""+(size) +" B";
135    }
136
137
138    /** parse the to string and strip out the mail address from "some name <address@somewhere>"
139     * @return someone@somewhere.yes
140     */

141    public static String JavaDoc grabAddress(String JavaDoc addddressssssss)
142    {
143       // kill white space
144
String JavaDoc strToCmd = addddressssssss.trim();
145
146       // check if the address contains a < if so then just use whats inside
147
// otherwise use the address given
148
int intFoundStart = strToCmd.indexOf('<');
149       if (intFoundStart != -1)
150       {
151          // found it strip everything from inside
152
int intFoundEnd = strToCmd.indexOf('>');
153          if (intFoundEnd != -1)
154          {
155             return strToCmd.substring(intFoundStart+1,intFoundEnd).trim();
156          }
157          else
158          {
159             return strToCmd.substring(intFoundStart+1,strToCmd.length()).trim();
160          }
161       }
162       else
163       {
164          // not found - use as is
165
return strToCmd;
166       }
167    }
168
169
170    /** I saw 5 variants
171          =?iso-8859-1?q?ugly=20est=20la?= ==> "ugly est la"
172          =?iso-8859-1?B?bej2gej1ot431re?= ==> decode base 64(bej2gej1ot431re)
173          =?utf-8?B?TWljcm9zb2Z0IE91dGxvb2sgVGVzdCBNZXNzYWdl?=
174          [La Lettre] =?ISO-8859-1?Q?Num=E9ro?=_=?ISO-8859-1?Q?sp=E9cial?=
175          =?windows-1252?Q? Frage H=E4uschen Lofoten ab 060704?= // #### not implemented...
176
177          WARNING: THIS ONLY DECODE THE FIRST.
178
179          Subject: [Sondage: les sentiments des =?ISO-8859-1?Q?Fran=E7ais?= =?ISO-8859-1?Q?=E0?= l'=?ISO-8859-1?Q?=E9gard?= de l'Europe]
180    */

181    public static String JavaDoc decodeCharsetCodedArgument_(String JavaDoc arg)
182    {
183       int beginOffest = 15;
184       int begCode =0;
185       String JavaDoc charset = "iso-8859-1"; // default
186

187       Pattern JavaDoc pat = Pattern.compile("=\\?([^?]*)\\?");
188       Matcher JavaDoc m = pat.matcher(arg);
189       if(m.find())
190       {
191          charset = m.group(1);
192          beginOffest = m.end(1)+3;
193          //System.out.println("Found: "+charset+": "+beginOffest);
194

195       }
196       else
197       {
198          return arg;
199       }
200
201       if(arg.length()<beginOffest+1)
202       {
203          return arg; // error...
204
}
205
206       // search for the coded portion delimiter end
207
int posEnd = arg.indexOf("?=", beginOffest+3);
208       if(posEnd==-1) return arg; // error
209
if(beginOffest>=arg.length()) return arg; // error
210

211       String JavaDoc coded = arg.substring(beginOffest, posEnd); //## out of bounds -1 ########
212

213
214
215       char chat = arg.charAt(beginOffest-2);
216       if(chat=='q' || chat=='Q')
217       {
218          coded = decodeQuotedPrintable(coded, charset);
219       }
220       else if(chat=='b' || chat=='B')
221       {
222          try
223          {
224            coded = new String JavaDoc(Utilities.decodeBase64(coded), charset);
225          }
226          catch(Exception JavaDoc e)
227          {
228            e.printStackTrace();
229            return arg;
230          }
231       }
232       else
233       {
234         return arg; // error
235
}
236
237       return arg.substring(0,begCode) + coded + arg.substring(posEnd+2);
238    }
239
240
241    /** decode quoted printable text
242    */

243    public static String JavaDoc decodeQuotedPrintable(String JavaDoc in, String JavaDoc charset)
244    {
245      StringBuffer JavaDoc sb = new StringBuffer JavaDoc(in);
246      ByteArrayOutputStream bos = new ByteArrayOutputStream();
247
248      for(int i=0; i<sb.length(); i++)
249      {
250        char ci = sb.charAt(i);
251
252        // ignore
253
if(ci == '\r') continue;
254
255
256        if(ci != '=')
257        {
258           bos.write((byte) ci);
259        }
260        else
261        {
262           int end = i+3;
263           if(end>sb.length()) end = sb.length();
264           String JavaDoc code = sb.substring(i+1, end);
265           if(code.equals("\r\n")) // ignore
266
{
267              i+=2;
268           }
269           else if(code.startsWith("\n")) // ignore
270
{
271              i+=1;
272           }
273           else
274           {
275              // parse char code
276
try
277              {
278                 bos.write((byte) Integer.parseInt(code, 16));
279                 i+=2;
280              }
281              catch(NumberFormatException JavaDoc e)
282              {
283                // System.out.println("Cannot parse quoted printable code '"+code+"'");
284
//e.printStackTrace();
285
}
286           }
287        }
288      }
289
290      try
291      {
292        return new String JavaDoc(bos.toByteArray(), charset);
293      }
294      catch(Exception JavaDoc e)
295      {
296        return in;
297      }
298    }
299
300
301    /** return false if one of the bytes is outside of [0,127]
302      char [ 0 : 127] <> byte[ 0 : 127]
303      char [128 : 255] <> byte[-128 : -1]
304    */

305    public static boolean is7Bits(byte[] chars)
306    {
307      if(chars==null) return true;
308
309      for(byte c: chars)
310      {
311        if(c>127) return false;
312        if(c<0) return false;
313      }
314      return true;
315    }
316
317
318    public static int byteCharToInt(byte b)
319    {
320      if(b<0) return 256+b;
321      return b;
322    }
323
324    /** encode the chars with values above 7 bits according to the quoted printable definition
325        //the return bytes are 7 bits => can be get with getBytes("us-ascii");
326    */

327    public static byte[] encodeMessageQuotedPrintable(byte[] bytes)
328    {
329        StringBuffer JavaDoc reply = new StringBuffer JavaDoc();
330        int lineLength = 0;
331        for(int i=0; i<bytes.length; i++)
332        {
333          int ci = byteCharToInt(bytes[i]);
334
335          if(ci==61) // =
336
{
337            lineLength += 3;
338            reply.append("="+getHexa(61));
339          }
340          else if(ci>=32 && ci<=126)
341          {
342            lineLength++;
343            if(lineLength>76)
344            {
345               reply.append("=\r\n"); // soft break.
346
lineLength = 0;
347            }
348
349            reply.append((char) ci);
350
351          }
352          else if(ci==10) // "\n"
353
{
354            lineLength += 3;
355            if(lineLength>76)
356            {
357                 reply.append("=\r\n");
358                 lineLength = 0;
359            }
360            reply.append("=0A");
361
362          }
363          else
364          {
365            lineLength += 3;
366            if(lineLength>76)
367            {
368                 reply.append("=\r\n");
369                 lineLength = 0;
370            }
371            reply.append("=");
372            reply.append(getHexa(ci));
373          }
374
375        } // end loop over the bytes
376

377        try
378        {
379          return reply.toString().getBytes("us-ascii");
380        }
381        catch(Exception JavaDoc e)
382        {
383          return reply.toString().getBytes();
384        }
385    }
386
387
388    /** encode single lines, as appearing in the header.
389        For the subject and addressees
390        Encodes only if necessary...
391        wraps the "=?utf-8?q?" + CODED TEXT + "?="
392    */

393    public static String JavaDoc encodeLine_QuotedPrintable(String JavaDoc text)
394    {
395      boolean needed = false;
396      String JavaDoc charset = CharsetUtils.getMinimalEncodingCharset(text);
397
398      StringBuffer JavaDoc reply = new StringBuffer JavaDoc();
399      byte[] textBytes = null;
400      try
401      {
402        textBytes = text.getBytes(charset); // utf-8
403
}
404      catch(Exception JavaDoc e)
405      {
406        textBytes = text.getBytes(); // this will NEVER occur
407
}
408
409      for(byte b: textBytes)
410      {
411        int ci = byteCharToInt(b);
412        //System.out.println(""+((int) ci));
413
if (ci==61) // =
414
{
415          needed = true;
416          reply.append("=");
417          reply.append(getHexa(61));
418        }
419        else if(ci>=32 && ci<128)
420        {
421          reply.append((char)b); // ok, no quote needed
422
}
423        else
424        {
425          needed = true;
426          reply.append("=");
427          reply.append(getHexa(ci));
428        }
429      }
430
431      if(needed)
432      {
433        // [March2005] was iso-8859-1 !
434
return "=?"+charset+"?q?"+ reply.toString() +"?=";
435      }
436      else
437      {
438        return reply.toString();
439      }
440    }
441
442
443    public static final String JavaDoc base16 = "0123456789ABCDEF";
444    public static String JavaDoc getHexa(int val)
445    {
446      int first = val/16;
447      int second = val-first*16;
448      return ""+base16.charAt(first)+""+base16.charAt(second);
449    }
450
451    /** try recurse until whole sentence is decoded
452    */

453    public static String JavaDoc decodeCharsetCodedArgumentFully(String JavaDoc in)
454    {
455       int level = 0;
456       String JavaDoc prec = in;
457       while(level<20)
458       {
459         String JavaDoc dec = decodeCharsetCodedArgument_(prec);
460         if(dec.equals(prec)) return dec;
461         prec = dec;
462         level++;
463       }
464       return prec;
465    }
466
467    public static void main(String JavaDoc[] aaa)
468    {
469        System.out.println("reply="+decodeCharsetCodedArgument_("=?iso-8859-1?q?hello=20I=20am?=AAABBB"));
470        System.out.println("reply="+decodeCharsetCodedArgument_("=?iso-8859-1?B?c3VucmlzZSBlLU5ld3NsZXR0ZXI=?=UU"));
471        System.out.println("reply="+decodeCharsetCodedArgument_("=?utf-8?B?TWljcm9zb2Z0IE91dGxvb2sgVGVzdCBNZXNzYWdl?="));
472        System.out.println("reply="+decodeCharsetCodedArgument_("=?iso-8859-15?Q?Lu:__Re:_Etablissement_d=E9finitif_de_JMA_en_Tha=EFlande?="));
473        System.out.println("reply="+decodeCharsetCodedArgument_("=?iso-2022-jp?B?MjCWnI+AlPWCtYLcgrWCvYFCjaGT+oLIgueJvY6egsmIp4KmgtyCt4KpgUg=?="));
474
475
476       String JavaDoc enc = encodeLine_QuotedPrintable("éééé");
477       System.out.println(""+enc);
478       System.out.println(decodeCharsetCodedArgument_(enc));
479
480       byte[] bytes = "\r\n".getBytes();
481       for(byte b: bytes)
482       {
483         int ib = byteCharToInt(b);
484         System.out.println(""+b+" "+ib);
485       }
486
487       byte[] b = encodeMessageQuotedPrintable("Hello\r\nComment =\n vas tú?".getBytes());
488       System.out.println("ENC="+new String JavaDoc(b));
489       System.out.println("DEC="+decodeQuotedPrintable(new String JavaDoc(b), "iso-8859-1"));
490
491       System.out.println(msgDateFormat(new Date()));
492       try
493       {
494         System.out.println(parseDateFromString("Tuesday, 17 Jan 2006 09:35:04 +01:00"));
495         System.out.println(parseDateFromString("Fr, 24 Jun 2005 03:55:07"));
496       } catch(Exception JavaDoc ex) {ex.printStackTrace();}
497
498    }
499
500
501 }
Popular Tags