# HG changeset patch # User Michael Schloh von Bennewitz # Date 1423604400 -3600 # Node ID ec8af0e3fbc23f67ddc3304cd646bc70aded4ba7 # Parent 9250fd79cb4e65db15da04051fd197b0278a4f29 Merge https://github.com/gggard/AndroidCaldavSyncAdapater/pull/206/ diff -r 9250fd79cb4e -r ec8af0e3fbc2 res/layout/activity_authenticator.xml --- a/res/layout/activity_authenticator.xml Tue Feb 10 21:55:00 2015 +0100 +++ b/res/layout/activity_authenticator.xml Tue Feb 10 22:40:00 2015 +0100 @@ -71,6 +71,14 @@ + + - - - - \ No newline at end of file diff -r 9250fd79cb4e -r ec8af0e3fbc2 res/values-de/strings_activity_authenticator.xml --- a/res/values-de/strings_activity_authenticator.xml Tue Feb 10 21:55:00 2015 +0100 +++ b/res/values-de/strings_activity_authenticator.xml Tue Feb 10 22:40:00 2015 +0100 @@ -24,6 +24,9 @@ Account bereits in Verwendung Verbindung erfolgreich (Kalender) Verbindung erfolgreich (mehrere Kalender) - + Überprüfe SSL Zertifikat + SSL Fehler + Nicht vertrauenswürdiges Zertifikat + \ No newline at end of file diff -r 9250fd79cb4e -r ec8af0e3fbc2 res/values/strings_activity_authenticator.xml --- a/res/values/strings_activity_authenticator.xml Tue Feb 10 21:55:00 2015 +0100 +++ b/res/values/strings_activity_authenticator.xml Tue Feb 10 22:40:00 2015 +0100 @@ -22,8 +22,10 @@ Connection refused Unknown error Account already added + SSL error Connection success (calendar) Connection success (multiple calendars) - + Check SSL Certificate + Untrusted certificate - \ No newline at end of file + diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/Constants.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/gege/caldavsyncadapter/Constants.java Tue Feb 10 22:40:00 2015 +0100 @@ -0,0 +1,10 @@ +package org.gege.caldavsyncadapter; + +/** + * @author Joseph Weigl + */ +public class Constants { + + public static final String USER_DATA_TRUST_ALL_KEY = "USER_DATA_TRUSTALL_KEY"; + +} diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java --- a/src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java Tue Feb 10 22:40:00 2015 +0100 @@ -1,6 +1,6 @@ /** * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger - * + * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute @@ -16,13 +16,17 @@ * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see . - * + * */ package org.gege.caldavsyncadapter.android.entities; -import java.net.URISyntaxException; -import java.text.ParseException; +import android.database.Cursor; +import android.net.Uri; +import android.provider.CalendarContract.Attendees; +import android.provider.CalendarContract.Events; +import android.provider.CalendarContract.Reminders; + import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.Component; import net.fortuna.ical4j.model.ComponentList; @@ -62,255 +66,258 @@ import net.fortuna.ical4j.model.property.Trigger; import net.fortuna.ical4j.model.property.Uid; import net.fortuna.ical4j.model.property.Version; + +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; + +import java.net.URISyntaxException; +import java.text.ParseException; + //import android.accounts.Account; //import android.content.ContentProviderClient; //import android.content.ContentValues; //import android.content.SyncStats; -import android.database.Cursor; -import android.net.Uri; //import android.os.RemoteException; -import android.provider.CalendarContract.Attendees; //import android.provider.CalendarContract.Calendars; -import android.provider.CalendarContract.Events; -import android.provider.CalendarContract.Reminders; - //import org.gege.caldavsyncadapter.Event; //import org.gege.caldavsyncadapter.caldav.CaldavFacade; -import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; //import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; //import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; public class AndroidEvent extends org.gege.caldavsyncadapter.Event { - private Uri muri; - - private Uri mAndroidCalendarUri; - - /** - * the list of attendees - */ - private PropertyList mAttendees = new PropertyList(); - - /** - * the list of reminders - */ - private ComponentList mReminders = new ComponentList(); + private Uri muri; - private Calendar mCalendar = null; + private Uri mAndroidCalendarUri; + + /** + * the list of attendees + */ + private PropertyList mAttendees = new PropertyList(); + + /** + * the list of reminders + */ + private ComponentList mReminders = new ComponentList(); + + private Calendar mCalendar = null; /* private Account mAccount = null; - private ContentProviderClient mProvider = null;*/ - - //public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) { - public AndroidEvent(Uri uri, Uri calendarUri) { - super(); - this.setUri(uri); + private ContentProviderClient mProvider = null;*/ + + //public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) { + public AndroidEvent(Uri uri, Uri calendarUri) { + super(); + this.setUri(uri); /* this.mAccount = account; - this.mProvider = provider;*/ - //this.setCounterpartUri(calendarUri); - mAndroidCalendarUri = calendarUri; - } - - public Calendar getIcsEvent() { - return mCalendar; - } - - public String getETag() { - String Result = ""; - if (this.ContentValues.containsKey(ETAG)) - Result = this.ContentValues.getAsString(ETAG); - return Result; - } + this.mProvider = provider;*/ + //this.setCounterpartUri(calendarUri); + mAndroidCalendarUri = calendarUri; + } - public void setETag(String eTag) { - this.ContentValues.put(ETAG, eTag); - } - - public Uri getUri() { - return muri; - } + public Calendar getIcsEvent() { + return mCalendar; + } - public void setUri(Uri uri) { - this.muri = uri; - } - - public Uri getAndroidCalendarUri() { - return mAndroidCalendarUri; - } - - @Override - public String toString() { - return this.getUri().toString(); - } - - /** - * reads an android event from a given cursor into {@link AndroidEvent#ContentValues} - * @param cur the cursor with the event - * @return success of this funtion - * @see AndroidEvent#ContentValues - */ - public boolean readContentValues(Cursor cur) { - this.setETag(cur.getString(cur.getColumnIndex(ETAG))); + public String getETag() { + String Result = ""; + if (this.ContentValues.containsKey(ETAG)) + Result = this.ContentValues.getAsString(ETAG); + return Result; + } - this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE))); - this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE))); - this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART))); - this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND))); - this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY))); - this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE))); - this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID))); - this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID))); - //this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read - this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION))); - this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION))); - this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL))); - - this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS))); - - this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE))); - this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION))); + public void setETag(String eTag) { + this.ContentValues.put(ETAG, eTag); + } - this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE))); - this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE))); - this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE))); - this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE))); - this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY))); - this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID))); - this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA))); - - return true; - } - - /** - * reads the attendees from a given cursor - * @param cur the cursor with the attendees - * @return success of this function - * @see AndroidEvent#mAttendees - */ - public boolean readAttendees(Cursor cur) { - Attendee attendee = null; - Organizer organizer = null; - ParameterList paraList = null; + public Uri getUri() { + return muri; + } - String Name = ""; - Cn cn = null; + public void setUri(Uri uri) { + this.muri = uri; + } - String Email = ""; + public Uri getAndroidCalendarUri() { + return mAndroidCalendarUri; + } - int Relationship = 0; - - - int Status = 0; - PartStat partstat = null; + @Override + public String toString() { + return this.getUri().toString(); + } - int Type = 0; - Role role = null; - - try { - while (cur.moveToNext()) { - Name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME)); - Email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL)); - Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP)); - Type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE)); - Status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS)); - - if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) { - organizer = new Organizer(); - organizer.setValue("mailto:" + Email); - paraList = organizer.getParameters(); - mAttendees.add(organizer); - } else { - attendee = new Attendee(); - attendee.setValue("mailto:" + Email); - paraList = attendee.getParameters(); - mAttendees.add(attendee); - } - - Rsvp rsvp = new Rsvp(true); - paraList.add(rsvp); + /** + * reads an android event from a given cursor into {@link AndroidEvent#ContentValues} + * + * @param cur the cursor with the event + * @return success of this funtion + * @see AndroidEvent#ContentValues + */ + public boolean readContentValues(Cursor cur) { + this.setETag(cur.getString(cur.getColumnIndex(ETAG))); - cn = new Cn(Name); - paraList.add(cn); - - if (Status == Attendees.ATTENDEE_STATUS_INVITED) - partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); - else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED) - partstat = new PartStat(PartStat.ACCEPTED.getValue()); - else if (Status == Attendees.ATTENDEE_STATUS_DECLINED) - partstat = new PartStat(PartStat.DECLINED.getValue()); - else if (Status == Attendees.ATTENDEE_STATUS_NONE) - partstat = new PartStat(PartStat.COMPLETED.getValue()); - else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE) - partstat = new PartStat(PartStat.TENTATIVE.getValue()); - else - partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); - paraList.add(partstat); + this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE))); + this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE))); + this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART))); + this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND))); + this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY))); + this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE))); + this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID))); + this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID))); + //this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read + this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION))); + this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION))); + this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL))); - if (Type == Attendees.TYPE_OPTIONAL) - role = new Role(Role.OPT_PARTICIPANT.getValue()); - else if (Type == Attendees.TYPE_NONE) - role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required? - else if (Type == Attendees.TYPE_REQUIRED) - role = new Role(Role.REQ_PARTICIPANT.getValue()); - else - role = new Role(Role.NON_PARTICIPANT.getValue()); - paraList.add(role); - } + this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS))); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - return true; - } - - /** - * reads the reminders from a given cursor - * @param cur the cursor with the reminders - * @return success of this function - */ - public boolean readReminder(Cursor cur) { - int Method; - int Minutes; - VAlarm reminder; - while (cur.moveToNext()) { - reminder = new VAlarm(); - Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD)); - Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1; - - - Dur dur = new Dur(0, 0, Minutes, 0); - Trigger tri = new Trigger(dur); - Value val = new Value(Duration.DURATION); - tri.getParameters().add(val); - reminder.getProperties().add(tri); + this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE))); + this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION))); - Description desc = new Description(); - desc.setValue("caldavsyncadapter standard description"); - reminder.getProperties().add(desc); + this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE))); + this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE))); + this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE))); + this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE))); + this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY))); + this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID))); + this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA))); + return true; + } - if (Method == Reminders.METHOD_EMAIL) - reminder.getProperties().add(Action.EMAIL); - else - reminder.getProperties().add(Action.DISPLAY); - - this.mReminders.add(reminder); - } - return true; - } - - /** - * generates a new ics-file. - * uses {@link AndroidEvent#ContentValues} as source. - * this should only be used when a new event has been generated within android. - * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter - * @return success of the function - * @see CalendarEvent#fetchBody() - */ - public boolean createIcs(String strUid) { - boolean Result = false; - TimeZone timezone = null; - TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); + /** + * reads the attendees from a given cursor + * + * @param cur the cursor with the attendees + * @return success of this function + * @see AndroidEvent#mAttendees + */ + public boolean readAttendees(Cursor cur) { + Attendee attendee = null; + Organizer organizer = null; + ParameterList paraList = null; + + String Name = ""; + Cn cn = null; + + String Email = ""; + + int Relationship = 0; + + + int Status = 0; + PartStat partstat = null; + + int Type = 0; + Role role = null; + + try { + while (cur.moveToNext()) { + Name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME)); + Email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL)); + Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP)); + Type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE)); + Status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS)); + + if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) { + organizer = new Organizer(); + organizer.setValue("mailto:" + Email); + paraList = organizer.getParameters(); + mAttendees.add(organizer); + } else { + attendee = new Attendee(); + attendee.setValue("mailto:" + Email); + paraList = attendee.getParameters(); + mAttendees.add(attendee); + } + + Rsvp rsvp = new Rsvp(true); + paraList.add(rsvp); + + cn = new Cn(Name); + paraList.add(cn); + + if (Status == Attendees.ATTENDEE_STATUS_INVITED) + partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); + else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED) + partstat = new PartStat(PartStat.ACCEPTED.getValue()); + else if (Status == Attendees.ATTENDEE_STATUS_DECLINED) + partstat = new PartStat(PartStat.DECLINED.getValue()); + else if (Status == Attendees.ATTENDEE_STATUS_NONE) + partstat = new PartStat(PartStat.COMPLETED.getValue()); + else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE) + partstat = new PartStat(PartStat.TENTATIVE.getValue()); + else + partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); + paraList.add(partstat); + + if (Type == Attendees.TYPE_OPTIONAL) + role = new Role(Role.OPT_PARTICIPANT.getValue()); + else if (Type == Attendees.TYPE_NONE) + role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required? + else if (Type == Attendees.TYPE_REQUIRED) + role = new Role(Role.REQ_PARTICIPANT.getValue()); + else + role = new Role(Role.NON_PARTICIPANT.getValue()); + paraList.add(role); + } + + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return true; + } + + /** + * reads the reminders from a given cursor + * + * @param cur the cursor with the reminders + * @return success of this function + */ + public boolean readReminder(Cursor cur) { + int Method; + int Minutes; + VAlarm reminder; + while (cur.moveToNext()) { + reminder = new VAlarm(); + Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD)); + Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1; + + + Dur dur = new Dur(0, 0, Minutes, 0); + Trigger tri = new Trigger(dur); + Value val = new Value(Duration.DURATION); + tri.getParameters().add(val); + reminder.getProperties().add(tri); + + Description desc = new Description(); + desc.setValue("caldavsyncadapter standard description"); + reminder.getProperties().add(desc); + + + if (Method == Reminders.METHOD_EMAIL) + reminder.getProperties().add(Action.EMAIL); + else + reminder.getProperties().add(Action.DISPLAY); + + this.mReminders.add(reminder); + } + return true; + } + + /** + * generates a new ics-file. + * uses {@link AndroidEvent#ContentValues} as source. + * this should only be used when a new event has been generated within android. + * + * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter + * @return success of the function + * @see CalendarEvent#fetchBody() + */ + public boolean createIcs(String strUid) { + boolean Result = false; + TimeZone timeZone = null; + TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); //TODO: do not simply create the ics-file new. take into account the RAWDATA if available /* * dtstart=1365598800000 @@ -335,232 +342,239 @@ * _sync_id=null * dirty=1 */ - - try { - mCalendar = new Calendar(); - PropertyList propCalendar = mCalendar.getProperties(); - propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); - propCalendar.add(Version.VERSION_2_0); - propCalendar.add(CalScale.GREGORIAN); - - VEvent event = new VEvent(); - mCalendar.getComponents().add(event); - PropertyList propEvent = event.getProperties(); - // DTSTAMP -> is created by new VEvent() automatical - //na - - // CREATED - //na - - // LAST-MODIFIED - //na - - // SEQUENCE - //na - - // DTSTART - long lngStart = this.ContentValues.getAsLong(Events.DTSTART); - String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE); - boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY); - if (lngStart > 0) { - DtStart dtStart = new DtStart(); - if (allDay) { - Date dateStart = new Date(); - dateStart.setTime(lngStart); - dtStart.setDate(dateStart); - } else { - DateTime datetimeStart = new DateTime(); - datetimeStart.setTime(lngStart); - dtStart.setDate(datetimeStart); + try { + mCalendar = new Calendar(); + PropertyList propCalendar = mCalendar.getProperties(); + propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); + propCalendar.add(Version.VERSION_2_0); + propCalendar.add(CalScale.GREGORIAN); - timezone = registry.getTimeZone(strTZStart); - dtStart.setTimeZone(timezone); - - // no timezone information for allDay events - mCalendar.getComponents().add(timezone.getVTimeZone()); - } - propEvent.add(dtStart); - } - - // DTEND - long lngEnd = this.ContentValues.getAsLong(Events.DTEND); - String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE); - if (strTZEnd == null) - strTZEnd = strTZStart; - if (lngEnd > 0) { - DtEnd dtEnd = new DtEnd(); - if (allDay) { - Date dateEnd = new Date(); - dateEnd.setTime(lngEnd); - dtEnd.setDate(dateEnd); - } else { - DateTime datetimeEnd = new DateTime(); - datetimeEnd.setTime(lngEnd); - dtEnd.setDate(datetimeEnd); - if (strTZEnd != null) - timezone = registry.getTimeZone(strTZEnd); - dtEnd.setTimeZone(timezone); - } - propEvent.add(dtEnd); - } - - // DURATION - if (this.ContentValues.containsKey(Events.DURATION)) { - String strDuration = this.ContentValues.getAsString(Events.DURATION); - if (strDuration != null) { - Duration duration = new Duration(); - duration.setValue(strDuration); - - propEvent.add(duration); - } - } + VEvent event = new VEvent(); + mCalendar.getComponents().add(event); + PropertyList propEvent = event.getProperties(); - //RRULE - if (this.ContentValues.containsKey(Events.RRULE)) { - String strRrule = this.ContentValues.getAsString(Events.RRULE); - if (strRrule != null) { - if (!strRrule.equals("")) { - RRule rrule = new RRule(); - rrule.setValue(strRrule); - propEvent.add(rrule); - } - } - } - - //RDATE - if (this.ContentValues.containsKey(Events.RDATE)) { - String strRdate = this.ContentValues.getAsString(Events.RDATE); - if (strRdate != null) { - if (!strRdate.equals("")) { - RDate rdate = new RDate(); - rdate.setValue(strRdate); - propEvent.add(rdate); - } - } - } - - //EXRULE - if (this.ContentValues.containsKey(Events.EXRULE)) { - String strExrule = this.ContentValues.getAsString(Events.EXRULE); - if (strExrule != null) { - if (!strExrule.equals("")) { - ExRule exrule = new ExRule(); - exrule.setValue(strExrule); - propEvent.add(exrule); - } - } - } - - //EXDATE - if (this.ContentValues.containsKey(Events.EXDATE)) { - String strExdate = this.ContentValues.getAsString(Events.EXDATE); - if (strExdate != null) { - if (!strExdate.equals("")) { - ExDate exdate = new ExDate(); - exdate.setValue(strExdate); - propEvent.add(exdate); - } - } - } - - //SUMMARY - if (this.ContentValues.containsKey(Events.TITLE)) { - String strTitle = this.ContentValues.getAsString(Events.TITLE); - if (strTitle != null) { - Summary summary = new Summary(strTitle); - propEvent.add(summary); - } - } - - //DESCIPTION - if (this.ContentValues.containsKey(Events.DESCRIPTION)) { - String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION); - if (strDescription != null) { - if (!strDescription.equals("")) { - Description description = new Description(strDescription); - propEvent.add(description); - } - } - } - - //LOCATION - if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) { - String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION); - if (strLocation != null) { - if (!strLocation.equals("")) { - Location location = new Location(strLocation); - propEvent.add(location); - } - } - } - - //CLASS / ACCESS_LEVEL - if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) { - int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL); - Clazz clazz = new Clazz(); - if (accessLevel == Events.ACCESS_PUBLIC) - clazz.setValue(Clazz.PUBLIC.getValue()); - else if (accessLevel == Events.ACCESS_PRIVATE) - clazz.setValue(Clazz.PRIVATE.getValue()); - else if (accessLevel == Events.ACCESS_CONFIDENTIAL) - clazz.setValue(Clazz.CONFIDENTIAL.getValue()); - else - clazz.setValue(Clazz.PUBLIC.getValue()); - - propEvent.add(clazz); - } - - //STATUS - if (this.ContentValues.containsKey(Events.STATUS)) { - int intStatus = this.ContentValues.getAsInteger(Events.STATUS); - if (intStatus > -1) { - Status status = new Status(); - if (intStatus == Events.STATUS_CANCELED) - status.setValue(Status.VEVENT_CANCELLED.getValue()); - else if (intStatus == Events.STATUS_CONFIRMED) - status.setValue(Status.VEVENT_CONFIRMED.getValue()); - else if (intStatus == Events.STATUS_TENTATIVE) - status.setValue(Status.VEVENT_TENTATIVE.getValue()); - - propEvent.add(status); - } - } + // DTSTAMP -> is created by new VEvent() automatical + //na - //UID - Uid uid = new Uid(strUid); - propEvent.add(uid); + // CREATED + //na - // Attendees - if (mAttendees.size() > 0) { - for (Object objProp: mAttendees) { - Property prop = (Property) objProp; - propEvent.add(prop); - } - } - - // Reminders - if (mReminders.size() > 0) { - for (Object objComp: mReminders) { - Component com = (Component) objComp; - event.getAlarms().add(com); - } - } - - } catch (ParseException e) { - e.printStackTrace(); - } - - return Result; - } - - /** - * marks the android event as already handled - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ + // LAST-MODIFIED + //na + + // SEQUENCE + //na + + // DTSTART + long lngStart = this.ContentValues.getAsLong(Events.DTSTART); + String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE); + boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY); + if (lngStart > 0) { + DtStart dtStart = new DtStart(); + if (allDay) { + Date dateStart = new Date(); + dateStart.setTime(lngStart); + dtStart.setDate(dateStart); + } else { + DateTime datetimeStart = new DateTime(); + datetimeStart.setTime(lngStart); + dtStart.setDate(datetimeStart); + + timeZone = registry.getTimeZone(strTZStart); + if (timeZone == null) { + java.util.TimeZone systemTimeZone = TimeZone.getTimeZone(strTZStart); + if (systemTimeZone == null) { + systemTimeZone = TimeZone.getDefault(); + } + timeZone = registry.getTimeZone(systemTimeZone.getID()); + } + dtStart.setTimeZone(timeZone); + + // no timezone information for allDay events + mCalendar.getComponents().add(timeZone.getVTimeZone()); + } + propEvent.add(dtStart); + } + + // DTEND + long lngEnd = this.ContentValues.getAsLong(Events.DTEND); + String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE); + if (strTZEnd == null) + strTZEnd = strTZStart; + if (lngEnd > 0) { + DtEnd dtEnd = new DtEnd(); + if (allDay) { + Date dateEnd = new Date(); + dateEnd.setTime(lngEnd); + dtEnd.setDate(dateEnd); + } else { + DateTime datetimeEnd = new DateTime(); + datetimeEnd.setTime(lngEnd); + dtEnd.setDate(datetimeEnd); + if (strTZEnd != null) + timeZone = registry.getTimeZone(strTZEnd); + dtEnd.setTimeZone(timeZone); + } + propEvent.add(dtEnd); + } + + // DURATION + if (this.ContentValues.containsKey(Events.DURATION)) { + String strDuration = this.ContentValues.getAsString(Events.DURATION); + if (strDuration != null) { + Duration duration = new Duration(); + duration.setValue(strDuration); + + propEvent.add(duration); + } + } + + //RRULE + if (this.ContentValues.containsKey(Events.RRULE)) { + String strRrule = this.ContentValues.getAsString(Events.RRULE); + if (strRrule != null) { + if (!strRrule.equals("")) { + RRule rrule = new RRule(); + rrule.setValue(strRrule); + propEvent.add(rrule); + } + } + } + + //RDATE + if (this.ContentValues.containsKey(Events.RDATE)) { + String strRdate = this.ContentValues.getAsString(Events.RDATE); + if (strRdate != null) { + if (!strRdate.equals("")) { + RDate rdate = new RDate(); + rdate.setValue(strRdate); + propEvent.add(rdate); + } + } + } + + //EXRULE + if (this.ContentValues.containsKey(Events.EXRULE)) { + String strExrule = this.ContentValues.getAsString(Events.EXRULE); + if (strExrule != null) { + if (!strExrule.equals("")) { + ExRule exrule = new ExRule(); + exrule.setValue(strExrule); + propEvent.add(exrule); + } + } + } + + //EXDATE + if (this.ContentValues.containsKey(Events.EXDATE)) { + String strExdate = this.ContentValues.getAsString(Events.EXDATE); + if (strExdate != null) { + if (!strExdate.equals("")) { + ExDate exdate = new ExDate(); + exdate.setValue(strExdate); + propEvent.add(exdate); + } + } + } + + //SUMMARY + if (this.ContentValues.containsKey(Events.TITLE)) { + String strTitle = this.ContentValues.getAsString(Events.TITLE); + if (strTitle != null) { + Summary summary = new Summary(strTitle); + propEvent.add(summary); + } + } + + //DESCIPTION + if (this.ContentValues.containsKey(Events.DESCRIPTION)) { + String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION); + if (strDescription != null) { + if (!strDescription.equals("")) { + Description description = new Description(strDescription); + propEvent.add(description); + } + } + } + + //LOCATION + if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) { + String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION); + if (strLocation != null) { + if (!strLocation.equals("")) { + Location location = new Location(strLocation); + propEvent.add(location); + } + } + } + + //CLASS / ACCESS_LEVEL + if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) { + int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL); + Clazz clazz = new Clazz(); + if (accessLevel == Events.ACCESS_PUBLIC) + clazz.setValue(Clazz.PUBLIC.getValue()); + else if (accessLevel == Events.ACCESS_PRIVATE) + clazz.setValue(Clazz.PRIVATE.getValue()); + else if (accessLevel == Events.ACCESS_CONFIDENTIAL) + clazz.setValue(Clazz.CONFIDENTIAL.getValue()); + else + clazz.setValue(Clazz.PUBLIC.getValue()); + + propEvent.add(clazz); + } + + //STATUS + if (this.ContentValues.containsKey(Events.STATUS)) { + int intStatus = this.ContentValues.getAsInteger(Events.STATUS); + if (intStatus > -1) { + Status status = new Status(); + if (intStatus == Events.STATUS_CANCELED) + status.setValue(Status.VEVENT_CANCELLED.getValue()); + else if (intStatus == Events.STATUS_CONFIRMED) + status.setValue(Status.VEVENT_CONFIRMED.getValue()); + else if (intStatus == Events.STATUS_TENTATIVE) + status.setValue(Status.VEVENT_TENTATIVE.getValue()); + + propEvent.add(status); + } + } + + //UID + Uid uid = new Uid(strUid); + propEvent.add(uid); + + // Attendees + if (mAttendees.size() > 0) { + for (Object objProp : mAttendees) { + Property prop = (Property) objProp; + propEvent.add(prop); + } + } + + // Reminders + if (mReminders.size() > 0) { + for (Object objComp : mReminders) { + Component com = (Component) objComp; + event.getAlarms().add(com); + } + } + + } catch (ParseException e) { + e.printStackTrace(); + } + + return Result; + } + + /** + * marks the android event as already handled + * @return + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + * @throws RemoteException + */ /* public boolean tagAndroidEvent() throws RemoteException { ContentValues values = new ContentValues(); diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java --- a/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java Tue Feb 10 22:40:00 2015 +0100 @@ -1,6 +1,6 @@ /** * Copyright (c) 2012-2013, Gerald Garcia - * + * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute @@ -16,24 +16,11 @@ * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see . - * + * */ package org.gege.caldavsyncadapter.authenticator; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; - -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.http.conn.HttpHostConnectException; -import org.gege.caldavsyncadapter.R; -import org.gege.caldavsyncadapter.caldav.CaldavFacade; -import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult; -import org.xml.sax.SAXException; - import android.accounts.Account; import android.accounts.AccountManager; import android.animation.Animator; @@ -45,430 +32,480 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.View; import android.view.inputmethod.EditorInfo; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; +import org.apache.http.conn.HttpHostConnectException; +import org.gege.caldavsyncadapter.Constants; +import org.gege.caldavsyncadapter.R; +import org.gege.caldavsyncadapter.caldav.CaldavFacade; +import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.Locale; + +import javax.xml.parsers.ParserConfigurationException; + /** * Activity which displays a login screen to the user, offering registration as * well. */ public class AuthenticatorActivity extends Activity { - - private static final String TAG = "AuthenticatorActivity"; - private static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account"; + private static final String TAG = "AuthenticatorActivity"; - public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY"; - public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME"; - public static final String USER_DATA_VERSION = "USER_DATA_VERSION"; - public static final String CURRENT_USER_DATA_VERSION = "1"; - - public static final String ACCOUNT_NAME_SPLITTER = "@"; - - /** - * The default email to populate the email field with. - */ - public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL"; + private static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account"; - /** - * Keep track of the login task to ensure we can cancel it if requested. - */ - private UserLoginTask mAuthTask = null; + public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY"; + public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME"; + public static final String USER_DATA_VERSION = "USER_DATA_VERSION"; + public static final String CURRENT_USER_DATA_VERSION = "1"; - // Values for email and password at the time of the login attempt. - private String mUser; - private String mPassword; - private Context mContext; + public static final String ACCOUNT_NAME_SPLITTER = "@"; - // UI references. - private EditText mUserView; - private EditText mPasswordView; - private View mLoginFormView; - private View mLoginStatusView; - private TextView mLoginStatusMessageView; + /** + * The default email to populate the email field with. + */ + public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL"; - private AccountManager mAccountManager; + /** + * Keep track of the login task to ensure we can cancel it if requested. + */ + private UserLoginTask mAuthTask = null; - private String mURL; - private EditText mURLView; - - private String mAccountname; - private EditText mAccountnameView; - - public AuthenticatorActivity() { - super(); - - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mAccountManager = AccountManager.get(this); + // Values for email and password at the time of the login attempt. + private String mUser; + private String mPassword; + private String mTrustAll; + private Context mContext; - setContentView(R.layout.activity_authenticator); + // UI references. + private EditText mUserView; + private EditText mPasswordView; + private View mLoginFormView; + private View mLoginStatusView; + private TextView mLoginStatusMessageView; + private CheckBox mTrustCheckBox; - // Set up the login form. - mUser = getIntent().getStringExtra(EXTRA_EMAIL); - mUserView = (EditText) findViewById(R.id.user); - mUserView.setText(mUser); - - mContext = getBaseContext(); + private AccountManager mAccountManager; - mPasswordView = (EditText) findViewById(R.id.password); - mPasswordView - .setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int id, - KeyEvent keyEvent) { - if (id == R.id.login || id == EditorInfo.IME_NULL) { - attemptLogin(); - return true; - } - return false; - } - }); + private String mURL; + private EditText mURLView; - - mURLView = (EditText) findViewById(R.id.url); - - mAccountnameView = (EditText) findViewById(R.id.accountname); - - mLoginFormView = findViewById(R.id.login_form); - mLoginStatusView = findViewById(R.id.login_status); - mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message); + private String mAccountname; + private EditText mAccountnameView; - findViewById(R.id.sign_in_button).setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - attemptLogin(); - } - }); - - - } + public AuthenticatorActivity() { + super(); - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.activity_authenticator, menu); - return true; - } + } - /** - * Attempts to sign in or register the account specified by the login form. - * If there are form errors (invalid email, missing fields, etc.), the - * errors are presented and no actual login attempt is made. - */ - public void attemptLogin() { - if (mAuthTask != null) { - return; - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - // Reset errors. - mUserView.setError(null); - mPasswordView.setError(null); + mAccountManager = AccountManager.get(this); - // Store values at the time of the login attempt. - mUser = mUserView.getText().toString(); - mPassword = mPasswordView.getText().toString(); - mURL = mURLView.getText().toString(); - mAccountname = mAccountnameView.getText().toString(); + setContentView(R.layout.activity_authenticator); - boolean cancel = false; - View focusView = null; - - if (!mAccountname.equals("")) { - Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE); - String TestUrl = mAccountManager.getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY); - if (TestUrl != null) { - mAccountnameView.setError(getString(R.string.error_account_already_in_use)); - focusView = mAccountnameView; - cancel = true; - } - } + // Set up the login form. + mUser = getIntent().getStringExtra(EXTRA_EMAIL); + mUserView = (EditText) findViewById(R.id.user); + mUserView.setText(mUser); - // Check for a valid password. - if (TextUtils.isEmpty(mPassword)) { - mPasswordView.setError(getString(R.string.error_field_required)); - focusView = mPasswordView; - cancel = true; - } else if (mPassword.length() < 4) { - mPasswordView.setError(getString(R.string.error_invalid_password)); - focusView = mPasswordView; - cancel = true; - } + mContext = getBaseContext(); - // Check for a valid email address. - if (TextUtils.isEmpty(mUser)) { - mUserView.setError(getString(R.string.error_field_required)); - focusView = mUserView; - cancel = true; - } - //else if (!mUser.contains("@")) { - // mUserView.setError(getString(R.string.error_invalid_email)); - // focusView = mUserView; - // cancel = true; - //} + mPasswordView = (EditText) findViewById(R.id.password); + mPasswordView + .setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int id, + KeyEvent keyEvent) { + if (id == R.id.login || id == EditorInfo.IME_NULL) { + attemptLogin(); + return true; + } + return false; + } + }); - if (cancel) { - // There was an error; don't attempt login and focus the first - // form field with an error. - focusView.requestFocus(); - } else { - // Show a progress spinner, and kick off a background task to - // perform the user login attempt. - mLoginStatusMessageView.setText(R.string.login_progress_signing_in); - showProgress(true); - mAuthTask = new UserLoginTask(); - mAuthTask.execute((Void) null); - } - } - /** - * Shows the progress UI and hides the login form. - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) - private void showProgress(final boolean show) { - // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow - // for very easy animations. If available, use these APIs to fade-in - // the progress spinner. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { - int shortAnimTime = getResources().getInteger( - android.R.integer.config_shortAnimTime); + mURLView = (EditText) findViewById(R.id.url); + // if the URL start with "https" show the option to disable SSL host verification + mURLView.addTextChangedListener(new TextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + String url = ((EditText) findViewById(R.id.url)).getText().toString(); + int visible = url.toLowerCase(Locale.getDefault()) + .startsWith("https") ? View.VISIBLE : View.GONE; + ((CheckBox) findViewById(R.id.trustall)).setVisibility(visible); + } - mLoginStatusView.setVisibility(View.VISIBLE); - mLoginStatusView.animate().setDuration(shortAnimTime) - .alpha(show ? 1 : 0) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mLoginStatusView.setVisibility(show ? View.VISIBLE - : View.GONE); - } - }); + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } - mLoginFormView.setVisibility(View.VISIBLE); - mLoginFormView.animate().setDuration(shortAnimTime) - .alpha(show ? 0 : 1) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mLoginFormView.setVisibility(show ? View.GONE - : View.VISIBLE); - } - }); - } else { - // The ViewPropertyAnimator APIs are not available, so simply show - // and hide the relevant UI components. - mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE); - mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); - } - } + @Override + public void afterTextChanged(Editable s) { + } + }); - - protected enum LoginResult { - MalformedURLException, - GeneralSecurityException, - UnkonwnException, - WrongCredentials, - InvalidResponse, - WrongUrl, - ConnectionRefused, - Success_Calendar, - Success_Collection, - Account_Already_In_Use - } - - - /** - * Represents an asynchronous login/registration task used to authenticate - * the user. - */ - public class UserLoginTask extends AsyncTask { + mAccountnameView = (EditText) findViewById(R.id.accountname); - @Override - protected LoginResult doInBackground(Void... params) { + mLoginFormView = findViewById(R.id.login_form); + mLoginStatusView = findViewById(R.id.login_status); + mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message); - TestConnectionResult result = null; - - try { - CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL); - String version = ""; - try { - version = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName; - } catch (NameNotFoundException e) { - version = "unknown"; - e.printStackTrace(); - } - facade.setVersion(version); - result = facade.testConnection(); - Log.i(TAG, "testConnection status="+result); - } catch (HttpHostConnectException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.ConnectionRefused; - } catch (MalformedURLException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.MalformedURLException; - } catch (UnsupportedEncodingException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.UnkonwnException; - } catch (ParserConfigurationException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.UnkonwnException; - } catch (SAXException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.InvalidResponse; - } catch (IOException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.UnkonwnException; - } catch (URISyntaxException e) { - Log.w(TAG,"testConnection", e); - return LoginResult.MalformedURLException; - } + findViewById(R.id.sign_in_button).setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + attemptLogin(); + } + } + ); - if (result == null) { - return LoginResult.UnkonwnException; - } - - switch (result) { - - case SUCCESS: - boolean OldAccount = false; - LoginResult Result = LoginResult.Success_Calendar; + mTrustCheckBox = (CheckBox) findViewById(R.id.trustall); - if (OldAccount) { - final Account account = new Account(mUser, ACCOUNT_TYPE); - if (mAccountManager.addAccountExplicitly(account, mPassword, null)) { - Log.v(TAG,"new account created"); - mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL); - } else { - Log.v(TAG,"no new account created"); - Result = LoginResult.Account_Already_In_Use; - } - } else { - final Account account; - if (mAccountname.equals("")) { - account = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, ACCOUNT_TYPE); - } else { - account = new Account(mAccountname, ACCOUNT_TYPE); - } - if (mAccountManager.addAccountExplicitly(account, mPassword, null)) { - Log.v(TAG,"new account created"); - mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL); - mAccountManager.setUserData(account, USER_DATA_USERNAME, mUser); - mAccountManager.setUserData(account, USER_DATA_VERSION, CURRENT_USER_DATA_VERSION); - } else { - Log.v(TAG,"no new account created"); - Result = LoginResult.Account_Already_In_Use; - } - } - - return Result; - case WRONG_CREDENTIAL: - return LoginResult.WrongCredentials; - - case WRONG_SERVER_STATUS: - return LoginResult.InvalidResponse; - - case WRONG_URL: - return LoginResult.WrongUrl; - - case WRONG_ANSWER: - return LoginResult.InvalidResponse; - - default: - return LoginResult.UnkonwnException; - - } - - } - + } - @Override - protected void onPostExecute(final LoginResult result) { - mAuthTask = null; - showProgress(false); + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + return true; + } - int duration = Toast.LENGTH_SHORT; - Toast toast = null; - - switch (result) { - case Success_Calendar: - toast = Toast.makeText(getApplicationContext(), R.string.success_calendar, duration); - toast.show(); - finish(); - break; - - case Success_Collection: - toast = Toast.makeText(getApplicationContext(), R.string.success_collection, duration); - toast.show(); - finish(); - break; - - case MalformedURLException: - - toast = Toast.makeText(getApplicationContext(), R.string.error_incorrect_url_format, duration); - toast.show(); - mURLView.setError(getString(R.string.error_incorrect_url_format)); - mURLView.requestFocus(); - break; - case InvalidResponse: - toast = Toast.makeText(getApplicationContext(), R.string.error_invalid_server_answer, duration); - toast.show(); - mURLView.setError(getString(R.string.error_invalid_server_answer)); - mURLView.requestFocus(); - break; - case WrongUrl: - toast = Toast.makeText(getApplicationContext(), R.string.error_wrong_url, duration); - toast.show(); - mURLView.setError(getString(R.string.error_wrong_url)); - mURLView.requestFocus(); - break; - - case WrongCredentials: - mPasswordView.setError(getString(R.string.error_incorrect_password)); - mPasswordView.requestFocus(); - break; - - case ConnectionRefused: - toast = Toast.makeText(getApplicationContext(), R.string.error_connection_refused, duration); - toast.show(); - mURLView.setError(getString(R.string.error_connection_refused)); - mURLView.requestFocus(); - break; - case Account_Already_In_Use: - toast = Toast.makeText(getApplicationContext(), R.string.error_account_already_in_use, duration); - toast.show(); - mURLView.setError(getString(R.string.error_account_already_in_use)); - mURLView.requestFocus(); - break; - default: - toast = Toast.makeText(getApplicationContext(), R.string.error_unkown_error, duration); - toast.show(); - mURLView.setError(getString(R.string.error_unkown_error)); - mURLView.requestFocus(); - break; - } - - - - - } + /** + * Attempts to sign in or register the account specified by the login form. + * If there are form errors (invalid email, missing fields, etc.), the + * errors are presented and no actual login attempt is made. + */ + public void attemptLogin() { + if (mAuthTask != null) { + return; + } - @Override - protected void onCancelled() { - mAuthTask = null; - showProgress(false); - } - } -} + // Reset errors. + mUserView.setError(null); + mPasswordView.setError(null); + + // Store values at the time of the login attempt. + mUser = mUserView.getText().toString(); + mPassword = mPasswordView.getText().toString(); + mURL = mURLView.getText().toString(); + mAccountname = mAccountnameView.getText().toString(); + mTrustAll = (mTrustCheckBox.isChecked() ? "false" : "true"); + boolean cancel = false; + View focusView = null; + + if (!mAccountname.equals("")) { + Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE); + String TestUrl = mAccountManager.getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY); + if (TestUrl != null) { + mAccountnameView.setError(getString(R.string.error_account_already_in_use)); + focusView = mAccountnameView; + cancel = true; + } + } + + // Check for a valid password. + if (TextUtils.isEmpty(mPassword)) { + mPasswordView.setError(getString(R.string.error_field_required)); + focusView = mPasswordView; + cancel = true; + } + + // Check for a valid email address. + if (TextUtils.isEmpty(mUser)) { + mUserView.setError(getString(R.string.error_field_required)); + focusView = mUserView; + cancel = true; + } + //else if (!mUser.contains("@")) { + // mUserView.setError(getString(R.string.error_invalid_email)); + // focusView = mUserView; + // cancel = true; + //} + + if (cancel) { + // There was an error; don't attempt login and focus the first + // form field with an error. + focusView.requestFocus(); + } else { + // Show a progress spinner, and kick off a background task to + // perform the user login attempt. + mLoginStatusMessageView.setText(R.string.login_progress_signing_in); + showProgress(true); + mAuthTask = new UserLoginTask(); + mAuthTask.execute((Void) null); + } + } + + /** + * Shows the progress UI and hides the login form. + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) + private void showProgress(final boolean show) { + // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow + // for very easy animations. If available, use these APIs to fade-in + // the progress spinner. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { + int shortAnimTime = getResources().getInteger( + android.R.integer.config_shortAnimTime); + + mLoginStatusView.setVisibility(View.VISIBLE); + mLoginStatusView.animate().setDuration(shortAnimTime) + .alpha(show ? 1 : 0) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLoginStatusView.setVisibility(show ? View.VISIBLE + : View.GONE); + } + }); + + mLoginFormView.setVisibility(View.VISIBLE); + mLoginFormView.animate().setDuration(shortAnimTime) + .alpha(show ? 0 : 1) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLoginFormView.setVisibility(show ? View.GONE + : View.VISIBLE); + } + }); + } else { + // The ViewPropertyAnimator APIs are not available, so simply show + // and hide the relevant UI components. + mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE); + mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); + } + } + + + protected enum LoginResult { + MalformedURLException, + GeneralSecurityException, + UnkonwnException, + WrongCredentials, + InvalidResponse, + WrongUrl, + ConnectionRefused, + Success_Calendar, + Success_Collection, + UNTRUSTED_CERT, + Account_Already_In_Use + } + + + /** + * Represents an asynchronous login/registration task used to authenticate + * the user. + */ + public class UserLoginTask extends AsyncTask { + + @Override + protected LoginResult doInBackground(Void... params) { + + TestConnectionResult result = null; + + try { + CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL, mTrustAll); + String version = ""; + try { + version = mContext.getPackageManager() + .getPackageInfo(mContext.getPackageName(), 0).versionName; + } catch (NameNotFoundException e) { + version = "unknown"; + e.printStackTrace(); + } + facade.setVersion(version); + result = facade.testConnection(); + Log.i(TAG, "testConnection status=" + result); + } catch (HttpHostConnectException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.ConnectionRefused; + } catch (MalformedURLException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.MalformedURLException; + } catch (UnsupportedEncodingException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.UnkonwnException; + } catch (ParserConfigurationException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.UnkonwnException; + } catch (SAXException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.InvalidResponse; + } catch (IOException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.UnkonwnException; + } catch (URISyntaxException e) { + Log.w(TAG, "testConnection", e); + return LoginResult.MalformedURLException; + } + + if (result == null) { + return LoginResult.UnkonwnException; + } + + switch (result) { + + case SSL_ERROR: + return LoginResult.UNTRUSTED_CERT; + case SUCCESS: + boolean OldAccount = false; + LoginResult Result = LoginResult.Success_Calendar; + + if (OldAccount) { + final Account account = new Account(mUser, ACCOUNT_TYPE); + if (mAccountManager.addAccountExplicitly(account, mPassword, null)) { + Log.v(TAG, "new account created"); + mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL); + } else { + Log.v(TAG, "no new account created"); + Result = LoginResult.Account_Already_In_Use; + } + } else { + final Account account; + if (mAccountname.equals("")) { + account = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, ACCOUNT_TYPE); + } else { + account = new Account(mAccountname, ACCOUNT_TYPE); + } + if (mAccountManager.addAccountExplicitly(account, mPassword, null)) { + Log.v(TAG, "new account created"); + mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL); + mAccountManager.setUserData(account, USER_DATA_USERNAME, mUser); + mAccountManager.setUserData(account, USER_DATA_VERSION, CURRENT_USER_DATA_VERSION); + mAccountManager.setUserData(account, Constants.USER_DATA_TRUST_ALL_KEY, mTrustAll); + } else { + Log.v(TAG, "no new account created"); + Result = LoginResult.Account_Already_In_Use; + } + } + + return Result; + + case WRONG_CREDENTIAL: + return LoginResult.WrongCredentials; + + case WRONG_SERVER_STATUS: + return LoginResult.InvalidResponse; + + case WRONG_URL: + return LoginResult.WrongUrl; + + case WRONG_ANSWER: + return LoginResult.InvalidResponse; + + default: + return LoginResult.UnkonwnException; + + } + + } + + + @Override + protected void onPostExecute(final LoginResult result) { + mAuthTask = null; + showProgress(false); + + int duration = Toast.LENGTH_SHORT; + Toast toast = null; + + switch (result) { + case Success_Calendar: + toast = Toast.makeText(getApplicationContext(), R.string.success_calendar, duration); + toast.show(); + finish(); + break; + + case Success_Collection: + toast = Toast.makeText(getApplicationContext(), R.string.success_collection, duration); + toast.show(); + finish(); + break; + + case MalformedURLException: + + toast = Toast.makeText(getApplicationContext(), R.string.error_incorrect_url_format, duration); + toast.show(); + mURLView.setError(getString(R.string.error_incorrect_url_format)); + mURLView.requestFocus(); + break; + case InvalidResponse: + toast = Toast.makeText(getApplicationContext(), R.string.error_invalid_server_answer, duration); + toast.show(); + mURLView.setError(getString(R.string.error_invalid_server_answer)); + mURLView.requestFocus(); + break; + case WrongUrl: + toast = Toast.makeText(getApplicationContext(), R.string.error_wrong_url, duration); + toast.show(); + mURLView.setError(getString(R.string.error_wrong_url)); + mURLView.requestFocus(); + break; + + case GeneralSecurityException: + break; + case UnkonwnException: + break; + case WrongCredentials: + mPasswordView.setError(getString(R.string.error_incorrect_password)); + mPasswordView.requestFocus(); + break; + + case ConnectionRefused: + toast = Toast.makeText(getApplicationContext(), R.string.error_connection_refused, duration); + toast.show(); + mURLView.setError(getString(R.string.error_connection_refused)); + mURLView.requestFocus(); + break; + case UNTRUSTED_CERT: + toast = Toast.makeText(getApplicationContext(), getString(R.string.error_untrusted_certificate), duration); + toast.show(); + mURLView.setError(getString(R.string.error_ssl)); + mURLView.requestFocus(); + break; + case Account_Already_In_Use: + toast = Toast.makeText(getApplicationContext(), R.string.error_account_already_in_use, duration); + toast.show(); + mURLView.setError(getString(R.string.error_account_already_in_use)); + mURLView.requestFocus(); + break; + default: + toast = Toast.makeText(getApplicationContext(), R.string.error_unkown_error, duration); + toast.show(); + mURLView.setError(getString(R.string.error_unkown_error)); + mURLView.requestFocus(); + break; + } + + + } + + @Override + protected void onCancelled() { + mAuthTask = null; + showProgress(false); + } + } +} \ No newline at end of file diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java --- a/src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java Tue Feb 10 22:40:00 2015 +0100 @@ -1,6 +1,6 @@ /** * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger - * + * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute @@ -16,31 +16,15 @@ * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see . - * + * */ package org.gege.caldavsyncadapter.caldav; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.SocketException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; +import android.accounts.Account; +import android.content.ContentProviderClient; +import android.content.Context; +import android.util.Log; import org.apache.http.HttpException; import org.apache.http.HttpHost; @@ -76,11 +60,12 @@ import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EntityUtils; import org.gege.caldavsyncadapter.BuildConfig; +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; +import org.gege.caldavsyncadapter.caldav.entities.CalendarList; import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; -import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; -import org.gege.caldavsyncadapter.caldav.entities.CalendarList; import org.gege.caldavsyncadapter.caldav.http.HttpPropFind; import org.gege.caldavsyncadapter.caldav.http.HttpReport; import org.gege.caldavsyncadapter.caldav.xml.CalendarHomeHandler; @@ -96,388 +81,410 @@ import org.xml.sax.SAXException; import org.xml.sax.XMLReader; -import android.accounts.Account; -import android.content.ContentProviderClient; -import android.content.Context; -import android.util.Log; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.SocketException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.SSLException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; public class CaldavFacade { - private static final String TAG = "CaldavFacade"; + private static final String TAG = "CaldavFacade"; - private final static String XML_VERSION = "\n"; + private final static String XML_VERSION = "\n"; - private String USER_AGENT = "CalDAV Sync Adapter (Android) https://github.com/gggard/AndroidCaldavSyncAdapater"; - private String VERSION = ""; + private String USER_AGENT = "CalDAV Sync Adapter (Android) https://github.com/gggard/AndroidCaldavSyncAdapater"; + private String VERSION = ""; - private static HttpClient httpClient; - private HttpContext mContext = null; - private AuthState mLastAuthState = null; - private AuthScope mLastAuthScope = null; - - private boolean trustAll = true; + private static HttpClient httpClient; + private HttpContext mContext = null; + private AuthState mLastAuthState = null; + private AuthScope mLastAuthScope = null; - private URL url; + private boolean mTrustAll = true; - private static HttpHost targetHost; - - private int lastStatusCode; - private String lastETag; - private String lastDav; + private URL url; - private String mstrcHeaderIfMatch = "If-Match"; - private String mstrcHeaderIfNoneMatch = "If-None-Match"; - - private Account mAccount = null; - private ContentProviderClient mProvider; - - protected HttpClient getHttpClient() { + private static HttpHost targetHost; - HttpParams params = new BasicHttpParams(); - params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); - params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); - params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); - HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + private int lastStatusCode; + private String lastETag; + private String lastDav; - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", new PlainSocketFactory(), 80)); - registry.register(new Scheme("https", (trustAll ? EasySSLSocketFactory.getSocketFactory() : SSLSocketFactory.getSocketFactory()), 443)); - DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params); - - return client; - } + private String mstrcHeaderIfMatch = "If-Match"; + private String mstrcHeaderIfNoneMatch = "If-None-Match"; - public CaldavFacade(String mUser, String mPassword, String mURL) throws MalformedURLException { - url = new URL(mURL); + private Account mAccount = null; + private ContentProviderClient mProvider; - httpClient = getHttpClient(); - UsernamePasswordCredentials upc = new UsernamePasswordCredentials(mUser, mPassword); + protected HttpClient getHttpClient() { - AuthScope as = null; - as = new AuthScope(url.getHost(), -1); - ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials(as, upc); - - mContext = new BasicHttpContext(); - CredentialsProvider credProvider = ((AbstractHttpClient) httpClient).getCredentialsProvider(); - mContext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider); - - //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html - ((AbstractHttpClient) httpClient).addRequestInterceptor(preemptiveAuth, 0); + HttpParams params = new BasicHttpParams(); + params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); + params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); + params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); - String proto = "http"; - int port = 80; + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", new PlainSocketFactory(), 80)); + registry.register(new Scheme("https", (mTrustAll ? EasySSLSocketFactory.getSocketFactory() : SSLSocketFactory + .getSocketFactory()), 443)); + DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params); - if (url.getProtocol().equalsIgnoreCase("https")) { - proto = "https"; - if (url.getPort() == -1) - port = 443; - else - port = url.getPort(); - } + return client; + } - if (url.getProtocol().equalsIgnoreCase("http")) { - proto = "http"; - if (url.getPort() == -1) - port = 80; - else - port = url.getPort(); - } - targetHost = new HttpHost(url.getHost(), port, proto); - } - - //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html - HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() { - @Override - public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { - AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); + public CaldavFacade(String mUser, String mPassword, String mURL, String trustAll) throws MalformedURLException { + url = new URL(mURL); - if (authState.getAuthScheme() == null) { - if (mLastAuthState != null) { - Log.d(TAG, "LastAuthState: restored with user " + mLastAuthState.getCredentials().getUserPrincipal().getName()); - authState.setAuthScheme(mLastAuthState.getAuthScheme()); - authState.setCredentials(mLastAuthState.getCredentials()); - } else { - Log.d(TAG, "LastAuthState: nothing to do"); - } - if (mLastAuthScope != null) { - authState.setAuthScope(mLastAuthScope); - Log.d(TAG, "LastAuthScope: restored"); - } else { - Log.d(TAG, "LastAuthScope: nothing to do"); - } - } else { - //AuthState and AuthScope have to be saved separate because of the AuthScope within AuthState gets lost, so we save it in a separate var. - mLastAuthState = authState; - Log.d(TAG, "LastAuthState: new with user " + mLastAuthState.getCredentials().getUserPrincipal().getName()); - if (authState.getAuthScope() != null) { - mLastAuthScope = authState.getAuthScope(); - Log.d(TAG, "LastAuthScope: new"); - } - } - } - }; + this.mTrustAll = Boolean.valueOf(trustAll); - public enum TestConnectionResult { - WRONG_CREDENTIAL, - WRONG_URL, - WRONG_SERVER_STATUS, - WRONG_ANSWER, - SUCCESS - } + httpClient = getHttpClient(); + UsernamePasswordCredentials upc = new UsernamePasswordCredentials(mUser, mPassword); - /** - * TODO: testConnection should return only an instance of - * TestConnectionResult without throwing an exception or only throw checked - * exceptions so you don't have to check the result of this function AND - * handle the exceptions - * @param context - * - * @return {@link TestConnectionResult} - * @throws HttpHostConnectException - * @throws IOException - * @throws URISyntaxException - * @throws ParserConfigurationException - * @throws SAXException - */ - public TestConnectionResult testConnection() throws HttpHostConnectException, IOException, URISyntaxException, ParserConfigurationException, SAXException { - Log.d(TAG, "start testConnection "); - try { - List calendars = new ArrayList(); - calendars = forceGetCalendarsFromUri(null, url.toURI()); - if (calendars.size() != 0) { - return TestConnectionResult.SUCCESS; - } + AuthScope as = null; + as = new AuthScope(url.getHost(), -1); + ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials(as, upc); - URI userPrincipal = getUserPrincipal(); - List calendarSets = getCalendarHomes(userPrincipal); - for (URI calendarSet : calendarSets) { - List calendarSetCalendars = getCalendarsFromSet(calendarSet); - calendars.addAll(calendarSetCalendars); - } - if (calendarSets.size() == 0) { - return TestConnectionResult.WRONG_ANSWER; - } - } catch (FileNotFoundException e) { - return TestConnectionResult.WRONG_URL; - } catch (SocketException e) { - return TestConnectionResult.WRONG_URL; - } catch (AuthenticationException e) { - return TestConnectionResult.WRONG_CREDENTIAL; - } catch (ClientProtocolException e) { - return TestConnectionResult.WRONG_SERVER_STATUS; - } catch (CaldavProtocolException e) { - return TestConnectionResult.WRONG_ANSWER; - } - return TestConnectionResult.SUCCESS; - } + mContext = new BasicHttpContext(); + CredentialsProvider credProvider = ((AbstractHttpClient) httpClient).getCredentialsProvider(); + mContext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider); - /** - * @param context May be null if no notification is needed - * @param uri - * @return - * @throws AuthenticationException - * @throws FileNotFoundException - */ - private List forceGetCalendarsFromUri(Context context, URI uri) throws AuthenticationException, FileNotFoundException { - List calendars = new ArrayList(); - Exception exception = null; - try { - calendars = getCalendarsFromSet(uri); - } catch (ClientProtocolException e) { - if (context != null) { - NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); - //NotificationsHelper.getCurrentSyncLog().addException(e); - } - exception = e; - } catch (FileNotFoundException e) { - if (context != null) { - NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); - //NotificationsHelper.getCurrentSyncLog().addException(e); - } - throw e; - } catch (IOException e) { - if (context != null) { - NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); - //NotificationsHelper.getCurrentSyncLog().addException(e); - } - exception = e; - } catch (CaldavProtocolException e) { + //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html + ((AbstractHttpClient) httpClient).addRequestInterceptor(preemptiveAuth, 0); - if (context != null) { - NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); - //NotificationsHelper.getCurrentSyncLog().addException(e); - } - exception = e; - } - if (exception != null && BuildConfig.DEBUG) { - Log.e(TAG, "Force get calendars from '" + uri.toString() - + "' failed " + exception.getClass().getCanonicalName() - + ": " + exception.getMessage()); - } - return calendars; - } + String proto = "http"; + int port = 80; - private final static String PROPFIND_USER_PRINCIPAL = XML_VERSION + - "" + - "" + - "" + - "" + - "" + - ""; - - private URI getUserPrincipal() throws SocketException, - ClientProtocolException, AuthenticationException, - FileNotFoundException, IOException, CaldavProtocolException, - URISyntaxException { - URI uri = this.url.toURI(); - HttpPropFind request = createPropFindRequest(uri, - PROPFIND_USER_PRINCIPAL, 0); - HttpResponse response = httpClient.execute(targetHost, request, mContext); - checkStatus(response); - ServerInfoHandler serverInfoHandler = new ServerInfoHandler(); - parseXML(response, serverInfoHandler); - String userPrincipal = null; - if (serverInfoHandler.currentUserPrincipal != null) { - userPrincipal = serverInfoHandler.currentUserPrincipal; - } else if (serverInfoHandler.principalUrl != null) { - userPrincipal = serverInfoHandler.principalUrl; - } else { - throw new CaldavProtocolException("no principal url found"); - } - try { - URI userPrincipalUri = new URI(userPrincipal); - userPrincipalUri = uri.resolve(userPrincipalUri); - if (BuildConfig.DEBUG) { - Log.d(TAG, - "Found userPrincipal: " + userPrincipalUri.toString()); - } - return userPrincipalUri; - } catch (URISyntaxException e) { - throw new CaldavProtocolException("principal url '" + userPrincipal - + "' malformed"); - } - } + if (url.getProtocol().equalsIgnoreCase("https")) { + proto = "https"; + if (url.getPort() == -1) + port = 443; + else + port = url.getPort(); + } - private final static String PROPFIND_CALENDAR_HOME_SET = XML_VERSION - + ""; + if (url.getProtocol().equalsIgnoreCase("http")) { + proto = "http"; + if (url.getPort() == -1) + port = 80; + else + port = url.getPort(); + } + targetHost = new HttpHost(url.getHost(), port, proto); + } - private List getCalendarHomes(URI userPrincipal) - throws ClientProtocolException, IOException, - AuthenticationException, FileNotFoundException, - CaldavProtocolException { - HttpPropFind request = createPropFindRequest(userPrincipal, - PROPFIND_CALENDAR_HOME_SET, 0); - HttpResponse response = httpClient.execute(targetHost, request, mContext); - checkStatus(response); - CalendarHomeHandler calendarHomeHandler = new CalendarHomeHandler( - userPrincipal); - parseXML(response, calendarHomeHandler); - List result = calendarHomeHandler.calendarHomeSet; - if (BuildConfig.DEBUG) { - Log.d(TAG, result.size() + " calendar-home-set found in " - + userPrincipal.toString()); - } - return result; - } + //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html + HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() { + @Override + public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { + AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); - private final static String PROPFIND_CALENDER_LIST = XML_VERSION - + "" - + "" - // + - // "" - // + - // " - + "" - //" - + ""; + if (authState.getAuthScheme() == null) { + if (mLastAuthState != null) { + Log.d(TAG, "LastAuthState: restored with user " + mLastAuthState.getCredentials() + .getUserPrincipal() + .getName()); + authState.setAuthScheme(mLastAuthState.getAuthScheme()); + authState.setCredentials(mLastAuthState.getCredentials()); + } else { + Log.d(TAG, "LastAuthState: nothing to do"); + } + if (mLastAuthScope != null) { + authState.setAuthScope(mLastAuthScope); + Log.d(TAG, "LastAuthScope: restored"); + } else { + Log.d(TAG, "LastAuthScope: nothing to do"); + } + } else { + //AuthState and AuthScope have to be saved separate because of the AuthScope within AuthState gets lost, so we save it in a separate var. + mLastAuthState = authState; + Log.d(TAG, "LastAuthState: new with user " + mLastAuthState.getCredentials() + .getUserPrincipal() + .getName()); + if (authState.getAuthScope() != null) { + mLastAuthScope = authState.getAuthScope(); + Log.d(TAG, "LastAuthScope: new"); + } + } + } + }; - - private List getCalendarsFromSet(URI calendarSet) - throws ClientProtocolException, IOException, - CaldavProtocolException, AuthenticationException, - FileNotFoundException { - HttpPropFind request = createPropFindRequest(calendarSet, PROPFIND_CALENDER_LIST, 1); - HttpResponse response = httpClient.execute(targetHost, request, mContext); - checkStatus(response); - CalendarsHandler calendarsHandler = new CalendarsHandler(calendarSet); - parseXML(response, calendarsHandler); - List result = calendarsHandler.calendars; - if (BuildConfig.DEBUG) { - Log.i(TAG, - result.size() + " calendars found in set " - + calendarSet.toString()); - } - return result; - } - - /** - * Discover CalDAV Calendars Mentioned in - * http://tools.ietf.org/html/draft-daboo-srv-caldav-10#section-6 and - * http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Discovery - *
    - *
  1. PROPFIND calendar-home-set on url - *
  2. PROPFIND DAV:current-user-principal or principal-URL on url - *
  3. PROPFIND calendar-home-set on current-user-principal or principal-URL - *
  4. PROPFIND displayname, resourcetype, getctag on CalendarHomeSets - *
