EasOutboxService.java revision 1ba0fd37a158c1477025aa530206fefdc4b3fe5b
1/*
2 * Copyright (C) 2008-2009 Marc Blank
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.exchange;
19
20import com.android.email.mail.MessagingException;
21import com.android.email.mail.transport.Rfc822Output;
22import com.android.email.provider.EmailContent.Mailbox;
23import com.android.email.provider.EmailContent.Message;
24import com.android.email.provider.EmailContent.MessageColumns;
25import com.android.email.provider.EmailContent.SyncColumns;
26
27import org.apache.http.HttpResponse;
28import org.apache.http.entity.InputStreamEntity;
29
30import android.content.ContentUris;
31import android.content.ContentValues;
32import android.content.Context;
33import android.database.Cursor;
34
35import java.io.File;
36import java.io.FileInputStream;
37import java.io.FileOutputStream;
38import java.io.IOException;
39import java.net.HttpURLConnection;
40
41public class EasOutboxService extends EasSyncService {
42
43    public static final int SEND_FAILED = 1;
44    public static final String MAILBOX_KEY_AND_NOT_SEND_FAILED =
45        MessageColumns.MAILBOX_KEY + "=? and " + SyncColumns.SERVER_ID + "!=" + SEND_FAILED;
46
47    public EasOutboxService(Context _context, Mailbox _mailbox) {
48        super(_context, _mailbox);
49        mContext = _context;
50    }
51
52    /**
53     * Send a single message via EAS
54     * Note that we mark messages SEND_FAILED when there is a permanent failure, rather than an
55     * IOException, which is handled by SyncManager with retries, backoffs, etc.
56     *
57     * @param cacheDir the cache directory for this context
58     * @param msgId the _id of the message to send
59     * @throws IOException
60     */
61    void sendMessage(File cacheDir, long msgId) throws IOException, MessagingException {
62        File tmpFile = File.createTempFile("eas_", "tmp", cacheDir);
63        // Write the output to a temporary file
64        try {
65            FileOutputStream fileStream = new FileOutputStream(tmpFile);
66            Rfc822Output.writeTo(mContext, msgId, fileStream);
67            fileStream.close();
68            // Now, get an input stream to our new file and create an entity with it
69            FileInputStream inputStream = new FileInputStream(tmpFile);
70            InputStreamEntity inputEntity =
71                new InputStreamEntity(inputStream, tmpFile.length());
72            // Send the post to the server
73            HttpResponse resp =
74                sendHttpClientPost("SendMail&SaveInSent=T", inputEntity);
75            inputStream.close();
76            int code = resp.getStatusLine().getStatusCode();
77            if (code == HttpURLConnection.HTTP_OK) {
78                userLog("Deleting message...");
79                mContext.getContentResolver().delete(ContentUris.withAppendedId(
80                        Message.CONTENT_URI, msgId), null, null);
81            } else {
82                // This case handles post-connection failures (i.e. errors coming back from the
83                // server)
84                // TODO Handle login failures?
85                ContentValues cv = new ContentValues();
86                cv.put(SyncColumns.SERVER_ID, SEND_FAILED);
87                Message.update(mContext, Message.CONTENT_URI, msgId, cv);
88            }
89            // TODO Implement the upcoming EmailServiceCallback for messageSent
90            // sendMessageResult(messageId, result);
91        } finally {
92            // Clean up the temporary file
93            if (tmpFile.exists()) {
94                tmpFile.delete();
95            }
96        }
97    }
98
99    @Override
100    public void run() {
101        mThread = Thread.currentThread();
102        File cacheDir = mContext.getCacheDir();
103        try {
104            Cursor c = mContext.getContentResolver().query(Message.CONTENT_URI,
105                    Message.ID_COLUMN_PROJECTION, MAILBOX_KEY_AND_NOT_SEND_FAILED,
106                    new String[] {Long.toString(mMailbox.mId)}, null);
107             try {
108                while (c.moveToNext()) {
109                    long msgId = c.getLong(0);
110                    if (msgId != 0) {
111                        sendMessage(cacheDir, msgId);
112                    }
113                }
114            } finally {
115                 c.close();
116            }
117        } catch (Exception e) {
118            mExitStatus = EXIT_EXCEPTION;
119        } finally {
120            userLog(mMailbox.mDisplayName, ": sync finished");
121            SyncManager.done(this);
122        }
123    }
124}