
package com.android.email;

import java.io.File;

import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.util.Log;

import com.android.email.activity.MessageCompose;
import com.android.email.mail.Address;
import com.android.email.mail.Message;
import com.android.email.mail.MessagingException;
import com.android.email.mail.internet.BinaryTempFileBody;
import com.android.email.service.BootReceiver;
import com.android.email.service.MailService;

public class Email extends Application
{
    public static Application app = null;
    public static File tempDirectory;
    public static final String LOG_TAG = "k9";

    public enum BACKGROUND_OPS
    {
        WHEN_CHECKED, ALWAYS, NEVER
    }

    private static int theme = android.R.style.Theme_Light;

    private static BACKGROUND_OPS backgroundOps = BACKGROUND_OPS.WHEN_CHECKED;
    /**
     * Some log messages can be sent to a file, so that the logs
     * can be read using unprivileged access (eg. Terminal Emulator)
     * on the phone, without adb.  Set to null to disable
     */
    public static final String logFile = null;
    //public static final String logFile = "/sdcard/k9mail/debug.log";

    /**
     * If this is enabled there will be additional logging information sent to
     * Log.d, including protocol dumps.
     * Controlled by Preferences at run-time
     */
    public static boolean DEBUG = false;

    /**
     * If this is enabled than logging that normally hides sensitive information
     * like passwords will show that information.
     */
    public static boolean DEBUG_SENSITIVE = false;

    /**
     * Can create messages containing stack traces that can be forwarded
     * to the development team.
     */
    public static boolean ENABLE_ERROR_FOLDER = true;
    public static String ERROR_FOLDER_NAME = "K9mail-errors";

    /**
     * The MIME type(s) of attachments we're willing to send. At the moment it is not possible
     * to open a chooser with a list of filter types, so the chooser is only opened with the first
     * item in the list. The entire list will be used to filter down attachments that are added
     * with Intent.ACTION_SEND.
     */
    public static final String[] ACCEPTABLE_ATTACHMENT_SEND_TYPES = new String[]
    {
        "*/*"
    };

    /**
     * The MIME type(s) of attachments we're willing to view.
     */
    public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[]
    {
        "*/*",
    };

    /**
     * The MIME type(s) of attachments we're not willing to view.
     */
    public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[]
    {
    };

    /**
     * The MIME type(s) of attachments we're willing to download to SD.
     */
    public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[]
    {
        "*/*",
    };

    /**
     * The MIME type(s) of attachments we're not willing to download to SD.
     */
    public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[]
    {
    };

    /**
     * The special name "INBOX" is used throughout the application to mean "Whatever folder
     * the server refers to as the user's Inbox. Placed here to ease use.
     */
    public static final String INBOX = "INBOX";

    /**
     * For use when displaying that no folder is selected
     */
    public static final String FOLDER_NONE = "-NONE-";

    public static final String LOCAL_UID_PREFIX = "K9LOCAL:";

    public static final String REMOTE_UID_PREFIX = "K9REMOTE:";

    public static final String K9MAIL_IDENTITY = "X-K9mail-Identity";

    /**
     * Specifies how many messages will be shown in a folder by default. This number is set
     * on each new folder and can be incremented with "Load more messages..." by the
     * VISIBLE_LIMIT_INCREMENT
     */
    public static int DEFAULT_VISIBLE_LIMIT = 25;

    /**
     * Number of additioanl messages to load when a user selectes "Load more messages..."
     */
    public static int VISIBLE_LIMIT_INCREMENT = 25;

    public static int MAX_SEND_ATTEMPTS = 5;

    /**
     * The maximum size of an attachment we're willing to download (either View or Save)
     * Attachments that are base64 encoded (most) will be about 1.375x their actual size
     * so we should probably factor that in. A 5MB attachment will generally be around
     * 6.8MB downloaded but only 5MB saved.
     */
    public static final int MAX_ATTACHMENT_DOWNLOAD_SIZE = (5 * 1024 * 1024);

    /**
     * Max time (in millis) the wake lock will be held for when background sync is happening
     */
    public static final int WAKE_LOCK_TIMEOUT = 600000;

    public static final int MANUAL_WAKE_LOCK_TIMEOUT = 120000;