- * @param context - * - * @return List of {@link DavCalendar} - * @throws ClientProtocolException - * http protocol error - * @throws IOException - * Connection lost - * @throws URISyntaxException - * url in Constructor malformed - * @throws CaldavProtocolException - * caldav protocol error - */ - //public Iterable getCalendarList(Context context) throws ClientProtocolException, - public CalendarList getCalendarList(Context context) throws ClientProtocolException, - IOException, URISyntaxException, ParserConfigurationException, - CaldavProtocolException { - try { - CalendarList Result = new CalendarList(this.mAccount, this.mProvider, CalendarSource.CalDAV, this.url.toString()); - List calendars = new ArrayList(); - - calendars = forceGetCalendarsFromUri(context, this.url.toURI()); - - if (calendars.size() == 0) { - // no calendars found, try the home-set - URI userPrincipal = getUserPrincipal(); - List calendarSets = getCalendarHomes(userPrincipal); - for (URI calendarSet : calendarSets) { - List calendarSetCalendars = getCalendarsFromSet(calendarSet); - calendars.addAll(calendarSetCalendars); - } - } - for (DavCalendar cal : calendars) { - Result.addCalendar(cal); - } - - //return calendars; - return Result; - } catch (AuthenticationException e) { - throw new IOException(e); - } - } + public enum TestConnectionResult { + WRONG_CREDENTIAL, + WRONG_URL, + WRONG_SERVER_STATUS, + WRONG_ANSWER, + SSL_ERROR, + SUCCESS + } - //public Iterable getCalendarEvents(DavCalendar calendar) - public ArrayList getCalendarEvents(DavCalendar calendar) - throws URISyntaxException, ClientProtocolException, IOException, - ParserConfigurationException, SAXException { + /** + * TODO: testConnection should return only an instance of + * TestConnectionResult without throwing an exception or only throw checked + * exceptions so you don't have to check the result of this function AND + * handle the exceptions + * + * @return {@link TestConnectionResult} + * @throws HttpHostConnectException + * @throws IOException + * @throws URISyntaxException + * @throws ParserConfigurationException + * @throws SAXException + */ + public TestConnectionResult testConnection() throws IOException, URISyntaxException, ParserConfigurationException, SAXException { + Log.d(TAG, "start testConnection "); + try { + List calendars = new ArrayList(); + calendars = forceGetCalendarsFromUri(null, url.toURI()); + if (calendars.size() != 0) { + return TestConnectionResult.SUCCESS; + } - ArrayList calendarEventList = new ArrayList(); + URI userPrincipal = getUserPrincipal(); + List calendarSets = getCalendarHomes(userPrincipal); + for (URI calendarSet : calendarSets) { + List calendarSetCalendars = getCalendarsFromSet(calendarSet); + calendars.addAll(calendarSetCalendars); + } + if (calendarSets.size() == 0) { + return TestConnectionResult.WRONG_ANSWER; + } + } catch (FileNotFoundException e) { + return TestConnectionResult.WRONG_URL; + } catch (SSLException e) { + return TestConnectionResult.SSL_ERROR; + } catch (SocketException e) { + return TestConnectionResult.WRONG_URL; + } catch (AuthenticationException e) { + return TestConnectionResult.WRONG_CREDENTIAL; + } catch (ClientProtocolException e) { + return TestConnectionResult.WRONG_SERVER_STATUS; + } catch (CaldavProtocolException e) { + return TestConnectionResult.WRONG_ANSWER; + } + return TestConnectionResult.SUCCESS; + } - String requestBody = "" - + "" + "" + "" - + "" + ""; + /** + * @param context May be null if no notification is needed + * @param uri + * @return + * @throws AuthenticationException + * @throws FileNotFoundException + */ + private List forceGetCalendarsFromUri(Context context, URI uri) throws AuthenticationException, FileNotFoundException { + List calendars = new ArrayList(); + Exception exception = null; + try { + calendars = getCalendarsFromSet(uri); + } catch (ClientProtocolException e) { + if (context != null) { + NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); + //NotificationsHelper.getCurrentSyncLog().addException(e); + } + exception = e; + } catch (FileNotFoundException e) { + if (context != null) { + NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); + //NotificationsHelper.getCurrentSyncLog().addException(e); + } + throw e; + } catch (IOException e) { + if (context != null) { + NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); + //NotificationsHelper.getCurrentSyncLog().addException(e); + } + exception = e; + } catch (CaldavProtocolException e) { - HttpPropFind request = null; - - String EventUri; + if (context != null) { + NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); + //NotificationsHelper.getCurrentSyncLog().addException(e); + } + exception = e; + } + if (exception != null && BuildConfig.DEBUG) { + Log.e(TAG, "Force get calendars from '" + uri.toString() + + "' failed " + exception.getClass().getCanonicalName() + + ": " + exception.getMessage()); + } + return calendars; + } + + private final static String PROPFIND_USER_PRINCIPAL = XML_VERSION + + "" + + "" + + "" + + "" + + "" + + ""; + + private URI getUserPrincipal() throws + AuthenticationException, + IOException, CaldavProtocolException, + URISyntaxException { + URI uri = this.url.toURI(); + HttpPropFind request = createPropFindRequest(uri, + PROPFIND_USER_PRINCIPAL, 0); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + checkStatus(response); + ServerInfoHandler serverInfoHandler = new ServerInfoHandler(); + parseXML(response, serverInfoHandler); + String userPrincipal = null; + if (serverInfoHandler.currentUserPrincipal != null) { + userPrincipal = serverInfoHandler.currentUserPrincipal; + } else if (serverInfoHandler.principalUrl != null) { + userPrincipal = serverInfoHandler.principalUrl; + } else { + throw new CaldavProtocolException("no principal url found"); + } + try { + URI userPrincipalUri = new URI(userPrincipal); + userPrincipalUri = uri.resolve(userPrincipalUri); + if (BuildConfig.DEBUG) { + Log.d(TAG, + "Found userPrincipal: " + userPrincipalUri.toString()); + } + return userPrincipalUri; + } catch (URISyntaxException e) { + throw new CaldavProtocolException("principal url '" + userPrincipal + + "' malformed"); + } + } + + private final static String PROPFIND_CALENDAR_HOME_SET = XML_VERSION + + ""; + + private List getCalendarHomes(URI userPrincipal) + throws ClientProtocolException, IOException, + AuthenticationException, FileNotFoundException, + CaldavProtocolException { + HttpPropFind request = createPropFindRequest(userPrincipal, + PROPFIND_CALENDAR_HOME_SET, 0); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + checkStatus(response); + CalendarHomeHandler calendarHomeHandler = new CalendarHomeHandler( + userPrincipal); + parseXML(response, calendarHomeHandler); + List result = calendarHomeHandler.calendarHomeSet; + if (BuildConfig.DEBUG) { + Log.d(TAG, result.size() + " calendar-home-set found in " + + userPrincipal.toString()); + } + return result; + } + + private final static String PROPFIND_CALENDER_LIST = XML_VERSION + + "" + + "" + // + + // "" + // + + // " + + "" + //" + + ""; + + + private List getCalendarsFromSet(URI calendarSet) + throws ClientProtocolException, IOException, + CaldavProtocolException, AuthenticationException, + FileNotFoundException { + HttpPropFind request = createPropFindRequest(calendarSet, PROPFIND_CALENDER_LIST, 1); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + checkStatus(response); + CalendarsHandler calendarsHandler = new CalendarsHandler(calendarSet); + parseXML(response, calendarsHandler); + List result = calendarsHandler.calendars; + if (BuildConfig.DEBUG) { + Log.i(TAG, + result.size() + " calendars found in set " + + calendarSet.toString() + ); + } + return result; + } + + /** + * Discover CalDAV Calendars Mentioned in + * http://tools.ietf.org/html/draft-daboo-srv-caldav-10#section-6 and + * http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Discovery + *
    + *
  1. PROPFIND calendar-home-set on url + *
  2. PROPFIND DAV:current-user-principal or principal-URL on url + *
  3. PROPFIND calendar-home-set on current-user-principal or principal-URL + *
  4. PROPFIND displayname, resourcetype, getctag on CalendarHomeSets + *
+ * + * @param context + * @return List of {@link DavCalendar} + * @throws ClientProtocolException http protocol error + * @throws IOException Connection lost + * @throws URISyntaxException url in Constructor malformed + * @throws CaldavProtocolException caldav protocol error + */ + //public Iterable getCalendarList(Context context) throws ClientProtocolException, + public CalendarList getCalendarList(Context context) throws ClientProtocolException, + IOException, URISyntaxException, ParserConfigurationException, + CaldavProtocolException { + try { + CalendarList Result = new CalendarList(this.mAccount, this.mProvider, CalendarSource.CalDAV, this.url + .toString()); + List calendars = new ArrayList(); + + calendars = forceGetCalendarsFromUri(context, this.url.toURI()); + + if (calendars.size() == 0) { + // no calendars found, try the home-set + URI userPrincipal = getUserPrincipal(); + List calendarSets = getCalendarHomes(userPrincipal); + for (URI calendarSet : calendarSets) { + List calendarSetCalendars = getCalendarsFromSet(calendarSet); + calendars.addAll(calendarSetCalendars); + } + } + for (DavCalendar cal : calendars) { + Result.addCalendar(cal); + } + + //return calendars; + return Result; + } catch (AuthenticationException e) { + throw new IOException(e); + } + } + + //public Iterable getCalendarEvents(DavCalendar calendar) + public ArrayList getCalendarEvents(DavCalendar calendar) + throws URISyntaxException, ClientProtocolException, IOException, + ParserConfigurationException, SAXException { + + ArrayList calendarEventList = new ArrayList(); + + String requestBody = "" + + "" + "" + "" + + "" + ""; + + HttpPropFind request = null; + + String EventUri; /*request = new HttpPropFind(); - request.setURI(calendar.getURI()); + request.setURI(calendar.getURI()); request.setHeader("Host", targetHost.getHostName()); request.setHeader("Depth", "1"); request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); @@ -487,380 +494,358 @@ } catch (UnsupportedEncodingException e) { throw new AssertionError("UTF-8 is unknown"); }*/ - request = this.createPropFindRequest(calendar.getURI(), requestBody, 1); - - Log.d(TAG, "Getting eTag by PROPFIND at " + request.getURI()); + request = this.createPropFindRequest(calendar.getURI(), requestBody, 1); - HttpResponse response = httpClient.execute(targetHost, request, mContext); + Log.d(TAG, "Getting eTag by PROPFIND at " + request.getURI()); - BufferedReader reader = new BufferedReader(new InputStreamReader( - response.getEntity().getContent(), "UTF-8")); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + String body = EntityUtils.toString(response.getEntity(), "UTF-8"); - String line; - String body = ""; - do { - line = reader.readLine(); - if (line != null) - body += line; - } while (line != null); + Log.d(TAG, "HttpResponse status=" + response.getStatusLine() + + " body= " + body); - Log.d(TAG, "HttpResponse status=" + response.getStatusLine() - + " body= " + body); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document dom = builder.parse(new InputSource(new ByteArrayInputStream( + body.getBytes("utf-8")))); + Element root = dom.getDocumentElement(); + NodeList items = root.getElementsByTagNameNS("*", "getetag"); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document dom = builder.parse(new InputSource(new ByteArrayInputStream( - body.getBytes("utf-8")))); - Element root = dom.getDocumentElement(); - NodeList items = root.getElementsByTagNameNS("*", "getetag"); + for (int i = 0; i < items.getLength(); i++) { + CalendarEvent calendarEvent = new CalendarEvent(this.mAccount, this.mProvider); - for (int i = 0; i < items.getLength(); i++) { - CalendarEvent calendarEvent = new CalendarEvent(this.mAccount, this.mProvider); + Node node = items.item(i); - Node node = items.item(i); + if (node.getTextContent().trim().length() == 0) + continue; // not an event - if (node.getTextContent().trim().length() == 0) - continue; // not an event + calendarEvent.setETag(node.getTextContent().trim()); + //calendarEvent.calendarURL = this.url; + calendarEvent.calendarURL = calendar.getURI().toURL(); - calendarEvent.setETag(node.getTextContent().trim()); - //calendarEvent.calendarURL = this.url; - calendarEvent.calendarURL = calendar.getURI().toURL(); + node = node.getParentNode(); // prop + node = node.getParentNode(); // propstat + node = node.getParentNode(); // response - node = node.getParentNode(); // prop - node = node.getParentNode(); // propstat - node = node.getParentNode(); // response + NodeList children = node.getChildNodes(); + for (int j = 0; j < children.getLength(); j++) { + Node childNode = children.item(j); + if ((childNode.getLocalName() != null) && (childNode.getLocalName() + .equalsIgnoreCase("href"))) { + EventUri = childNode.getTextContent().trim(); + //HINT: bugfix for zimbra calendar: replace("@", "%40") + EventUri = EventUri.replace("@", "%40"); + calendarEvent.setUri(new URI(EventUri)); + } + } - NodeList children = node.getChildNodes(); - for (int j = 0; j < children.getLength(); j++) { - Node childNode = children.item(j); - if ((childNode.getLocalName()!=null) && (childNode.getLocalName().equalsIgnoreCase("href"))) { - EventUri = childNode.getTextContent().trim(); - //HINT: bugfix for zimbra calendar: replace("@", "%40") - EventUri = EventUri.replace("@", "%40"); - calendarEvent.setUri(new URI(EventUri)); - } - } + calendarEventList.add(calendarEvent); - calendarEventList.add(calendarEvent); + } - } + return calendarEventList; + } - return calendarEventList; - } - - private void parseXML(HttpResponse response, ContentHandler contentHandler) - throws IOException, CaldavProtocolException { - InputStream is = response.getEntity().getContent(); - /*BufferedReader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8")); - String Content = ""; + private void parseXML(HttpResponse response, ContentHandler contentHandler) + throws IOException, CaldavProtocolException { + InputStream is = response.getEntity().getContent(); + /*BufferedReader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String Content = ""; String Line = bReader.readLine(); while (Line != null) { Content += Line; Line = bReader.readLine(); }*/ - - SAXParserFactory factory = SAXParserFactory.newInstance(); - try { - SAXParser parser = factory.newSAXParser(); - XMLReader reader = parser.getXMLReader(); - reader.setContentHandler(contentHandler); - reader.parse(new InputSource(is)); - } catch (ParserConfigurationException e) { - throw new AssertionError("ParserConfigurationException " - + e.getMessage()); - } catch (IllegalStateException e) { - throw new CaldavProtocolException(e.getMessage()); - } catch (SAXException e) { - throw new CaldavProtocolException(e.getMessage()); - } - } - private void checkStatus(HttpResponse response) - throws AuthenticationException, FileNotFoundException, - ClientProtocolException { - final int statusCode = response.getStatusLine().getStatusCode(); - lastStatusCode = statusCode; - if (response.containsHeader("ETag")) - lastETag = response.getFirstHeader("ETag").getValue(); - else - lastETag = ""; - if (response.containsHeader("DAV")) - lastDav = response.getFirstHeader("DAV").getValue(); - else - lastDav = ""; - - switch (statusCode) { - case 401: - throw new AuthenticationException(); - case 404: - throw new FileNotFoundException(); - case 409: //Conflict - case 412: - case 200: - case 201: - case 204: - case 207: - return; - default: - throw new ClientProtocolException("StatusCode: " + statusCode); - } - } + SAXParserFactory factory = SAXParserFactory.newInstance(); + try { + SAXParser parser = factory.newSAXParser(); + XMLReader reader = parser.getXMLReader(); + reader.setContentHandler(contentHandler); + reader.parse(new InputSource(is)); + } catch (ParserConfigurationException e) { + throw new AssertionError("ParserConfigurationException " + + e.getMessage()); + } catch (IllegalStateException e) { + throw new CaldavProtocolException(e.getMessage()); + } catch (SAXException e) { + throw new CaldavProtocolException(e.getMessage()); + } + } - private HttpPropFind createPropFindRequest(URI uri, String data, int depth) { - HttpPropFind request = new HttpPropFind(); + private void checkStatus(HttpResponse response) + throws AuthenticationException, FileNotFoundException, + ClientProtocolException { + final int statusCode = response.getStatusLine().getStatusCode(); + lastStatusCode = statusCode; + if (response.containsHeader("ETag")) + lastETag = response.getFirstHeader("ETag").getValue(); + else + lastETag = ""; + if (response.containsHeader("DAV")) + lastDav = response.getFirstHeader("DAV").getValue(); + else + lastDav = ""; - request.setURI(uri); - //request.setHeader("Host", targetHost.getHostName()); - request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); - request.setHeader("Depth", Integer.toString(depth)); - request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); - try { - request.setEntity(new StringEntity(data, "UTF-8")); - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 is unknown"); - } - return request; - } - - private HttpDelete createDeleteRequest(URI uri) { - HttpDelete request = new HttpDelete(); - request.setURI(uri); - //request.setHeader("Host", targetHost.getHostName()); - request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); - request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); - return request; - } + switch (statusCode) { + case 401: + throw new AuthenticationException(); + case 404: + throw new FileNotFoundException(); + case 409: //Conflict + case 412: + case 200: + case 201: + case 204: + case 207: + return; + default: + throw new ClientProtocolException("StatusCode: " + statusCode); + } + } - private HttpPut createPutRequest(URI uri, String data, int depth) { - HttpPut request = new HttpPut(); - request.setURI(uri); - //request.setHeader("Host", targetHost.getHostName()); - request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); - //request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); - request.setHeader("Content-Type", "text/calendar; charset=UTF-8"); - try { - request.setEntity(new StringEntity(data, "UTF-8")); - //request.setEntity(new StringEntity(data)); - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 is unknown"); - } - return request; - } - - private static HttpReport createReportRequest(URI uri, String data, int depth) { - HttpReport request = new HttpReport(); - request.setURI(uri); - //request.setHeader("Host", targetHost.getHostName()); - request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); - request.setHeader("Depth", Integer.toString(depth)); - request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); - //request.setHeader("Content-Type", "text/xml;charset=\"UTF-8\""); - try { - request.setEntity(new StringEntity(data)); - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 is unknown"); - } - return request; - } - - public static void fetchEvent_old(CalendarEvent calendarEvent) - throws ClientProtocolException, IOException { - HttpGet request = null; + private HttpPropFind createPropFindRequest(URI uri, String data, int depth) { + HttpPropFind request = new HttpPropFind(); - request = new HttpGet(); - request.setURI(calendarEvent.getUri()); - request.setHeader("Host", targetHost.getHostName()); - request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); + request.setURI(uri); + //request.setHeader("Host", targetHost.getHostName()); + request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); + request.setHeader("Depth", Integer.toString(depth)); + request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); + try { + request.setEntity(new StringEntity(data, "UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new AssertionError("UTF-8 is unknown"); + } + return request; + } - HttpResponse response = httpClient.execute(targetHost, request); + private HttpDelete createDeleteRequest(URI uri) { + HttpDelete request = new HttpDelete(); + request.setURI(uri); + //request.setHeader("Host", targetHost.getHostName()); + request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); + request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); + return request; + } - BufferedReader reader = new BufferedReader(new InputStreamReader( - response.getEntity().getContent(), "UTF-8")); + private HttpPut createPutRequest(URI uri, String data, int depth) { + HttpPut request = new HttpPut(); + request.setURI(uri); + //request.setHeader("Host", targetHost.getHostName()); + request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); + //request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); + request.setHeader("Content-Type", "text/calendar; charset=UTF-8"); + try { + request.setEntity(new StringEntity(data, "UTF-8")); + //request.setEntity(new StringEntity(data)); + } catch (UnsupportedEncodingException e) { + throw new AssertionError("UTF-8 is unknown"); + } + return request; + } - String line; - String body = ""; - do { - line = reader.readLine(); - if (line != null) - body += line + "\n"; - } while (line != null); + private static HttpReport createReportRequest(URI uri, String data, int depth) { + HttpReport request = new HttpReport(); + request.setURI(uri); + //request.setHeader("Host", targetHost.getHostName()); + request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); + request.setHeader("Depth", Integer.toString(depth)); + request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); + //request.setHeader("Content-Type", "text/xml;charset=\"UTF-8\""); + try { + request.setEntity(new StringEntity(data)); + } catch (UnsupportedEncodingException e) { + throw new AssertionError("UTF-8 is unknown"); + } + return request; + } - calendarEvent.setICSasString(body); + public static void fetchEvent_old(CalendarEvent calendarEvent) + throws ClientProtocolException, IOException { + HttpGet request = null; - Log.d(TAG, "HttpResponse GET event status=" + response.getStatusLine() - + " body= " + body); - } - - public static boolean getEvent(CalendarEvent calendarEvent) throws ClientProtocolException, IOException { - boolean Result = false; - HttpReport request = null; + request = new HttpGet(); + request.setURI(calendarEvent.getUri()); + request.setHeader("Host", targetHost.getHostName()); + request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); - //HINT: bugfix for google calendar: replace("@", "%40") - String data = XML_VERSION + - "" + - "" + - "" + - "" + - "" + - "" + calendarEvent.getUri().getRawPath().replace("@", "%40") + "" + - ""; + HttpResponse response = httpClient.execute(targetHost, request); + String body = EntityUtils.toString(response.getEntity(), "UTF-8"); - URI calendarURI = null; - try { - calendarURI = calendarEvent.calendarURL.toURI(); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - //request = createReportRequest(calendarEvent.getUri(), data, 1); - request = createReportRequest(calendarURI, data, 1); + calendarEvent.setICSasString(body); - HttpResponse response = httpClient.execute(targetHost, request); + Log.d(TAG, "HttpResponse GET event status=" + response.getStatusLine() + + " body= " + body); + } - BufferedReader reader = new BufferedReader(new InputStreamReader( - response.getEntity().getContent(), "UTF-8")); + public static boolean getEvent(CalendarEvent calendarEvent) throws ClientProtocolException, IOException { + boolean Result = false; + HttpReport request = null; - String line; - String body = ""; - do { - line = reader.readLine(); - if (line != null) - body += line + "\n"; - } while (line != null); + //HINT: bugfix for google calendar: replace("@", "%40") + String data = XML_VERSION + + "" + + "" + + "" + + "" + + "" + + "" + calendarEvent.getUri().getRawPath().replace("@", "%40") + "" + + ""; - if (calendarEvent.setICSasMultiStatus(body)) - Result = true; + URI calendarURI = null; + try { + calendarURI = calendarEvent.calendarURL.toURI(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + //request = createReportRequest(calendarEvent.getUri(), data, 1); + request = createReportRequest(calendarURI, data, 1); - return Result; - } - - - /** - * sends a update event request to the server - * @param uri the full URI of the event on server side. example: http://caldav.example.com/principal/user/calendar/e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter.ics - * @param data the full ical-data for the event - * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to update this version - * @return - */ - public boolean updateEvent(URI uri, String data, String ETag) { - boolean Result = false; - - try { - HttpPut request = createPutRequest(uri, data, 1); - request.addHeader(mstrcHeaderIfMatch, ETag); - HttpResponse response = httpClient.execute(targetHost, request, mContext); - checkStatus(response); - if ((lastStatusCode == 200) || (lastStatusCode == 201) || (lastStatusCode == 204)) { - Result = true; - } else if (lastStatusCode == 412) { - //Precondition failed - Result = false; - } else if (lastStatusCode == 409) { - //Conflict - Result = false; - } else { - Log.w(TAG, "Unkown StatusCode during creation of an event"); - } - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (AuthenticationException e) { - e.printStackTrace(); - } - return Result; - } - - /** - * sends a create event request to server - * @param uri the full URI of the new event on server side. example: http://caldav.example.com/principal/user/calendar/e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter.ics - * @param data the full ical-data for the new event - * @return success of this function - */ - public boolean createEvent(URI uri, String data) { - boolean Result = false; - - try { - HttpPut request = createPutRequest(uri, data, 1); - request.addHeader(mstrcHeaderIfNoneMatch, "*"); - HttpResponse response = httpClient.execute(targetHost, request, mContext); - checkStatus(response); - if (lastStatusCode == 201) { - Result = true; - } else { - Log.w(TAG, "Unkown StatusCode during creation of an event"); - } - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (AuthenticationException e) { - e.printStackTrace(); - } - return Result; - } - - /** - * sends a delete event request to the server - * @param calendarEventUri the full URI of the event on server side. example: http://caldav.example.com/principal/user/calendar/e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter.ics - * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to delete this version - * @return success of this function - */ - public boolean deleteEvent(URI calendarEventUri, String ETag) { - boolean Result = false; - - try { - HttpDelete request = createDeleteRequest(calendarEventUri); - request.addHeader(mstrcHeaderIfMatch, ETag); - HttpResponse response = httpClient.execute(targetHost, request, mContext); - checkStatus(response); - if ((lastStatusCode == 204) || (lastStatusCode == 200)) { - Result = true; - } else { - Log.w(TAG, "Unkown StatusCode during deletion of an event"); - } - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - if (lastStatusCode == 404) { - //the event has already been deleted on server side. no action needed - Result = true; - } else { - e.printStackTrace(); - } - } catch (AuthenticationException e) { - e.printStackTrace(); - } - - return Result; - } - - /** - * returns the ETAG send by the last server response. - * @return the ETAG - */ - public String getLastETag() { - return lastETag; - } - - /** - * returns the DAV-Options send by the last server response. - * @return the DAV-Options - */ - public String getLastDav() { - return lastDav; - } - - public void setVersion(String version) { - VERSION = version; - ((AbstractHttpClient) httpClient).getParams().setParameter(CoreProtocolPNames.USER_AGENT, this.USER_AGENT + " Version:" + VERSION); - } - - public void setAccount(Account account) { - this.mAccount = account; - } - public void setProvider(ContentProviderClient provider) { - this.mProvider = provider; - } -} \ No newline at end of file + HttpResponse response = httpClient.execute(targetHost, request); + String body = EntityUtils.toString(response.getEntity(), "UTF-8"); + + if (calendarEvent.setICSasMultiStatus(body)) + Result = true; + + return Result; + } + + + /** + * sends a update event request to the server + * + * @param uri the full URI of the event on server side. example: http://caldav.example.com/principal/user/calendar/e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter.ics + * @param data the full ical-data for the event + * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to update this version + * @return + */ + public boolean updateEvent(URI uri, String data, String ETag) { + boolean Result = false; + + try { + HttpPut request = createPutRequest(uri, data, 1); + request.addHeader(mstrcHeaderIfMatch, ETag); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + checkStatus(response); + if ((lastStatusCode == 200) || (lastStatusCode == 201) || (lastStatusCode == 204)) { + Result = true; + } else if (lastStatusCode == 412) { + //Precondition failed + Result = false; + } else if (lastStatusCode == 409) { + //Conflict + Result = false; + } else { + Log.w(TAG, "Unkown StatusCode during creation of an event"); + } + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (AuthenticationException e) { + e.printStackTrace(); + } + return Result; + } + + /** + * sends a create event request to server + * + * @param uri the full URI of the new event on server side. example: http://caldav.example.com/principal/user/calendar/e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter.ics + * @param data the full ical-data for the new event + * @return success of this function + */ + public boolean createEvent(URI uri, String data) { + boolean Result = false; + + try { + HttpPut request = createPutRequest(uri, data, 1); + request.addHeader(mstrcHeaderIfNoneMatch, "*"); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + checkStatus(response); + if (lastStatusCode == 201) { + Result = true; + } else { + Log.w(TAG, "Unkown StatusCode during creation of an event"); + } + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (AuthenticationException e) { + e.printStackTrace(); + } + return Result; + } + + /** + * sends a delete event request to the server + * + * @param calendarEventUri the full URI of the event on server side. example: http://caldav.example.com/principal/user/calendar/e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter.ics + * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to delete this version + * @return success of this function + */ + public boolean deleteEvent(URI calendarEventUri, String ETag) { + boolean Result = false; + + try { + HttpDelete request = createDeleteRequest(calendarEventUri); + request.addHeader(mstrcHeaderIfMatch, ETag); + HttpResponse response = httpClient.execute(targetHost, request, mContext); + checkStatus(response); + if ((lastStatusCode == 204) || (lastStatusCode == 200)) { + Result = true; + } else { + Log.w(TAG, "Unkown StatusCode during deletion of an event"); + } + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + if (lastStatusCode == 404) { + //the event has already been deleted on server side. no action needed + Result = true; + } else { + e.printStackTrace(); + } + } catch (AuthenticationException e) { + e.printStackTrace(); + } + + return Result; + } + + /** + * returns the ETAG send by the last server response. + * + * @return the ETAG + */ + public String getLastETag() { + return lastETag; + } + + /** + * returns the DAV-Options send by the last server response. + * + * @return the DAV-Options + */ + public String getLastDav() { + return lastDav; + } + + public void setVersion(String version) { + VERSION = version; + ((AbstractHttpClient) httpClient).getParams() + .setParameter(CoreProtocolPNames.USER_AGENT, this.USER_AGENT + " Version:" + VERSION); + } + + public void setAccount(Account account) { + this.mAccount = account; + } + + public void setProvider(ContentProviderClient provider) { + this.mProvider = provider; + } +} diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/caldav/CopyOfEasySSLSocketFactory.java --- a/src/org/gege/caldavsyncadapter/caldav/CopyOfEasySSLSocketFactory.java Tue Feb 10 21:55:00 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/** - * Copyright (c) 2012-2013, Gerald Garcia - * - * This file is part of Andoid Caldav Sync Adapter Free. - * - * Andoid Caldav Sync Adapter Free 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. - * - * Andoid Caldav Sync Adapter Free 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 Andoid Caldav Sync Adapter Free. - * If not, see . - * - */ - -package org.gege.caldavsyncadapter.caldav; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; - -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.scheme.LayeredSocketFactory; -import org.apache.http.conn.scheme.SocketFactory; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; - -/** - * This socket factory will create ssl socket that accepts self signed - * certificate - * - * @author olamy - * @version $Id: EasySSLSocketFactory.java 765355 2009-04-15 20:59:07Z evenisse - * $ - * @since 1.2.3 - */ -public class CopyOfEasySSLSocketFactory implements SocketFactory, - LayeredSocketFactory { - - private SSLContext sslcontext = null; - - private static SSLContext createEasySSLContext() throws IOException { - try { - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, new TrustManager[] { new EasyX509TrustManager( - null) }, null); - return context; - } catch (Exception e) { - throw new IOException(e.getMessage()); - } - } - - private SSLContext getSSLContext() throws IOException { - if (this.sslcontext == null) { - this.sslcontext = createEasySSLContext(); - } - return this.sslcontext; - } - - /** - * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, - * java.lang.String, int, java.net.InetAddress, int, - * org.apache.http.params.HttpParams) - */ - public Socket connectSocket(Socket sock, String host, int port, - InetAddress localAddress, int localPort, HttpParams params) - throws IOException, UnknownHostException, ConnectTimeoutException { - int connTimeout = HttpConnectionParams.getConnectionTimeout(params); - int soTimeout = HttpConnectionParams.getSoTimeout(params); - - InetSocketAddress remoteAddress = new InetSocketAddress(host, port); - SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); - - if ((localAddress != null) || (localPort > 0)) { - // we need to bind explicitly - if (localPort < 0) { - localPort = 0; // indicates "any" - } - InetSocketAddress isa = new InetSocketAddress(localAddress, - localPort); - sslsock.bind(isa); - } - - sslsock.connect(remoteAddress, connTimeout); - sslsock.setSoTimeout(soTimeout); - return sslsock; - - } - - /** - * @see org.apache.http.conn.scheme.SocketFactory#createSocket() - */ - public Socket createSocket() throws IOException { - return getSSLContext().getSocketFactory().createSocket(); - } - - /** - * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket) - */ - public boolean isSecure(Socket socket) throws IllegalArgumentException { - return true; - } - - /** - * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, - * java.lang.String, int, boolean) - */ - public Socket createSocket(Socket socket, String host, int port, - boolean autoClose) throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(); - } - - // ------------------------------------------------------------------- - // javadoc in org.apache.http.conn.scheme.SocketFactory says : - // Both Object.equals() and Object.hashCode() must be overridden - // for the correct operation of some connection managers - // ------------------------------------------------------------------- - - public boolean equals(Object obj) { - return ((obj != null) && obj.getClass().equals( - CopyOfEasySSLSocketFactory.class)); - } - - public int hashCode() { - return CopyOfEasySSLSocketFactory.class.hashCode(); - } - -} \ No newline at end of file diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java --- a/src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java Tue Feb 10 22:40:00 2015 +0100 @@ -54,7 +54,8 @@ private static final EasySSLSocketFactory DEFAULT_FACTORY = new EasySSLSocketFactory(); - public static EasySSLSocketFactory getSocketFactory() { + public static EasySSLSocketFactory getSocketFactory + () { return DEFAULT_FACTORY; } diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java --- a/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java Tue Feb 10 22:40:00 2015 +0100 @@ -1,6 +1,6 @@ /** * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger - * + * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute @@ -16,27 +16,11 @@ * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see . - * + * */ package org.gege.caldavsyncadapter.caldav.entities; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; - -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.http.client.ClientProtocolException; -import org.gege.caldavsyncadapter.CalendarColors; -import org.gege.caldavsyncadapter.Event; -import org.gege.caldavsyncadapter.android.entities.AndroidEvent; -import org.gege.caldavsyncadapter.caldav.CaldavFacade; -import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; -import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; -import org.xml.sax.SAXException; - import android.accounts.Account; import android.content.ContentProviderClient; import android.content.ContentUris; @@ -49,618 +33,674 @@ import android.provider.CalendarContract.Events; import android.util.Log; +import org.apache.http.client.ClientProtocolException; +import org.gege.caldavsyncadapter.CalendarColors; +import org.gege.caldavsyncadapter.Event; +import org.gege.caldavsyncadapter.android.entities.AndroidEvent; +import org.gege.caldavsyncadapter.caldav.CaldavFacade; +import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; +import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.parsers.ParserConfigurationException; + public class DavCalendar { - public enum CalendarSource { - undefined, Android, CalDAV - } - - private static final String TAG = "Calendar"; - - /** - * stores the CTAG of a calendar - */ - public static String CTAG = Calendars.CAL_SYNC1; - - /** - * stores the URI of a calendar - * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname - */ - public static String URI = Calendars._SYNC_ID; - - public static String SERVERURL = Calendars.CAL_SYNC2; - - private String strCalendarColor = ""; - - private ArrayList mNotifyList = new ArrayList(); + public enum CalendarSource { + undefined, Android, CalDAV + } - /** - * the event transformed into ContentValues - */ - public ContentValues ContentValues = new ContentValues(); - - private Account mAccount = null; - private ContentProviderClient mProvider = null; - - public boolean foundServerSide = false; - public boolean foundClientSide = false; - public CalendarSource Source = CalendarSource.undefined; - - public String ServerUrl = ""; - - private ArrayList mCalendarEvents = new ArrayList(); - - private int mTagCounter = 1; - - /** - * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname - */ - public URI getURI() { - String strUri = this.getContentValueAsString(DavCalendar.URI); - URI result = null; - try { - result = new URI(strUri); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - return result; - } + private static final String TAG = "Calendar"; - /** - * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname - */ - public void setURI(URI uri) { - this.setContentValueAsString(DavCalendar.URI, uri.toString()); - } + /** + * stores the CTAG of a calendar + */ + public static String CTAG = Calendars.CAL_SYNC1; - /** - * example: Cleartext Display Name - */ - public String getCalendarDisplayName() { - return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME); - } + /** + * stores the URI of a calendar + * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname + */ + public static String URI = Calendars._SYNC_ID; - /** - * example: Cleartext Display Name - */ - public void setCalendarDisplayName(String displayName) { - this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName); - } - + public static String SERVERURL = Calendars.CAL_SYNC2; - /** - * example: 1143 - */ - public void setCTag(String cTag, boolean Update) { - this.setContentValueAsString(DavCalendar.CTAG, cTag); - if (Update) { - //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); - try { - this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - } - - /** - * example: 1143 - */ - public String getcTag() { - return this.getContentValueAsString(DavCalendar.CTAG); - } - - /** - * example: #FFCCAA - */ - public void setCalendarColorAsString(String color) { - int maxlen = 6; - - this.strCalendarColor = color; - if (!color.equals("")) { - String strColor = color.replace("#", ""); - if (strColor.length() > maxlen) - strColor = strColor.substring(0, maxlen); - int intColor = Integer.parseInt(strColor, 16); - this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor); - } - } + private String strCalendarColor = ""; - /** - * example: #FFCCAA - */ - public String getCalendarColorAsString() { - return this.strCalendarColor; - } + private ArrayList mNotifyList = new ArrayList(); - /** - * example 12345 - */ - public int getCalendarColor() { - return this.getContentValueAsInt(Calendars.CALENDAR_COLOR); - } - - /** - * example 12345 - */ - public void setCalendarColor(int color) { - this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color); - } + /** + * the event transformed into ContentValues + */ + public ContentValues ContentValues = new ContentValues(); - /** - * example: - * should be: calendarname - * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ - */ - public String getCalendarName() { - return this.getContentValueAsString(Calendars.NAME); - } + private Account mAccount = null; + private ContentProviderClient mProvider = null; - /** - * example: - * should be: calendarname - * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ - */ - public void setCalendarName(String calendarName) { - this.setContentValueAsString(Calendars.NAME, calendarName); - } + public boolean foundServerSide = false; + public boolean foundClientSide = false; + public CalendarSource Source = CalendarSource.undefined; - /** - * example: 8 - */ - public int getAndroidCalendarId() { - return this.getContentValueAsInt(Calendars._ID); - } + public String ServerUrl = ""; - /** - * example: 8 - */ - public void setAndroidCalendarId(int androidCalendarId) { - this.setContentValueAsInt(Calendars._ID, androidCalendarId); - } + private ArrayList mCalendarEvents = new ArrayList(); - /** - * example: content://com.android.calendar/calendars/8 - */ - public Uri getAndroidCalendarUri() { - return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId()); - } - - /** - * empty constructor - */ - public DavCalendar(CalendarSource source) { - this.Source = source; - } - - /** - * creates an new instance from a cursor - * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI - */ - public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, CalendarSource source, String serverUrl) { - this.mAccount = account; - this.mProvider = provider; - this.foundClientSide = true; - this.Source = source; - this.ServerUrl = serverUrl; + private int mTagCounter = 1; - String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID)); - String strName = cur.getString(cur.getColumnIndex(Calendars.NAME)); - String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME)); - String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG)); - String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL)); - int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID)); + /** + * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname + */ + public URI getURI() { + String strUri = this.getContentValueAsString(DavCalendar.URI); + URI result = null; + try { + result = new URI(strUri); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return result; + } - this.setCalendarName(strName); - this.setCalendarDisplayName(strDisplayName); - this.setCTag(strCTAG, false); - this.setAndroidCalendarId(intAndroidCalendarId); - - if (strSyncID == null) { - this.correctSyncID(strName); - strSyncID = strName; - } - if (strServerUrl == null) { - this.correctServerUrl(serverUrl); - } - URI uri = null; - try { - uri = new URI(strSyncID); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - this.setURI(uri); - } - - /** - * checks a given list of android calendars for a specific android calendar. - * this calendar should be a server calendar as it is searched for. - * if the calendar is not found, it will be created. - * @param androidCalList the list of android calendars - * @param context - * @return the found android calendar or null of fails - * @throws RemoteException - */ - public Uri checkAndroidCalendarList(CalendarList androidCalList, android.content.Context context) throws RemoteException { - Uri androidCalendarUri = null; - boolean isCalendarExist = false; - - DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI()); - if (androidCalendar != null) { - isCalendarExist = true; - androidCalendar.foundServerSide = true; - } - + /** + * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname + */ + public void setURI(URI uri) { + this.setContentValueAsString(DavCalendar.URI, uri.toString()); + } - if (!isCalendarExist) { - DavCalendar newCal = this.createNewAndroidCalendar(this, androidCalList.getCalendarList().size(), context); - if (newCal != null) { - androidCalList.addCalendar(newCal); - androidCalendarUri = newCal.getAndroidCalendarUri(); - } - } else { - androidCalendarUri = androidCalendar.getAndroidCalendarUri(); - if (!this.getCalendarColorAsString().equals("")) { - //serverCalendar.updateCalendarColor(returnedCalendarUri, serverCalendar); - this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, this.getCalendarColor()); - } - if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) && - (androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) { - String serverDisplayName = this.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); - String clientDisplayName = androidCalendar.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); - if (!serverDisplayName.equals(clientDisplayName)) - this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, serverDisplayName); - } - } - - return androidCalendarUri; - } - - /** - * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI (_SYNC_ID) - * @param calendarUri the real calendarUri - * @return success of this function - */ - private boolean correctSyncID(String calendarUri) { - boolean Result = false; - Log.v(TAG, "correcting SyncID for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); - - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(DavCalendar.URI, calendarUri); - - try { - mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); - Result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - - return Result; - } - - /** - * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98) - * @param serverUrl the current serverurl - * @return success of this function - */ - private boolean correctServerUrl(String serverUrl) { - boolean Result = false; - Log.v(TAG, "correcting ServerUrl for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); - - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(DavCalendar.SERVERURL, serverUrl); - - try { - mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); - Result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - - return Result; - } - - /** - * creates a new androidCalendar - * @param serverCalendar - * @param index - * @param context - * @return the new androidCalendar or null if fails - */ - private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, android.content.Context context) { - Uri newUri = null; - DavCalendar Result = null; - - final ContentValues contentValues = new ContentValues(); - contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString()); - contentValues.put(DavCalendar.SERVERURL, this.ServerUrl); + /** + * example: Cleartext Display Name + */ + public String getCalendarDisplayName() { + return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME); + } - contentValues.put(Calendars.VISIBLE, 1); - contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName()); - contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name); - contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type); - contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name); - contentValues.put(Calendars.SYNC_EVENTS, 1); - contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); - - if (!serverCalendar.getCalendarColorAsString().equals("")) { - contentValues.put(Calendars.CALENDAR_COLOR, serverCalendar.getCalendarColor()); - } else { - // find a color - //int index = mList.size(); - index = index % CalendarColors.colors.length; - contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[index]); - } + /** + * example: Cleartext Display Name + */ + public void setCalendarDisplayName(String displayName) { + this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName); + } - try { - newUri = mProvider.insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), contentValues); - } catch (RemoteException e) { - e.printStackTrace(); - } - // it is possible that this calendar already exists but the provider failed to find it within isCalendarExist() - // the adapter would try to create a new calendar but the provider fails again to create a new calendar. - if (newUri != null) { - long newCalendarId = ContentUris.parseId(newUri); + /** + * example: 1143 + */ + public void setCTag(String cTag, boolean Update) { + this.setContentValueAsString(DavCalendar.CTAG, cTag); + if (Update) { + //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); + try { + this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } - Cursor cur = null; - Uri uri = Calendars.CONTENT_URI; - String selection = "(" + Calendars._ID + " = ?)"; - String[] selectionArgs = new String[] {String.valueOf(newCalendarId)}; + /** + * example: 1143 + */ + public String getcTag() { + return this.getContentValueAsString(DavCalendar.CTAG); + } - // Submit the query and get a Cursor object back. - try { - cur = mProvider.query(uri, null, selection, selectionArgs, null); - } catch (RemoteException e) { - e.printStackTrace(); - } - - if (cur != null) { - while (cur.moveToNext()) { - Result = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl); - Result.foundServerSide = true; - } - cur.close(); - //if (Result != null) - // this.mList.add(Result); - } - Log.i(TAG, "New calendar created : URI=" + Result.getAndroidCalendarUri()); - NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", "new calendar found: " + Result.getCalendarDisplayName()); - mNotifyList.add(Result.getAndroidCalendarUri()); - } - - return Result; - } - - /** - * there is no corresponding calendar on server side. time to delete this calendar on android side. - * @return - */ - public boolean deleteAndroidCalendar() { - boolean Result = false; - - String mSelectionClause = "(" + Calendars._ID + " = ?)"; - int calendarId = this.getAndroidCalendarId(); - String[] mSelectionArgs = {Long.toString(calendarId)}; - - int CountDeleted = 0; - try { - CountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs); - Log.i(TAG,"Calendar deleted: " + String.valueOf(calendarId)); - this.mNotifyList.add(this.getAndroidCalendarUri()); - Result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - Log.d(TAG, "Android Calendars deleted: " + Integer.toString(CountDeleted)); - - return Result; - } + /** + * example: #FFCCAA + */ + public void setCalendarColorAsString(String color) { + int maxlen = 6; - /** - * updates the android calendar - * @param calendarUri the uri of the androidCalendar - * @param target must be from android.provider.CalendarContract.Calendars - * @param value the new value for the target - * @throws RemoteException - */ - private void updateAndroidCalendar(Uri calendarUri, String target, int value) throws RemoteException { - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(target, value); - - mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); - } + this.strCalendarColor = color; + if (!color.equals("")) { + String strColor = color.replace("#", ""); + if (strColor.length() > maxlen) + strColor = strColor.substring(0, maxlen); + int intColor = Integer.parseInt(strColor, 16); + this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor); + } + } - /** - * updates the android calendar - * @param calendarUri the uri of the androidCalendar - * @param target must be from android.provider.CalendarContract.Calendars - * @param value the new value for the target - * @throws RemoteException - */ - private void updateAndroidCalendar(Uri calendarUri, String target, String value) throws RemoteException { - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(target, value); - - mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); - } - - /** - * marks the android event as already handled - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ - public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException { - boolean Result = false; - - ContentValues values = new ContentValues(); - //values.put(Event.INTERNALTAG, 1); - values.put(Event.INTERNALTAG, mTagCounter); - //values.put(Event.INTERNALTAG, String.valueOf(mTagCounter)); - - int RowCount = this.mProvider.update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), values, null, null); - //Log.v(TAG,"event tag nr: " + String.valueOf(mTagCounter)); - //Log.v(TAG,"Rows updated: " + String.valueOf(RowCount)); - - if (RowCount == 1) { - Result = true; - mTagCounter += 1; - } else { - Log.v(TAG,"EVENT NOT TAGGED!"); - } - - return Result; - } - - /** - * removes the tag of all android events - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ - public int untagAndroidEvents() throws RemoteException { - int RowCount = 0; - int Steps = 100; - ContentValues values = new ContentValues(); - values.put(Event.INTERNALTAG, 0); + /** + * example: #FFCCAA + */ + public String getCalendarColorAsString() { + return this.strCalendarColor; + } - for (int i=1; i < this.mTagCounter; i = i + Steps) { - String mSelectionClause = "(CAST(" + Event.INTERNALTAG + " AS INT) >= ?) AND (CAST(" + Event.INTERNALTAG + " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + Steps), Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; - RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs); - } - /*String mSelectionClause = "(" + Event.INTERNALTAG + " > ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] mSelectionArgs = {"0", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; + /** + * example 12345 + */ + public int getCalendarColor() { + return this.getContentValueAsInt(Calendars.CALENDAR_COLOR); + } + + /** + * example 12345 + */ + public void setCalendarColor(int color) { + this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color); + } + + /** + * example: + * should be: calendarname + * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ + */ + public String getCalendarName() { + return this.getContentValueAsString(Calendars.NAME); + } + + /** + * example: + * should be: calendarname + * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ + */ + public void setCalendarName(String calendarName) { + this.setContentValueAsString(Calendars.NAME, calendarName); + } + + /** + * example: 8 + */ + public int getAndroidCalendarId() { + return this.getContentValueAsInt(Calendars._ID); + } + + /** + * example: 8 + */ + public void setAndroidCalendarId(int androidCalendarId) { + this.setContentValueAsInt(Calendars._ID, androidCalendarId); + } + + /** + * example: content://com.android.calendar/calendars/8 + */ + public Uri getAndroidCalendarUri() { + return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId()); + } + + /** + * empty constructor + */ + public DavCalendar(CalendarSource source) { + this.Source = source; + } + + /** + * creates an new instance from a cursor + * + * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI + */ + public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, CalendarSource source, String serverUrl) { + this.mAccount = account; + this.mProvider = provider; + this.foundClientSide = true; + this.Source = source; + this.ServerUrl = serverUrl; + + String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID)); + String strName = cur.getString(cur.getColumnIndex(Calendars.NAME)); + String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME)); + String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG)); + String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL)); + String strCalendarColor = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_COLOR)); + int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID)); + + this.setCalendarName(strName); + this.setCalendarDisplayName(strDisplayName); + this.setCTag(strCTAG, false); + this.setAndroidCalendarId(intAndroidCalendarId); + this.setCalendarColor(Integer.parseInt(strCalendarColor)); + + if (strSyncID == null) { + this.correctSyncID(strName); + strSyncID = strName; + } + if (strServerUrl == null) { + this.correctServerUrl(serverUrl); + } + URI uri = null; + try { + uri = new URI(strSyncID); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + this.setURI(uri); + } + + /** + * checks a given list of android calendars for a specific android calendar. + * this calendar should be a server calendar as it is searched for. + * if the calendar is not found, it will be created. + * + * @param androidCalList the list of android calendars + * @param context + * @return the found android calendar or null of fails + * @throws RemoteException + */ + public Uri checkAndroidCalendarList(CalendarList androidCalList, android.content.Context context) throws RemoteException { + Uri androidCalendarUri = null; + boolean isCalendarExist = false; + + DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI()); + if (androidCalendar != null) { + isCalendarExist = true; + androidCalendar.foundServerSide = true; + } + + + if (!isCalendarExist) { + DavCalendar newCal = this.createNewAndroidCalendar(this, androidCalList.getCalendarList() + .size(), context); + if (newCal != null) { + androidCalList.addCalendar(newCal); + androidCalendarUri = newCal.getAndroidCalendarUri(); + } + } else { + androidCalendarUri = androidCalendar.getAndroidCalendarUri(); + if (!this.getCalendarColorAsString().equals("")) { + this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, getColorAsHex(this.getCalendarColorAsString())); + } + if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) && + (androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) { + String serverDisplayName = this.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); + String clientDisplayName = androidCalendar.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); + if (!serverDisplayName.equals(clientDisplayName)) + this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, serverDisplayName); + } + } + + return androidCalendarUri; + } + + /** + * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI (_SYNC_ID) + * + * @param calendarUri the real calendarUri + * @return success of this function + */ + private boolean correctSyncID(String calendarUri) { + boolean Result = false; + Log.v(TAG, "correcting SyncID for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); + + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(DavCalendar.URI, calendarUri); + + try { + mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); + Result = true; + } catch (RemoteException e) { + e.printStackTrace(); + } + + return Result; + } + + /** + * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98) + * + * @param serverUrl the current serverurl + * @return success of this function + */ + private boolean correctServerUrl(String serverUrl) { + boolean Result = false; + Log.v(TAG, "correcting ServerUrl for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); + + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(DavCalendar.SERVERURL, serverUrl); + + try { + mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); + Result = true; + } catch (RemoteException e) { + e.printStackTrace(); + } + + return Result; + } + + /** + * creates a new androidCalendar + * + * @param serverCalendar + * @param index + * @param context + * @return the new androidCalendar or null if fails + */ + private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, android.content.Context context) { + Uri newUri = null; + DavCalendar Result = null; + + final ContentValues contentValues = new ContentValues(); + contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString()); + contentValues.put(DavCalendar.SERVERURL, this.ServerUrl); + + contentValues.put(Calendars.VISIBLE, 1); + contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName()); + contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name); + contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type); + contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name); + contentValues.put(Calendars.SYNC_EVENTS, 1); + contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); + + String calendarColorAsString = serverCalendar.getCalendarColorAsString(); + if (!calendarColorAsString.isEmpty()) { + int color = getColorAsHex(calendarColorAsString); + contentValues.put(Calendars.CALENDAR_COLOR, color); + } else { + // find a color + //int index = mList.size(); + index = index % CalendarColors.colors.length; + contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[2]); + } + + try { + newUri = mProvider.insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), contentValues); + } catch (RemoteException e) { + e.printStackTrace(); + } + + // it is possible that this calendar already exists but the provider failed to find it within isCalendarExist() + // the adapter would try to create a new calendar but the provider fails again to create a new calendar. + if (newUri != null) { + long newCalendarId = ContentUris.parseId(newUri); + + Cursor cur = null; + Uri uri = Calendars.CONTENT_URI; + String selection = "(" + Calendars._ID + " = ?)"; + String[] selectionArgs = new String[]{String.valueOf(newCalendarId)}; + + // Submit the query and get a Cursor object back. + try { + cur = mProvider.query(uri, null, selection, selectionArgs, null); + } catch (RemoteException e) { + e.printStackTrace(); + } + + if (cur != null) { + while (cur.moveToNext()) { + Result = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl); + Result.foundServerSide = true; + } + cur.close(); + //if (Result != null) + // this.mList.add(Result); + } + Log.i(TAG, "New calendar created : URI=" + Result.getAndroidCalendarUri()); + NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", "new calendar found: " + Result + .getCalendarDisplayName()); + mNotifyList.add(Result.getAndroidCalendarUri()); + } + + return Result; + } + + private int getColorAsHex(String calendarColorAsString) { + int color = 0x0000FF00; + Pattern p = Pattern.compile("#?(\\p{XDigit}{6})(\\p{XDigit}{2})?"); + Matcher m = p.matcher(calendarColorAsString); + if (m.find()) { + int color_rgb = Integer.parseInt(m.group(1), 16); + int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF; + color = (color_alpha << 24) | color_rgb; + } + return color; + } + + /** + * there is no corresponding calendar on server side. time to delete this calendar on android side. + * + * @return + */ + public boolean deleteAndroidCalendar() { + boolean Result = false; + + String mSelectionClause = "(" + Calendars._ID + " = ?)"; + int calendarId = this.getAndroidCalendarId(); + String[] mSelectionArgs = {Long.toString(calendarId)}; + + int CountDeleted = 0; + try { + CountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs); + Log.i(TAG, "Calendar deleted: " + String.valueOf(calendarId)); + this.mNotifyList.add(this.getAndroidCalendarUri()); + Result = true; + } catch (RemoteException e) { + e.printStackTrace(); + } + Log.d(TAG, "Android Calendars deleted: " + Integer.toString(CountDeleted)); + + return Result; + } + + /** + * updates the android calendar + * + * @param calendarUri the uri of the androidCalendar + * @param target must be from android.provider.CalendarContract.Calendars + * @param value the new value for the target + * @throws RemoteException + */ + private void updateAndroidCalendar(Uri calendarUri, String target, int value) throws RemoteException { + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(target, value); + + mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); + } + + /** + * updates the android calendar + * + * @param calendarUri the uri of the androidCalendar + * @param target must be from android.provider.CalendarContract.Calendars + * @param value the new value for the target + * @throws RemoteException + */ + private void updateAndroidCalendar(Uri calendarUri, String target, String value) throws RemoteException { + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(target, value); + + mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); + } + + /** + * marks the android event as already handled + * + * @return + * @throws RemoteException + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + */ + public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException { + boolean Result = false; + + ContentValues values = new ContentValues(); + //values.put(Event.INTERNALTAG, 1); + values.put(Event.INTERNALTAG, mTagCounter); + //values.put(Event.INTERNALTAG, String.valueOf(mTagCounter)); + + int RowCount = this.mProvider.update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), values, null, null); + //Log.v(TAG,"event tag nr: " + String.valueOf(mTagCounter)); + //Log.v(TAG,"Rows updated: " + String.valueOf(RowCount)); + + if (RowCount == 1) { + Result = true; + mTagCounter += 1; + } else { + Log.v(TAG, "EVENT NOT TAGGED!"); + } + + return Result; + } + + /** + * removes the tag of all android events + * + * @return + * @throws RemoteException + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + */ + public int untagAndroidEvents() throws RemoteException { + int RowCount = 0; + int Steps = 100; + ContentValues values = new ContentValues(); + values.put(Event.INTERNALTAG, 0); + + for (int i = 1; i < this.mTagCounter; i = i + Steps) { + String mSelectionClause = "(CAST(" + Event.INTERNALTAG + " AS INT) >= ?) AND (CAST(" + Event.INTERNALTAG + " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + Steps), Long.toString(ContentUris + .parseId(this.getAndroidCalendarUri()))}; + RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs); + } + /*String mSelectionClause = "(" + Event.INTERNALTAG + " > ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] mSelectionArgs = {"0", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs);*/ - - //Log.d(TAG, "Rows reseted: " + RowCount.toString()); - return RowCount; - } - /** - * Events not being tagged are for deletion - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ - public int deleteUntaggedEvents() throws RemoteException { - String mSelectionClause = "(" + Event.INTERNALTAG + " < ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] mSelectionArgs = {"1", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; - - int CountDeleted = this.mProvider.delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), mSelectionClause, mSelectionArgs); - //Log.d(TAG, "Rows deleted: " + CountDeleted.toString()); - return CountDeleted; - } - - private Uri SyncAdapterCalendar() { - return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type); - } - private Uri SyncAdapter() { - return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type); - } - private static Uri asSyncAdapter(Uri uri, String account, String accountType) { - return uri.buildUpon() - .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") - .appendQueryParameter(Calendars.ACCOUNT_NAME, account) - .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); - } - - public void setAccount(Account account) { - this.mAccount = account; - } - public void setProvider(ContentProviderClient provider) { - this.mProvider = provider; - } - - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @return the value for the item - */ - private String getContentValueAsString(String Item) { - String Result = ""; - if (this.ContentValues.containsKey(Item)) - Result = this.ContentValues.getAsString(Item); - return Result; - } - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @return the value for the item - */ - private int getContentValueAsInt(String Item) { - int Result = 0; - if (this.ContentValues.containsKey(Item)) - Result = this.ContentValues.getAsInteger(Item); - return Result; - } - - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @param Value the value for the item - * @return success of this function - */ - private boolean setContentValueAsString(String Item, String Value) { - boolean Result = false; - - if (this.ContentValues.containsKey(Item)) - this.ContentValues.remove(Item); - this.ContentValues.put(Item, Value); - - return Result; - } - - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @param Value the value for the item - * @return success of this function - */ - private boolean setContentValueAsInt(String Item, int Value) { - boolean Result = false; - - if (this.ContentValues.containsKey(Item)) - this.ContentValues.remove(Item); - this.ContentValues.put(Item, Value); - - return Result; - } - - public ArrayList getNotifyList() { - return this.mNotifyList; - } - public ArrayList getCalendarEvents() { - return this.mCalendarEvents; - } - - public boolean readCalendarEvents(CaldavFacade facade) { - boolean Result = false; - - try { - this.mCalendarEvents = facade.getCalendarEvents(this); - Result = true; - } catch (ClientProtocolException e) { - e.printStackTrace(); - Result = false; - } catch (URISyntaxException e) { - e.printStackTrace(); - Result = false; - } catch (IOException e) { - e.printStackTrace(); - Result = false; - } catch (ParserConfigurationException e) { - e.printStackTrace(); - Result = false; - } catch (SAXException e) { - e.printStackTrace(); - Result = false; - } - - return Result; - } - + //Log.d(TAG, "Rows reseted: " + RowCount.toString()); + return RowCount; + } + + /** + * Events not being tagged are for deletion + * + * @return + * @throws RemoteException + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + */ + public int deleteUntaggedEvents() throws RemoteException { + String mSelectionClause = "(" + Event.INTERNALTAG + " < ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] mSelectionArgs = {"1", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; + + int CountDeleted = this.mProvider.delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), mSelectionClause, mSelectionArgs); + //Log.d(TAG, "Rows deleted: " + CountDeleted.toString()); + return CountDeleted; + } + + private Uri SyncAdapterCalendar() { + return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type); + } + + private Uri SyncAdapter() { + return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type); + } + + private static Uri asSyncAdapter(Uri uri, String account, String accountType) { + return uri.buildUpon() + .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true") + .appendQueryParameter(Calendars.ACCOUNT_NAME, account) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); + } + + public void setAccount(Account account) { + this.mAccount = account; + } + + public void setProvider(ContentProviderClient provider) { + this.mProvider = provider; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @return the value for the item + */ + private String getContentValueAsString(String Item) { + String Result = ""; + if (this.ContentValues.containsKey(Item)) + Result = this.ContentValues.getAsString(Item); + return Result; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @return the value for the item + */ + private int getContentValueAsInt(String Item) { + int Result = 0; + if (this.ContentValues.containsKey(Item)) + Result = this.ContentValues.getAsInteger(Item); + return Result; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @param Value the value for the item + * @return success of this function + */ + private boolean setContentValueAsString(String Item, String Value) { + boolean Result = false; + + if (this.ContentValues.containsKey(Item)) + this.ContentValues.remove(Item); + this.ContentValues.put(Item, Value); + + return Result; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @param Value the value for the item + * @return success of this function + */ + private boolean setContentValueAsInt(String Item, int Value) { + boolean Result = false; + + if (this.ContentValues.containsKey(Item)) + this.ContentValues.remove(Item); + this.ContentValues.put(Item, Value); + + return Result; + } + + public ArrayList getNotifyList() { + return this.mNotifyList; + } + + public ArrayList getCalendarEvents() { + return this.mCalendarEvents; + } + + public boolean readCalendarEvents(CaldavFacade facade) { + boolean Result = false; + + try { + this.mCalendarEvents = facade.getCalendarEvents(this); + Result = true; + } catch (ClientProtocolException e) { + e.printStackTrace(); + Result = false; + } catch (URISyntaxException e) { + e.printStackTrace(); + Result = false; + } catch (IOException e) { + e.printStackTrace(); + Result = false; + } catch (ParserConfigurationException e) { + e.printStackTrace(); + Result = false; + } catch (SAXException e) { + e.printStackTrace(); + Result = false; + } + + return Result; + } + } diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java --- a/src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java Tue Feb 10 22:40:00 2015 +0100 @@ -26,6 +26,8 @@ public class HttpReport extends HttpEntityEnclosingRequestBase implements HttpUriRequest { + public static final String USER_DATA_TRUST_ALL_KEY = "USER_DATA_TRUSTALL_KEY"; + @Override public String getMethod() { return "REPORT"; diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java --- a/src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java Tue Feb 10 22:40:00 2015 +0100 @@ -1,6 +1,6 @@ /** * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger - * + * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute @@ -16,36 +16,11 @@ * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see . - * + * */ package org.gege.caldavsyncadapter.syncadapter; -import java.io.IOException; -import java.net.URI; -//import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.ArrayList; -//import java.security.GeneralSecurityException; - -import javax.xml.parsers.ParserConfigurationException; - -import net.fortuna.ical4j.data.ParserException; - -import org.apache.http.ParseException; -import org.apache.http.client.ClientProtocolException; -import org.gege.caldavsyncadapter.Event; -import org.gege.caldavsyncadapter.android.entities.AndroidEvent; -import org.gege.caldavsyncadapter.authenticator.AuthenticatorActivity; -import org.gege.caldavsyncadapter.caldav.CaldavFacade; -import org.gege.caldavsyncadapter.caldav.CaldavProtocolException; -import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; -import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; -import org.gege.caldavsyncadapter.caldav.entities.CalendarList; -import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; -import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; -import org.xml.sax.SAXException; - import android.accounts.Account; import android.accounts.AccountManager; import android.content.AbstractThreadedSyncAdapter; @@ -66,18 +41,45 @@ import android.provider.CalendarContract.Reminders; import android.util.Log; +import net.fortuna.ical4j.data.ParserException; + +import org.apache.http.ParseException; +import org.apache.http.client.ClientProtocolException; +import org.gege.caldavsyncadapter.Constants; +import org.gege.caldavsyncadapter.Event; +import org.gege.caldavsyncadapter.android.entities.AndroidEvent; +import org.gege.caldavsyncadapter.authenticator.AuthenticatorActivity; +import org.gege.caldavsyncadapter.caldav.CaldavFacade; +import org.gege.caldavsyncadapter.caldav.CaldavProtocolException; +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; +import org.gege.caldavsyncadapter.caldav.entities.CalendarList; +import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; +import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; +import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; + +import javax.xml.parsers.ParserConfigurationException; + +//import java.net.MalformedURLException; +//import java.security.GeneralSecurityException; + public class SyncAdapter extends AbstractThreadedSyncAdapter { - private static final String TAG = "SyncAdapter"; - private AccountManager mAccountManager; - private String mVersion = ""; - private int mCountPerformSync = 0; - private int mCountSyncCanceled = 0; - private int mCountProviderFailed = 0; - - private int mCountProviderFailedMax = 3; + private static final String TAG = "SyncAdapter"; + private AccountManager mAccountManager; + private String mVersion = ""; + private int mCountPerformSync = 0; + private int mCountSyncCanceled = 0; + private int mCountProviderFailed = 0; + + private int mCountProviderFailedMax = 3; // private Context mContext; - + /* private static final String[] CALENDAR_PROJECTION = new String[] { Calendars._ID, // 0 @@ -102,81 +104,87 @@ Events.CALENDAR_ID }; */ - - // ignore same CTag - //private static final boolean FORCE_SYNCHRONIZE = false; - // drop all calendar before synchro - //private static final boolean DROP_CALENDAR_EVENTS = false; - - public SyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - //android.os.Debug.waitForDebugger(); - mAccountManager = AccountManager.get(context); - try { - mVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; - } catch (NameNotFoundException e) { - e.printStackTrace(); - } + + // ignore same CTag + //private static final boolean FORCE_SYNCHRONIZE = false; + // drop all calendar before synchro + //private static final boolean DROP_CALENDAR_EVENTS = false; + + public SyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + //android.os.Debug.waitForDebugger(); + mAccountManager = AccountManager.get(context); + try { + mVersion = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0).versionName; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } // mContext = context; - } + } - @Override - public void onPerformSync(Account account, Bundle extras, String authority, - ContentProviderClient provider, SyncResult syncResult) { - boolean bolError = false; - - String url = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_URL_KEY); - this.mCountPerformSync += 1; - Log.v(TAG, "onPerformSync() count:" + String.valueOf(this.mCountPerformSync) + " on " + account.name + " with URL " + url); + @Override + public void onPerformSync(Account account, Bundle extras, String authority, + ContentProviderClient provider, SyncResult syncResult) { + boolean bolError = false; - CalendarList serverCalList; - - CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url); - androidCalList.readCalendarFromClient(); - ArrayList notifyList = new ArrayList(); + String url = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_URL_KEY); + String trust = mAccountManager.getUserData(account, Constants.USER_DATA_TRUST_ALL_KEY); + this.mCountPerformSync += 1; + Log.v(TAG, "onPerformSync() count:" + String.valueOf(this.mCountPerformSync) + " on " + account.name + " with URL " + url); - try { - String Username = ""; - String UserDataVersion = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_VERSION); - if (UserDataVersion == null) { - Username = account.name; - } else { - Username = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_USERNAME); - } + CalendarList serverCalList; - CaldavFacade facade = new CaldavFacade(Username, mAccountManager.getPassword(account), url); - facade.setAccount(account); - facade.setProvider(provider); - facade.setVersion(mVersion); - serverCalList = facade.getCalendarList(this.getContext()); - //String davProperties = facade.getLastDav(); - Log.i(TAG, String.valueOf(androidCalList.getCalendarList().size()) + " calendars found at android"); - - for (DavCalendar serverCalendar : serverCalList.getCalendarList()) { - Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar.getURI()); + CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url); + androidCalList.readCalendarFromClient(); + ArrayList notifyList = new ArrayList(); - Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this.getContext()); + try { + String Username = ""; + String UserDataVersion = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_VERSION); + if (UserDataVersion == null) { + Username = account.name; + } else { + Username = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_USERNAME); + } - // check if the adapter was able to get an existing calendar or create a new one - if (androidCalendarUri != null) { - // the provider seems to work correct, reset the counter - mCountProviderFailed = 0; - DavCalendar androidCalendar = androidCalList.getCalendarByAndroidUri(androidCalendarUri); - - //if ((FORCE_SYNCHRONIZE) || (androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) { - if ((androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) { - Log.d(TAG, "CTag has changed, something to synchronise"); - if (serverCalendar.readCalendarEvents(facade)) { - this.synchroniseEvents(androidCalendar, serverCalendar, syncResult.stats, notifyList); + CaldavFacade facade = new CaldavFacade(Username, mAccountManager.getPassword(account), url, trust); + facade.setAccount(account); + facade.setProvider(provider); + facade.setVersion(mVersion); + serverCalList = facade.getCalendarList(this.getContext()); + //String davProperties = facade.getLastDav(); + Log.i(TAG, String.valueOf(androidCalList.getCalendarList() + .size()) + " calendars found at android"); - Log.d(TAG, "Updating stored CTag"); - //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); - androidCalendar.setCTag(serverCalendar.getcTag(), true); - } else { - Log.d(TAG, "unable to read events from server calendar"); - } - } else { - Log.d(TAG, "CTag has not changed, nothing to do"); + for (DavCalendar serverCalendar : serverCalList.getCalendarList()) { + Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar + .getURI()); + + Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this + .getContext()); + + // check if the adapter was able to get an existing calendar or create a new one + if (androidCalendarUri != null) { + // the provider seems to work correct, reset the counter + mCountProviderFailed = 0; + DavCalendar androidCalendar = androidCalList.getCalendarByAndroidUri(androidCalendarUri); + + //if ((FORCE_SYNCHRONIZE) || (androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) { + if ((androidCalendar.getcTag() == null) || (!androidCalendar.getcTag() + .equals(serverCalendar.getcTag()))) { + Log.d(TAG, "CTag has changed, something to synchronise"); + if (serverCalendar.readCalendarEvents(facade)) { + this.synchroniseEvents(androidCalendar, serverCalendar, syncResult.stats, notifyList); + + Log.d(TAG, "Updating stored CTag"); + //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); + androidCalendar.setCTag(serverCalendar.getcTag(), true); + } else { + Log.d(TAG, "unable to read events from server calendar"); + } + } else { + Log.d(TAG, "CTag has not changed, nothing to do"); /* this is unnecessary. "SkippedEntries" are: * Counter for tracking how many entries, either from the server or the local store, @@ -196,52 +204,53 @@ int count = countCursor.getInt(0); syncResult.stats.numSkippedEntries += count; countCursor.close();*/ - - } - - this.checkDirtyAndroidEvents(provider, account, androidCalendarUri, facade, serverCalendar.getURI(), syncResult.stats, notifyList); - } else { - // this happens if the data provider failes to get an existing or create a new calendar - mCountProviderFailed += 1; - Log.e(TAG, "failed to get an existing or create a new calendar"); - syncResult.stats.numIoExceptions += 1; - if (mCountProviderFailed >= mCountProviderFailedMax) { - // see issue #96 - NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "are you using CyanogenMod in Incognito Mode?"); - } else { - NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "the provider failed to get an existing or create a new calendar"); - } - bolError = true; - } - } - - if (!bolError) { - // check whether a calendar is not synced -> delete it at android - androidCalList.deleteCalendarOnClientSideOnly(this.getContext()); - } - - // notify the ContentResolver - for (Uri uri : androidCalList.getNotifyList()) { - this.getContext().getContentResolver().notifyChange(uri, null); - } - for (Uri uri : serverCalList.getNotifyList()) { - this.getContext().getContentResolver().notifyChange(uri, null); - } - for (Uri uri : notifyList) { - this.getContext().getContentResolver().notifyChange(uri, null); - } - - //Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString()); - //Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString()); - Log.i(TAG,"Entries: " + String.valueOf(syncResult.stats.numEntries)); - Log.i(TAG,"Rows inserted: " + String.valueOf(syncResult.stats.numInserts)); - Log.i(TAG,"Rows updated: " + String.valueOf(syncResult.stats.numUpdates)); - Log.i(TAG,"Rows deleted: " + String.valueOf(syncResult.stats.numDeletes)); - Log.i(TAG,"Rows skipped: " + String.valueOf(syncResult.stats.numSkippedEntries)); - Log.i(TAG,"Io Exceptions: " + String.valueOf(syncResult.stats.numIoExceptions)); - Log.i(TAG,"Parse Exceptions: " + String.valueOf(syncResult.stats.numParseExceptions)); - Log.i(TAG,"Auth Exceptions: " + String.valueOf(syncResult.stats.numAuthExceptions)); - Log.i(TAG,"Conflict Detected Exceptions: " + String.valueOf(syncResult.stats.numConflictDetectedExceptions)); + + } + + this.checkDirtyAndroidEvents(provider, account, androidCalendarUri, facade, serverCalendar + .getURI(), syncResult.stats, notifyList); + } else { + // this happens if the data provider failes to get an existing or create a new calendar + mCountProviderFailed += 1; + Log.e(TAG, "failed to get an existing or create a new calendar"); + syncResult.stats.numIoExceptions += 1; + if (mCountProviderFailed >= mCountProviderFailedMax) { + // see issue #96 + NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "are you using CyanogenMod in Incognito Mode?"); + } else { + NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "the provider failed to get an existing or create a new calendar"); + } + bolError = true; + } + } + + if (!bolError) { + // check whether a calendar is not synced -> delete it at android + androidCalList.deleteCalendarOnClientSideOnly(this.getContext()); + } + + // notify the ContentResolver + for (Uri uri : androidCalList.getNotifyList()) { + this.getContext().getContentResolver().notifyChange(uri, null); + } + for (Uri uri : serverCalList.getNotifyList()) { + this.getContext().getContentResolver().notifyChange(uri, null); + } + for (Uri uri : notifyList) { + this.getContext().getContentResolver().notifyChange(uri, null); + } + + //Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString()); + //Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString()); + Log.i(TAG, "Entries: " + String.valueOf(syncResult.stats.numEntries)); + Log.i(TAG, "Rows inserted: " + String.valueOf(syncResult.stats.numInserts)); + Log.i(TAG, "Rows updated: " + String.valueOf(syncResult.stats.numUpdates)); + Log.i(TAG, "Rows deleted: " + String.valueOf(syncResult.stats.numDeletes)); + Log.i(TAG, "Rows skipped: " + String.valueOf(syncResult.stats.numSkippedEntries)); + Log.i(TAG, "Io Exceptions: " + String.valueOf(syncResult.stats.numIoExceptions)); + Log.i(TAG, "Parse Exceptions: " + String.valueOf(syncResult.stats.numParseExceptions)); + Log.i(TAG, "Auth Exceptions: " + String.valueOf(syncResult.stats.numAuthExceptions)); + Log.i(TAG, "Conflict Detected Exceptions: " + String.valueOf(syncResult.stats.numConflictDetectedExceptions)); /*} catch (final AuthenticatorException e) { syncResult.stats.numParseExceptions++; @@ -260,119 +269,125 @@ } catch (final ParseException e) { syncResult.stats.numParseExceptions++; Log.e(TAG, "ParseException", e); - NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (parsing)", e.getMessage()); + NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (parsing)", e + .getMessage()); //NotificationsHelper.getCurrentSyncLog().addException(e); /*} catch (final JSONException e) { syncResult.stats.numParseExceptions++; Log.e(TAG, "JSONException", e);*/ - } catch (Exception e) { - Log.e(TAG, "Updating calendar exception " + e.getClass().getName(), e); + } catch (Exception e) { + Log.e(TAG, "Updating calendar exception " + e.getClass().getName(), e); syncResult.stats.numParseExceptions++; - NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (general)", e.getMessage()); + NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (general)", e + .getMessage()); //NotificationsHelper.getCurrentSyncLog().addException(e); - //throw new RuntimeException(e); - } - } + //throw new RuntimeException(e); + } + } - public void onSyncCanceled () { - //TODO: implement SyncCanceled - this.mCountSyncCanceled += 1; - Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled)); - } + public void onSyncCanceled() { + //TODO: implement SyncCanceled + this.mCountSyncCanceled += 1; + Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled)); + } - - /** - * both calender event and android event have been found. - * server wins always at the moment. - * @param androidCalendar - * @param serverCalendar - * @param stats - * @param notifyList - * @throws ClientProtocolException - * @throws URISyntaxException - * @throws IOException - * @throws ParserConfigurationException - * @throws SAXException - * @throws RemoteException - * @throws CaldavProtocolException - * @throws ParserException - * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent) - * @see SyncAdapter#tagAndroidEvent(ContentProviderClient, Account, AndroidEvent) - * @see SyncAdapter#untagAndroidEvents(ContentProviderClient, Account, Uri) - * @see SyncAdapter#deleteUntaggedEvents(ContentProviderClient, Account, Uri) - */ - private void synchroniseEvents( - DavCalendar androidCalendar, - DavCalendar serverCalendar, - SyncStats stats, - ArrayList notifyList - ) throws ClientProtocolException, URISyntaxException, IOException, ParserConfigurationException, SAXException, RemoteException, CaldavProtocolException, ParserException { + + /** + * both calender event and android event have been found. + * server wins always at the moment. + * + * @param androidCalendar + * @param serverCalendar + * @param stats + * @param notifyList + * @throws ClientProtocolException + * @throws URISyntaxException + * @throws IOException + * @throws ParserConfigurationException + * @throws SAXException + * @throws RemoteException + * @throws CaldavProtocolException + * @throws ParserException + * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent) + * @see SyncAdapter#tagAndroidEvent(ContentProviderClient, Account, AndroidEvent) + * @see SyncAdapter#untagAndroidEvents(ContentProviderClient, Account, Uri) + * @see SyncAdapter#deleteUntaggedEvents(ContentProviderClient, Account, Uri) + */ + private void synchroniseEvents( + DavCalendar androidCalendar, + DavCalendar serverCalendar, + SyncStats stats, + ArrayList notifyList + ) throws ClientProtocolException, URISyntaxException, IOException, ParserConfigurationException, SAXException, RemoteException, CaldavProtocolException, ParserException { /*if (DROP_CALENDAR_EVENTS) { dropAllEvents(account, provider, androidCalendar.getAndroidCalendarUri()); }*/ - - int rowInsert = 0; - int rowUpdate = 0; - int rowTag = 0; - int rowDelete = 0; - int rowUntag = 0; - int rowSkip = 0; - - for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) { - try { - AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar); - - Log.i(TAG, "Event " + calendarEvent.getUri().toString()+ " androidUri="+androidEvent); - - if (androidEvent == null) { + + int rowInsert = 0; + int rowUpdate = 0; + int rowTag = 0; + int rowDelete = 0; + int rowUntag = 0; + int rowSkip = 0; + + for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) { + try { + AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar); + + Log.i(TAG, "Event " + calendarEvent.getUri() + .toString() + " androidUri=" + androidEvent); + + if (androidEvent == null) { /* new android event */ - if (calendarEvent.createAndroidEvent(androidCalendar)) { - rowInsert += 1; - androidEvent = calendarEvent.getAndroidEvent(androidCalendar); - notifyList.add(androidEvent.getUri()); - } else { - rowSkip += 1; - } - } else { + if (calendarEvent.createAndroidEvent(androidCalendar)) { + rowInsert += 1; + androidEvent = calendarEvent.getAndroidEvent(androidCalendar); + notifyList.add(androidEvent.getUri()); + } else { + rowSkip += 1; + } + } else { /* the android exists */ - String androidETag = androidEvent.getETag(); - if (androidETag == null) - androidETag = ""; - Log.d(TAG, "Event compare: " + androidETag + " <> " + calendarEvent.getETag().toString()); - if ((androidEvent.getETag() == null) || (!androidETag.equals(calendarEvent.getETag()))) { + String androidETag = androidEvent.getETag(); + if (androidETag == null) + androidETag = ""; + Log.d(TAG, "Event compare: " + androidETag + " <> " + calendarEvent.getETag() + .toString()); + if ((androidEvent.getETag() == null) || (!androidETag.equals(calendarEvent.getETag()))) { /* the android event is getting updated */ - if (calendarEvent.updateAndroidEvent(androidEvent)) { - rowUpdate += 1; - notifyList.add(androidEvent.getUri()); - } else { - rowSkip += 1; - } - } - } - if (androidEvent != null) - //if (androidEvent.tagAndroidEvent()) - if (androidCalendar.tagAndroidEvent(androidEvent)) - rowTag += 1; - - - } catch (ParserException ex) { - Log.e(TAG, "Parser exception", ex); - stats.numParseExceptions++; + if (calendarEvent.updateAndroidEvent(androidEvent)) { + rowUpdate += 1; + notifyList.add(androidEvent.getUri()); + } else { + rowSkip += 1; + } + } + } + if (androidEvent != null) + //if (androidEvent.tagAndroidEvent()) + if (androidCalendar.tagAndroidEvent(androidEvent)) + rowTag += 1; - NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (parsing)", ex.getMessage()); - //NotificationsHelper.getCurrentSyncLog().addException(ex); - } catch (CaldavProtocolException ex) { - Log.e(TAG, "Caldav exception", ex); - stats.numParseExceptions++; - NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage()); - //NotificationsHelper.getCurrentSyncLog().addException(ex); - } - } - - rowDelete = androidCalendar.deleteUntaggedEvents(); - rowUntag = androidCalendar.untagAndroidEvents(); + } catch (ParserException ex) { + Log.e(TAG, "Parser exception", ex); + stats.numParseExceptions++; + + NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (parsing)", ex + .getMessage()); + //NotificationsHelper.getCurrentSyncLog().addException(ex); + } catch (CaldavProtocolException ex) { + Log.e(TAG, "Caldav exception", ex); + stats.numParseExceptions++; + + NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage()); + //NotificationsHelper.getCurrentSyncLog().addException(ex); + } + } + + rowDelete = androidCalendar.deleteUntaggedEvents(); + rowUntag = androidCalendar.untagAndroidEvents(); /*Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString()); Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString()); @@ -380,188 +395,192 @@ Log.i(TAG,"Rows updated: " + String.valueOf(rowUpdate)); Log.i(TAG,"Rows deleted: " + String.valueOf(rowDelete)); Log.i(TAG,"Rows skipped: " + String.valueOf(rowSkip));*/ - Log.i(TAG,"Rows tagged: " + String.valueOf(rowTag)); - Log.i(TAG,"Rows untagged: " + String.valueOf(rowUntag)); - - stats.numInserts += rowInsert; - stats.numUpdates += rowUpdate; - stats.numDeletes += rowDelete; - stats.numSkippedEntries += rowSkip; - stats.numEntries += rowInsert + rowUpdate + rowDelete; + Log.i(TAG, "Rows tagged: " + String.valueOf(rowTag)); + Log.i(TAG, "Rows untagged: " + String.valueOf(rowUntag)); - } - - /** - * checks the android events for the dirty flag. - * the flag is set by android when the event has been changed. - * the dirty flag is removed when an android event has been updated from calendar event - * @param provider - * @param account - * @param calendarUri - * @param facade - * @param caldavCalendarUri - * @param stats - * @param notifyList - * @return count of dirty events - */ - private int checkDirtyAndroidEvents( - ContentProviderClient provider, - Account account, - Uri calendarUri, - CaldavFacade facade, - URI caldavCalendarUri, - SyncStats stats, - ArrayList notifyList - ) { - Cursor curEvent = null; - Cursor curAttendee = null; - Cursor curReminder = null; - Long EventID; - Long CalendarID; - AndroidEvent androidEvent = null; - int rowDirty = 0; - int rowInsert = 0; - int rowUpdate = 0; - int rowDelete = 0; - - try { - CalendarID = ContentUris.parseId(calendarUri); - String selection = "(" + Events.DIRTY + " = ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] selectionArgs = new String[] {"1", CalendarID.toString()}; - curEvent = provider.query(Events.CONTENT_URI, null, selection, selectionArgs, null); - - while (curEvent.moveToNext()) { - EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID)); - Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID); - - //androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri); - androidEvent = new AndroidEvent(returnedUri, calendarUri); - androidEvent.readContentValues(curEvent); - - selection = "(" + Attendees.EVENT_ID + " = ?)"; - selectionArgs = new String[] {String.valueOf(EventID)}; - curAttendee = provider.query(Attendees.CONTENT_URI, null, selection, selectionArgs, null); - selection = "(" + Reminders.EVENT_ID + " = ?)"; - selectionArgs = new String[] {String.valueOf(EventID)}; - curReminder = provider.query(Reminders.CONTENT_URI, null, selection, selectionArgs, null); - androidEvent.readAttendees(curAttendee); - androidEvent.readReminder(curReminder); - curAttendee.close(); - curReminder.close(); - - String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID); - - boolean Deleted = false; - int intDeleted = 0; - intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED)); - Deleted = (intDeleted == 1); + stats.numInserts += rowInsert; + stats.numUpdates += rowUpdate; + stats.numDeletes += rowDelete; + stats.numSkippedEntries += rowSkip; + stats.numEntries += rowInsert + rowUpdate + rowDelete; - if (SyncID == null) { - // new Android event - String newGUID = java.util.UUID.randomUUID().toString() + "-caldavsyncadapter"; - String calendarPath = caldavCalendarUri.getPath(); - if (!calendarPath.endsWith("/")) - calendarPath += "/"; + } - SyncID = calendarPath + newGUID + ".ics"; - - androidEvent.createIcs(newGUID); - - if (facade.createEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString())) { - //HINT: bugfix for google calendar replace("@", "%40") - if (SyncID.contains("@")) - SyncID = SyncID.replace("@", "%40"); - ContentValues values = new ContentValues(); - values.put(Events._SYNC_ID, SyncID); + /** + * checks the android events for the dirty flag. + * the flag is set by android when the event has been changed. + * the dirty flag is removed when an android event has been updated from calendar event + * + * @param provider + * @param account + * @param calendarUri + * @param facade + * @param caldavCalendarUri + * @param stats + * @param notifyList + * @return count of dirty events + */ + private int checkDirtyAndroidEvents( + ContentProviderClient provider, + Account account, + Uri calendarUri, + CaldavFacade facade, + URI caldavCalendarUri, + SyncStats stats, + ArrayList notifyList + ) { + Cursor curEvent = null; + Cursor curAttendee = null; + Cursor curReminder = null; + Long EventID; + Long CalendarID; + AndroidEvent androidEvent = null; + int rowDirty = 0; + int rowInsert = 0; + int rowUpdate = 0; + int rowDelete = 0; - //google doesn't send the etag after creation - //HINT: my SabreDAV send always the same etag after putting a new event - //String LastETag = facade.getLastETag(); - //if (!LastETag.equals("")) { - // values.put(Event.ETAG, LastETag); - //} else { - //so get the etag with a new REPORT - CalendarEvent calendarEvent = new CalendarEvent(account, provider); - calendarEvent.calendarURL = caldavCalendarUri.toURL(); - URI SyncURI = new URI(SyncID); - calendarEvent.setUri(SyncURI); - CaldavFacade.getEvent(calendarEvent); - values.put(Event.ETAG, calendarEvent.getETag()); - //} - values.put(Event.UID, newGUID); - values.put(Events.DIRTY, 0); - values.put(Event.RAWDATA, androidEvent.getIcsEvent().toString()); - - int rowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), values, null, null); - if (rowCount == 1) { - rowInsert += 1; - notifyList.add(androidEvent.getUri()); - } - } - } else if (Deleted) { - // deleted Android event - if (facade.deleteEvent(URI.create(SyncID), androidEvent.getETag())) { - String mSelectionClause = "(" + Events._ID + "= ?)"; - String[] mSelectionArgs = {String.valueOf(EventID)}; - - int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs); - - if (countDeleted == 1) { - rowDelete += 1; - notifyList.add(androidEvent.getUri()); - } - } - } else { - //update the android event to the server - String uid = androidEvent.getUID(); - if ((uid == null) || (uid.equals(""))) { - //COMPAT: this is needed because in the past, the UID was not stored in the android event - CalendarEvent calendarEvent = new CalendarEvent(account, provider); - URI syncURI = new URI(SyncID); - calendarEvent.setUri(syncURI); - calendarEvent.calendarURL = caldavCalendarUri.toURL(); - if (calendarEvent.fetchBody()) { - calendarEvent.readContentValues(); - uid = calendarEvent.getUID(); - } - } - if (uid != null) { - androidEvent.createIcs(uid); - - if (facade.updateEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString(), androidEvent.getETag())) { - selection = "(" + Events._ID + "= ?)"; - selectionArgs = new String[] {EventID.toString()}; - androidEvent.ContentValues.put(Events.DIRTY, 0); + try { + CalendarID = ContentUris.parseId(calendarUri); + String selection = "(" + Events.DIRTY + " = ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] selectionArgs = new String[]{"1", CalendarID.toString()}; + curEvent = provider.query(Events.CONTENT_URI, null, selection, selectionArgs, null); - //google doesn't send the etag after update - String LastETag = facade.getLastETag(); - if (!LastETag.equals("")) { - androidEvent.ContentValues.put(Event.ETAG, LastETag); - } else { - //so get the etag with a new REPORT - CalendarEvent calendarEvent = new CalendarEvent(account, provider); - calendarEvent.calendarURL = caldavCalendarUri.toURL(); - URI SyncURI = new URI(SyncID); - calendarEvent.setUri(SyncURI); - CaldavFacade.getEvent(calendarEvent); - androidEvent.ContentValues.put(Event.ETAG, calendarEvent.getETag()); - } - androidEvent.ContentValues.put(Event.RAWDATA, androidEvent.getIcsEvent().toString()); - int RowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), androidEvent.ContentValues, null, null); - - if (RowCount == 1) { - rowUpdate += 1; - notifyList.add(androidEvent.getUri()); - } - } else { - rowDirty += 1; - } - } else { - rowDirty += 1; - } - } - } - curEvent.close(); + while (curEvent.moveToNext()) { + EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID)); + Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID); + + //androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri); + androidEvent = new AndroidEvent(returnedUri, calendarUri); + androidEvent.readContentValues(curEvent); + + selection = "(" + Attendees.EVENT_ID + " = ?)"; + selectionArgs = new String[]{String.valueOf(EventID)}; + curAttendee = provider.query(Attendees.CONTENT_URI, null, selection, selectionArgs, null); + selection = "(" + Reminders.EVENT_ID + " = ?)"; + selectionArgs = new String[]{String.valueOf(EventID)}; + curReminder = provider.query(Reminders.CONTENT_URI, null, selection, selectionArgs, null); + androidEvent.readAttendees(curAttendee); + androidEvent.readReminder(curReminder); + curAttendee.close(); + curReminder.close(); + + String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID); + + boolean Deleted = false; + int intDeleted = 0; + intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED)); + Deleted = (intDeleted == 1); + + if (SyncID == null) { + // new Android event + String newGUID = java.util.UUID.randomUUID().toString() + "-caldavsyncadapter"; + String calendarPath = caldavCalendarUri.getPath(); + if (!calendarPath.endsWith("/")) + calendarPath += "/"; + + SyncID = calendarPath + newGUID + ".ics"; + + androidEvent.createIcs(newGUID); + + if (facade.createEvent(URI.create(SyncID), androidEvent.getIcsEvent() + .toString())) { + //HINT: bugfix for google calendar replace("@", "%40") + if (SyncID.contains("@")) + SyncID = SyncID.replace("@", "%40"); + ContentValues values = new ContentValues(); + values.put(Events._SYNC_ID, SyncID); + + //google doesn't send the etag after creation + //HINT: my SabreDAV send always the same etag after putting a new event + //String LastETag = facade.getLastETag(); + //if (!LastETag.equals("")) { + // values.put(Event.ETAG, LastETag); + //} else { + //so get the etag with a new REPORT + CalendarEvent calendarEvent = new CalendarEvent(account, provider); + calendarEvent.calendarURL = caldavCalendarUri.toURL(); + URI SyncURI = new URI(SyncID); + calendarEvent.setUri(SyncURI); + CaldavFacade.getEvent(calendarEvent); + values.put(Event.ETAG, calendarEvent.getETag()); + //} + values.put(Event.UID, newGUID); + values.put(Events.DIRTY, 0); + values.put(Event.RAWDATA, androidEvent.getIcsEvent().toString()); + + int rowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), values, null, null); + if (rowCount == 1) { + rowInsert += 1; + notifyList.add(androidEvent.getUri()); + } + } + } else if (Deleted) { + // deleted Android event + if (facade.deleteEvent(URI.create(SyncID), androidEvent.getETag())) { + String mSelectionClause = "(" + Events._ID + "= ?)"; + String[] mSelectionArgs = {String.valueOf(EventID)}; + + int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs); + + if (countDeleted == 1) { + rowDelete += 1; + notifyList.add(androidEvent.getUri()); + } + } + } else { + //update the android event to the server + String uid = androidEvent.getUID(); + if ((uid == null) || (uid.equals(""))) { + //COMPAT: this is needed because in the past, the UID was not stored in the android event + CalendarEvent calendarEvent = new CalendarEvent(account, provider); + URI syncURI = new URI(SyncID); + calendarEvent.setUri(syncURI); + calendarEvent.calendarURL = caldavCalendarUri.toURL(); + if (calendarEvent.fetchBody()) { + calendarEvent.readContentValues(); + uid = calendarEvent.getUID(); + } + } + if (uid != null) { + androidEvent.createIcs(uid); + + if (facade.updateEvent(URI.create(SyncID), androidEvent.getIcsEvent() + .toString(), androidEvent.getETag())) { + selection = "(" + Events._ID + "= ?)"; + selectionArgs = new String[]{EventID.toString()}; + androidEvent.ContentValues.put(Events.DIRTY, 0); + + //google doesn't send the etag after update + String LastETag = facade.getLastETag(); + if (!LastETag.equals("")) { + androidEvent.ContentValues.put(Event.ETAG, LastETag); + } else { + //so get the etag with a new REPORT + CalendarEvent calendarEvent = new CalendarEvent(account, provider); + calendarEvent.calendarURL = caldavCalendarUri.toURL(); + URI SyncURI = new URI(SyncID); + calendarEvent.setUri(SyncURI); + CaldavFacade.getEvent(calendarEvent); + androidEvent.ContentValues.put(Event.ETAG, calendarEvent.getETag()); + } + androidEvent.ContentValues.put(Event.RAWDATA, androidEvent.getIcsEvent() + .toString()); + int RowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), androidEvent.ContentValues, null, null); + + if (RowCount == 1) { + rowUpdate += 1; + notifyList.add(androidEvent.getUri()); + } + } else { + rowDirty += 1; + } + } else { + rowDirty += 1; + } + } + } + curEvent.close(); /*if ((rowInsert > 0) || (rowUpdate > 0) || (rowDelete > 0) || (rowDirty > 0)) { Log.i(TAG,"Android Rows inserted: " + String.valueOf(rowInsert)); @@ -569,33 +588,33 @@ Log.i(TAG,"Android Rows deleted: " + String.valueOf(rowDelete)); Log.i(TAG,"Android Rows dirty: " + String.valueOf(rowDirty)); }*/ - - stats.numInserts += rowInsert; - stats.numUpdates += rowUpdate; - stats.numDeletes += rowDelete; - stats.numSkippedEntries += rowDirty; - stats.numEntries += rowInsert + rowUpdate + rowDelete; - } catch (RemoteException e) { - e.printStackTrace(); - } catch (URISyntaxException e) { - // TODO Automatisch generierter Erfassungsblock - e.printStackTrace(); - } catch (ClientProtocolException e) { - // TODO Automatisch generierter Erfassungsblock - e.printStackTrace(); - } catch (IOException e) { - // TODO Automatisch generierter Erfassungsblock - e.printStackTrace(); - } catch (CaldavProtocolException e) { - // TODO Automatisch generierter Erfassungsblock - e.printStackTrace(); - } catch (ParserException e) { - // TODO Automatisch generierter Erfassungsblock - e.printStackTrace(); - } - - return rowDirty; - } + + stats.numInserts += rowInsert; + stats.numUpdates += rowUpdate; + stats.numDeletes += rowDelete; + stats.numSkippedEntries += rowDirty; + stats.numEntries += rowInsert + rowUpdate + rowDelete; + } catch (RemoteException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + // TODO Automatisch generierter Erfassungsblock + e.printStackTrace(); + } catch (ClientProtocolException e) { + // TODO Automatisch generierter Erfassungsblock + e.printStackTrace(); + } catch (IOException e) { + // TODO Automatisch generierter Erfassungsblock + e.printStackTrace(); + } catch (CaldavProtocolException e) { + // TODO Automatisch generierter Erfassungsblock + e.printStackTrace(); + } catch (ParserException e) { + // TODO Automatisch generierter Erfassungsblock + e.printStackTrace(); + } + + return rowDirty; + } /* private Account UpgradeAccount(Account OldAccount) { String Username = OldAccount.name; @@ -624,13 +643,13 @@ selection, selectionArgs); }*/ - - private static Uri asSyncAdapter(Uri uri, String account, String accountType) { - return uri.buildUpon() - .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") - .appendQueryParameter(Calendars.ACCOUNT_NAME, account) - .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); - } + + private static Uri asSyncAdapter(Uri uri, String account, String accountType) { + return uri.buildUpon() + .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true") + .appendQueryParameter(Calendars.ACCOUNT_NAME, account) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); + } }