am 35177585: Merge "Remove Imap2 from AOSP tree" into jb-ub-mail
* commit '35177585a24b608582536c3d2c6633f8ee486511': Remove Imap2 from AOSP tree
This commit is contained in:
commit
ee6ca4e7b2
|
@ -1,21 +0,0 @@
|
|||
# Copyright 2012, The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := Imap2
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
include $(BUILD_PHONY_PACKAGE)
|
|
@ -1,203 +0,0 @@
|
|||
/* Copyright (C) 2012 The Android Open Source Project.
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.email.imap2.Imap2SyncService.Connection;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.service.EmailServiceStatus;
|
||||
import com.android.emailcommon.utility.AttachmentUtilities;
|
||||
import com.android.emailsync.PartRequest;
|
||||
import com.android.mail.providers.UIProvider;
|
||||
|
||||
import org.apache.james.mime4j.decoder.Base64InputStream;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Handle IMAP2 attachment loading
|
||||
*/
|
||||
public class AttachmentLoader {
|
||||
static private final int CHUNK_SIZE = 16*1024;
|
||||
|
||||
private final Context mContext;
|
||||
private final Attachment mAttachment;
|
||||
private final long mAttachmentId;
|
||||
private final long mMessageId;
|
||||
private final Message mMessage;
|
||||
private final Imap2SyncService mService;
|
||||
|
||||
public AttachmentLoader(Imap2SyncService service, PartRequest req) {
|
||||
mService = service;
|
||||
mContext = service.mContext;
|
||||
mAttachment = req.mAttachment;
|
||||
mAttachmentId = mAttachment.mId;
|
||||
mMessageId = mAttachment.mMessageKey;
|
||||
mMessage = Message.restoreMessageWithId(mContext, mMessageId);
|
||||
}
|
||||
|
||||
private void doStatusCallback(int status) {
|
||||
try {
|
||||
Imap2SyncManager.callback().loadAttachmentStatus(mMessageId, mAttachmentId, status, 0);
|
||||
} catch (RemoteException e) {
|
||||
// No danger if the client is no longer around
|
||||
}
|
||||
}
|
||||
|
||||
private void doProgressCallback(int progress) {
|
||||
try {
|
||||
Imap2SyncManager.callback().loadAttachmentStatus(mMessageId, mAttachmentId,
|
||||
EmailServiceStatus.IN_PROGRESS, progress);
|
||||
} catch (RemoteException e) {
|
||||
// No danger if the client is no longer around
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close, ignoring errors (as during cleanup)
|
||||
* @param c a Closeable
|
||||
*/
|
||||
private void close(Closeable c) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save away the contentUri for this Attachment and notify listeners
|
||||
* @throws IOException
|
||||
*/
|
||||
private void finishLoadAttachment(File file, OutputStream os) throws IOException {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
if (mAttachment.mEncoding != null &&
|
||||
"base64".equals(mAttachment.mEncoding.toLowerCase())) {
|
||||
in = new Base64InputStream(in);
|
||||
}
|
||||
AttachmentUtilities.saveAttachment(mContext, in, mAttachment);
|
||||
doStatusCallback(EmailServiceStatus.SUCCESS);
|
||||
} catch (FileNotFoundException e) {
|
||||
// Not bloody likely, as we just created it successfully
|
||||
throw new IOException("Attachment file not found?");
|
||||
} finally {
|
||||
close(in);
|
||||
}
|
||||
}
|
||||
|
||||
private void readPart (ImapInputStream in, String tag, OutputStream out) throws IOException {
|
||||
String res = in.readLine();
|
||||
int bstart = res.indexOf("body[");
|
||||
if (bstart < 0)
|
||||
bstart = res.indexOf("BODY[");
|
||||
if (bstart < 0)
|
||||
return;
|
||||
int bend = res.indexOf(']', bstart);
|
||||
if (bend < 0)
|
||||
return;
|
||||
int br = res.indexOf('{');
|
||||
if (br > 0) {
|
||||
Parser p = new Parser(res, br + 1);
|
||||
int expectedLength = p.parseInteger();
|
||||
int remainingLength = expectedLength;
|
||||
int totalRead = 0;
|
||||
byte[] buf = new byte[CHUNK_SIZE];
|
||||
int lastCallbackPct = -1;
|
||||
int lastCallbackTotalRead = 0;
|
||||
while (remainingLength > 0) {
|
||||
int rdlen = (remainingLength > CHUNK_SIZE ? CHUNK_SIZE : remainingLength);
|
||||
int bytesRead = in.read(buf, 0, rdlen);
|
||||
totalRead += bytesRead;
|
||||
out.write(buf, 0, bytesRead);
|
||||
remainingLength -= bytesRead;
|
||||
int pct = (totalRead * 100) / expectedLength;
|
||||
// Callback only if we've read at least 1% more and have read more than CHUNK_SIZE
|
||||
// We don't want to spam the Email app
|
||||
if ((pct > lastCallbackPct) && (totalRead > (lastCallbackTotalRead + CHUNK_SIZE))) {
|
||||
// Report progress back to the UI
|
||||
doProgressCallback(pct);
|
||||
lastCallbackTotalRead = totalRead;
|
||||
lastCallbackPct = pct;
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
String line = in.readLine();
|
||||
if (!line.endsWith(")")) {
|
||||
mService.errorLog("Bad part?");
|
||||
throw new IOException();
|
||||
}
|
||||
line = in.readLine();
|
||||
if (!line.startsWith(tag)) {
|
||||
mService.userLog("Bad part?");
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an attachment, based on the PartRequest passed in the constructor
|
||||
* @throws IOException
|
||||
*/
|
||||
public void loadAttachment(Connection conn) throws IOException {
|
||||
if (mMessage == null) {
|
||||
doStatusCallback(EmailServiceStatus.MESSAGE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
if (mAttachment.mUiState == UIProvider.AttachmentState.SAVED) {
|
||||
return;
|
||||
}
|
||||
// Say we've started loading the attachment
|
||||
doProgressCallback(0);
|
||||
|
||||
try {
|
||||
OutputStream os = null;
|
||||
File tmpFile = null;
|
||||
try {
|
||||
tmpFile = File.createTempFile("imap_", "tmp", mContext.getCacheDir());
|
||||
os = new FileOutputStream(tmpFile);
|
||||
String tag = mService.writeCommand(conn.writer, "uid fetch " + mMessage.mServerId +
|
||||
" body[" + mAttachment.mLocation + ']');
|
||||
readPart(conn.reader, tag, os);
|
||||
finishLoadAttachment(tmpFile, os);
|
||||
return;
|
||||
} catch (FileNotFoundException e) {
|
||||
mService.errorLog("Can't get attachment; write file not found?");
|
||||
doStatusCallback(EmailServiceStatus.ATTACHMENT_NOT_FOUND);
|
||||
} finally {
|
||||
close(os);
|
||||
if (tmpFile != null) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Report the error, but also report back to the service
|
||||
doStatusCallback(EmailServiceStatus.CONNECTION_ERROR);
|
||||
throw e;
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.app.Service;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SyncResult;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
|
||||
public class EmailSyncAdapterService extends Service {
|
||||
private static final String TAG = "Imap EmailSyncAdapterService";
|
||||
private static SyncAdapterImpl sSyncAdapter = null;
|
||||
private static final Object sSyncAdapterLock = new Object();
|
||||
|
||||
private static final String[] ID_PROJECTION = new String[] {EmailContent.RECORD_ID};
|
||||
private static final String ACCOUNT_AND_TYPE_INBOX =
|
||||
MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.TYPE + '=' + Mailbox.TYPE_INBOX;
|
||||
|
||||
public EmailSyncAdapterService() {
|
||||
super();
|
||||
}
|
||||
|
||||
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
|
||||
private Context mContext;
|
||||
|
||||
public SyncAdapterImpl(Context context) {
|
||||
super(context, true /* autoInitialize */);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPerformSync(Account account, Bundle extras,
|
||||
String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
try {
|
||||
EmailSyncAdapterService.performSync(mContext, account, extras,
|
||||
authority, provider, syncResult);
|
||||
} catch (OperationCanceledException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
synchronized (sSyncAdapterLock) {
|
||||
if (sSyncAdapter == null) {
|
||||
sSyncAdapter = new SyncAdapterImpl(getApplicationContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return sSyncAdapter.getSyncAdapterBinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial integration with system SyncManager; we tell our EAS ExchangeService to start an
|
||||
* inbox sync when we get the signal from the system SyncManager.
|
||||
*/
|
||||
private static void performSync(Context context, Account account, Bundle extras,
|
||||
String authority, ContentProviderClient provider, SyncResult syncResult)
|
||||
throws OperationCanceledException {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
Log.i(TAG, "performSync");
|
||||
|
||||
// Find the (EmailProvider) account associated with this email address
|
||||
Cursor accountCursor =
|
||||
cr.query(com.android.emailcommon.provider.Account.CONTENT_URI,
|
||||
ID_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?", new String[] {account.name},
|
||||
null);
|
||||
try {
|
||||
if (accountCursor.moveToFirst()) {
|
||||
long accountId = accountCursor.getLong(0);
|
||||
// Now, find the inbox associated with the account
|
||||
Cursor mailboxCursor = cr.query(Mailbox.CONTENT_URI, ID_PROJECTION,
|
||||
ACCOUNT_AND_TYPE_INBOX, new String[] {Long.toString(accountId)}, null);
|
||||
try {
|
||||
if (mailboxCursor.moveToFirst()) {
|
||||
Log.i(TAG, "Mail sync requested for " + account.name);
|
||||
// Ask for a sync from our sync manager
|
||||
//***
|
||||
//SyncServiceManager.serviceRequest(mailboxCursor.getLong(0),
|
||||
// SyncServiceManager.SYNC_KICK);
|
||||
}
|
||||
} finally {
|
||||
mailboxCursor.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
accountCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,377 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.Api;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.provider.ProviderUnavailableException;
|
||||
import com.android.emailcommon.service.AccountServiceProxy;
|
||||
import com.android.emailcommon.service.EmailServiceCallback;
|
||||
import com.android.emailcommon.service.IEmailService;
|
||||
import com.android.emailcommon.service.IEmailServiceCallback;
|
||||
import com.android.emailcommon.service.IEmailServiceCallback.Stub;
|
||||
import com.android.emailcommon.service.SearchParams;
|
||||
import com.android.emailcommon.service.SyncWindow;
|
||||
import com.android.emailsync.AbstractSyncService;
|
||||
import com.android.emailsync.PartRequest;
|
||||
import com.android.emailsync.SyncManager;
|
||||
import com.android.mail.providers.UIProvider;
|
||||
import com.android.mail.providers.UIProvider.AccountCapabilities;
|
||||
import com.android.mail.providers.UIProvider.LastSyncResult;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class Imap2SyncManager extends SyncManager {
|
||||
|
||||
// Callbacks as set up via setCallback
|
||||
private static final RemoteCallbackList<IEmailServiceCallback> mCallbackList =
|
||||
new RemoteCallbackList<IEmailServiceCallback>();
|
||||
|
||||
private static final EmailServiceCallback sCallbackProxy =
|
||||
new EmailServiceCallback(mCallbackList);
|
||||
|
||||
private Intent mIntent;
|
||||
|
||||
private static String PROTOCOL;
|
||||
|
||||
/**
|
||||
* Create our EmailService implementation here.
|
||||
*/
|
||||
private final IEmailService.Stub mBinder = new IEmailService.Stub() {
|
||||
|
||||
@Override
|
||||
public int getApiLevel() {
|
||||
return Api.LEVEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle validate(HostAuth hostAuth) throws RemoteException {
|
||||
return new Imap2SyncService(Imap2SyncManager.this,
|
||||
new Mailbox()).validateAccount(hostAuth, Imap2SyncManager.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle autoDiscover(String userName, String password) throws RemoteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSync(long mailboxId, boolean userRequest) throws RemoteException {
|
||||
SyncManager imapService = INSTANCE;
|
||||
if (imapService == null) return;
|
||||
Imap2SyncService svc = (Imap2SyncService) imapService.mServiceMap.get(mailboxId);
|
||||
if (svc == null) {
|
||||
startManualSync(mailboxId, userRequest ? SYNC_UI_REQUEST : SYNC_SERVICE_START_SYNC,
|
||||
null);
|
||||
} else {
|
||||
svc.ping();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSync(long mailboxId) throws RemoteException {
|
||||
stopManualSync(mailboxId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAttachment(long attachmentId, boolean background) throws RemoteException {
|
||||
Attachment att = Attachment.restoreAttachmentWithId(Imap2SyncManager.this, attachmentId);
|
||||
log("loadAttachment " + attachmentId + ": " + att.mFileName);
|
||||
sendMessageRequest(new PartRequest(att, null, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFolderList(long accountId) throws RemoteException {
|
||||
//***
|
||||
//reloadFolderList(ImapService.this, accountId, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hostChanged(long accountId) throws RemoteException {
|
||||
SyncManager exchangeService = INSTANCE;
|
||||
if (exchangeService == null) return;
|
||||
ConcurrentHashMap<Long, SyncError> syncErrorMap = exchangeService.mSyncErrorMap;
|
||||
// Go through the various error mailboxes
|
||||
for (long mailboxId: syncErrorMap.keySet()) {
|
||||
SyncError error = syncErrorMap.get(mailboxId);
|
||||
// If it's a login failure, look a little harder
|
||||
Mailbox m = Mailbox.restoreMailboxWithId(exchangeService, mailboxId);
|
||||
// If it's for the account whose host has changed, clear the error
|
||||
// If the mailbox is no longer around, remove the entry in the map
|
||||
if (m == null) {
|
||||
syncErrorMap.remove(mailboxId);
|
||||
} else if (error != null && m.mAccountKey == accountId) {
|
||||
error.fatal = false;
|
||||
error.holdEndTime = 0;
|
||||
}
|
||||
}
|
||||
// Stop any running syncs
|
||||
exchangeService.stopAccountSyncs(accountId, true);
|
||||
// Kick ExchangeService
|
||||
kick("host changed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogging(int flags) throws RemoteException {
|
||||
// Protocol logging
|
||||
//Eas.setUserDebug(flags);
|
||||
// Sync logging
|
||||
setUserDebug(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMeetingResponse(long messageId, int response) throws RemoteException {
|
||||
// Not used in IMAP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMore(long messageId) throws RemoteException {
|
||||
}
|
||||
|
||||
// The following three methods are not implemented in this version
|
||||
@Override
|
||||
public boolean createFolder(long accountId, String name) throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteFolder(long accountId, String name) throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renameFolder(long accountId, String oldName, String newName)
|
||||
throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(IEmailServiceCallback cb) throws RemoteException {
|
||||
mCallbackList.register(cb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAccountPIMData(long accountId) throws RemoteException {
|
||||
// Not required for IMAP
|
||||
}
|
||||
|
||||
@Override
|
||||
public int searchMessages(long accountId, SearchParams params, long destMailboxId)
|
||||
throws RemoteException {
|
||||
SyncManager ssm = INSTANCE;
|
||||
if (ssm == null) return 0;
|
||||
Mailbox mailbox = Mailbox.restoreMailboxWithId(ssm, params.mMailboxId);
|
||||
Imap2SyncService svc = new Imap2SyncService(ssm, mailbox);
|
||||
setMailboxSyncStatus(destMailboxId, UIProvider.SyncStatus.USER_QUERY);
|
||||
boolean ioError = false;
|
||||
try {
|
||||
return svc.searchMailbox(ssm, accountId, params, destMailboxId);
|
||||
} catch (IOException e) {
|
||||
ioError = true;
|
||||
return 0;
|
||||
} finally {
|
||||
// Report ioError status back
|
||||
setMailboxLastSyncResult(destMailboxId,
|
||||
ioError ? LastSyncResult.CONNECTION_ERROR : LastSyncResult.SUCCESS);
|
||||
setMailboxSyncStatus(destMailboxId, UIProvider.SyncStatus.NO_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(long accountId) throws RemoteException {
|
||||
// Not required for IMAP
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCapabilities(Account acct) throws RemoteException {
|
||||
return AccountCapabilities.SYNCABLE_FOLDERS |
|
||||
AccountCapabilities.FOLDER_SERVER_SEARCH |
|
||||
AccountCapabilities.UNDO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceUpdated(String emailAddress) throws RemoteException {
|
||||
SyncManager ssm = INSTANCE;
|
||||
if (ssm == null) return;
|
||||
log("serviceUpdated called for " + emailAddress);
|
||||
Cursor c = ssm.getContentResolver().query(Account.CONTENT_URI, Account.ID_PROJECTION,
|
||||
AccountColumns.EMAIL_ADDRESS + "=?", new String[] { emailAddress }, null);
|
||||
if (c == null) return;
|
||||
try {
|
||||
if (c.moveToNext()) {
|
||||
long accountId = c.getLong(0);
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(AccountColumns.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH);
|
||||
values.put(AccountColumns.SYNC_LOOKBACK, SyncWindow.SYNC_WINDOW_AUTO);
|
||||
// Say we can push (at least, we'll try)
|
||||
mResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI, accountId),
|
||||
values, null, null);
|
||||
log("Sync interval and lookback set for " + emailAddress);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static public IEmailServiceCallback callback() {
|
||||
return sCallbackProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountObserver getAccountObserver(Handler handler) {
|
||||
return new AccountObserver(handler) {
|
||||
@Override
|
||||
public void newAccount(long acctId) {
|
||||
// Create the Inbox for the account if it doesn't exist
|
||||
Context context = getContext();
|
||||
Account acct = Account.restoreAccountWithId(context, acctId);
|
||||
if (acct == null) return;
|
||||
long inboxId = Mailbox.findMailboxOfType(context, acctId, Mailbox.TYPE_INBOX);
|
||||
if (inboxId != Mailbox.NO_MAILBOX) {
|
||||
return;
|
||||
}
|
||||
Mailbox inbox = new Mailbox();
|
||||
inbox.mDisplayName = context.getString(R.string.mailbox_name_server_inbox);
|
||||
inbox.mServerId = "Inbox";
|
||||
inbox.mAccountKey = acct.mId;
|
||||
inbox.mType = Mailbox.TYPE_INBOX;
|
||||
inbox.mSyncInterval = acct.mSyncInterval;
|
||||
inbox.save(getContext());
|
||||
log("Creating inbox for account: " + acct.mDisplayName);
|
||||
Imap2SyncManager.kick("New account");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup() {
|
||||
// No special behavior
|
||||
}
|
||||
|
||||
private static final String ACCOUNT_KEY_IN = MailboxColumns.ACCOUNT_KEY + " in (";
|
||||
private String mAccountSelector;
|
||||
@Override
|
||||
public String getAccountsSelector() {
|
||||
if (mAccountSelector == null) {
|
||||
StringBuilder sb = new StringBuilder(ACCOUNT_KEY_IN);
|
||||
boolean first = true;
|
||||
synchronized (mAccountList) {
|
||||
for (Account account : mAccountList) {
|
||||
if (!first) {
|
||||
sb.append(',');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
sb.append(account.mId);
|
||||
}
|
||||
}
|
||||
sb.append(')');
|
||||
mAccountSelector = sb.toString();
|
||||
}
|
||||
return mAccountSelector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractSyncService getServiceForMailbox(Context context, Mailbox mailbox) {
|
||||
return new Imap2SyncService(context, mailbox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountList collectAccounts(Context context, AccountList accounts) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, null, null,
|
||||
null);
|
||||
// We must throw here; callers might use the information we provide for reconciliation, etc.
|
||||
if (c == null) throw new ProviderUnavailableException();
|
||||
try {
|
||||
if (PROTOCOL == null) {
|
||||
PROTOCOL = getString(R.string.protocol_imap);
|
||||
}
|
||||
while (c.moveToNext()) {
|
||||
long hostAuthId = c.getLong(Account.CONTENT_HOST_AUTH_KEY_RECV_COLUMN);
|
||||
if (hostAuthId > 0) {
|
||||
HostAuth ha = HostAuth.restoreHostAuthWithId(context, hostAuthId);
|
||||
if (ha != null && ha.mProtocol.equals(PROTOCOL)) {
|
||||
Account account = new Account();
|
||||
account.restore(c);
|
||||
account.mHostAuthRecv = ha;
|
||||
accounts.add(account);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccountManagerType() {
|
||||
return getString(R.string.account_manager_type_imap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getServiceIntent() {
|
||||
if (mIntent == null) {
|
||||
mIntent = new Intent(this, Imap2SyncManager.class);
|
||||
}
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stub getCallbackProxy() {
|
||||
return sCallbackProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runAccountReconcilerSync(Context context) {
|
||||
alwaysLog("Reconciling accounts...");
|
||||
new AccountServiceProxy(context).reconcileAccounts(
|
||||
getString(R.string.protocol_imap), getAccountManagerType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartService(Mailbox mailbox) {
|
||||
// No special behavior
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,196 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.Device;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.VendorPolicyLoader;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ImapId {
|
||||
private static String sImapId;
|
||||
|
||||
/**
|
||||
* Return, or create and return, an string suitable for use in an IMAP ID message.
|
||||
* This is constructed similarly to the way the browser sets up its user-agent strings.
|
||||
* See RFC 2971 for more details. The output of this command will be a series of key-value
|
||||
* pairs delimited by spaces (there is no point in returning a structured result because
|
||||
* this will be sent as-is to the IMAP server). No tokens, parenthesis or "ID" are included,
|
||||
* because some connections may append additional values.
|
||||
*
|
||||
* The following IMAP ID keys may be included:
|
||||
* name Android package name of the program
|
||||
* os "android"
|
||||
* os-version "version; model; build-id"
|
||||
* vendor Vendor of the client/server
|
||||
* x-android-device-model Model (only revealed if release build)
|
||||
* x-android-net-operator Mobile network operator (if known)
|
||||
* AGUID A device+account UID
|
||||
*
|
||||
* In addition, a vendor policy .apk can append key/value pairs.
|
||||
*
|
||||
* @param userName the username of the account
|
||||
* @param host the host (server) of the account
|
||||
* @param capabilities a list of the capabilities from the server
|
||||
* @return a String for use in an IMAP ID message.
|
||||
*/
|
||||
public static String getImapId(Context context, String userName, String host,
|
||||
String capabilities) {
|
||||
// The first section is global to all IMAP connections, and generates the fixed
|
||||
// values in any IMAP ID message
|
||||
synchronized (ImapId.class) {
|
||||
if (sImapId == null) {
|
||||
TelephonyManager tm =
|
||||
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
String networkOperator = tm.getNetworkOperatorName();
|
||||
if (networkOperator == null) networkOperator = "";
|
||||
|
||||
sImapId = makeCommonImapId(context.getPackageName(), Build.VERSION.RELEASE,
|
||||
Build.VERSION.CODENAME, Build.MODEL, Build.ID, Build.MANUFACTURER,
|
||||
networkOperator);
|
||||
}
|
||||
}
|
||||
|
||||
// This section is per Store, and adds in a dynamic elements like UID's.
|
||||
// We don't cache the result of this work, because the caller does anyway.
|
||||
StringBuilder id = new StringBuilder(sImapId);
|
||||
|
||||
// Optionally add any vendor-supplied id keys
|
||||
String vendorId = VendorPolicyLoader.getInstance(context).getImapIdValues(userName, host,
|
||||
capabilities);
|
||||
if (vendorId != null) {
|
||||
id.append(' ');
|
||||
id.append(vendorId);
|
||||
}
|
||||
|
||||
// Generate a UID that mixes a "stable" device UID with the email address
|
||||
try {
|
||||
String devUID;
|
||||
try {
|
||||
devUID = Device.getDeviceId(context);
|
||||
} catch (IOException e) {
|
||||
// This would only happen with file system failure; it's fine to generate one
|
||||
devUID = "_dev" + System.currentTimeMillis();
|
||||
}
|
||||
MessageDigest messageDigest;
|
||||
messageDigest = MessageDigest.getInstance("SHA-1");
|
||||
messageDigest.update(userName.getBytes());
|
||||
messageDigest.update(devUID.getBytes());
|
||||
byte[] uid = messageDigest.digest();
|
||||
String hexUid = Base64.encodeToString(uid, Base64.NO_WRAP);
|
||||
id.append(" \"AGUID\" \"");
|
||||
id.append(hexUid);
|
||||
id.append('\"');
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
Log.d(Logging.LOG_TAG, "couldn't obtain SHA-1 hash for device UID");
|
||||
}
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that actually builds the static part of the IMAP ID string. This is
|
||||
* separated from getImapId for testability. There is no escaping or encoding in IMAP ID so
|
||||
* any rogue chars must be filtered here.
|
||||
*
|
||||
* @param packageName context.getPackageName()
|
||||
* @param version Build.VERSION.RELEASE
|
||||
* @param codeName Build.VERSION.CODENAME
|
||||
* @param model Build.MODEL
|
||||
* @param id Build.ID
|
||||
* @param vendor Build.MANUFACTURER
|
||||
* @param networkOperator TelephonyManager.getNetworkOperatorName()
|
||||
* @return the static (never changes) portion of the IMAP ID
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static String makeCommonImapId(String packageName, String version,
|
||||
String codeName, String model, String id, String vendor, String networkOperator) {
|
||||
|
||||
// Before building up IMAP ID string, pre-filter the input strings for "legal" chars
|
||||
// This is using a fairly arbitrary char set intended to pass through most reasonable
|
||||
// version, model, and vendor strings: a-z A-Z 0-9 - _ + = ; : . , / <space>
|
||||
// The most important thing is *not* to pass parens, quotes, or CRLF, which would break
|
||||
// the format of the IMAP ID list.
|
||||
Pattern p = Pattern.compile("[^a-zA-Z0-9-_\\+=;:\\.,/ ]");
|
||||
packageName = p.matcher(packageName).replaceAll("");
|
||||
version = p.matcher(version).replaceAll("");
|
||||
codeName = p.matcher(codeName).replaceAll("");
|
||||
model = p.matcher(model).replaceAll("");
|
||||
id = p.matcher(id).replaceAll("");
|
||||
vendor = p.matcher(vendor).replaceAll("");
|
||||
networkOperator = p.matcher(networkOperator).replaceAll("");
|
||||
|
||||
// "name" "com.android.email"
|
||||
StringBuffer sb = new StringBuffer("\"name\" \"");
|
||||
sb.append(packageName);
|
||||
sb.append("\"");
|
||||
|
||||
// "os" "android"
|
||||
sb.append(" \"os\" \"android\"");
|
||||
|
||||
// "os-version" "version; build-id"
|
||||
sb.append(" \"os-version\" \"");
|
||||
if (version.length() > 0) {
|
||||
sb.append(version);
|
||||
} else {
|
||||
// default to "1.0"
|
||||
sb.append("1.0");
|
||||
}
|
||||
// add the build ID or build #
|
||||
if (id.length() > 0) {
|
||||
sb.append("; ");
|
||||
sb.append(id);
|
||||
}
|
||||
sb.append("\"");
|
||||
|
||||
// "vendor" "the vendor"
|
||||
if (vendor.length() > 0) {
|
||||
sb.append(" \"vendor\" \"");
|
||||
sb.append(vendor);
|
||||
sb.append("\"");
|
||||
}
|
||||
|
||||
// "x-android-device-model" the device model (on release builds only)
|
||||
if ("REL".equals(codeName)) {
|
||||
if (model.length() > 0) {
|
||||
sb.append(" \"x-android-device-model\" \"");
|
||||
sb.append(model);
|
||||
sb.append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
// "x-android-mobile-net-operator" "name of network operator"
|
||||
if (networkOperator.length() > 0) {
|
||||
sb.append(" \"x-android-mobile-net-operator\" \"");
|
||||
sb.append(networkOperator);
|
||||
sb.append("\"");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ImapInputStream extends FilterInputStream {
|
||||
|
||||
public ImapInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public String readLine () throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (true) {
|
||||
int b = read();
|
||||
// Line ends with \n; ignore \r
|
||||
// I'm not sure this is the right thing with a raw \r (no \n following)
|
||||
if (b < 0)
|
||||
throw new IOException("Socket closed in readLine");
|
||||
if (b == '\n')
|
||||
return sb.toString();
|
||||
else if (b != '\r') {
|
||||
sb.append((char)b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ready () throws IOException {
|
||||
return this.available() > 0;
|
||||
}
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Parser {
|
||||
String str;
|
||||
int pos;
|
||||
int len;
|
||||
static final String white = "\r\n \t";
|
||||
|
||||
public Parser (String _str) {
|
||||
str = _str;
|
||||
pos = 0;
|
||||
len = str.length();
|
||||
}
|
||||
|
||||
public Parser (String _str, int start) {
|
||||
str = _str;
|
||||
pos = start;
|
||||
len = str.length();
|
||||
}
|
||||
|
||||
public void skipWhite () {
|
||||
while ((pos < len) && white.indexOf(str.charAt(pos)) >= 0)
|
||||
pos++;
|
||||
}
|
||||
|
||||
public String parseAtom () {
|
||||
skipWhite();
|
||||
int start = pos;
|
||||
while ((pos < len) && white.indexOf(str.charAt(pos)) < 0)
|
||||
pos++;
|
||||
if (pos > start)
|
||||
return str.substring(start, pos);
|
||||
return null;
|
||||
}
|
||||
|
||||
public char nextChar () {
|
||||
if (pos >= len)
|
||||
return 0;
|
||||
else
|
||||
return str.charAt(pos++);
|
||||
}
|
||||
|
||||
public char peekChar () {
|
||||
if (pos >= len)
|
||||
return 0;
|
||||
else
|
||||
return str.charAt(pos);
|
||||
}
|
||||
|
||||
public String parseString () {
|
||||
return parseString(false);
|
||||
}
|
||||
|
||||
public String parseStringOrAtom () {
|
||||
return parseString(true);
|
||||
}
|
||||
|
||||
public String parseString (boolean orAtom) {
|
||||
skipWhite();
|
||||
char c = nextChar();
|
||||
if (c != '\"') {
|
||||
if (c == '{') {
|
||||
int cnt = parseInteger();
|
||||
c = nextChar();
|
||||
if (c != '}')
|
||||
return null;
|
||||
int start = pos + 2;
|
||||
int end = start + cnt;
|
||||
String s = str.substring(start, end);
|
||||
pos = end;
|
||||
return s;
|
||||
} else if (orAtom) {
|
||||
backChar();
|
||||
return parseAtom();
|
||||
} else if (c == 'n' || c == 'N') {
|
||||
parseAtom();
|
||||
return null;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
int start = pos;
|
||||
boolean quote = false;
|
||||
while (true) {
|
||||
c = nextChar();
|
||||
if (c == 0)
|
||||
return null;
|
||||
else if (quote)
|
||||
quote = false;
|
||||
else if (c == '\\')
|
||||
quote = true;
|
||||
else if (c == '\"')
|
||||
break;
|
||||
}
|
||||
return str.substring(start, pos - 1);
|
||||
}
|
||||
|
||||
public void backChar () {
|
||||
if (pos > 0)
|
||||
pos--;
|
||||
}
|
||||
|
||||
public String parseListOrNil () {
|
||||
String list = parseList();
|
||||
if (list == null) {
|
||||
parseAtom();
|
||||
list = "";
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public String parseList () {
|
||||
skipWhite();
|
||||
if (nextChar() != '(') {
|
||||
backChar();
|
||||
return null;
|
||||
}
|
||||
int start = pos;
|
||||
int level = 0;
|
||||
boolean quote = false;
|
||||
boolean string = false;
|
||||
while (true) {
|
||||
char c = nextChar();
|
||||
if (c == 0) {
|
||||
return null;
|
||||
} else if (quote) {
|
||||
quote = false;
|
||||
} else if (c == '\\' && string) {
|
||||
quote = true;
|
||||
} else if (c == '\"') {
|
||||
string = !string;
|
||||
} else if (c == '(' && !string) {
|
||||
level++;
|
||||
} else if (c == '{' && !string) {
|
||||
// Check for string literal
|
||||
Parser p = new Parser(str, pos);
|
||||
int cnt = p.parseInteger();
|
||||
if (cnt > 0 && p.nextChar() == '}') {
|
||||
pos = p.pos + 2 + cnt;
|
||||
}
|
||||
} else if (c == ')' && !string) {
|
||||
if (level-- == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str.substring(start, pos - 1);
|
||||
}
|
||||
|
||||
public int parseInteger () {
|
||||
skipWhite();
|
||||
int start = pos;
|
||||
while (pos < len) {
|
||||
char c = str.charAt(pos);
|
||||
if (c >= '0' && c <= '9')
|
||||
pos++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (pos > start) {
|
||||
// We know these are positive integers
|
||||
int sum = 0;
|
||||
for (int i = start; i < pos; i++) {
|
||||
sum = (sum * 10) + (str.charAt(i) - '0');
|
||||
}
|
||||
return sum;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] gatherInts () {
|
||||
int[] list = new int[128];
|
||||
int size = 128;
|
||||
int offs = 0;
|
||||
while (true) {
|
||||
int i = parseInteger();
|
||||
if (i >= 0) {
|
||||
if (offs == size) {
|
||||
// Double the size of the array as necessary
|
||||
size <<= 1;
|
||||
int[] tmp = new int[size];
|
||||
System.arraycopy(list, 0, tmp, 0, offs);
|
||||
list = tmp;
|
||||
}
|
||||
list[offs++] = i;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
int[] res = new int[offs];
|
||||
System.arraycopy(list, 0, res, 0, offs);
|
||||
return res;
|
||||
}
|
||||
public Integer[] gatherIntegers () {
|
||||
ArrayList<Integer> list = new ArrayList<Integer>();
|
||||
while (true) {
|
||||
Integer i = parseInteger();
|
||||
if (i >= 0) {
|
||||
list.add(i);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return list.toArray(new Integer[list.size()]);
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
public class QuotedPrintable {
|
||||
static public String toString (String str) {
|
||||
int len = str.length();
|
||||
// Make sure we don't get an index out of bounds error with the = character
|
||||
int max = len - 2;
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
try {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
if (c == '=') {
|
||||
if (i < max) {
|
||||
char n = str.charAt(++i);
|
||||
if (n == '\r') {
|
||||
n = str.charAt(++i);
|
||||
if (n == '\n')
|
||||
continue;
|
||||
else
|
||||
System.err.println("Not valid QP");
|
||||
} else {
|
||||
// Must be less than 0x80, right?
|
||||
int a;
|
||||
if (n >= '0' && n <= '9')
|
||||
a = (n - '0') << 4;
|
||||
else
|
||||
a = (10 + (n - 'A')) << 4;
|
||||
|
||||
n = str.charAt(++i);
|
||||
if (n >= '0' && n <= '9')
|
||||
c = (char) (a + (n - '0'));
|
||||
else
|
||||
c = (char) (a + 10 + (n - 'A'));
|
||||
}
|
||||
} if (i + 1 == len)
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.append(c);
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
}
|
||||
String ret = sb.toString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static public String encode (String str) {
|
||||
int len = str.length();
|
||||
StringBuffer sb = new StringBuffer(len + len>>2);
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
char c = str.charAt(i++);
|
||||
if (c < 0x80) {
|
||||
sb.append(c);
|
||||
} else {
|
||||
sb.append('&');
|
||||
sb.append('#');
|
||||
sb.append((int)c);
|
||||
sb.append(';');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static public int decode (byte[] bytes, int len) {
|
||||
// Make sure we don't get an index out of bounds error with the = character
|
||||
int max = len - 2;
|
||||
int pos = 0;
|
||||
try {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = (char)bytes[i];
|
||||
if (c == '=') {
|
||||
if (i < max) {
|
||||
char n = (char)bytes[++i];
|
||||
if (n == '\r') {
|
||||
n = (char)bytes[++i];
|
||||
if (n == '\n')
|
||||
continue;
|
||||
else
|
||||
System.err.println("Not valid QP");
|
||||
} else {
|
||||
// Must be less than 0x80, right?
|
||||
int a;
|
||||
if (n >= '0' && n <= '9')
|
||||
a = (n - '0') << 4;
|
||||
else
|
||||
a = (10 + (n - 'A')) << 4;
|
||||
|
||||
n = (char)bytes[++i];
|
||||
if (n >= '0' && n <= '9')
|
||||
c = (char) (a + (n - '0'));
|
||||
else
|
||||
c = (char) (a + 10 + (n - 'A'));
|
||||
}
|
||||
} if (i + 1 > len)
|
||||
continue;
|
||||
}
|
||||
|
||||
bytes[pos++] = (byte)c;
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.imap2;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.service.SearchParams;
|
||||
import com.android.emailsync.Request;
|
||||
|
||||
/**
|
||||
* SearchRequest is the wrapper for server search requests.
|
||||
*/
|
||||
public class SearchRequest extends Request {
|
||||
public final SearchParams mParams;
|
||||
|
||||
public SearchRequest(SearchParams _params) {
|
||||
super(Message.NO_MESSAGE);
|
||||
mParams = _params;
|
||||
}
|
||||
|
||||
// SearchRequests are unique by their mailboxId
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof SearchRequest)) return false;
|
||||
return ((SearchRequest)o).mParams.mMailboxId == mParams.mMailboxId;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int)mParams.mMailboxId;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue