Android Open Source - sms-backup-plus Backup Imap Store






From Project

Back to project page sms-backup-plus.

License

The source code is released under:

Apache License

If you think the Android project sms-backup-plus listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2010 Jan Berkel <jan.berkel@gmail.com>
 */*from   ww w  . j  a  va  2  s .c  o  m*/
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.zegoggles.smssync.mail;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Folder.FolderType;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.imap.ImapResponse;
import com.fsck.k9.mail.store.imap.ImapStore;
import com.zegoggles.smssync.MmsConsts;
import com.zegoggles.smssync.SmsConsts;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import static android.content.Context.CONNECTIVITY_SERVICE;
import static com.zegoggles.smssync.App.LOCAL_LOGV;
import static com.zegoggles.smssync.App.TAG;
import static java.util.Collections.sort;

public class BackupImapStore extends ImapStore {
    private final Context context;
    private final Map<DataType, BackupFolder> openFolders = new HashMap<DataType, BackupFolder>();

    public BackupImapStore(final Context context, final String uri) throws MessagingException {
        super(new BackupStoreConfig(uri),
                getTrustedSocketFactory(context, uri),
                (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE));
        this.context = context;
    }

    public BackupFolder getFolder(DataType type) throws MessagingException {
        BackupFolder folder = openFolders.get(type);
        if (folder == null) {
            String label = type.getFolder(context);
            if (label == null) throw new IllegalStateException("label is null");

            folder = createAndOpenFolder(type, label);
            openFolders.put(type, folder);
        }
        return folder;
    }

    public void closeFolders() {
        Collection<BackupFolder> folders = openFolders.values();
        for (BackupFolder folder : folders) {
            try {
                folder.close();
            } catch (Exception e) {
                Log.w(TAG, e);
            }
        }
        openFolders.clear();
    }

    @Override public String toString() {
        return "BackupImapStore{" +
                "uri=" + getStoreUriForLogging() +
                '}';
    }

    /**
     * @return a uri which can be used for logging (i.e. with credentials masked)
     */
    public String getStoreUriForLogging() {
        Uri uri = Uri.parse(this.mStoreConfig.getStoreUri());
        String userInfo = uri.getUserInfo();

        if (!TextUtils.isEmpty(userInfo) && userInfo.contains(":")) {
            String[] parts = userInfo.split(":", 2);
            userInfo = parts[0]+":"+(parts[1].replaceAll(".", "X"));
            String host = uri.getHost();
            if (uri.getPort() != -1) {
                host += ":"+uri.getPort();
            }
            return uri.buildUpon().encodedAuthority(userInfo + "@" + host).toString();
        } else {
            return uri.toString();
        }
    }

    /* package, for testing */ TrustedSocketFactory getTrustedSocketFactory() {
        return mTrustedSocketFactory;
    }

    private @NotNull BackupFolder createAndOpenFolder(DataType type, @NotNull String label) throws MessagingException {
        try {
            BackupFolder folder = new BackupFolder(this, label, type);
            if (!folder.exists()) {
                Log.i(TAG, "Label '" + label + "' does not exist yet. Creating.");
                folder.create(FolderType.HOLDS_MESSAGES);
            }
            folder.open(Folder.OPEN_MODE_RW);
            return folder;
        } catch (IllegalArgumentException e) {
            // thrown inside K9
            Log.e(TAG, "K9 error", e);
            throw new MessagingException(e.getMessage());
        }
    }

    public String getStoreUri() {
        return mStoreConfig.getStoreUri();
    }

    public class BackupFolder extends ImapFolder {
        private final DataType type;

        public BackupFolder(ImapStore store, String name, DataType type) {
            super(store, name);
            this.type = type;
        }

