diff --git a/app/src/main/java/eu/faircode/email/CalendarHelper.java b/app/src/main/java/eu/faircode/email/CalendarHelper.java
new file mode 100644
index 0000000000..54cc00be69
--- /dev/null
+++ b/app/src/main/java/eu/faircode/email/CalendarHelper.java
@@ -0,0 +1,176 @@
+package eu.faircode.email;
+
+/*
+ This file is part of FairEmail.
+
+ FairEmail is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ FairEmail is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FairEmail. If not, see .
+
+ Copyright 2018-2022 by Marcel Bokhorst (M66B)
+*/
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.CalendarContract;
+import android.text.TextUtils;
+
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+import biweekly.ICalVersion;
+import biweekly.component.VEvent;
+import biweekly.io.TimezoneInfo;
+import biweekly.io.WriteContext;
+import biweekly.io.scribe.property.RecurrenceRuleScribe;
+import biweekly.parameter.ParticipationStatus;
+import biweekly.property.Attendee;
+import biweekly.property.RecurrenceRule;
+import biweekly.util.ICalDate;
+
+public class CalendarHelper {
+ static void insert(Context context, TimezoneInfo tz, VEvent event,
+ String selectedAccount, String selectedName, EntityMessage message) {
+ String summary = (event.getSummary() == null ? null : event.getSummary().getValue());
+ String description = (event.getDescription() == null ? null : event.getDescription().getValue());
+ String location = (event.getLocation() == null ? null : event.getLocation().getValue());
+
+ ICalDate start = (event.getDateStart() == null ? null : event.getDateStart().getValue());
+ ICalDate end = (event.getDateEnd() == null ? null : event.getDateEnd().getValue());
+
+ String rrule = null;
+ RecurrenceRule recurrence = event.getRecurrenceRule();
+ if (recurrence != null) {
+ RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
+ WriteContext wcontext = new WriteContext(ICalVersion.V2_0, tz, null);
+ rrule = scribe.writeText(recurrence, wcontext);
+ }
+
+ String uid = (event.getUid() == null ? null : event.getUid().getValue());
+
+ if (TextUtils.isEmpty(uid) || start == null || end == null)
+ return;
+
+ ContentResolver resolver = context.getContentResolver();
+ try (Cursor cursor = resolver.query(CalendarContract.Calendars.CONTENT_URI,
+ new String[]{CalendarContract.Calendars._ID},
+ CalendarContract.Calendars.VISIBLE + " <> 0 AND " +
+ CalendarContract.Calendars.ACCOUNT_NAME + " = ?" +
+ (selectedName == null
+ ? ""
+ : " AND " + CalendarContract.Calendars.CALENDAR_DISPLAY_NAME + " = ?"),
+ selectedName == null
+ ? new String[]{selectedAccount}
+ : new String[]{selectedAccount, selectedName},
+ null)) {
+ if (cursor.getCount() == 0)
+ EntityLog.log(context, EntityLog.Type.General, message,
+ "Account not found account=" + selectedAccount + ":" + selectedName);
+
+ if (cursor.moveToNext()) {
+ // https://developer.android.com/guide/topics/providers/calendar-provider#add-event
+ // https://developer.android.com/reference/android/provider/CalendarContract.EventsColumns
+ ContentValues values = new ContentValues();
+ values.put(CalendarContract.Events.CALENDAR_ID, cursor.getLong(0));
+ if (!TextUtils.isEmpty(uid))
+ values.put(CalendarContract.Events.UID_2445, uid);
+ values.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
+ values.put(CalendarContract.Events.DTSTART, start.getTime());
+ values.put(CalendarContract.Events.DTEND, end.getTime());
+ if (rrule != null)
+ values.put(CalendarContract.Events.RRULE, rrule);
+ if (!TextUtils.isEmpty(summary))
+ values.put(CalendarContract.Events.TITLE, summary);
+ if (!TextUtils.isEmpty(description))
+ values.put(CalendarContract.Events.DESCRIPTION, description);
+ if (!TextUtils.isEmpty(location))
+ values.put(CalendarContract.Events.EVENT_LOCATION, location);
+ values.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_TENTATIVE);
+
+ Uri uri = resolver.insert(CalendarContract.Events.CONTENT_URI, values);
+ long eventId = Long.parseLong(uri.getLastPathSegment());
+ EntityLog.log(context, EntityLog.Type.General, message, "Inserted event" +
+ " id=" + eventId +
+ " uid=" + uid +
+ " start=" + new Date(start.getTime()) +
+ " end=" + new Date(end.getTime()) +
+ " summary=" + summary);
+ }
+ }
+ }
+
+ static void update(Context context, VEvent event, EntityMessage message) {
+ String uid = (event.getUid() == null ? null : event.getUid().getValue());
+ if (TextUtils.isEmpty(uid))
+ return;
+
+ List attendees = event.getAttendees();
+ if (attendees == null || attendees.size() == 0)
+ return;
+
+ ParticipationStatus status = attendees.get(0).getParticipationStatus();
+ if (!ParticipationStatus.ACCEPTED.equals(status) &&
+ !ParticipationStatus.DECLINED.equals(status))
+ return;
+
+ ContentResolver resolver = context.getContentResolver();
+ try (Cursor cursor = resolver.query(CalendarContract.Events.CONTENT_URI,
+ new String[]{CalendarContract.Events._ID},
+ CalendarContract.Events.UID_2445 + " = ?",
+ new String[]{uid},
+ null)) {
+ while (cursor.moveToNext()) {
+ long eventId = cursor.getLong(0);
+
+ // https://developer.android.com/guide/topics/providers/calendar-provider#modify-calendar
+ Uri updateUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventId);
+ ContentValues values = new ContentValues();
+ if (ParticipationStatus.ACCEPTED.equals(status))
+ values.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CONFIRMED);
+ else
+ values.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CANCELED);
+ int rows = resolver.update(updateUri, values, null, null);
+
+ EntityLog.log(context, EntityLog.Type.General, message,
+ "Updated event id=" + eventId + " uid=" + uid + " rows=" + rows);
+ }
+ }
+ }
+
+ static void delete(Context context, VEvent event, EntityMessage message) {
+ String uid = (event.getUid() == null ? null : event.getUid().getValue());
+ if (TextUtils.isEmpty(uid))
+ return;
+
+ ContentResolver resolver = context.getContentResolver();
+ try (Cursor cursor = resolver.query(CalendarContract.Events.CONTENT_URI,
+ new String[]{CalendarContract.Events._ID},
+ CalendarContract.Events.UID_2445 + " = ? ",
+ new String[]{uid},
+ null)) {
+ while (cursor.moveToNext()) {
+ long eventId = cursor.getLong(0);
+
+ // https://developer.android.com/guide/topics/providers/calendar-provider#delete-event
+ Uri deleteUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventId);
+ int rows = resolver.delete(deleteUri, null, null);
+ EntityLog.log(context, EntityLog.Type.General, message,
+ "Deleted event id=" + eventId + " uid=" + uid + " rows=" + rows);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java
index c693757db8..a17b63fd18 100644
--- a/app/src/main/java/eu/faircode/email/MessageHelper.java
+++ b/app/src/main/java/eu/faircode/email/MessageHelper.java
@@ -22,15 +22,10 @@ package eu.faircode.email;
import static android.system.OsConstants.ENOSPC;
import android.Manifest;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
-import android.provider.CalendarContract;
import android.system.ErrnoException;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -145,14 +140,9 @@ import javax.mail.internet.ParameterList;
import javax.mail.internet.ParseException;
import biweekly.Biweekly;
-import biweekly.ICalVersion;
import biweekly.ICalendar;
import biweekly.component.VEvent;
-import biweekly.io.WriteContext;
-import biweekly.io.scribe.property.RecurrenceRuleScribe;
import biweekly.property.Method;
-import biweekly.property.RecurrenceRule;
-import biweekly.util.ICalDate;
public class MessageHelper {
private boolean ensuredEnvelope = false;
@@ -3885,126 +3875,43 @@ public class MessageHelper {
EntityFolder.SYSTEM.equals(folder.type) ||
EntityFolder.USER.equals(folder.type)));
- if (!permission || !received || account == null || account.calendar == null)
+ if (!permission || !received || account == null || account.calendar == null) {
EntityLog.log(context, "Event not processed" +
" permission=" + permission +
" account=" + (account != null) +
" calendar=" + (account == null ? null : account.calendar) +
" folder=" + (folder != null) + ":" + (folder == null ? null : folder.type) +
" received=" + received);
- else {
- File file = local.getFile(context);
- ICalendar icalendar = Biweekly.parse(file).first();
- String method = (icalendar.getMethod() == null ? null : icalendar.getMethod().getValue());
+ return;
+ }
- VEvent event = icalendar.getEvents().get(0);
+ File file = local.getFile(context);
+ ICalendar icalendar = Biweekly.parse(file).first();
- String summary = (event.getSummary() == null ? null : event.getSummary().getValue());
- String description = (event.getDescription() == null ? null : event.getDescription().getValue());
- String location = (event.getLocation() == null ? null : event.getLocation().getValue());
+ Method method = icalendar.getMethod();
+ if (method == null)
+ return;
- ICalDate start = (event.getDateStart() == null ? null : event.getDateStart().getValue());
- ICalDate end = (event.getDateEnd() == null ? null : event.getDateEnd().getValue());
+ VEvent event = icalendar.getEvents().get(0);
- String rrule = null;
- RecurrenceRule recurrence = event.getRecurrenceRule();
- if (recurrence != null) {
- RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
- WriteContext wcontext = new WriteContext(ICalVersion.V2_0, icalendar.getTimezoneInfo(), null);
- rrule = scribe.writeText(recurrence, wcontext);
+ if (method.isRequest() || method.isCancel())
+ CalendarHelper.delete(context, event, message);
+
+ if (method.isRequest()) {
+ String selectedAccount;
+ String selectedName;
+ try {
+ JSONObject jselected = new JSONObject(account.calendar);
+ selectedAccount = jselected.getString("account");
+ selectedName = jselected.getString("name");
+ } catch (Throwable ex) {
+ Log.i(ex);
+ selectedAccount = account.calendar;
+ selectedName = null;
}
- String uid = (event.getUid() == null ? null : event.getUid().getValue());
-
- EntityLog.log(context, EntityLog.Type.General, message, "Processing event" +
- " uid=" + uid +
- " method=" + method +
- " start=" + (start != null) +
- " end=" + (end != null) +
- " rrule=" + rrule +
- " calendar=" + account.calendar);
-
- if (!TextUtils.isEmpty(uid) &&
- icalendar.getMethod() != null &&
- start != null && end != null) {
- ContentResolver resolver = context.getContentResolver();
-
- if (icalendar.getMethod().isRequest() || icalendar.getMethod().isCancel())
- try (Cursor cursor = resolver.query(CalendarContract.Events.CONTENT_URI,
- new String[]{CalendarContract.Events._ID},
- CalendarContract.Events.UID_2445 + " = ? ",
- new String[]{uid},
- null)) {
- while (cursor.moveToNext()) {
- long eventId = cursor.getLong(0);
-
- // https://developer.android.com/guide/topics/providers/calendar-provider#delete-event
- Uri deleteUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventId);
- int rows = resolver.delete(deleteUri, null, null);
- EntityLog.log(context, EntityLog.Type.General, message,
- "Deleted event id=" + eventId + " rows=" + rows);
- }
- }
-
- if (icalendar.getMethod().isRequest()) {
- String selectedAccount;
- String selectedName;
- try {
- JSONObject jselected = new JSONObject(account.calendar);
- selectedAccount = jselected.getString("account");
- selectedName = jselected.getString("name");
- } catch (Throwable ex) {
- Log.i(ex);
- selectedAccount = account.calendar;
- selectedName = null;
- }
-
- try (Cursor cursor = resolver.query(CalendarContract.Calendars.CONTENT_URI,
- new String[]{CalendarContract.Calendars._ID},
- CalendarContract.Calendars.VISIBLE + " <> 0 AND " +
- CalendarContract.Calendars.ACCOUNT_NAME + " = ?" +
- (selectedName == null
- ? ""
- : " AND " + CalendarContract.Calendars.CALENDAR_DISPLAY_NAME + " = ?"),
- selectedName == null
- ? new String[]{selectedAccount}
- : new String[]{selectedAccount, selectedName},
- null)) {
- if (cursor.getCount() == 0)
- EntityLog.log(context, EntityLog.Type.General, message,
- "Account not found username=" + account.user);
-
- if (cursor.moveToNext()) {
- // https://developer.android.com/guide/topics/providers/calendar-provider#add-event
- // https://developer.android.com/reference/android/provider/CalendarContract.EventsColumns
- ContentValues values = new ContentValues();
- values.put(CalendarContract.Events.CALENDAR_ID, cursor.getLong(0));
- if (!TextUtils.isEmpty(uid))
- values.put(CalendarContract.Events.UID_2445, uid);
- values.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
- values.put(CalendarContract.Events.DTSTART, start.getTime());
- values.put(CalendarContract.Events.DTEND, end.getTime());
- if (rrule != null)
- values.put(CalendarContract.Events.RRULE, rrule);
- if (!TextUtils.isEmpty(summary))
- values.put(CalendarContract.Events.TITLE, summary);
- if (!TextUtils.isEmpty(description))
- values.put(CalendarContract.Events.DESCRIPTION, description);
- if (!TextUtils.isEmpty(location))
- values.put(CalendarContract.Events.EVENT_LOCATION, location);
- values.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_TENTATIVE);
-
- Uri uri = resolver.insert(CalendarContract.Events.CONTENT_URI, values);
- long eventId = Long.parseLong(uri.getLastPathSegment());
- EntityLog.log(context, EntityLog.Type.General, message, "Inserted event" +
- " id=" + eventId +
- " start=" + new Date(start.getTime()) +
- " end=" + new Date(end.getTime()) +
- " summary=" + summary);
- }
- }
- }
- }
+ CalendarHelper.insert(context, icalendar.getTimezoneInfo(), event,
+ selectedAccount, selectedName, message);
}
} catch (Throwable ex) {
Log.w(ex);
diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java
index 204663374b..a2049cc19d 100644
--- a/app/src/main/java/eu/faircode/email/ServiceSend.java
+++ b/app/src/main/java/eu/faircode/email/ServiceSend.java
@@ -25,22 +25,16 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
-import android.net.Uri;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.provider.CalendarContract;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@@ -78,10 +72,7 @@ import javax.mail.internet.MimeMessage;
import biweekly.Biweekly;
import biweekly.ICalendar;
import biweekly.component.VEvent;
-import biweekly.parameter.ParticipationStatus;
-import biweekly.property.Attendee;
import biweekly.property.Method;
-import biweekly.property.Uid;
public class ServiceSend extends ServiceBase implements SharedPreferences.OnSharedPreferenceChangeListener {
private TupleUnsent lastUnsent = null;
@@ -900,40 +891,8 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar
return;
VEvent event = icalendar.getEvents().get(0);
- Uid uid = event.getUid();
- List attendees = event.getAttendees();
- if (uid == null || attendees == null || attendees.size() == 0)
- return;
-
- ParticipationStatus status = attendees.get(0).getParticipationStatus();
- if (!ParticipationStatus.ACCEPTED.equals(status) &&
- !ParticipationStatus.DECLINED.equals(status))
- return;
-
- ContentResolver resolver = getContentResolver();
- try (Cursor cursor = resolver.query(CalendarContract.Events.CONTENT_URI,
- new String[]{CalendarContract.Events._ID},
- CalendarContract.Events.UID_2445 + " = ? ",
- new String[]{uid.getValue()},
- null)) {
- while (cursor.moveToNext()) {
- long eventId = cursor.getLong(0);
-
- // https://developer.android.com/guide/topics/providers/calendar-provider#modify-calendar
- Uri updateUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventId);
- ContentValues values = new ContentValues();
- if (ParticipationStatus.ACCEPTED.equals(status))
- values.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CONFIRMED);
- else
- values.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CANCELED);
- int rows = resolver.update(updateUri, values, null, null);
-
- EntityMessage message = db.message().getMessage(sid);
- EntityLog.log(this, EntityLog.Type.General, message,
- "Updated event id=" + eventId + " rows=" + rows);
- }
- }
-
+ EntityMessage message = db.message().getMessage(sid);
+ CalendarHelper.update(this, event, message);
break;
} catch (Throwable ex) {
Log.e(ex);