com.naryx.tagfusion.cfm.mail.cfMailMessageData.java Source code

Java tutorial

Introduction

Here is the source code for com.naryx.tagfusion.cfm.mail.cfMailMessageData.java

Source

/* 
 *  Copyright (C) 2000 - 2008 TagServlet Ltd
 *
 *  This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
 *  
 *  OpenBD is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  Free Software Foundation,version 3.
 *  
 *  OpenBD 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 General Public License
 *  along with OpenBD.  If not, see http://www.gnu.org/licenses/
 *  
 *  Additional permission under GNU GPL version 3 section 7
 *  
 *  If you modify this Program, or any covered work, by linking or combining 
 *  it with any of the JARS listed in the README.txt (or a modified version of 
 *  (that library), containing parts covered by the terms of that JAR, the 
 *  licensors of this Program grant you additional permission to convey the 
 *  resulting work. 
 *  README.txt @ http://www.openbluedragon.org/license/README.txt
 *  
 *  http://www.openbluedragon.org/
 */

package com.naryx.tagfusion.cfm.mail;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Enumeration;

import javax.activation.MimeType;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.UIDFolder;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;

import org.apache.commons.io.IOUtils;

import com.nary.util.UTF7Converter;
import com.naryx.tagfusion.cfm.engine.cfArrayData;
import com.naryx.tagfusion.cfm.engine.cfBooleanData;
import com.naryx.tagfusion.cfm.engine.cfDateData;
import com.naryx.tagfusion.cfm.engine.cfEngine;
import com.naryx.tagfusion.cfm.engine.cfNumberData;
import com.naryx.tagfusion.cfm.engine.cfSession;
import com.naryx.tagfusion.cfm.engine.cfStringData;
import com.naryx.tagfusion.cfm.engine.cfStructData;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;

public class cfMailMessageData extends cfStructData implements java.io.Serializable {

    private static final long serialVersionUID = 1L;

    public cfMailMessageData(cfSession _Session) {
        super();
    }

    public void getMessage(cfImapConnection imapConnection, String rootFolder, long messageID, String _attachURI,
            String _attachDIR) throws cfmRunTimeException {
        try {
            Folder folderToList;

            if (rootFolder == null || rootFolder.length() == 0)
                folderToList = imapConnection.mailStore.getDefaultFolder();
            else
                folderToList = imapConnection.mailStore.getFolder(rootFolder);

            if ((folderToList.getType() & Folder.HOLDS_MESSAGES) != 0) {

                if (!folderToList.isOpen())
                    folderToList.open(Folder.READ_ONLY);

                boolean bResult = false;
                if (folderToList instanceof UIDFolder)
                    bResult = extractMessage(((UIDFolder) folderToList).getMessageByUID(messageID), messageID,
                            _attachURI, _attachDIR);
                else
                    bResult = extractMessage(folderToList.getMessage((int) messageID), messageID, _attachURI,
                            _attachDIR);

                if (!bResult)
                    imapConnection.setStatus(false, "Message does not exist");
                else
                    imapConnection.setStatus(true, "");

                folderToList.close(false);
            }

        } catch (Exception E) {
            imapConnection.setStatus(false, E.getMessage());
        }
    }

    private static cfArrayData extractAddresses(Address[] addresses) throws cfmRunTimeException {
        if (addresses == null || addresses.length == 0)
            return null;

        cfArrayData AD = cfArrayData.createArray(1);

        for (int x = 0; x < addresses.length; x++) {
            cfStructData sdFrom = new cfStructData();
            String name = ((InternetAddress) addresses[x]).getPersonal();
            if (name != null)
                sdFrom.setData("name", new cfStringData(name));

            sdFrom.setData("email", new cfStringData(((InternetAddress) addresses[x]).getAddress()));
            AD.addElement(sdFrom);
        }
        return AD;
    }

