Simple email application for Android. Original source code: https://framagit.org/dystopia-project/simple-email
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
7.8 KiB

6 years ago
6 years ago
  1. package eu.faircode.email;
  2. /*
  3. This file is part of FairEmail.
  4. FairEmail is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. NetGuard is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with NetGuard. If not, see <http://www.gnu.org/licenses/>.
  14. Copyright 2018 by Marcel Bokhorst (M66B)
  15. */
  16. import android.content.Context;
  17. import android.os.Handler;
  18. import android.util.Log;
  19. import com.sun.mail.imap.IMAPFolder;
  20. import com.sun.mail.imap.IMAPMessage;
  21. import com.sun.mail.imap.IMAPStore;
  22. import java.util.Date;
  23. import java.util.Properties;
  24. import java.util.concurrent.ExecutorService;
  25. import java.util.concurrent.Executors;
  26. import javax.mail.Folder;
  27. import javax.mail.Message;
  28. import javax.mail.Session;
  29. import javax.mail.search.AndTerm;
  30. import javax.mail.search.BodyTerm;
  31. import javax.mail.search.ComparisonTerm;
  32. import javax.mail.search.FromStringTerm;
  33. import javax.mail.search.OrTerm;
  34. import javax.mail.search.ReceivedDateTerm;
  35. import javax.mail.search.SubjectTerm;
  36. import androidx.lifecycle.GenericLifecycleObserver;
  37. import androidx.lifecycle.Lifecycle;
  38. import androidx.lifecycle.LifecycleOwner;
  39. import androidx.paging.PagedList;
  40. public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMessageEx> {
  41. private Context context;
  42. private long fid;
  43. private String search;
  44. private Handler mainHandler;
  45. private IBoundaryCallbackMessages intf;
  46. private ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
  47. private boolean enabled = false;
  48. private IMAPStore istore = null;
  49. private IMAPFolder ifolder = null;
  50. private Message[] imessages = null;
  51. interface IBoundaryCallbackMessages {
  52. void onLoading();
  53. void onLoaded();
  54. void onError(Context context, Throwable ex);
  55. }
  56. BoundaryCallbackMessages(Context context, LifecycleOwner owner, long folder, String search, IBoundaryCallbackMessages intf) {
  57. this.context = context;
  58. this.fid = folder;
  59. this.search = search;
  60. this.mainHandler = new Handler(context.getMainLooper());
  61. this.intf = intf;
  62. owner.getLifecycle().addObserver(new GenericLifecycleObserver() {
  63. @Override
  64. public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
  65. if (event == Lifecycle.Event.ON_DESTROY)
  66. new Thread(new Runnable() {
  67. @Override
  68. public void run() {
  69. Log.i(Helper.TAG, "Boundary close");
  70. try {
  71. if (istore != null)
  72. istore.close();
  73. } catch (Throwable ex) {
  74. Log.e(Helper.TAG, "Boundary " + ex + "\n" + Log.getStackTraceString(ex));
  75. } finally {
  76. istore = null;
  77. ifolder = null;
  78. imessages = null;
  79. }
  80. }
  81. }).start();
  82. }
  83. });
  84. }
  85. void setEnabled(boolean enabled) {
  86. this.enabled = enabled;
  87. }
  88. @Override
  89. public void onItemAtEndLoaded(final TupleMessageEx itemAtEnd) {
  90. Log.i(Helper.TAG, "onItemAtEndLoaded enabled=" + enabled);
  91. if (!enabled)
  92. return;
  93. load(itemAtEnd.received);
  94. }
  95. void load(final long before) {
  96. executor.submit(new Runnable() {
  97. @Override
  98. public void run() {
  99. try {
  100. mainHandler.post(new Runnable() {
  101. @Override
  102. public void run() {
  103. intf.onLoading();
  104. }
  105. });
  106. DB db = DB.getInstance(context);
  107. EntityFolder folder = db.folder().getFolder(fid);
  108. EntityAccount account = db.account().getAccount(folder.account);
  109. if (imessages == null) {
  110. // Refresh token
  111. if (account.auth_type == Helper.AUTH_TYPE_GMAIL) {
  112. account.password = Helper.refreshToken(context, "com.google", account.user, account.password);
  113. db.account().setAccountPassword(account.id, account.password);
  114. }
  115. Properties props = MessageHelper.getSessionProperties(context, account.auth_type);
  116. props.setProperty("mail.imap.throwsearchexception", "true");
  117. Session isession = Session.getInstance(props, null);
  118. Log.i(Helper.TAG, "Boundary connecting account=" + account.name);
  119. istore = (IMAPStore) isession.getStore("imaps");
  120. istore.connect(account.host, account.port, account.user, account.password);
  121. Log.i(Helper.TAG, "Boundary opening folder=" + folder.name);
  122. ifolder = (IMAPFolder) istore.getFolder(folder.name);
  123. ifolder.open(Folder.READ_WRITE);
  124. Log.i(Helper.TAG, "Boundary searching=" + search + " before=" + new Date(before));
  125. imessages = ifolder.search(
  126. new AndTerm(
  127. new ReceivedDateTerm(ComparisonTerm.LT, new Date(before)),
  128. new OrTerm(
  129. new FromStringTerm(search),
  130. new OrTerm(
  131. new SubjectTerm(search),
  132. new BodyTerm(search)))));
  133. Log.i(Helper.TAG, "Boundary found messages=" + imessages.length);
  134. }
  135. int index = imessages.length - 1;
  136. while (index >= 0) {
  137. if (imessages[index].getReceivedDate().getTime() < before)
  138. try {
  139. Log.i(Helper.TAG, "Boundary sync uid=" + ifolder.getUID(imessages[index]));
  140. ServiceSynchronize.synchronizeMessage(context, folder, ifolder, (IMAPMessage) imessages[index], true);
  141. break;
  142. } catch (Throwable ex) {
  143. Log.e(Helper.TAG, "Boundary " + ex + "\n" + Log.getStackTraceString(ex));
  144. }
  145. index--;
  146. }
  147. EntityOperation.process(context); // download small attachments
  148. Log.i(Helper.TAG, "Boundary done");
  149. } catch (final Throwable ex) {
  150. Log.e(Helper.TAG, "Boundary " + ex + "\n" + Log.getStackTraceString(ex));
  151. mainHandler.post(new Runnable() {
  152. @Override
  153. public void run() {
  154. intf.onError(context, ex);
  155. }
  156. });
  157. } finally {
  158. mainHandler.post(new Runnable() {
  159. @Override
  160. public void run() {
  161. intf.onLoaded();
  162. }
  163. });
  164. }
  165. }
  166. });
  167. }
  168. }