/*
* 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".
*/
package com.funambol.syncclient.blackberry.email.impl;
import net.rim.blackberry.api.mail.Folder;
import net.rim.blackberry.api.mail.Message;
import net.rim.blackberry.api.mail.Address;
import net.rim.blackberry.api.mail.TextBodyPart;
import net.rim.device.api.i18n.SimpleDateFormat;//CHANGE
import java.util.*;
import com.funambol.syncclient.blackberry.Configuration;
import com.funambol.syncclient.common.StringTools;
import com.funambol.syncclient.util.StaticDataHelper;
/**
* An implementation of MailParser
*
*/
public class XMLMailParser implements MailParser
{
private String tagArray[] = { "read",
"replied",
"modified",
"received",
"created",
"flagged",
"deleted",
"emailitem",
"forwarded" };
private static final String START_MARKER = "<Email>";
private static final String END_MARKER = "</Email>";
private static final String UTC_TIMEZONE = "UTC";
private static Hashtable h;
private Enumeration em;
private MIMEParser mp;
private static final String READ = "read";
private static final String REPLIED = "replied";
private static final String MODIFIED = "modified";
private static final String RECIEVED = "recieved";
private static final String CREATED = "created";
private static final String FLAGGED = "flagged";
private static final String DELETED = "deleted";
private static final String FORWARDED = "forwarded";
private Message mailmessage;
private String foldername;
private int commandId = 4;
/**
*
*Constructor
*
*/
public XMLMailParser()
{
mp = new MIMEParser();
}
/**
*
* Returns the commandID
*
*/
public int getCommandId()
{
return commandId++;
}
public void setCommandId(int commandId)
{
this.commandId = commandId;
}
/**
*
* Sets the parse params
* @param String: fname
* @param Message: message
*/
public void setParseParams(String fname, Message message)
{
this.mailmessage = message;
this.foldername = fname;
}
/**
*
* Method to parse the message String & build the message object
* @param String: messageString
* @param String: locURI
*/
public Message parseMessage(String messageString,String locURI) {
Message msg = null;
String toParse = messageString;
h = buildMapFromXML(toParse);
if (h != null) {
String emailitem= mimedata(h);
msg = mp.parseMessage(emailitem, locURI);
String field = getValue(h, READ);
addBooleanField(msg, field, READ);
field =getValue(h, FORWARDED);
addBooleanField(msg, field, FORWARDED);
field =getValue(h, REPLIED);
addBooleanField(msg, field, REPLIED);
field = getValue(h, RECIEVED);//RECEIVED
addDateField(msg, field, RECIEVED);//RECEIVED
field = getValue(h, MODIFIED);
addDateField(msg, field, MODIFIED);
field = getValue(h, CREATED);
addDateField(msg, field, CREATED);
field = getValue(h, DELETED);
addBooleanField(msg, field, DELETED);
field = getValue(h, FLAGGED);
addBooleanField(msg, field, FLAGGED);
}
return msg;
}
/**
* Method to format the message object and build the message string
*
* @throws Exception
*/
private String formatMessageObject() throws Exception
{
StringBuffer messageBuffer = new StringBuffer();
messageBuffer.append("<emailitem>" + "\n" + "<![CDATA[");
///
MessageIDStore msgIdStore = new MessageIDStore();
String messageIDfromStore = msgIdStore.getServerId(new Integer(mailmessage.getMessageId()).toString());
if(messageIDfromStore != null){
msgIdStore.setMessageMappingKey();
if(msgIdStore.getClientId(messageIDfromStore) != null){
messageBuffer.append("Message-ID: "
+ msgIdStore.getClientId(messageIDfromStore) + "\r\n");
}
else{
messageBuffer.append("Message-ID: "+mailmessage.getMessageId()+"\r\n");
}
}
else{
messageBuffer.append("Message-ID: "+mailmessage.getMessageId()+"\r\n");
msgIdStore.add(foldername + "/" + new Integer(mailmessage.getMessageId()).toString(),
new Integer(mailmessage.getMessageId()).toString());
}
if(mailmessage.getFrom() != null){
messageBuffer.append("From: "+mailmessage.getFrom().getAddr()+"\r\n");
}
else{
messageBuffer.append("From: " + Configuration.mailAddress + "\r\n");
}
messageBuffer.append("To: ");
Address[] addressList=mailmessage.getRecipients(Message.RecipientType.TO);
for(int i=0;i<addressList.length;i++){
if(i > 0){
messageBuffer.append(";");
}
messageBuffer.append(addressList[i].getAddr());
}
messageBuffer.append("\r\n");
// FIXME: please implement here the CC field and more
String subject = mailmessage.getSubject();
if (subject == null){
subject = "(no subject)";
}
messageBuffer.append("Subject: " + subject + "\r\n");
messageBuffer.append("Content-Type: " + mailmessage.getContentType()+"\r\n");
SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ");
StringBuffer date = new StringBuffer(formatter.format(mailmessage.getSentDate()));
// Add timezone offset
Calendar gmt = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar local = Calendar.getInstance();
gmt.setTime(mailmessage.getSentDate());
local.setTime(mailmessage.getSentDate());
int hourDiff = local.get(Calendar.HOUR_OF_DAY) - gmt.get(Calendar.HOUR_OF_DAY);
date.append( (hourDiff>0) ? "+" : "-" );
date.append( (hourDiff<9 && hourDiff>-9) ? "0" : "" );
date.append( hourDiff );
date.append( "00" );
messageBuffer.append("Date: " + date + "\r\n");
messageBuffer.append("\r\n");//end of headers
if ((TextBodyPart)mailmessage.getContent() != null) {
messageBuffer.append(((TextBodyPart)mailmessage.getContent()).getContent());
}
messageBuffer.append("\r\n]]>\r\n");
messageBuffer.append("</emailitem>");
return messageBuffer.toString();
}
/**
*
* Converts the date to string
*
*/
private String convertFromDatetoString()
{
StringBuffer date = new StringBuffer();
Calendar cal = Calendar.getInstance();
cal.setTime(mailmessage.getSentDate());
date.append(cal.get(Calendar.YEAR));
if((cal.get(Calendar.MONTH) + 1) > 9){
date.append(cal.get(Calendar.MONTH) + 1);
}
else{
date.append("0"+cal.get(Calendar.MONTH));
}
if(cal.get(Calendar.DATE) > 9) {
date.append(cal.get(Calendar.DATE));
}
else{
date.append("0"+cal.get(Calendar.DATE));
}
date.append("T");
if(cal.get(Calendar.HOUR) > 9){
date.append(cal.get(Calendar.HOUR));
}
else{
date.append("0"+cal.get(Calendar.HOUR));
}
if(cal.get(Calendar.MINUTE) > 9){
date.append(cal.get(Calendar.MINUTE));
}
else{
date.append("0"+cal.get(Calendar.MINUTE));
}
if(cal.get(Calendar.SECOND) > 9){
date.append(cal.get(Calendar.SECOND));
}
else{
date.append("0"+cal.get(Calendar.SECOND));
}
date.append("Z");
return date.toString();
}
/**
*
*Method to convert entire email data to string
*
**/
public String toString()
{
StringBuffer messageBuffer = new StringBuffer();
messageBuffer.append("<Email>");
// FIXME: handle the flags properly!!
messageBuffer.append("\n");
messageBuffer.append("<read>true</read>"+"\n");
messageBuffer.append("<received>"+convertFromDatetoString()+"</received>"+"\n");
messageBuffer.append("<created>"+convertFromDatetoString()+"</created> "+"\n");
try{
messageBuffer.append(formatMessageObject());
}
catch(Exception e){
StaticDataHelper.log(e.getMessage());
}
messageBuffer.append("\n");
messageBuffer.append("</Email>");
messageBuffer.append("\n");
return messageBuffer.toString();
}
/**
*
*Returns the value for a key from the hashtable
* @param Hashtable: eventMap
* @param String: key
**/
private String getValue(Hashtable eventMap, String key) {
Object val = eventMap.get(key);
String value = val == null ? "" : val.toString();
return value.trim();
}
/**
* Creates a hashtable with keys and values
*
* @param String: messageString
*/
private Hashtable buildMapFromXML(String messageString)
{
StaticDataHelper.log("messageString--->\n" + messageString);
int startMarkerIndex = messageString.indexOf(START_MARKER);//<Email>
int endMarkerIndex = messageString.indexOf(END_MARKER);//</Email>
if (startMarkerIndex == -1 || endMarkerIndex == -1)
{
StaticDataHelper.log("[EMAIL]Error in XMLMailParser.buildMapFromXML(:String). Improper data in the XML message from server (no " + START_MARKER + " tag). Returning null");
return null;
}
Hashtable eventMap = new Hashtable();
String startTag = "";
String endTag = "";
String degeneratedTag = "";
String data = "";
boolean quotedPrintable = false;
for (int i = 0; i < tagArray.length; i++)
{
String tag = tagArray[i];
startTag = "<" + tag + ">";
int startTagIndex = messageString.indexOf(startTag);
if (startTagIndex == -1)
{
if (!tag.equalsIgnoreCase("emailitem")){
continue;
}
// Parse <emailitem enc="quoted-printable">
startTag = "<" + tag;
startTagIndex = messageString.indexOf(startTag);
if (startTagIndex == -1){
continue;
}
int closeStartTagIndex = messageString.indexOf(">", startTagIndex);
startTag = messageString.substring(startTagIndex, closeStartTagIndex+1);
StaticDataHelper.log("Found tag: " + startTag);
if(startTag.equalsIgnoreCase("<emailitem enc=\"quoted-printable\">")){
quotedPrintable = true;
StaticDataHelper.log("Email is encoded in quoted-printable");
}
}
degeneratedTag = "<" + tag + "/>";
int degeneratedTagIndex = messageString.indexOf(degeneratedTag);
if (degeneratedTagIndex != -1)
{
continue;
}
endTag = "</" + tag + ">";
int endTagIndex = messageString.indexOf(endTag);
if (endTagIndex != -1)
{
data = messageString.substring(startTagIndex + startTag.length(), endTagIndex);
}
else
{
data = "";
}
if (data.length() > 0)
{
if (quotedPrintable) {
data = StringTools.QPdecode(data);
}
//data = StringTools.unescapeXml(data);
}
eventMap.put(tag, data);
}
return eventMap;
}
/**
* Adds boolean fields
*
* @param Message: msg
* @param String: field
* @param String: name
*/
private void addBooleanField(Message msg,
String field,
String name)
{
if (!field.equals(""))
{
boolean b = field.equals("true") ? true : false;
if (name.indexOf("read") >= 0)
{
msg.setFlag(Message.Flag.OPENED,b);
}
else if (name.indexOf("deleted") >= 0)
{
msg.setFlag(Message.Flag.DELETED,b);
}
}
}
/**
* Adds the date field to the message header
*
* @param Message: msg
* @param String: field
* @param String: name
*/
public void addDateField(Message msg,
String field,
String name)
{
if (!field.equals(""))
{
msg.addHeader(name+"date",field);
}
}
/**
* Returns the value of emailitem
*
* @param HashTable : h
*/
private String mimedata(Hashtable h)
{
String valuemime = "";
Enumeration emime = h.keys();
while (emime.hasMoreElements())
{
Object keyobj = emime.nextElement();
String keymime = keyobj.toString();
if (keymime.indexOf("emailitem") >= 0)
{
valuemime = (String)h.get(keyobj);
}
}
return valuemime;
}
}