    private boolean extractMessage(Message Mess, long messageID, String attachURI, String attachDIR) {
        cfArrayData ADD = cfArrayData.createArray(1);

        try {

            setData("subject", new cfStringData(Mess.getSubject()));
            setData("id", new cfNumberData(messageID));

            //--- Pull out all the headers
            cfStructData headers = new cfStructData();
            Enumeration<Header> eH = Mess.getAllHeaders();
            String headerKey;
            while (eH.hasMoreElements()) {
                Header hdr = eH.nextElement();

                headerKey = hdr.getName().replace('-', '_').toLowerCase();
                if (headers.containsKey(headerKey)) {
                    headers.setData(headerKey,
                            new cfStringData(headers.getData(headerKey).toString() + ";" + hdr.getValue()));
                } else
                    headers.setData(headerKey, new cfStringData(hdr.getValue()));
            }

            setData("headers", headers);

            // Get the Date
            Date DD = Mess.getReceivedDate();
            if (DD == null)
                setData("rxddate", new cfDateData(System.currentTimeMillis()));
            else
                setData("rxddate", new cfDateData(DD.getTime()));

            DD = Mess.getSentDate();
            if (DD == null)
                setData("sentdate", new cfDateData(System.currentTimeMillis()));
            else
                setData("sentdate", new cfDateData(DD.getTime()));

            // Get the FROM field
            Address[] from = Mess.getFrom();
            if (from != null && from.length > 0) {
                cfStructData sdFrom = new cfStructData();
                String name = ((InternetAddress) from[0]).getPersonal();
                if (name != null)
                    sdFrom.setData("name", new cfStringData(name));

                sdFrom.setData("email", new cfStringData(((InternetAddress) from[0]).getAddress()));
                setData("from", sdFrom);
            }

            //--[ Get the TO/CC/BCC field
            cfArrayData AD = extractAddresses(Mess.getRecipients(Message.RecipientType.TO));
            if (AD != null)
                setData("to", AD);

            AD = extractAddresses(Mess.getRecipients(Message.RecipientType.CC));
            if (AD != null)
                setData("cc", AD);

            AD = extractAddresses(Mess.getRecipients(Message.RecipientType.BCC));
            if (AD != null)
                setData("bcc", AD);

            AD = extractAddresses(Mess.getReplyTo());
            if (AD != null)
                setData("replyto", AD);

            //--[ Set the flags
            setData("answered", cfBooleanData.getcfBooleanData(Mess.isSet(Flags.Flag.ANSWERED)));
            setData("deleted", cfBooleanData.getcfBooleanData(Mess.isSet(Flags.Flag.DELETED)));
            setData("draft", cfBooleanData.getcfBooleanData(Mess.isSet(Flags.Flag.DRAFT)));
            setData("flagged", cfBooleanData.getcfBooleanData(Mess.isSet(Flags.Flag.FLAGGED)));
            setData("recent", cfBooleanData.getcfBooleanData(Mess.isSet(Flags.Flag.RECENT)));
            setData("seen", cfBooleanData.getcfBooleanData(Mess.isSet(Flags.Flag.SEEN)));

            setData("size", new cfNumberData(Mess.getSize()));
            setData("lines", new cfNumberData(Mess.getLineCount()));

            String tmp = Mess.getContentType();
            if (tmp.indexOf(";") != -1)
                tmp = tmp.substring(0, tmp.indexOf(";"));

            setData("mimetype", new cfStringData(tmp));

            // Get the body of the email
            extractBody(Mess, ADD, attachURI, attachDIR);

        } catch (Exception E) {
            return false;
        }

        setData("body", ADD);
        return true;
    }

