Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa4f090f authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Remove legacy calendar/task/WebDAV code

parent c71dc2ba
Loading
Loading
Loading
Loading
+2 −20
Original line number Diff line number Diff line
@@ -50,27 +50,9 @@ configurations.all {
}

dependencies {
    // Apache Commons
    compile 'org.apache.commons:commons-lang3:3.4'
    compile 'commons-io:commons-io:2.4'
    // Lombok for useful @helpers
    provided 'org.projectlombok:lombok:1.16.6'
    // ical4j for parsing/generating iCalendars
    compile('org.mnode.ical4j:ical4j:2.0-beta1') {      // update ICAL_PRODID in Constants too!
        // we don't need content builders, see https://github.com/ical4j/ical4j/wiki/Groovy
        exclude group: 'org.codehaus.groovy', module: 'groovy-all'
    }
    compile('org.slf4j:slf4j-android:1.7.12')       // slf4j is used by ical4j
    // dnsjava for querying SRV/TXT records
    compile 'dnsjava:dnsjava:2.1.7'
    // HttpClient 4.3, Android flavour for WebDAV operations
    compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1'
    //compile project(':lib:httpclient-android')
    // SimpleXML for parsing and generating WebDAV messages
    compile('org.simpleframework:simple-xml:2.7.1') {
        exclude group: 'stax', module: 'stax-api'
        exclude group: 'xpp3', module: 'xpp3'
    }
    provided 'org.projectlombok:lombok:1.16.6'
    compile('org.slf4j:slf4j-android:1.7.12')

    compile project(':dav4android')
    compile project(':vcard4android')
+1 −3
Original line number Diff line number Diff line
@@ -7,8 +7,6 @@
 */
package at.bitfire.davdroid;

import net.fortuna.ical4j.model.property.ProdId;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@@ -19,7 +17,7 @@ public class Constants {
		WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app",
		WEB_URL_VIEW_LOGS = "https://github.com/bitfireAT/davdroid/wiki/How-to-view-the-logs";

	public static final ProdId ICAL_PRODID = new ProdId("-//bitfire web engineering//DAVdroid " + BuildConfig.VERSION_CODE + " (ical4j 2.0-beta1)//EN");
	//public static final ProdId ICAL_PRODID = new ProdId("-//bitfire web engineering//DAVdroid " + BuildConfig.VERSION_CODE + " (ical4j 2.0-beta1)//EN");

    public static final Logger log = LoggerFactory.getLogger("davdroid");
}
+0 −166
Original line number Diff line number Diff line
/*
 * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package at.bitfire.davdroid;

import android.util.Log;

import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.property.DateListProperty;

import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.SimpleTimeZone;

public class DateUtils {
    private final static String TAG = "davdroid.DateUtils";

	public static final TimeZoneRegistry tzRegistry = TimeZoneRegistryFactory.getInstance().createRegistry();

	static {
		// disable automatic time-zone updates (causes unwanted network traffic)
		System.setProperty("net.fortuna.ical4j.timezone.update.enabled", "false");
	}


	// time zones

    public static String findAndroidTimezoneID(String tz) {
        String deviceTZ = null;
        String availableTZs[] = SimpleTimeZone.getAvailableIDs();

        // first, try to find an exact match (case insensitive)
        for (String availableTZ : availableTZs)
            if (availableTZ.equalsIgnoreCase(tz)) {
                deviceTZ = availableTZ;
                break;
            }

        // if that doesn't work, try to find something else that matches
        if (deviceTZ == null) {
            Log.w(TAG, "Coulnd't find time zone with matching identifiers, trying to guess");
            for (String availableTZ : availableTZs)
                if (StringUtils.indexOfIgnoreCase(tz, availableTZ) != -1) {
                    deviceTZ = availableTZ;
                    break;
                }
        }

        // if that doesn't work, use UTC as fallback
        if (deviceTZ == null) {
	        final String defaultTZ = TimeZone.getDefault().getID();
            Log.e(TAG, "Couldn't identify time zone, using system default (" + defaultTZ + ") as fallback");
            deviceTZ = defaultTZ;
        }

        return deviceTZ;
    }


	// recurrence sets

	/**
	 * Concatenates, if necessary, multiple RDATE/EXDATE lists and converts them to
	 * a formatted string which Android calendar provider can process.
	 * Android expects this format: "[TZID;]date1,date2,date3" where date is "yyyymmddThhmmss" (when
	 * TZID is given) or "yyyymmddThhmmssZ". We don't use the TZID format here because then we're limited
	 * to one time-zone, while an iCalendar may contain multiple EXDATE/RDATE lines with different time zones.
	 * @param dates		one more more lists of RDATE or EXDATE
	 * @param allDay    indicates whether the event is an all-day event or not
	 * @return			formatted string for Android calendar provider:
	 *                  - in case of all-day events, all dates/times are returned as yyyymmddT000000Z
	 *                  - in case of timed events, all dates/times are returned as UTC time: yyyymmddThhmmssZ
	 */
	public static String recurrenceSetsToAndroidString(List<? extends DateListProperty> dates, boolean allDay) throws ParseException {
		List<String> strDates = new LinkedList<>();

		/*        rdate/exdate: DATE                                DATE_TIME
		    all-day             store as ...T000000Z                cut off time and store as ...T000000Z
		    event with time     (ignored)                           store as ...ThhmmssZ
		*/
		final DateFormat dateFormatUtcMidnight = new SimpleDateFormat("yyyyMMdd'T'000000'Z'");

		for (DateListProperty dateListProp : dates) {
			final Value type = dateListProp.getDates().getType();

			if (Value.DATE_TIME.equals(type)) {         // DATE-TIME values will be stored in UTC format for Android
				if (allDay) {
					DateList dateList = dateListProp.getDates();
					for (Date date : dateList)
						strDates.add(dateFormatUtcMidnight.format(date));
				} else {
					dateListProp.setUtc(true);
					strDates.add(dateListProp.getValue());
				}

			} else if (Value.DATE.equals(type))       // DATE values have to be converted to DATE-TIME <date>T000000Z for Android
				for (Date date : dateListProp.getDates())
					strDates.add(dateFormatUtcMidnight.format(date));
		}
		return StringUtils.join(strDates, ",");
	}

	/**
	 * Takes a formatted string as provided by the Android calendar provider and returns a DateListProperty
	 * constructed from these values.
	 * @param dbStr     formatted string from Android calendar provider (RDATE/EXDATE field)
	 *                  expected format: "[TZID;]date1,date2,date3" where date is "yyyymmddThhmmss[Z]"
	 * @param type      subclass of DateListProperty, e.g. RDate or ExDate
	 * @param allDay    true: list will contain DATE values; false: list will contain DATE_TIME values
	 * @return          instance of "type" containing the parsed dates/times from the string
	 */
	public static DateListProperty androidStringToRecurrenceSet(String dbStr, Class<? extends DateListProperty> type, boolean allDay) throws ParseException {
		// 1. split string into time zone and actual dates
		TimeZone timeZone;
		String datesStr;
		final int limiter = dbStr.indexOf(';');
		if (limiter != -1) {    // TZID given
			timeZone = DateUtils.tzRegistry.getTimeZone(dbStr.substring(0, limiter));
			datesStr = dbStr.substring(limiter + 1);
		} else {
			timeZone = null;
			datesStr = dbStr;
		}

		// 2. process date string and generate list of DATEs or DATE-TIMEs
		DateList dateList;
		if (allDay) {
			dateList = new DateList(Value.DATE);
			for (String s: StringUtils.split(datesStr, ','))
				dateList.add(new Date(new DateTime(s)));
		} else {
			dateList = new DateList(datesStr, Value.DATE_TIME, timeZone);
			if (timeZone == null)
				dateList.setUtc(true);
		}

		// 3. generate requested DateListProperty (RDate/ExDate) from list of DATEs or DATE-TIMEs
		DateListProperty list;
		try {
			list = (DateListProperty)type.getDeclaredConstructor(new Class[] { DateList.class } ).newInstance(dateList);
			if (dateList.getTimeZone() != null)
				list.setTimeZone(dateList.getTimeZone());
		} catch (Exception e) {
			throw new ParseException("Couldn't create date/time list by reflection", -1);
		}

		return list;
	}

}
+0 −80
Original line number Diff line number Diff line
/*
 * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */
package at.bitfire.davdroid;

import android.util.Log;

import java.net.URI;
import java.net.URISyntaxException;

public class URIUtils {
	private static final String TAG = "davdroid.URIUtils";

	
	public static String ensureTrailingSlash(String href) {
		if (!href.endsWith("/")) {
			Log.d(TAG, "Implicitly appending trailing slash to collection " + href);
			return href + "/";
		} else
			return href;
	}
	
	public static URI ensureTrailingSlash(URI href) {
		if (!href.getPath().endsWith("/")) {
			try {
				URI newURI = new URI(href.getScheme(), href.getAuthority(), href.getPath() + "/", null, null);
				Log.d(TAG, "Appended trailing slash to collection " + href + " -> " + newURI);
				href = newURI;
			} catch (URISyntaxException e) {
			}
		}
		return href;
	}


	/**
	 * Parse a received absolute/relative URL and generate a normalized URI that can be compared.
	 * @param original	    URI to be parsed, may be absolute or relative. Encoded characters will be decoded!
     * @param mustBePath    true if it's known that original is a path (may contain ":") and not an URI, i.e. ":" is not the scheme separator
	 * @return			    normalized URI
	 * @throws URISyntaxException
	 */
	public static URI parseURI(String original, boolean mustBePath) throws URISyntaxException {
        if (mustBePath) {
            // may contain ":"
            // case 1: "my:file"        won't be parsed by URI correctly because it would consider "my" as URI scheme
            // case 2: "path/my:file"   will be parsed by URI correctly
            // case 3: "my:path/file"   won't be parsed by URI correctly because it would consider "my" as URI scheme
            int idxSlash = original.indexOf('/'),
                idxColon = original.indexOf(':');
            if (idxColon != -1) {
                // colon present
                if ((idxSlash != -1) && idxSlash < idxColon)     // There's a slash, and it's before the colon → everything OK
                    ;
                else    // No slash before the colon; we have to put it there
                    original = "./" + original;
            }
        }

        // escape some common invalid characters – servers keep sending unescaped crap like "my calendar.ics" or "{guid}.vcf"
        // this is only a hack, because for instance, "[" may be valid in URLs (IPv6 literal in host name)
        String repaired = original
                .replaceAll(" ", "%20")
                .replaceAll("\\{", "%7B")
                .replaceAll("\\}", "%7D");
        if (!repaired.equals(original))
            Log.w(TAG, "Repaired invalid URL: " + original + " -> " + repaired);

		URI uri = new URI(repaired);
		URI normalized = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment());
		Log.v(TAG, "Normalized URI " + original + " -> " + normalized.toASCIIString() + " assuming that it was " +
                (mustBePath ? "a path name" : "an URI or path name"));
		return normalized;
	}

}
+0 −78
Original line number Diff line number Diff line
/*
 * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */
package at.bitfire.davdroid.resource;

import android.util.Log;

import org.apache.http.impl.client.CloseableHttpClient;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

import java.io.StringWriter;
import java.net.URISyntaxException;

import at.bitfire.davdroid.webdav.DavCalendarQuery;
import at.bitfire.davdroid.webdav.DavCompFilter;
import at.bitfire.davdroid.webdav.DavFilter;
import at.bitfire.davdroid.webdav.DavMultiget;
import at.bitfire.davdroid.webdav.DavProp;

public class CalDavCalendar extends WebDavCollection<Event> {
	private final static String TAG = "davdroid.CalDAVCalendar";

	public CalDavCalendar(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
		super(httpClient, baseURL, user, password, preemptiveAuth);
	}

	@Override
	protected String memberAcceptedMimeTypes()
	{
		return "text/calendar";
	}

	@Override
	protected DavMultiget.Type multiGetType() {
		return DavMultiget.Type.CALENDAR;
	}
	
	@Override
	protected Event newResourceSkeleton(String name, String ETag) {
		return new Event(name, ETag);
	}
	
	
	@Override
	public String getMemberETagsQuery() {
		DavCalendarQuery query = new DavCalendarQuery();

		// prop
		DavProp prop = new DavProp();
		prop.setGetetag(new DavProp.GetETag());
		query.setProp(prop);

		// filter
		DavFilter filter = new DavFilter();
		query.setFilter(filter);

		DavCompFilter compFilter = new DavCompFilter("VCALENDAR");
		filter.setCompFilter(compFilter);

		compFilter.setCompFilter(new DavCompFilter("VEVENT"));

		Serializer serializer = new Persister();
		StringWriter writer = new StringWriter();
		try {
			serializer.write(query, writer);
		} catch (Exception e) {
			Log.e(TAG, "Couldn't prepare REPORT query", e);
			return null;
		}

		return writer.toString();
	}
}
Loading