Email Java

/*
 * Funambol is a mobile platform developed by Funambol, Inc. 
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission 
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE 
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License 
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 * 
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite 
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably 
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
/**
 * A utility class providing methods to convert date information contained in
 * Date objects into RFC2822 and UTC ('Zulu') strings, and to
 * build Date objects starting from string representations of
 * dates in RFC2822 and UTC format
 */
public class MailDateFormatter {
    
    /** Format date as: MM/DD */
    public static final int FORMAT_MONTH_DAY = 0;
    /** Format date as: MM/DD/YYYY */
    public static final int FORMAT_MONTH_DAY_YEAR = 1;
    /** Format date as: hh:mm */
    public static final int FORMAT_HOURS_MINUTES = 2;
    /** Format date as: hh:mm:ss */
    public static final int FORMAT_HOURS_MINUTES_SECONDS = 3;
    /** Format date as: DD/MM */
    public static final int FORMAT_DAY_MONTH = 4;
    /** Format date as: DD/MM/YYYY */
    public static final int FORMAT_DAY_MONTH_YEAR = 5;
    
    /** Device offset, as string */
    private static String deviceOffset = "+0000";
    /** Device offset, in millis */
    private static long millisDeviceOffset = 0;
    /** Names of the months */
    private static String[] monthNames = new String[] {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
     
    /**
     * Transforms data contained in a Date object (expressed in
     * UTC) in a string formatted as per RFC2822 in local time (par. 3.3)
     *
     * @return A string representing the date contained in the passed
     *         Date object formatted as per RFC 2822 and in local
     *         time
     */
    public static String dateToRfc2822(Date date) {
        
        Calendar deviceTime = Calendar.getInstance();
        deviceTime.setTime(date);
   
        String dayweek = "";
        int dayOfWeek = deviceTime.get(deviceTime.DAY_OF_WEEK);
        switch (dayOfWeek) {
            case 1 : dayweek = "Sun"; break;
            case 2 : dayweek = "Mon"; break;
            case 3 : dayweek = "Tue"; break;
            case 4 : dayweek = "Wed"; break;
            case 5 : dayweek = "Thu"; break;
            case 6 : dayweek = "Fri"; break;
            case 7 : dayweek = "Sat"; break;
        }
        
        int dayOfMonth = deviceTime.get(deviceTime.DAY_OF_MONTH);
        
        String monthInYear = getMonthName(deviceTime.get(deviceTime.MONTH));
        
        int year = deviceTime.get(deviceTime.YEAR);
        int hourOfDay = deviceTime.get(deviceTime.HOUR_OF_DAY);
        int minutes = deviceTime.get(deviceTime.MINUTE);
        int seconds = deviceTime.get(deviceTime.SECOND);
        
        String rfc = dayweek + ", " +                                   // Tue
                dayOfMonth + " " +                                      // 7
                monthInYear + " " +                                     // Nov
                year + " " +                                            // 2006
                hourOfDay + ":" + minutes + ":" + seconds + " " +       // 14:13:26
                deviceOffset;                                           //+0200  
        return rfc;
    }
    
    
    /**
     * Converts a Date object into a string in 'Zulu' format
     *
     * @param d
     *            A Date object to be converted into a string in
     *            'Zulu' format
     * @return A string representing the date contained in the passed
     *         Date object in 'Zulu' format (e.g.
     *         yyyyMMDDThhmmssZ)
     */
    public static String dateToUTC(Date d) {
        StringBuffer date = new StringBuffer();
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        
        date.append(cal.get(Calendar.YEAR));
        
        date.append(printTwoDigits(cal.get(Calendar.MONTH) + 1))
            .append(printTwoDigits(cal.get(Calendar.DATE)))
            .append("T");
        
        date.append(printTwoDigits(cal.get(Calendar.HOUR_OF_DAY)))
            .append(printTwoDigits(cal.get(Calendar.MINUTE)))
            .append(printTwoDigits(cal.get(Calendar.SECOND)))
            .append("Z");
        
        return date.toString();
    }
    
    
    /**
     * A method that returns a string rapresenting a date.
     *
     * @param date the date
     *
     * @param format the format as one of
     * FORMAT_MONTH_DAY,
     * FORMAT_MONTH_DAY_YEAR,
     * FORMAT_HOURS_MINUTES,
     * FORMAT_HOURS_MINUTES_SECONDS
     * FORMAT_DAY_MONTH
     * FORMAT_DAY_MONTH_YEAR
     * constants
     *
     * @param separator the separator to be used
     */
    public static String getFormattedStringFromDate(
            Date date, int format, String separator) {
        
        Calendar cal=Calendar.getInstance();
        cal.setTime(date);
        StringBuffer ret = new StringBuffer();
        
        switch (format) {
            case FORMAT_HOURS_MINUTES:
                //if pm and hour == 0 we want to write 12, not 0
                if (cal.get(Calendar.AM_PM)==Calendar.PM
                        && cal.get(Calendar.HOUR) == 0) {
                    ret.append("12");
                } else {
                    ret.append(cal.get(Calendar.HOUR));
                }
                ret.append(separator)
                    .append(printTwoDigits(cal.get(Calendar.MINUTE)))
                    .append(getAMPM(cal));
                break;
                
            case FORMAT_HOURS_MINUTES_SECONDS:
                //if pm and hour == 0 we want to write 12, not 0
                if (cal.get(Calendar.AM_PM)==Calendar.PM
                        && cal.get(Calendar.HOUR) == 0) {
                    ret.append("12");
                } else {
                    ret.append(cal.get(Calendar.HOUR));
                }
                ret.append(separator)
                    .append(printTwoDigits(cal.get(Calendar.MINUTE)))
                    .append(separator)
                    .append(cal.get(Calendar.SECOND))
                    .append(getAMPM(cal));
                break;
                
            case FORMAT_MONTH_DAY:
                ret.append(cal.get(Calendar.MONTH)+1)
                    .append(separator)
                    .append(cal.get(Calendar.DAY_OF_MONTH));
                break;
                
            case FORMAT_DAY_MONTH:
                ret.append(cal.get(Calendar.DAY_OF_MONTH))
                    .append(separator)
                    .append(cal.get(Calendar.MONTH)+1);
                break;
                
            case FORMAT_MONTH_DAY_YEAR:
                ret.append(cal.get(Calendar.MONTH)+1)
                    .append(separator)
                    .append(cal.get(Calendar.DAY_OF_MONTH))
                    .append(separator)
                    .append(cal.get(Calendar.YEAR));
                break;
                
            case FORMAT_DAY_MONTH_YEAR:
                ret.append(cal.get(Calendar.DAY_OF_MONTH))
                    .append(separator)
                    .append(cal.get(Calendar.MONTH)+1)
                    .append(separator)
                    .append(cal.get(Calendar.YEAR));
                break;
                
            default:
              //  Log.error("getFormattedStringFromDate: invalid format ("+
                //        format+")");
        }
        
        return ret.toString();
    }
    
    /**
     * Returns a localized string representation of Date.
     */
    public static String formatLocalTime(Date d) {
        int dateFormat = FORMAT_MONTH_DAY_YEAR;
        int timeFormat = FORMAT_HOURS_MINUTES;
        
        if(!System.getProperty("microedition.locale").equals("en")) {
            dateFormat = FORMAT_DAY_MONTH_YEAR;
        }
        return getFormattedStringFromDate(d,FORMAT_MONTH_DAY_YEAR,"/")
                +" "+getFormattedStringFromDate(d,FORMAT_HOURS_MINUTES,":");
    }
    
    
    /**
     * Parses the string in RFC 2822 format and return a Date
     * object. 


     * Parse strings like:
     * Thu, 03 May 2007 14:45:38 GMT
     * Thu, 03 May 2007 14:45:38 GMT+0200
     * Thu,  1 Feb 2007 03:57:01 -0800
     * Fri, 04 May 2007 13:40:17 PDT
     * 
     * @param d the date representation to parse
     * @return a date, if valid, or null on error
     *
     */
    public static Date parseRfc2822Date(String stringDate) {
        if (stringDate == null) {
            return null;
        }
        
        long hourOffset=0;
        long minOffset=0;
        Calendar cal = Calendar.getInstance();
        
        try {
            
            // We use the ' ' as separator and we expect only one space. We
            // clean the string to remove extra spaces
            StringBuffer cleanedDate = new StringBuffer();
            char previous = 'a';
            for(int i=0;i                char ch = stringDate.charAt(i);
                if (ch != ' ' || previous != ' ') {
                    cleanedDate.append(ch);
                }
                previous = ch;
            }
            stringDate = cleanedDate.toString();
           // Log.debug("Cleaned date: " + stringDate);
            
            // Just skip the weekday if present
            int start = stringDate.indexOf(',');
            //put start after ", "
            start = (start == -1) ? 0 : start + 2;
            
            stringDate = stringDate.substring(start).trim();
            start = 0;
            
            // Get day of month
            int end = stringDate.indexOf(' ', start);
           
            //4  Nov 2008 10:30:05 -0400
            
            int day =1;
            try {
               day = Integer.parseInt(stringDate.substring(start, end)); 
            } catch (NumberFormatException ex) {
                day = Integer.parseInt(stringDate.substring(start+3, end));
            }
            
            cal.set(Calendar.DAY_OF_MONTH,day);
            
            // Get month
            start = end + 1;
            end = stringDate.indexOf(' ', start);
            cal.set(Calendar.MONTH, getMonthNumber(stringDate.substring(start, end)));
            // Get year
            start = end + 1;
            end = stringDate.indexOf(' ', start);
            cal.set(Calendar.YEAR,
                    Integer.parseInt(stringDate.substring(start, end)));
            // Get hour
            start = end + 1;
            end = stringDate.indexOf(':', start);
            cal.set(Calendar.HOUR_OF_DAY,
                    Integer.parseInt(stringDate.substring(start, end).trim()));
            // Get min
            start = end + 1;
            end = stringDate.indexOf(':', start);
            cal.set(Calendar.MINUTE,
                    Integer.parseInt(stringDate.substring(start, end)));
            // Get sec
            start = end + 1;
            end = stringDate.indexOf(' ', start);
            cal.set(Calendar.SECOND,
                    Integer.parseInt(stringDate.substring(start, end)));
            // Get OFFSET
            start = end +1;
            end = stringDate.indexOf('\r', start);
            
            // Process Timezone, checking first for the actual RFC2822 format,
            // and then for nthe obsolete syntax.
            char sign = '+';
            String hourDiff = "0";
            String minDiff = "0";
            String offset = stringDate.substring(start).trim();
            if (offset.startsWith("+") || offset.startsWith("-")) {
                if(offset.length() >= 5 ){
                    sign = offset.charAt(0);
                    hourDiff = offset.substring(1,3);
                    minDiff = offset.substring(3,5);
                }
                else if(offset.length() == 3){
                    sign = offset.charAt(0);
                    hourDiff = offset.substring(1);
                    minDiff = "00";
                }
                // Convert offset to int
                hourOffset = Long.parseLong(hourDiff);
                minOffset = Long.parseLong(minDiff);
                if(sign == '-') {
                    hourOffset = -hourOffset;
                }
            }
            else if(offset.equals("EDT")){
                hourOffset = -4;
            }
            else if(offset.equals("EST") || offset.equals("CDT")){
                hourOffset = -5;
            }
            else if(offset.equals("CST") || offset.equals("MDT")){
                hourOffset = -6;
            }
            else if(offset.equals("PDT") || offset.equals("MST")){
                hourOffset = -7;
            }
            else if(offset.equals("PST")){
                hourOffset = -8;
            }
            else if(offset.equals("GMT") || offset.equals("UT")){
                hourOffset = 0;
            }
            else if (offset.substring(0,3).equals("GMT") && offset.length() > 3){
                sign = offset.charAt(3);
                hourDiff = offset.substring(4,6);
                minDiff = offset.substring(6,8);                
            }
            long millisOffset = (hourOffset * 3600000) + (minOffset * 60000);
     
            Date gmtDate = cal.getTime();
            long millisDate = gmtDate.getTime();
            
            millisDate -= millisOffset;
            
            gmtDate.setTime(millisDate);
            return gmtDate;
            
        } catch (Exception e) {
      
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * Convert the given date (GMT) into the local date.
     * NOTE: changes the original date too!
     * Should we change it to a void toLocalDate(Date) that changes the
     * input date only?
     */
    public static Date getDeviceLocalDate (Date gmtDate){
        if (null != gmtDate){
            /*long dateInMillis = gmtDate.getTime();
            Date deviceDate = new Date();
            deviceDate.setTime(dateInMillis+millisDeviceOffset);
            return deviceDate;
             **/
            gmtDate.setTime(gmtDate.getTime()+millisDeviceOffset);
            return gmtDate;
        }
        else {
            return null;
        }
    }
    
    
    /**
     * Gets a Date object from a string representing a date in
     * 'Zulu' format (yyyyMMddTHHmmssZ)
     *
     * @param utc
     *            date in 'Zulu' format (yyyyMMddTHHmmssZ)
     * @return A Date object obtained starting from a time in
     *         milliseconds from the Epoch
     */
    public static Date parseUTCDate(String utc) {
        
        int day = 0;
        int month = 0;
        int year = 0;
        int hour = 0;
        int minute = 0;
        int second = 0;
        Calendar calendar = null;
        
        day = Integer.parseInt(utc.substring(6, 8));
        month = Integer.parseInt(utc.substring(4, 6));
        year = Integer.parseInt(utc.substring(0, 4));
        hour = Integer.parseInt(utc.substring(9, 11));
        minute = Integer.parseInt(utc.substring(11, 13));
        second = Integer.parseInt(utc.substring(13, 15));
        
        
        calendar = Calendar.getInstance();
        
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        
        
        Date date = calendar.getTime();
        long dateInMillis = date.getTime();
            
        date.setTime(dateInMillis+millisDeviceOffset);
            
        return date;
    }
    
    public static void setTimeZone(String timeZone){
        
        if (timeZone == null || timeZone.length() < 5) {
           // Log.error("setTimeZone: invalid timezone " + timeZone);
        }
        try {
            deviceOffset = timeZone;
            String hstmz = deviceOffset.substring(1, 3);
            String mstmz = deviceOffset.substring(3, 5);
            
            long hhtmz = Long.parseLong(hstmz);
            long mmtmz = Long.parseLong(mstmz);
            millisDeviceOffset = (hhtmz * 3600000) + (mmtmz * 60000);
            if(deviceOffset.charAt(0)=='-') {
                millisDeviceOffset *= -1;
            }   
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * returns a date with string representation of the month
     * @param date input date in the format MM/DD/YYYY HH:MMp/a
     * @return a representation of the date in the format  DD, YYYY HH:MM
     */
    public static String getReplyDateString(String date) {
        StringBuffer ret = new StringBuffer();
        //Replace the month number with the month name
        String monthName = getMonthName(
                Integer.parseInt(date.substring(0, date.indexOf('/')))-1
                );
        String day = date.substring(date.indexOf('/')+1, date.lastIndexOf('/'));
        String yearAndTime = date.substring(date.lastIndexOf('/')+1);
        
        ret.append(monthName).append(" ").append(day).append(", ").append(yearAndTime);
        //Replace the slash char between DD and YYYY with ", "
        return ret.toString();
    } 
    
    //------------------------------------------------------------- Private methods
    /**
     * Get the number of the month, given the name.
     */
    private static int getMonthNumber(String name) {
        for(int i=0, l=monthNames.length; i            if(monthNames[i].equals(name)) {
                return i;
            }
        }
        return -1;
    }
    /**
     * Get the name of the month, given the number.
     */
    private static String getMonthName(int number) {
        if(number>=0 && number            return monthNames[number];
        }
        else return null;
    }
    private static String getAMPM(Calendar cal) {
        return (cal.get(Calendar.AM_PM)==Calendar.AM)?"a":"p";
    }
    
    /**
     * Returns a string representation of number with at least 2 digits
     */
    private static String printTwoDigits(int number) {
        if (number>9) {
            return String.valueOf(number);
        } else {
            return "0"+number;
        }
    }
}