        public List<ImapMessage> getMessages(final int max, final boolean flagged, final Date since)
                throws MessagingException {
            if (LOCAL_LOGV)
                Log.v(TAG, String.format(Locale.ENGLISH, "getMessages(%d, %b, %s)", max, flagged, since));

            final List<ImapMessage> messages;
            final ImapSearcher searcher = new ImapSearcher() {
                @Override
                public List<ImapResponse> search() throws IOException, MessagingException {
                    final StringBuilder sb = new StringBuilder("UID SEARCH 1:*")
                            .append(' ')
                            .append(getQuery())
                            .append(" UNDELETED");
                    if (since != null) sb.append(" SENTSINCE ").append(RFC3501_DATE.format(since));
                    if (flagged) sb.append(" FLAGGED");

                    return executeSimpleCommand(sb.toString().trim());
                }
            };

            final List<ImapMessage> msgs = search(searcher, null);

            Log.i(TAG, "Found " + msgs.size() + " msgs" + (since == null ? "" : " (since " + since + ")"));
            if (max > 0 && msgs.size() > max) {
                if (LOCAL_LOGV) Log.v(TAG, "Fetching envelopes");

                FetchProfile fp = new FetchProfile();
                fp.add(FetchProfile.Item.DATE);
                fetch(msgs, fp, null);

                if (LOCAL_LOGV) Log.v(TAG, "Sorting");
                //Debug.startMethodTracing("sorting");
                sort(msgs, MessageComparator.INSTANCE);
                //Debug.stopMethodTracing();
                if (LOCAL_LOGV) Log.v(TAG, "Sorting done");

                messages = new ArrayList<ImapMessage>(max);
                messages.addAll(msgs.subList(0, max));
            } else {
                messages = msgs;
            }

            Collections.reverse(messages);

            return messages;
        }

        private String getQuery() {
            switch (this.type) {
            /* MMS/SMS are special cases since we need to support legacy backup headers */
                case SMS:
                    return
                            String.format(Locale.ENGLISH, "(OR HEADER %s \"%s\" (NOT HEADER %s \"\" (OR HEADER %s \"%d\" HEADER %s \"%d\")))",
                                    Headers.DATATYPE.toUpperCase(Locale.ENGLISH), type,
                                    Headers.DATATYPE.toUpperCase(Locale.ENGLISH),
                                    Headers.TYPE.toUpperCase(Locale.ENGLISH), SmsConsts.MESSAGE_TYPE_INBOX,
                                    Headers.TYPE.toUpperCase(Locale.ENGLISH), SmsConsts.MESSAGE_TYPE_SENT);
                case MMS:
                    return
                            String.format(Locale.ENGLISH, "(OR HEADER %s \"%s\" (NOT HEADER %s \"\" HEADER %s \"%s\"))",
                                    Headers.DATATYPE.toUpperCase(Locale.ENGLISH), type,
                                    Headers.DATATYPE.toUpperCase(Locale.ENGLISH),
                                    Headers.TYPE.toUpperCase(Locale.ENGLISH), MmsConsts.LEGACY_HEADER);

                default:
                    return String.format(Locale.ENGLISH, "(HEADER %s \"%s\")", Headers.DATATYPE.toUpperCase(Locale.ENGLISH), type);
            }
        }

        // TODO should not have to override these methods, but mockito fails to generate working mocks otherwise :/
        @Override
        public boolean equals(Object o) {
            return super.equals(o);
        }

        @Override
        public void fetch(List<ImapMessage> messages, FetchProfile fp, MessageRetrievalListener<ImapMessage> listener) throws MessagingException {
            super.fetch(messages, fp, listener);
        }

        @Override
        public Map<String, String> appendMessages(List<? extends Message> messages) throws MessagingException {
            return super.appendMessages(messages);
        }
    }

    static class MessageComparator implements Comparator<Message> {
        static final MessageComparator INSTANCE = new MessageComparator();
        static final Date EARLY = new Date(0);