    public static final int PUSH_WAKE_LOCK_TIMEOUT = 60000;

    public static final int MAIL_SERVICE_WAKE_LOCK_TIMEOUT = 30000;

    public static final int BOOT_RECEIVER_WAKE_LOCK_TIMEOUT = 60000;


    /**
     * LED color used for the new email notitication
     */
    public static final int NOTIFICATION_LED_COLOR = 0xffff00ff;

    /**
     * Time the LED is on when blicking on new email notification
     */
    public static final int NOTIFICATION_LED_ON_TIME = 500;

    /**
     * Time the LED is off when blicking on new email notification
     */
    public static final int NOTIFICATION_LED_OFF_TIME = 2000;

    public static final boolean NOTIFICATION_LED_WHILE_SYNCING = false;
    public static final int NOTIFICATION_LED_DIM_COLOR = 0x77770077;
    public static final int NOTIFICATION_LED_FAST_ON_TIME = 100;
    public static final int NOTIFICATION_LED_FAST_OFF_TIME = 100;

    public static final int NOTIFICATION_LED_SENDING_FAILURE_COLOR = 0xffff0000;

    // Must not conflict with an account number
    public static final int FETCHING_EMAIL_NOTIFICATION_ID      = -4;
    public static final int FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID      = -1;
    public static final int FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT = -2;
    public static final int CONNECTIVITY_ID = -3;