    private void extractBody(Part Mess, cfArrayData AD, String attachURI, String attachDIR) throws Exception {

        if (Mess.isMimeType("multipart/*")) {

            Multipart mp = (Multipart) Mess.getContent();
            int count = mp.getCount();
            for (int i = 0; i < count; i++)
                extractBody(mp.getBodyPart(i), AD, attachURI, attachDIR);

        } else {

            cfStructData sd = new cfStructData();

            String tmp = Mess.getContentType();
            if (tmp.indexOf(";") != -1)
                tmp = tmp.substring(0, tmp.indexOf(";"));

            sd.setData("mimetype", new cfStringData(tmp));

            String filename = getFilename(Mess);
            String dispos = getDisposition(Mess);

            MimeType messtype = new MimeType(tmp);
            // Note that we can't use Mess.isMimeType() here due to bug #2080
            if ((dispos == null || dispos.equalsIgnoreCase(Part.INLINE)) && messtype.match("text/*")) {

                Object content;
                String contentType = Mess.getContentType().toLowerCase();
                // support aliases of UTF-7 - UTF7, UNICODE-1-1-UTF-7, csUnicode11UTF7, UNICODE-2-0-UTF-7
                if (contentType.indexOf("utf-7") != -1 || contentType.indexOf("utf7") != -1) {
                    InputStream ins = Mess.getInputStream();
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    IOUtils.copy(ins, bos);
                    content = new String(UTF7Converter.convert(bos.toByteArray()));
                } else {
                    try {
                        content = Mess.getContent();
                    } catch (UnsupportedEncodingException e) {
                        content = Mess.getInputStream();
                    } catch (IOException ioe) {
                        // This will happen on BD/Java when the attachment has no content
                        // NOTE: this is the fix for bug NA#3198.
                        content = "";
                    }
                }

                if (content instanceof InputStream) {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    IOUtils.copy((InputStream) content, bos);
                    sd.setData("content", new cfStringData(new String(bos.toByteArray())));
                } else {
                    sd.setData("content", new cfStringData(content.toString()));
                }

                sd.setData("file", cfBooleanData.FALSE);
                sd.setData("filename", new cfStringData(filename == null ? "" : filename));

            } else if (attachDIR != null) {

                sd.setData("content", new cfStringData(""));

                if (filename == null || filename.length() == 0)
                    filename = "unknownfile";

                filename = getAttachedFilename(attachDIR, filename);

                //--[ An attachment, save it out to disk
                try {
                    BufferedInputStream in = new BufferedInputStream(Mess.getInputStream());
                    BufferedOutputStream out = new BufferedOutputStream(
                            cfEngine.thisPlatform.getFileIO().getFileOutputStream(new File(attachDIR + filename)));
                    IOUtils.copy(in, out);

                    out.flush();
                    out.close();
                    in.close();

                    sd.setData("file", cfBooleanData.TRUE);
                    sd.setData("filename", new cfStringData(filename));
                    if (attachURI.charAt(attachURI.length() - 1) != '/')
                        sd.setData("url", new cfStringData(attachURI + '/' + filename));
                    else
                        sd.setData("url", new cfStringData(attachURI + filename));
                    sd.setData("size", new cfNumberData((int) new File(attachDIR + filename).length()));

                } catch (Exception ignoreException) {
                    // NOTE: this could happen when we don't have permission to write to the specified directory
                    //       so let's log an error message to make this easier to debug.
                    cfEngine.log("-] Failed to save attachment to " + attachDIR + filename + ", exception=["
                            + ignoreException.toString() + "]");
                }

            } else {
                sd.setData("file", cfBooleanData.FALSE);
                sd.setData("content", new cfStringData(""));
            }

            AD.addElement(sd);
        }
    }

    public static String getDisposition(Part _mess) throws MessagingException {
        String dispos = _mess.getDisposition();
        // getDisposition isn't 100% reliable 
        if (dispos == null) {
            String[] disposHdr = _mess.getHeader("Content-Disposition");
            if (disposHdr != null && disposHdr.length > 0 && disposHdr[0].startsWith(Part.ATTACHMENT)) {
                return Part.ATTACHMENT;
            }
        }

        return dispos;
    }

    public static String getFilename(Part Mess) throws MessagingException {
        // Part.getFileName() doesn't take into account any encoding that may have been 
        // applied to the filename so in order to obtain the correct filename we
        // need to retrieve it from the Content-Disposition

        String[] contentType = Mess.getHeader("Content-Disposition");
        if (contentType != null && contentType.length > 0) {
            int nameStartIndx = contentType[0].indexOf("filename=\"");
            if (nameStartIndx != -1) {
                String filename = contentType[0].substring(nameStartIndx + 10,
                        contentType[0].indexOf('\"', nameStartIndx + 10));
                try {
                    filename = MimeUtility.decodeText(filename);
                    return filename;
                } catch (UnsupportedEncodingException e) {
                }
            }
        }

        // couldn't determine it using the above, so fall back to more reliable but 
        // less correct option
        return Mess.getFileName();
    }

    private static String getAttachedFilename(String attachDIR, String filename) {
        try {
            filename = MimeUtility.decodeText(filename);
        } catch (UnsupportedEncodingException e) {
        }

        filename = filename.replace(' ', '_').replace('/', '_');
        File fileN = new File(attachDIR, filename);

        int x = 1;
        while (fileN.exists())
            fileN = new File(attachDIR, (x++) + "_" + filename);

        return fileN.getName();
    }
}