        public int compare(final Message m1, final Message m2) {
            final Date d1 = m1 == null ? EARLY : m1.getSentDate() != null ? m1.getSentDate() : EARLY;
            final Date d2 = m2 == null ? EARLY : m2.getSentDate() != null ? m2.getSentDate() : EARLY;
            return d2.compareTo(d1);
        }
    }

    public static boolean isValidImapFolder(String imapFolder) {
        return !(imapFolder == null || imapFolder.length() == 0) &&
               !(imapFolder.charAt(0) == '/' || imapFolder.charAt(0) == ' ' || imapFolder.charAt(imapFolder.length() - 1) == ' ');
    }

    public static boolean isValidUri(String uri) {
        if (TextUtils.isEmpty(uri)) return false;
        Uri parsed = Uri.parse(uri);
        return parsed != null &&
                !TextUtils.isEmpty(parsed.getAuthority()) &&
                !TextUtils.isEmpty(parsed.getHost()) &&
                !TextUtils.isEmpty(parsed.getScheme()) &&
                ("imap+ssl+".equalsIgnoreCase(parsed.getScheme()) ||
                "imap+ssl".equalsIgnoreCase(parsed.getScheme()) ||
                "imap".equalsIgnoreCase(parsed.getScheme()) ||
                "imap+tls+".equalsIgnoreCase(parsed.getScheme()) ||
                "imap+tls".equalsIgnoreCase(parsed.getScheme()));
    }

    // reimplement trust-all logic which was removed in
    // https://github.com/k9mail/k-9/commit/daea7f1ecdb4515298a6c57dd5a829689426c2c9
    private static TrustedSocketFactory getTrustedSocketFactory(Context context, String storeUri) {
        try {
            if (isInsecureStoreUri(new URI(storeUri))) {
                Log.d(TAG, "insecure store uri specified, trusting ALL certificates");
                return AllTrustedSocketFactory.INSTANCE;
            }
        } catch (URISyntaxException ignored) {
        }
        return new DefaultTrustedSocketFactory(context);
    }

    private static boolean isInsecureStoreUri(URI uri) {
        return "imap+tls".equals(uri.getScheme()) || "imap+ssl".equals(uri.getScheme());
    }
}




Java Source Code List