    /*
     * http://www.w3schools.com/media/media_mimeref.asp
     * + png
     */
    public static final String[][] CONTENT_TYPE_BY_EXTENSION_MAP = new String[][]
    {
        { "",       "application/octet-stream" },
        { "323",    "text/h323"},
        { "acx",    "application/internet-property-stream"},
        { "ai",     "application/postscript"},
        { "aif",    "audio/x-aiff"},
        { "aifc",   "audio/x-aiff"},
        { "aiff",   "audio/x-aiff"},
        { "asf",    "video/x-ms-asf"},
        { "asr",    "video/x-ms-asf"},
        { "asx",    "video/x-ms-asf"},
        { "au",     "audio/basic"},
        { "avi",    "video/x-msvideo"},
        { "axs",    "application/olescript"},
        { "bas",    "text/plain"},
        { "bcpio",  "application/x-bcpio"},
        { "bin",    "application/octet-stream"},
        { "bmp",    "image/bmp"},
        { "c",      "text/plain"},
        { "cat",    "application/vnd.ms-pkiseccat"},
        { "cdf",    "application/x-cdf"},
        { "cer",    "application/x-x509-ca-cert"},
        { "class",  "application/octet-stream"},
        { "clp",    "application/x-msclip"},
        { "cmx",    "image/x-cmx"},
        { "cod",    "image/cis-cod"},
        { "cpio",   "application/x-cpio"},
        { "crd",    "application/x-mscardfile"},
        { "crl",    "application/pkix-crl"},
        { "crt",    "application/x-x509-ca-cert"},
        { "csh",    "application/x-csh"},
        { "css",    "text/css"},
        { "dcr",    "application/x-director"},
        { "der",    "application/x-x509-ca-cert"},
        { "dir",    "application/x-director"},
        { "dll",    "application/x-msdownload"},
        { "dms",    "application/octet-stream"},
        { "doc",    "application/msword"},
        { "dot",    "application/msword"},
        { "dvi",    "application/x-dvi"},
        { "dxr",    "application/x-director"},
        { "eps",    "application/postscript"},
        { "etx",    "text/x-setext"},
        { "evy",    "application/envoy"},
        { "exe",    "application/octet-stream"},
        { "fif",    "application/fractals"},
        { "flr",    "x-world/x-vrml"},
        { "gif",    "image/gif"},
        { "gtar",   "application/x-gtar"},
        { "gz",     "application/x-gzip"},
        { "h",      "text/plain"},
        { "hdf",    "application/x-hdf"},
        { "hlp",    "application/winhlp"},
        { "hqx",    "application/mac-binhex40"},
        { "hta",    "application/hta"},
        { "htc",    "text/x-component"},
        { "htm",    "text/html"},
        { "html",   "text/html"},
        { "htt",    "text/webviewhtml"},
        { "ico",    "image/x-icon"},
        { "ief",    "image/ief"},
        { "iii",    "application/x-iphone"},
        { "ins",    "application/x-internet-signup"},
        { "isp",    "application/x-internet-signup"},
        { "jfif",   "image/pipeg"},
        { "jpe",    "image/jpeg"},
        { "jpeg",   "image/jpeg"},
        { "jpg",    "image/jpeg"},
        { "js",     "application/x-javascript"},
        { "latex",  "application/x-latex"},
        { "lha",    "application/octet-stream"},
        { "lsf",    "video/x-la-asf"},
        { "lsx",    "video/x-la-asf"},
        { "lzh",    "application/octet-stream"},
        { "m13",    "application/x-msmediaview"},
        { "m14",    "application/x-msmediaview"},
        { "m3u",    "audio/x-mpegurl"},
        { "man",    "application/x-troff-man"},
        { "mdb",    "application/x-msaccess"},
        { "me",     "application/x-troff-me"},
        { "mht",    "message/rfc822"},
        { "mhtml",  "message/rfc822"},
        { "mid",    "audio/mid"},
        { "mny",    "application/x-msmoney"},
        { "mov",    "video/quicktime"},
        { "movie",  "video/x-sgi-movie"},
        { "mp2",    "video/mpeg"},
        { "mp3",    "audio/mpeg"},
        { "mpa",    "video/mpeg"},
        { "mpe",    "video/mpeg"},
        { "mpeg",   "video/mpeg"},
        { "mpg",    "video/mpeg"},
        { "mpp",    "application/vnd.ms-project"},
        { "mpv2",   "video/mpeg"},
        { "ms",     "application/x-troff-ms"},
        { "mvb",    "application/x-msmediaview"},
        { "nws",    "message/rfc822"},
        { "oda",    "application/oda"},
        { "p10",    "application/pkcs10"},
        { "p12",    "application/x-pkcs12"},
        { "p7b",    "application/x-pkcs7-certificates"},
        { "p7c",    "application/x-pkcs7-mime"},
        { "p7m",    "application/x-pkcs7-mime"},
        { "p7r",    "application/x-pkcs7-certreqresp"},
        { "p7s",    "application/x-pkcs7-signature"},
        { "pbm",    "image/x-portable-bitmap"},
        { "pdf",    "application/pdf"},
        { "pfx",    "application/x-pkcs12"},
        { "pgm",    "image/x-portable-graymap"},
        { "pko",    "application/ynd.ms-pkipko"},
        { "pma",    "application/x-perfmon"},
        { "pmc",    "application/x-perfmon"},
        { "pml",    "application/x-perfmon"},
        { "pmr",    "application/x-perfmon"},
        { "pmw",    "application/x-perfmon"},
        { "png",    "image/png"},
        { "pnm",    "image/x-portable-anymap"},
        { "pot,",   "application/vnd.ms-powerpoint"},
        { "ppm",    "image/x-portable-pixmap"},
        { "pps",    "application/vnd.ms-powerpoint"},
        { "ppt",    "application/vnd.ms-powerpoint"},
        { "prf",    "application/pics-rules"},
        { "ps",     "application/postscript"},
        { "pub",    "application/x-mspublisher"},
        { "qt",     "video/quicktime"},
        { "ra",     "audio/x-pn-realaudio"},
        { "ram",    "audio/x-pn-realaudio"},
        { "ras",    "image/x-cmu-raster"},
        { "rgb",    "image/x-rgb"},
        { "rmi",    "audio/mid"},
        { "roff",   "application/x-troff"},
        { "rtf",    "application/rtf"},
        { "rtx",    "text/richtext"},
        { "scd",    "application/x-msschedule"},
        { "sct",    "text/scriptlet"},
        { "setpay", "application/set-payment-initiation"},
        { "setreg", "application/set-registration-initiation"},
        { "sh",     "application/x-sh"},
        { "shar",   "application/x-shar"},
        { "sit",    "application/x-stuffit"},
        { "snd",    "audio/basic"},
        { "spc",    "application/x-pkcs7-certificates"},
        { "spl",    "application/futuresplash"},
        { "src",    "application/x-wais-source"},
        { "sst",    "application/vnd.ms-pkicertstore"},
        { "stl",    "application/vnd.ms-pkistl"},
        { "stm",    "text/html"},
        { "svg",    "image/svg+xml"},
        { "sv4cpio","application/x-sv4cpio"},
        { "sv4crc", "application/x-sv4crc"},
        { "swf",    "application/x-shockwave-flash"},
        { "t",      "application/x-troff"},
        { "tar",    "application/x-tar"},
        { "tcl",    "application/x-tcl"},
        { "tex",    "application/x-tex"},
        { "texi",   "application/x-texinfo"},
        { "texinfo","application/x-texinfo"},
        { "tgz",    "application/x-compressed"},
        { "tif",    "image/tiff"},
        { "tiff",   "image/tiff"},
        { "tr",     "application/x-troff"},
        { "trm",    "application/x-msterminal"},
        { "tsv",    "text/tab-separated-values"},
        { "txt",    "text/plain"},
        { "uls",    "text/iuls"},
        { "ustar",  "application/x-ustar"},
        { "vcf",    "text/x-vcard"},
        { "vrml",   "x-world/x-vrml"},
        { "wav",    "audio/x-wav"},
        { "wcm",    "application/vnd.ms-works"},
        { "wdb",    "application/vnd.ms-works"},
        { "wks",    "application/vnd.ms-works"},
        { "wmf",    "application/x-msmetafile"},
        { "wps",    "application/vnd.ms-works"},
        { "wri",    "application/x-mswrite"},
        { "wrl",    "x-world/x-vrml"},
        { "wrz",    "x-world/x-vrml"},
        { "xaf",    "x-world/x-vrml"},
        { "xbm",    "image/x-xbitmap"},
        { "xla",    "application/vnd.ms-excel"},
        { "xlc",    "application/vnd.ms-excel"},
        { "xlm",    "application/vnd.ms-excel"},
        { "xls",    "application/vnd.ms-excel"},
        { "xlt",    "application/vnd.ms-excel"},
        { "xlw",    "application/vnd.ms-excel"},
        { "xof",    "x-world/x-vrml"},
        { "xpm",    "image/x-xpixmap"},
        { "xwd",    "image/x-xwindowdump"},
        { "z",      "application/x-compress"},
        { "zip",    "application/zip"}
    };

