|
|
@ -259,11 +259,11 @@ class Core {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case EntityOperation.MOVE:
|
|
|
|
case EntityOperation.MOVE:
|
|
|
|
onMove(context, jargs, false, folder, message, (IMAPStore) istore, (IMAPFolder) ifolder, state);
|
|
|
|
onMove(context, jargs, false, folder, Arrays.asList(message), (IMAPStore) istore, (IMAPFolder) ifolder, state);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case EntityOperation.COPY:
|
|
|
|
case EntityOperation.COPY:
|
|
|
|
onMove(context, jargs, true, folder, message, (IMAPStore) istore, (IMAPFolder) ifolder, state);
|
|
|
|
onMove(context, jargs, true, folder, Arrays.asList(message), (IMAPStore) istore, (IMAPFolder) ifolder, state);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case EntityOperation.FETCH:
|
|
|
|
case EntityOperation.FETCH:
|
|
|
@ -665,7 +665,7 @@ class Core {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void onMove(Context context, JSONArray jargs, boolean copy, EntityFolder folder, EntityMessage message, IMAPStore istore, IMAPFolder ifolder, State state) throws JSONException, MessagingException, IOException {
|
|
|
|
private static void onMove(Context context, JSONArray jargs, boolean copy, EntityFolder folder, List<EntityMessage> messages, IMAPStore istore, IMAPFolder ifolder, State state) throws JSONException, MessagingException, IOException {
|
|
|
|
// Move message
|
|
|
|
// Move message
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
|
|
|
|
|
|
|
@ -674,96 +674,120 @@ class Core {
|
|
|
|
boolean autoread = jargs.optBoolean(1, false);
|
|
|
|
boolean autoread = jargs.optBoolean(1, false);
|
|
|
|
Flags flags = ifolder.getPermanentFlags();
|
|
|
|
Flags flags = ifolder.getPermanentFlags();
|
|
|
|
|
|
|
|
|
|
|
|
// Get source message
|
|
|
|
|
|
|
|
Message imessage = ifolder.getMessageByUID(message.uid);
|
|
|
|
|
|
|
|
if (imessage == null)
|
|
|
|
|
|
|
|
throw new MessageRemovedException();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get target folder
|
|
|
|
// Get target folder
|
|
|
|
EntityFolder target = db.folder().getFolder(id);
|
|
|
|
EntityFolder target = db.folder().getFolder(id);
|
|
|
|
if (target == null)
|
|
|
|
if (target == null)
|
|
|
|
throw new FolderNotFoundException();
|
|
|
|
throw new FolderNotFoundException();
|
|
|
|
IMAPFolder itarget = (IMAPFolder) istore.getFolder(target.name);
|
|
|
|
IMAPFolder itarget = (IMAPFolder) istore.getFolder(target.name);
|
|
|
|
|
|
|
|
|
|
|
|
// Some providers do not support copying drafts
|
|
|
|
// Get source messages
|
|
|
|
|
|
|
|
Map<Message, EntityMessage> map = new HashMap<>();
|
|
|
|
|
|
|
|
for (EntityMessage message : messages)
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Message imessage = ifolder.getMessageByUID(message.uid);
|
|
|
|
|
|
|
|
if (imessage != null)
|
|
|
|
|
|
|
|
map.put(imessage, message);
|
|
|
|
|
|
|
|
} catch (MessageRemovedException ex) {
|
|
|
|
|
|
|
|
Log.w(ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Some providers do not support the COPY operation for drafts
|
|
|
|
if (EntityFolder.DRAFTS.equals(folder.type) || EntityFolder.DRAFTS.equals(target.type)) {
|
|
|
|
if (EntityFolder.DRAFTS.equals(folder.type) || EntityFolder.DRAFTS.equals(target.type)) {
|
|
|
|
Log.i(folder.name + " move from " + folder.type + " to " + target.type);
|
|
|
|
Log.i(folder.name + " move from " + folder.type + " to " + target.type);
|
|
|
|
|
|
|
|
|
|
|
|
File file = File.createTempFile("draft", "." + message.id, context.getCacheDir());
|
|
|
|
List<Message> icopies = new ArrayList<>();
|
|
|
|
try (OutputStream os = new FileOutputStream(file)) {
|
|
|
|
for (Message imessage : map.keySet()) {
|
|
|
|
imessage.writeTo(os);
|
|
|
|
EntityMessage message = map.get(imessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Properties props = MessageHelper.getSessionProperties();
|
|
|
|
File file = File.createTempFile("draft", "." + message.id, context.getCacheDir());
|
|
|
|
Session isession = Session.getInstance(props, null);
|
|
|
|
try (OutputStream os = new FileOutputStream(file)) {
|
|
|
|
|
|
|
|
imessage.writeTo(os);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Message icopy;
|
|
|
|
Properties props = MessageHelper.getSessionProperties();
|
|
|
|
try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
|
|
|
|
Session isession = Session.getInstance(props, null);
|
|
|
|
icopy = new MimeMessage(isession, is);
|
|
|
|
|
|
|
|
}
|
|
|
|
Message icopy;
|
|
|
|
|
|
|
|
try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
|
|
|
|
|
|
|
|
icopy = new MimeMessage(isession, is);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
file.delete();
|
|
|
|
file.delete();
|
|
|
|
|
|
|
|
|
|
|
|
// Auto read
|
|
|
|
// Auto read
|
|
|
|
if (autoread && flags.contains(Flags.Flag.SEEN))
|
|
|
|
if (autoread && flags.contains(Flags.Flag.SEEN))
|
|
|
|
icopy.setFlag(Flags.Flag.SEEN, true);
|
|
|
|
icopy.setFlag(Flags.Flag.SEEN, true);
|
|
|
|
|
|
|
|
|
|
|
|
if (message.ui_answered && flags.contains(Flags.Flag.ANSWERED))
|
|
|
|
if (message.ui_answered && flags.contains(Flags.Flag.ANSWERED))
|
|
|
|
icopy.setFlag(Flags.Flag.ANSWERED, true);
|
|
|
|
icopy.setFlag(Flags.Flag.ANSWERED, true);
|
|
|
|
|
|
|
|
|
|
|
|
// Set drafts flag
|
|
|
|
// Set drafts flag
|
|
|
|
icopy.setFlag(Flags.Flag.DRAFT, EntityFolder.DRAFTS.equals(target.type));
|
|
|
|
icopy.setFlag(Flags.Flag.DRAFT, EntityFolder.DRAFTS.equals(target.type));
|
|
|
|
|
|
|
|
|
|
|
|
itarget.appendMessages(new Message[]{icopy});
|
|
|
|
icopies.add(icopy);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
itarget.appendMessages(icopies.toArray(new Message[0]));
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Auto read
|
|
|
|
for (Message imessage : map.keySet()) {
|
|
|
|
if (autoread && flags.contains(Flags.Flag.SEEN))
|
|
|
|
EntityMessage message = map.get(imessage);
|
|
|
|
imessage.setFlag(Flags.Flag.SEEN, true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (message.ui_answered && flags.contains(Flags.Flag.ANSWERED))
|
|
|
|
// Auto read
|
|
|
|
imessage.setFlag(Flags.Flag.ANSWERED, true);
|
|
|
|
if (autoread && flags.contains(Flags.Flag.SEEN))
|
|
|
|
|
|
|
|
imessage.setFlag(Flags.Flag.SEEN, true);
|
|
|
|
|
|
|
|
|
|
|
|
ifolder.copyMessages(new Message[]{imessage}, itarget);
|
|
|
|
if (message.ui_answered && flags.contains(Flags.Flag.ANSWERED))
|
|
|
|
|
|
|
|
imessage.setFlag(Flags.Flag.ANSWERED, true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ifolder.copyMessages(map.keySet().toArray(new Message[0]), itarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Delete source
|
|
|
|
// Delete source
|
|
|
|
if (!copy) {
|
|
|
|
if (!copy) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
imessage.setFlag(Flags.Flag.DELETED, true);
|
|
|
|
for (Message imessage : map.keySet())
|
|
|
|
|
|
|
|
imessage.setFlag(Flags.Flag.DELETED, true);
|
|
|
|
} catch (MessageRemovedException ignored) {
|
|
|
|
} catch (MessageRemovedException ignored) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ifolder.expunge();
|
|
|
|
ifolder.expunge();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fetch appended/copied when needed
|
|
|
|
// Fetch appended/copied when needed
|
|
|
|
if (!TextUtils.isEmpty(message.msgid) &&
|
|
|
|
if (!target.synchronize || !istore.hasCapability("IDLE"))
|
|
|
|
(!target.synchronize || !istore.hasCapability("IDLE")))
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
itarget.open(READ_WRITE);
|
|
|
|
itarget.open(READ_WRITE);
|
|
|
|
try {
|
|
|
|
|
|
|
|
Long uid = findUid(itarget, message.msgid, false);
|
|
|
|
for (EntityMessage message : map.values())
|
|
|
|
if (uid != null) {
|
|
|
|
if (!TextUtils.isEmpty(message.msgid))
|
|
|
|
JSONArray fargs = new JSONArray();
|
|
|
|
try {
|
|
|
|
fargs.put(uid);
|
|
|
|
Long uid = findUid(itarget, message.msgid, false);
|
|
|
|
onFetch(context, fargs, target, itarget, state);
|
|
|
|
if (uid != null) {
|
|
|
|
}
|
|
|
|
JSONArray fargs = new JSONArray();
|
|
|
|
} finally {
|
|
|
|
fargs.put(uid);
|
|
|
|
itarget.close();
|
|
|
|
onFetch(context, fargs, target, itarget, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
Log.w(ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Log.w(ex);
|
|
|
|
Log.w(ex);
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
if (itarget.isOpen())
|
|
|
|
|
|
|
|
itarget.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Delete junk contacts
|
|
|
|
// Delete junk contacts
|
|
|
|
if (EntityFolder.JUNK.equals(target.type)) {
|
|
|
|
if (EntityFolder.JUNK.equals(target.type))
|
|
|
|
Address[] recipients = (message.reply != null ? message.reply : message.from);
|
|
|
|
for (EntityMessage message : map.values()) {
|
|
|
|
if (recipients != null)
|
|
|
|
Address[] recipients = (message.reply != null ? message.reply : message.from);
|
|
|
|
for (Address recipient : recipients) {
|
|
|
|
if (recipients != null)
|
|
|
|
String email = ((InternetAddress) recipient).getAddress();
|
|
|
|
for (Address recipient : recipients) {
|
|
|
|
int count = db.contact().deleteContact(target.account, EntityContact.TYPE_FROM, email);
|
|
|
|
String email = ((InternetAddress) recipient).getAddress();
|
|
|
|
Log.i("Deleted contact email=" + email + " count=" + count);
|
|
|
|
int count = db.contact().deleteContact(target.account, EntityContact.TYPE_FROM, email);
|
|
|
|
}
|
|
|
|
Log.i("Deleted contact email=" + email + " count=" + count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void onFetch(Context context, JSONArray jargs, EntityFolder folder, IMAPFolder ifolder, State state) throws JSONException, MessagingException, IOException {
|
|
|
|
private static void onFetch(Context context, JSONArray jargs, EntityFolder folder, IMAPFolder ifolder, State state) throws JSONException, MessagingException, IOException {
|
|
|
|