com.zegoggles.smssync.App.java
com.zegoggles.smssync.Consts.java
com.zegoggles.smssync.MmsConsts.java
com.zegoggles.smssync.SmsConsts.java
com.zegoggles.smssync.activity.Dialogs.java
com.zegoggles.smssync.activity.MainActivity.java
com.zegoggles.smssync.activity.StatusPreference.java
com.zegoggles.smssync.activity.auth.AccountManagerAuthActivity.java
com.zegoggles.smssync.activity.auth.WebAuthActivity.java
com.zegoggles.smssync.activity.donation.DonationActivity.java
com.zegoggles.smssync.auth.TokenRefreshException.java
com.zegoggles.smssync.auth.TokenRefresher.java
com.zegoggles.smssync.auth.XOAuthConsumer.java
com.zegoggles.smssync.calendar.CalendarAccessorPost40.java
com.zegoggles.smssync.calendar.CalendarAccessorPre40.java
com.zegoggles.smssync.calendar.CalendarAccessor.java
com.zegoggles.smssync.compat.ComposeSmsActivity.java
com.zegoggles.smssync.compat.HeadlessSmsSendService.java
com.zegoggles.smssync.compat.MmsReceiver.java
com.zegoggles.smssync.compat.SmsReceiver.java
com.zegoggles.smssync.compat.package-info.java
com.zegoggles.smssync.contacts.ContactAccessorPost20.java
com.zegoggles.smssync.contacts.ContactAccessorPre20.java
com.zegoggles.smssync.contacts.ContactAccessor.java
com.zegoggles.smssync.contacts.ContactGroupIds.java
com.zegoggles.smssync.contacts.ContactGroup.java
com.zegoggles.smssync.contacts.Group.java
com.zegoggles.smssync.mail.AllTrustedSocketFactory.java
com.zegoggles.smssync.mail.Attachment.java
com.zegoggles.smssync.mail.BackupImapStore.java
com.zegoggles.smssync.mail.BackupStoreConfig.java
com.zegoggles.smssync.mail.CallFormatter.java
com.zegoggles.smssync.mail.ConversionResult.java
com.zegoggles.smssync.mail.DataType.java
com.zegoggles.smssync.mail.HeaderGenerator.java
com.zegoggles.smssync.mail.Headers.java
com.zegoggles.smssync.mail.MessageConverter.java
com.zegoggles.smssync.mail.MessageGenerator.java
com.zegoggles.smssync.mail.MmsSupport.java
com.zegoggles.smssync.mail.PersonLookup.java
com.zegoggles.smssync.mail.PersonRecord.java
com.zegoggles.smssync.preferences.AddressStyle.java
com.zegoggles.smssync.preferences.AuthMode.java
com.zegoggles.smssync.preferences.AuthPreferences.java
com.zegoggles.smssync.preferences.BackupManagerWrapper.java
com.zegoggles.smssync.preferences.CalendarPreferences.java
com.zegoggles.smssync.preferences.CallLogTypes.java
com.zegoggles.smssync.preferences.Defaults.java
com.zegoggles.smssync.preferences.MarkAsReadTypes.java
com.zegoggles.smssync.preferences.PreferenceBackupAgent.java
com.zegoggles.smssync.preferences.Preferences.java
com.zegoggles.smssync.preferences.ServerPreferences.java
com.zegoggles.smssync.receiver.BackupBroadcastReceiver.java
com.zegoggles.smssync.receiver.SmsBroadcastReceiver.java
com.zegoggles.smssync.service.Alarms.java
com.zegoggles.smssync.service.BackupConfig.java
com.zegoggles.smssync.service.BackupCursors.java
com.zegoggles.smssync.service.BackupItemsFetcher.java
com.zegoggles.smssync.service.BackupQueryBuilder.java
com.zegoggles.smssync.service.BackupTask.java
com.zegoggles.smssync.service.BackupType.java
com.zegoggles.smssync.service.BulkFetcher.java
com.zegoggles.smssync.service.CalendarSyncer.java
com.zegoggles.smssync.service.RestoreConfig.java
com.zegoggles.smssync.service.RestoreTask.java
com.zegoggles.smssync.service.ServiceBase.java
com.zegoggles.smssync.service.SmsBackupService.java
com.zegoggles.smssync.service.SmsRestoreService.java
com.zegoggles.smssync.service.UserCanceled.java
com.zegoggles.smssync.service.WhatsAppItemsFetcher.java
com.zegoggles.smssync.service.exception.BackupDisabledException.java
com.zegoggles.smssync.service.exception.ConnectivityException.java
com.zegoggles.smssync.service.exception.LocalizableException.java
com.zegoggles.smssync.service.exception.NoConnectionException.java
com.zegoggles.smssync.service.exception.RequiresBackgroundDataException.java
com.zegoggles.smssync.service.exception.RequiresLoginException.java
com.zegoggles.smssync.service.exception.RequiresWifiException.java
com.zegoggles.smssync.service.exception.SmsProviderNotWritableException.java
com.zegoggles.smssync.service.state.BackupState.java
com.zegoggles.smssync.service.state.RestoreState.java
com.zegoggles.smssync.service.state.SmsSyncState.java
com.zegoggles.smssync.service.state.State.java
com.zegoggles.smssync.tasks.OAuthCallbackTask.java
com.zegoggles.smssync.tasks.RequestTokenTask.java
com.zegoggles.smssync.utils.AppLog.java
com.zegoggles.smssync.utils.ListPreferenceHelper.java
com.zegoggles.smssync.utils.Sanitizer.java
com.zegoggles.smssync.utils.ThreadHelper.java