    public class Intents
    {

        public class EmailReceived
        {
            public static final String ACTION_EMAIL_RECEIVED    = "com.android.email.intent.action.EMAIL_RECEIVED";
            public static final String EXTRA_ACCOUNT            = "com.android.email.intent.extra.ACCOUNT";
            public static final String EXTRA_FOLDER             = "com.android.email.intent.extra.FOLDER";
            public static final String EXTRA_SENT_DATE          = "com.android.email.intent.extra.SENT_DATE";
            public static final String EXTRA_FROM               = "com.android.email.intent.extra.FROM";
            public static final String EXTRA_TO                 = "com.android.email.intent.extra.TO";
            public static final String EXTRA_CC                 = "com.android.email.intent.extra.CC";
            public static final String EXTRA_BCC                = "com.android.email.intent.extra.BCC";
            public static final String EXTRA_SUBJECT            = "com.android.email.intent.extra.SUBJECT";
            public static final String EXTRA_FROM_SELF          = "com.android.email.intent.extra.FROM_SELF";
        }

    }

    /**
     * Called throughout the application when the number of accounts has changed. This method
     * enables or disables the Compose activity, the boot receiver and the service based on
     * whether any accounts are configured.
     */
    public static void setServicesEnabled(Context context)
    {

        int acctLength = Preferences.getPreferences(context).getAccounts().length;

        setServicesEnabled(context, acctLength > 0, null);

    }

    public static void setServicesEnabled(Context context, Integer wakeLockId)
    {
        setServicesEnabled(context, Preferences.getPreferences(context).getAccounts().length > 0, wakeLockId);
    }

