|
|
@ -431,184 +431,178 @@ public class ServiceSynchronize extends LifecycleService {
|
|
|
|
throw new IllegalStateException("synchronize folders", ex);
|
|
|
|
throw new IllegalStateException("synchronize folders", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Synchronize folders
|
|
|
|
|
|
|
|
for (EntityFolder folder : db.folder().getFolders(account.id))
|
|
|
|
for (EntityFolder folder : db.folder().getFolders(account.id))
|
|
|
|
db.folder().setFolderState(folder.id, null);
|
|
|
|
db.folder().setFolderState(folder.id, null);
|
|
|
|
for (final EntityFolder folder : db.folder().getFolders(account.id, true))
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, account.name + " sync folder " + folder.name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderState(folder.id, "connecting");
|
|
|
|
// Synchronize folders
|
|
|
|
|
|
|
|
for (final EntityFolder folder : db.folder().getFolders(account.id, true)) {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, account.name + " sync folder " + folder.name);
|
|
|
|
|
|
|
|
|
|
|
|
final IMAPFolder ifolder = (IMAPFolder) istore.getFolder(folder.name);
|
|
|
|
db.folder().setFolderState(folder.id, "connecting");
|
|
|
|
ifolder.open(Folder.READ_WRITE);
|
|
|
|
|
|
|
|
folders.put(folder, ifolder);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderState(folder.id, "connected");
|
|
|
|
final IMAPFolder ifolder = (IMAPFolder) istore.getFolder(folder.name);
|
|
|
|
db.folder().setFolderError(folder.id, null);
|
|
|
|
ifolder.open(Folder.READ_WRITE);
|
|
|
|
|
|
|
|
folders.put(folder, ifolder);
|
|
|
|
|
|
|
|
|
|
|
|
// Listen for new and deleted messages
|
|
|
|
db.folder().setFolderState(folder.id, "connected");
|
|
|
|
ifolder.addMessageCountListener(new MessageCountAdapter() {
|
|
|
|
db.folder().setFolderError(folder.id, null);
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void messagesAdded(MessageCountEvent e) {
|
|
|
|
|
|
|
|
synchronized (lock) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " messages added");
|
|
|
|
|
|
|
|
for (Message imessage : e.getMessages())
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
synchronizeMessage(folder, ifolder, (IMAPMessage) imessage);
|
|
|
|
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
|
|
|
|
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Keep folder connection alive
|
|
|
|
|
|
|
|
Thread noop = new Thread(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
// Listen for new and deleted messages
|
|
|
|
|
|
|
|
ifolder.addMessageCountListener(new MessageCountAdapter() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void messagesAdded(MessageCountEvent e) {
|
|
|
|
|
|
|
|
synchronized (lock) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " messages added");
|
|
|
|
|
|
|
|
for (Message imessage : e.getMessages())
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
synchronizeMessage(folder, ifolder, (IMAPMessage) imessage);
|
|
|
|
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
|
|
|
|
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
|
|
|
|
state.notifyAll();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
|
|
|
|
state.notifyAll();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void messagesRemoved(MessageCountEvent e) {
|
|
|
|
public void messagesRemoved(MessageCountEvent e) {
|
|
|
|
synchronized (lock) {
|
|
|
|
synchronized (lock) {
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " messages removed");
|
|
|
|
|
|
|
|
for (Message imessage : e.getMessages())
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
long uid = ifolder.getUID(imessage);
|
|
|
|
Log.i(Helper.TAG, folder.name + " messages removed");
|
|
|
|
|
|
|
|
for (Message imessage : e.getMessages())
|
|
|
|
DB db = DB.getInstance(ServiceSynchronize.this);
|
|
|
|
try {
|
|
|
|
int count = db.message().deleteMessage(folder.id, uid);
|
|
|
|
long uid = ifolder.getUID(imessage);
|
|
|
|
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, "Deleted uid=" + uid + " count=" + count);
|
|
|
|
DB db = DB.getInstance(ServiceSynchronize.this);
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
int count = db.message().deleteMessage(folder.id, uid);
|
|
|
|
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, "Deleted uid=" + uid + " count=" + count);
|
|
|
|
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
|
|
|
|
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
|
|
|
|
state.notifyAll();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
|
|
|
|
state.notifyAll();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fetch e-mail
|
|
|
|
// Fetch e-mail
|
|
|
|
synchronizeMessages(account, folder, ifolder, state);
|
|
|
|
synchronizeMessages(account, folder, ifolder, state);
|
|
|
|
|
|
|
|
|
|
|
|
// Flags (like "seen") at the remote could be changed while synchronizing
|
|
|
|
// Flags (like "seen") at the remote could be changed while synchronizing
|
|
|
|
|
|
|
|
|
|
|
|
// Listen for changed messages
|
|
|
|
// Listen for changed messages
|
|
|
|
ifolder.addMessageChangedListener(new MessageChangedListener() {
|
|
|
|
ifolder.addMessageChangedListener(new MessageChangedListener() {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void messageChanged(MessageChangedEvent e) {
|
|
|
|
public void messageChanged(MessageChangedEvent e) {
|
|
|
|
synchronized (lock) {
|
|
|
|
synchronized (lock) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
Log.i(Helper.TAG, folder.name + " message changed");
|
|
|
|
Log.i(Helper.TAG, folder.name + " message changed");
|
|
|
|
synchronizeMessage(folder, ifolder, (IMAPMessage) e.getMessage());
|
|
|
|
synchronizeMessage(folder, ifolder, (IMAPMessage) e.getMessage());
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
synchronized (state) {
|
|
|
|
state.notifyAll();
|
|
|
|
state.notifyAll();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
Log.i(Helper.TAG, folder.name + " start noop");
|
|
|
|
|
|
|
|
while (state.running && ifolder.isOpen()) {
|
|
|
|
// Keep folder connection alive
|
|
|
|
Log.i(Helper.TAG, folder.name + " request NOOP");
|
|
|
|
Thread noop = new Thread(new Runnable() {
|
|
|
|
ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
|
|
|
|
@Override
|
|
|
|
public Object doCommand(IMAPProtocol p) throws ProtocolException {
|
|
|
|
public void run() {
|
|
|
|
Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
|
|
|
|
try {
|
|
|
|
p.simpleCommand("NOOP", null);
|
|
|
|
Log.i(Helper.TAG, folder.name + " start noop");
|
|
|
|
Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
|
|
|
|
while (state.running && ifolder.isOpen()) {
|
|
|
|
return null;
|
|
|
|
Log.i(Helper.TAG, folder.name + " request NOOP");
|
|
|
|
|
|
|
|
ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
|
|
|
|
|
|
|
|
public Object doCommand(IMAPProtocol p) throws ProtocolException {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
|
|
|
|
|
|
|
|
p.simpleCommand("NOOP", null);
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Thread.sleep(FOLDER_NOOP_INTERVAL);
|
|
|
|
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
|
|
|
|
Log.w(Helper.TAG, folder.name + " noop " + ex.getMessage());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Thread.sleep(FOLDER_NOOP_INTERVAL);
|
|
|
|
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
|
|
|
|
Log.w(Helper.TAG, folder.name + " noop " + ex.getMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
}
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
synchronized (state) {
|
|
|
|
state.notifyAll();
|
|
|
|
state.notifyAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " end noop");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " end noop");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, "sync.noop." + folder.id);
|
|
|
|
}
|
|
|
|
noop.start();
|
|
|
|
}, "sync.noop." + folder.id);
|
|
|
|
noops.add(noop);
|
|
|
|
noop.start();
|
|
|
|
|
|
|
|
noops.add(noop);
|
|
|
|
|
|
|
|
|
|
|
|
// Receive folder events
|
|
|
|
// Receive folder events
|
|
|
|
Thread idle = new Thread(new Runnable() {
|
|
|
|
Thread idle = new Thread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
Log.i(Helper.TAG, folder.name + " start idle");
|
|
|
|
Log.i(Helper.TAG, folder.name + " start idle");
|
|
|
|
while (state.running && ifolder.isOpen()) {
|
|
|
|
while (state.running && ifolder.isOpen()) {
|
|
|
|
Log.i(Helper.TAG, folder.name + " do idle");
|
|
|
|
Log.i(Helper.TAG, folder.name + " do idle");
|
|
|
|
ifolder.idle(false);
|
|
|
|
ifolder.idle(false);
|
|
|
|
Log.i(Helper.TAG, folder.name + " done idle");
|
|
|
|
Log.i(Helper.TAG, folder.name + " done idle");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
reportError(account.name, folder.name, ex);
|
|
|
|
|
|
|
|
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (state) {
|
|
|
|
synchronized (state) {
|
|
|
|
state.notifyAll();
|
|
|
|
state.notifyAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " end idle");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
Log.i(Helper.TAG, folder.name + " end idle");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, "sync.idle." + folder.id);
|
|
|
|
}
|
|
|
|
idle.start();
|
|
|
|
}, "sync.idle." + folder.id);
|
|
|
|
idlers.add(idle);
|
|
|
|
idle.start();
|
|
|
|
} catch (MessagingException ex) {
|
|
|
|
idlers.add(idle);
|
|
|
|
// Don't show to user
|
|
|
|
}
|
|
|
|
throw new FolderClosedException(folders.get(folder), "start folder", ex);
|
|
|
|
|
|
|
|
} catch (IOException ex) {
|
|
|
|
|
|
|
|
// Don't show to user
|
|
|
|
|
|
|
|
throw new FolderClosedException(folders.get(folder), "start folder", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BroadcastReceiver processReceiver = new BroadcastReceiver() {
|
|
|
|
BroadcastReceiver processReceiver = new BroadcastReceiver() {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|