• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.exchange.eas;
2 
3 import android.content.Context;
4 import android.database.Cursor;
5 
6 import com.android.emailcommon.TrafficFlags;
7 import com.android.emailcommon.provider.Account;
8 import com.android.emailcommon.provider.EmailContent.Message;
9 import com.android.emailcommon.provider.EmailContent.MessageColumns;
10 import com.android.emailcommon.provider.EmailContent.SyncColumns;
11 import com.android.emailcommon.provider.Mailbox;
12 import com.android.emailcommon.service.SyncWindow;
13 import com.android.exchange.Eas;
14 import com.android.exchange.adapter.AbstractSyncParser;
15 import com.android.exchange.adapter.EmailSyncParser;
16 import com.android.exchange.adapter.Serializer;
17 import com.android.exchange.adapter.Tags;
18 
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 
23 /**
24  * Subclass to handle sync details for mail collections.
25  */
26 public class EasSyncMail extends EasSyncCollectionTypeBase {
27 
28     /**
29      * The projection used for building the fetch request list.
30      */
31     private static final String[] FETCH_REQUEST_PROJECTION = { SyncColumns.SERVER_ID };
32     private static final int FETCH_REQUEST_SERVER_ID = 0;
33 
34     private static final int EMAIL_WINDOW_SIZE = 10;
35 
36 
37     @Override
getTrafficFlag()38     public int getTrafficFlag() {
39         return TrafficFlags.DATA_EMAIL;
40     }
41 
42     @Override
setSyncOptions(final Context context, final Serializer s, final double protocolVersion, final Account account, final Mailbox mailbox, final boolean isInitialSync, final int numWindows)43     public void setSyncOptions(final Context context, final Serializer s,
44             final double protocolVersion, final Account account, final Mailbox mailbox,
45             final boolean isInitialSync, final int numWindows) throws IOException {
46         if (isInitialSync) {
47             // No special options to set for initial mailbox sync.
48             return;
49         }
50 
51         // Check for messages that aren't fully loaded.
52         final ArrayList<String> messagesToFetch = addToFetchRequestList(context, mailbox);
53         // The "empty" case is typical; we send a request for changes, and also specify a sync
54         // window, body preference type (HTML for EAS 12.0 and later; MIME for EAS 2.5), and
55         // truncation
56         // If there are fetch requests, we only want the fetches (i.e. no changes from the server)
57         // so we turn MIME support off.  Note that we are always using EAS 2.5 if there are fetch
58         // requests
59         if (messagesToFetch.isEmpty()) {
60             // Permanently delete if in trash mailbox
61             // In Exchange 2003, deletes-as-moves tag = true; no tag = false
62             // In Exchange 2007 and up, deletes-as-moves tag is "0" (false) or "1" (true)
63             final boolean isTrashMailbox = mailbox.mType == Mailbox.TYPE_TRASH;
64             if (protocolVersion < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) {
65                 if (!isTrashMailbox) {
66                     s.tag(Tags.SYNC_DELETES_AS_MOVES);
67                 }
68             } else {
69                 s.data(Tags.SYNC_DELETES_AS_MOVES, isTrashMailbox ? "0" : "1");
70             }
71             s.tag(Tags.SYNC_GET_CHANGES);
72 
73             final int windowSize = numWindows * EMAIL_WINDOW_SIZE;
74             if (windowSize > MAX_WINDOW_SIZE  + EMAIL_WINDOW_SIZE) {
75                 throw new IOException("Max window size reached and still no data");
76             }
77             s.data(Tags.SYNC_WINDOW_SIZE,
78                     String.valueOf(windowSize < MAX_WINDOW_SIZE ? windowSize : MAX_WINDOW_SIZE));
79             s.start(Tags.SYNC_OPTIONS);
80             // Set the lookback appropriately (EAS calls this a "filter")
81             s.data(Tags.SYNC_FILTER_TYPE, getEmailFilter(account, mailbox));
82             // Set the truncation amount for all classes
83             if (protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) {
84                 s.start(Tags.BASE_BODY_PREFERENCE);
85                 // HTML for email
86                 s.data(Tags.BASE_TYPE, Eas.BODY_PREFERENCE_HTML);
87                 s.data(Tags.BASE_TRUNCATION_SIZE, Eas.EAS12_TRUNCATION_SIZE);
88                 s.end();
89             } else {
90                 // Use MIME data for EAS 2.5
91                 s.data(Tags.SYNC_MIME_SUPPORT, Eas.MIME_BODY_PREFERENCE_MIME);
92                 s.data(Tags.SYNC_MIME_TRUNCATION, Eas.EAS2_5_TRUNCATION_SIZE);
93             }
94             s.end();
95         } else {
96             // If we have any messages that are not fully loaded, ask for plain text rather than
97             // MIME, to guarantee we'll get usable text body. This also means we should NOT ask for
98             // new messages -- we only want data for the message explicitly fetched.
99             s.start(Tags.SYNC_OPTIONS);
100             s.data(Tags.SYNC_MIME_SUPPORT, Eas.MIME_BODY_PREFERENCE_TEXT);
101             s.data(Tags.SYNC_TRUNCATION, Eas.EAS2_5_TRUNCATION_SIZE);
102             s.end();
103 
104             // Add FETCH commands for messages that need a body (i.e. we didn't find it during our
105             // earlier sync; this happens only in EAS 2.5 where the body couldn't be found after
106             // parsing the message's MIME data).
107             s.start(Tags.SYNC_COMMANDS);
108             for (final String serverId : messagesToFetch) {
109                 s.start(Tags.SYNC_FETCH).data(Tags.SYNC_SERVER_ID, serverId).end();
110             }
111             s.end();
112         }
113     }
114 
115     @Override
getParser(final Context context, final Account account, final Mailbox mailbox, final InputStream is)116     public AbstractSyncParser getParser(final Context context, final Account account,
117             final Mailbox mailbox, final InputStream is) throws IOException {
118         return new EmailSyncParser(context, is, mailbox, account);
119     }
120 
121     /**
122      * Query the provider for partially loaded messages.
123      * @return Server ids for partially loaded messages.
124      */
addToFetchRequestList(final Context context, final Mailbox mailbox)125     private ArrayList<String> addToFetchRequestList(final Context context, final Mailbox mailbox) {
126         final ArrayList<String> messagesToFetch = new ArrayList<String>();
127         final Cursor c = context.getContentResolver().query(Message.CONTENT_URI,
128                 FETCH_REQUEST_PROJECTION,  MessageColumns.FLAG_LOADED + "=" +
129                 Message.FLAG_LOADED_PARTIAL + " AND " +  MessageColumns.MAILBOX_KEY + "=?",
130                 new String[] {Long.toString(mailbox.mId)}, null);
131         if (c != null) {
132             try {
133                 while (c.moveToNext()) {
134                     messagesToFetch.add(c.getString(FETCH_REQUEST_SERVER_ID));
135                 }
136             } finally {
137                 c.close();
138             }
139         }
140         return messagesToFetch;
141     }
142 
143     /**
144      * Get the sync window for this collection and translate it to EAS's value for that (EAS refers
145      * to this as the "filter").
146      * @param account The {@link Account} for this sync; its sync window is used if the mailbox
147      *                doesn't specify an override.
148      * @param mailbox The {@link Mailbox} for this sync.
149      * @return The EAS string value for the sync window specified for this mailbox.
150      */
getEmailFilter(final Account account, final Mailbox mailbox)151     private String getEmailFilter(final Account account, final Mailbox mailbox) {
152         final int syncLookback = mailbox.mSyncLookback == SyncWindow.SYNC_WINDOW_ACCOUNT
153                 ? account.mSyncLookback : mailbox.mSyncLookback;
154         switch (syncLookback) {
155             case SyncWindow.SYNC_WINDOW_1_DAY:
156                 return Eas.FILTER_1_DAY;
157             case SyncWindow.SYNC_WINDOW_3_DAYS:
158                 return Eas.FILTER_3_DAYS;
159             case SyncWindow.SYNC_WINDOW_1_WEEK:
160                 return Eas.FILTER_1_WEEK;
161             case SyncWindow.SYNC_WINDOW_2_WEEKS:
162                 return Eas.FILTER_2_WEEKS;
163             case SyncWindow.SYNC_WINDOW_1_MONTH:
164                 return Eas.FILTER_1_MONTH;
165             case SyncWindow.SYNC_WINDOW_ALL:
166                 return Eas.FILTER_ALL;
167             default:
168                 // Auto window is deprecated and will also use the default.
169                 return Eas.FILTER_1_WEEK;
170         }
171     }
172 }
173