package com.kescoode.xmail.service.task;
import android.content.Context;
import com.fsck.k9.mail.*;
import com.fsck.k9.mail.internet.MessageExtractor;
import com.fsck.k9.mail.store.RemoteStore;
import com.kescoode.adk.log.Logger;
import com.kescoode.xmail.db.FolderDao;
import com.kescoode.xmail.domain.Account;
import com.kescoode.xmail.domain.LocalFolder;
import com.kescoode.xmail.domain.LocalStore;
import com.kescoode.xmail.event.SyncFolderEvent;
import com.kescoode.xmail.service.task.internal.Command;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* 同步文件夹,目前只做Pull,不做Push
*
* @author Kesco Lin
*/
public class SyncFolderCommand extends Command {
private final RemoteStore remoteStore;
private final LocalStore localStore;
private final LocalFolder folder;
private final int page;
/**
* 构造方法
*
* @param context 上下文
* @param account 邮件帐户
* @param folder 邮件文件夹
* @param page 需要更新的页数,以0为基准
*/
public SyncFolderCommand(Context context, Account account, LocalFolder folder, int page) {
super(context, account);
this.remoteStore = account.getRemoteStore();
this.localStore = account.getLocalStore();
this.folder = folder;
this.page = page + 1;
}
@Override
public void task() {
try {
remoteStore.checkSettings();
syncFolder(folder);
folder.setLastUpdate(System.currentTimeMillis());
FolderDao dao = new FolderDao(context);
dao.updateFolder4Id(folder);
} catch (MessagingException e) {
Logger.e(e.getMessage());
sendBroadCaset(new SyncFolderEvent(folder.getId(), SyncFolderEvent.FAIL, SyncFolderEvent.FAIL));
}
}
protected void syncFolder(final LocalFolder folder) throws MessagingException {
/* 和K-9一样,我们不同步发件箱 */
String folderName = folder.getName();
if (folderName.equals(account.getOutboxFolderName())) {
return;
}
localStore.checkSettings();
final Folder remote = remoteStore.getFolder(folder.getName());
folder.open(Folder.OPEN_MODE_RW);
remote.open(Folder.OPEN_MODE_RW);
int total = remote.getMessageCount();
int unread = remote.getUnreadMessageCount();
int flagged = remote.getFlaggedMessageCount();
Logger.d("Remote Server:\ntotal: %d\nunread: %d\nflagged: %d", total, unread, flagged);
int news = Math.max(total - page * account.getDisplayCount(), 0) + 1;
// TODO: 这里的未读数是错误的,要改正
folder.setUnreadMessageCount(news + folder.getUnreadMessageCount());
folder.setMessageCount(total);
folder.setFlaggedCount(flagged);
List<? extends Message> remoteMessages = remote.getMessages(news, total,
null /* 根据K9的源码,这里是默认为空 */, null);
downloadMessage(remote, remoteMessages);
sendBroadCaset(new SyncFolderEvent(folder.getId(), total, news));
folder.close();
remote.close();
}
protected void downloadMessage(final Folder remote, List<? extends Message> remoteMessages)
throws MessagingException {
// TODO: 目前是把邮件的所有部分都拉过来,以后做附件的时候优化
final List<Message> smallEmails = new ArrayList<>();
final List<Message> largerEmails = new ArrayList<>();
FetchProfile fp = new FetchProfile();
if (remote.supportsFetchingFlags()) {
fp.add(FetchProfile.Item.FLAGS);
}
fp.add(FetchProfile.Item.ENVELOPE);
Logger.d("Fetch Basic Emails");
remote.fetch(remoteMessages, fp, new MessageRetrievalListener() {
@Override
public void messageStarted(String uid, int number, int ofTotal) {
/* Empty */
}
@Override
public void messageFinished(Message message, int number, int ofTotal) {
if (account.getMaximumAutoDownloadMessageSize() > 0 &&
message.getSize() > account.getMaximumAutoDownloadMessageSize()) {
largerEmails.add(message);
} else {
smallEmails.add(message);
}
}
@Override
public void messagesFinished(int total) {
/* Empty */
}
});
Logger.d("Download %d emails smaller than the larger settings", smallEmails.size());
fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY);
remote.fetch(smallEmails, fp, new MessageRetrievalListener() {
@Override
public void messageStarted(String uid, int number, int ofTotal) {
/* Empty */
}
@Override
public void messageFinished(Message message, int number, int ofTotal) {
try {
folder.appendMessages(Collections.singletonList(message));
} catch (MessagingException e) {
e.printStackTrace();
}
}
@Override
public void messagesFinished(int total) {
/* Empty */
}
});
Logger.d("Download %d larger emails", largerEmails.size());
fp = new FetchProfile();
fp.add(FetchProfile.Item.STRUCTURE);
remote.fetch(largerEmails, fp, new MessageRetrievalListener() {
@Override
public void messageStarted(String uid, int number, int ofTotal) {
}
@Override
public void messageFinished(Message message, int number, int ofTotal) {
try {
if (message.getBody() == null) {
FetchProfile tmpFp = new FetchProfile();
tmpFp.add(FetchProfile.Item.BODY_SANE);
remote.fetch(Collections.singletonList(message), tmpFp, null);
} else {
Set<Part> viewables = MessageExtractor.collectTextParts(message);
for (Part part : viewables) {
remote.fetchPart(message, part, null);
}
}
folder.appendMessages(Collections.singletonList(message));
} catch (MessagingException e) {
throw new RuntimeException("Can fetch all part from remote mail.");
}
}
@Override
public void messagesFinished(int total) {
}
}
);
}
}