    public static void setServicesEnabled(Context context, boolean enabled, Integer wakeLockId)
    {

        PackageManager pm = context.getPackageManager();

        if (!enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
        {
            /*
             * If no accounts now exist but the service is still enabled we're about to disable it
             * so we'll reschedule to kill off any existing alarms.
             */
            MailService.actionReschedule(context, wakeLockId);
        }
        Class[] classes = { MessageCompose.class, BootReceiver.class, MailService.class };

        for (Class clazz : classes)
        {

            boolean alreadyEnabled = pm.getComponentEnabledSetting(new ComponentName(context, clazz)) ==
                                     PackageManager.COMPONENT_ENABLED_STATE_ENABLED;

            if (enabled != alreadyEnabled)
            {
                pm.setComponentEnabledSetting(
                    new ComponentName(context, clazz),
                    enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                    PackageManager.DONT_KILL_APP);
            }
        }

        if (enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
        {
            /*
             * And now if accounts do exist then we've just enabled the service and we want to
             * schedule alarms for the new accounts.
             */
            MailService.actionReschedule(context, wakeLockId);
        }

    }

    public static void save(SharedPreferences.Editor editor)
    {
        editor.putBoolean("enableDebugLogging", Email.DEBUG);
        editor.putBoolean("enableSensitiveLogging", Email.DEBUG_SENSITIVE);
        editor.putString("backgroundOperations", Email.backgroundOps.toString());
        editor.putInt("theme", theme);
    }

    @Override
    public void onCreate()
    {
        super.onCreate();
        app = this;
        Preferences prefs = Preferences.getPreferences(this);
        SharedPreferences sprefs = prefs.getPreferences();
        DEBUG = sprefs.getBoolean("enableDebugLogging", false);
        DEBUG_SENSITIVE = sprefs.getBoolean("enableSensitiveLogging", false);

        try
        {
            setBackgroundOps(BACKGROUND_OPS.valueOf(sprefs.getString("backgroundOperations", "WHEN_CHECKED")));
        }
        catch (Exception e)
        {
            setBackgroundOps(BACKGROUND_OPS.WHEN_CHECKED);
        }

        Email.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
        MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts());

        /*
         * We have to give MimeMessage a temp directory because File.createTempFile(String, String)
         * doesn't work in Android and MimeMessage does not have access to a Context.
         */
        BinaryTempFileBody.setTempDirectory(getCacheDir());

        /*
         * Enable background sync of messages
         */

        setServicesEnabled(this);

        MessagingController.getInstance(this).addListener(new MessagingListener()
        {
            @Override
            public void synchronizeMailboxNewMessage(Account account, String folder, Message message)
            {
                try
                {
                    Uri uri = Uri.parse("email://messages/" + account.getAccountNumber() + "/" + Uri.encode(folder) + "/" + Uri.encode(message.getUid()));
                    Intent intent = new Intent(Email.Intents.EmailReceived.ACTION_EMAIL_RECEIVED, uri);
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_ACCOUNT, account.getDescription());
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_FOLDER, folder);
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_SENT_DATE, message.getSentDate());
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_FROM, Address.toString(message.getFrom()));
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_TO, Address.toString(message.getRecipients(Message.RecipientType.TO)));
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_CC, Address.toString(message.getRecipients(Message.RecipientType.CC)));
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_BCC, Address.toString(message.getRecipients(Message.RecipientType.BCC)));
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_SUBJECT, message.getSubject());
                    intent.putExtra(Email.Intents.EmailReceived.EXTRA_FROM_SELF, account.isAnIdentity(message.getFrom()));
                    Email.this.sendBroadcast(intent);
                    Log.d(Email.LOG_TAG, "Broadcasted intent: " + message.getSubject());
                }
                catch (MessagingException e)
                {
                    Log.w(Email.LOG_TAG, "Account=" + account.getName() + " folder=" + folder + "message uid=" + message.getUid(), e);
                }
            }
        });

    }

    public static int getK9Theme()
    {
        return theme;
    }

    public static void setK9Theme(int ntheme)
    {
        theme = ntheme;
    }

    public static BACKGROUND_OPS getBackgroundOps()
    {
        return backgroundOps;
    }

    public static void setBackgroundOps(BACKGROUND_OPS backgroundOps)
    {
        Email.backgroundOps = backgroundOps;
    }

    public static void setBackgroundOps(String nbackgroundOps)
    {
        Email.backgroundOps = BACKGROUND_OPS.valueOf(nbackgroundOps);
    }
}








