Merge https://github.com/gggard/AndroidCaldavSyncAdapater/pull/206/

Tue, 10 Feb 2015 22:40:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 22:40:00 +0100
changeset 8
ec8af0e3fbc2
parent 7
9250fd79cb4e
child 9
bcc778a42b8c

Merge https://github.com/gggard/AndroidCaldavSyncAdapater/pull/206/

res/layout/activity_authenticator.xml file | annotate | diff | comparison | revisions
res/menu/activity_authenticator.xml file | annotate | diff | comparison | revisions
res/values-de/strings_activity_authenticator.xml file | annotate | diff | comparison | revisions
res/values/strings_activity_authenticator.xml file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/Constants.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/caldav/CopyOfEasySSLSocketFactory.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java file | annotate | diff | comparison | revisions
src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java file | annotate | diff | comparison | revisions
     1.1 --- a/res/layout/activity_authenticator.xml	Tue Feb 10 21:55:00 2015 +0100
     1.2 +++ b/res/layout/activity_authenticator.xml	Tue Feb 10 22:40:00 2015 +0100
     1.3 @@ -71,6 +71,14 @@
     1.4  
     1.5                  <requestFocus />
     1.6              </EditText>
     1.7 +            
     1.8 +    		<CheckBox
     1.9 +    		    android:id="@+id/trustall"
    1.10 +    		    android:layout_width="wrap_content"
    1.11 +    		    android:layout_height="wrap_content"
    1.12 +    		    android:checked="true"
    1.13 +    		    android:text="@string/trustall"
    1.14 +    		    android:visibility="gone" />
    1.15  
    1.16              <EditText
    1.17                  android:id="@+id/accountname"
     2.1 --- a/res/menu/activity_authenticator.xml	Tue Feb 10 21:55:00 2015 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,8 +0,0 @@
     2.4 -<menu xmlns:android="http://schemas.android.com/apk/res/android" >
     2.5 -
     2.6 -    <item
     2.7 -        android:id="@+id/menu_forgot_password"
     2.8 -        android:showAsAction="never"
     2.9 -        android:title="@string/menu_forgot_password"/>
    2.10 -
    2.11 -</menu>
    2.12 \ No newline at end of file
     3.1 --- a/res/values-de/strings_activity_authenticator.xml	Tue Feb 10 21:55:00 2015 +0100
     3.2 +++ b/res/values-de/strings_activity_authenticator.xml	Tue Feb 10 22:40:00 2015 +0100
     3.3 @@ -24,6 +24,9 @@
     3.4      <string name="error_account_already_in_use" >Account bereits in Verwendung</string>
     3.5      <string name="success_calendar">Verbindung erfolgreich (Kalender)</string>
     3.6      <string name="success_collection">Verbindung erfolgreich (mehrere Kalender)</string>
     3.7 -    
     3.8 +    <string name="trustall">Überprüfe SSL Zertifikat</string>
     3.9 +    <string name="error_ssl">SSL Fehler</string>
    3.10 +    <string name="error_untrusted_certificate">Nicht vertrauenswürdiges Zertifikat</string>
    3.11 +
    3.12  
    3.13  </resources>
    3.14 \ No newline at end of file
     4.1 --- a/res/values/strings_activity_authenticator.xml	Tue Feb 10 21:55:00 2015 +0100
     4.2 +++ b/res/values/strings_activity_authenticator.xml	Tue Feb 10 22:40:00 2015 +0100
     4.3 @@ -22,8 +22,10 @@
     4.4      <string name="error_connection_refused">Connection refused</string>
     4.5      <string name="error_unkown_error">Unknown error</string>
     4.6      <string name="error_account_already_in_use">Account already added</string>
     4.7 +    <string name="error_ssl">SSL error</string>
     4.8      <string name="success_calendar">Connection success (calendar)</string>
     4.9      <string name="success_collection">Connection success (multiple calendars)</string>
    4.10 -    
    4.11 +    <string name="trustall">Check SSL Certificate</string>
    4.12 +    <string name="error_untrusted_certificate">Untrusted certificate</string>
    4.13  
    4.14 -</resources>
    4.15 \ No newline at end of file
    4.16 +</resources>
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/org/gege/caldavsyncadapter/Constants.java	Tue Feb 10 22:40:00 2015 +0100
     5.3 @@ -0,0 +1,10 @@
     5.4 +package org.gege.caldavsyncadapter;
     5.5 +
     5.6 +/**
     5.7 + * @author Joseph Weigl
     5.8 + */
     5.9 +public class Constants {
    5.10 +
    5.11 +    public static final String USER_DATA_TRUST_ALL_KEY = "USER_DATA_TRUSTALL_KEY";
    5.12 +
    5.13 +}
     6.1 --- a/src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java	Tue Feb 10 21:55:00 2015 +0100
     6.2 +++ b/src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java	Tue Feb 10 22:40:00 2015 +0100
     6.3 @@ -1,6 +1,6 @@
     6.4  /**
     6.5   * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger
     6.6 - * 
     6.7 + *
     6.8   * This file is part of Andoid Caldav Sync Adapter Free.
     6.9   *
    6.10   * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
    6.11 @@ -16,13 +16,17 @@
    6.12   * You should have received a copy of the GNU General Public License
    6.13   * along with Andoid Caldav Sync Adapter Free.  
    6.14   * If not, see <http://www.gnu.org/licenses/>.
    6.15 - * 
    6.16 + *
    6.17   */
    6.18  
    6.19  package org.gege.caldavsyncadapter.android.entities;
    6.20  
    6.21 -import java.net.URISyntaxException;
    6.22 -import java.text.ParseException;
    6.23 +import android.database.Cursor;
    6.24 +import android.net.Uri;
    6.25 +import android.provider.CalendarContract.Attendees;
    6.26 +import android.provider.CalendarContract.Events;
    6.27 +import android.provider.CalendarContract.Reminders;
    6.28 +
    6.29  import net.fortuna.ical4j.model.Calendar;
    6.30  import net.fortuna.ical4j.model.Component;
    6.31  import net.fortuna.ical4j.model.ComponentList;
    6.32 @@ -62,255 +66,258 @@
    6.33  import net.fortuna.ical4j.model.property.Trigger;
    6.34  import net.fortuna.ical4j.model.property.Uid;
    6.35  import net.fortuna.ical4j.model.property.Version;
    6.36 +
    6.37 +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
    6.38 +
    6.39 +import java.net.URISyntaxException;
    6.40 +import java.text.ParseException;
    6.41 +
    6.42  //import android.accounts.Account;
    6.43  //import android.content.ContentProviderClient;
    6.44  //import android.content.ContentValues;
    6.45  //import android.content.SyncStats;
    6.46 -import android.database.Cursor;
    6.47 -import android.net.Uri;
    6.48  //import android.os.RemoteException;
    6.49 -import android.provider.CalendarContract.Attendees;
    6.50  //import android.provider.CalendarContract.Calendars;
    6.51 -import android.provider.CalendarContract.Events;
    6.52 -import android.provider.CalendarContract.Reminders;
    6.53 -
    6.54  //import org.gege.caldavsyncadapter.Event;
    6.55  //import org.gege.caldavsyncadapter.caldav.CaldavFacade;
    6.56 -import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
    6.57  //import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
    6.58  //import org.gege.caldavsyncadapter.syncadapter.SyncAdapter;
    6.59  
    6.60  public class AndroidEvent extends org.gege.caldavsyncadapter.Event {
    6.61  
    6.62 -	private Uri muri;
    6.63 -	
    6.64 -	private Uri mAndroidCalendarUri;
    6.65 -	
    6.66 -	/**
    6.67 -	 * the list of attendees
    6.68 -	 */
    6.69 -	private PropertyList mAttendees = new PropertyList();
    6.70 -	
    6.71 -	/**
    6.72 -	 * the list of reminders 
    6.73 -	 */
    6.74 -	private ComponentList mReminders = new ComponentList();
    6.75 +    private Uri muri;
    6.76  
    6.77 -	private Calendar mCalendar = null;
    6.78 +    private Uri mAndroidCalendarUri;
    6.79 +
    6.80 +    /**
    6.81 +     * the list of attendees
    6.82 +     */
    6.83 +    private PropertyList mAttendees = new PropertyList();
    6.84 +
    6.85 +    /**
    6.86 +     * the list of reminders
    6.87 +     */
    6.88 +    private ComponentList mReminders = new ComponentList();
    6.89 +
    6.90 +    private Calendar mCalendar = null;
    6.91  
    6.92  /*	private Account mAccount = null;
    6.93 -	private ContentProviderClient mProvider = null;*/
    6.94 -	
    6.95 -	//public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) {
    6.96 -	public AndroidEvent(Uri uri, Uri calendarUri) {
    6.97 -		super();
    6.98 -		this.setUri(uri);
    6.99 +    private ContentProviderClient mProvider = null;*/
   6.100 +
   6.101 +    //public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) {
   6.102 +    public AndroidEvent(Uri uri, Uri calendarUri) {
   6.103 +        super();
   6.104 +        this.setUri(uri);
   6.105  /*		this.mAccount = account;
   6.106 -		this.mProvider = provider;*/
   6.107 -		//this.setCounterpartUri(calendarUri);
   6.108 -		mAndroidCalendarUri = calendarUri;
   6.109 -	}
   6.110 -	
   6.111 -	public Calendar getIcsEvent() {
   6.112 -		return mCalendar;
   6.113 -	}
   6.114 -	
   6.115 -	public String getETag() {
   6.116 -		String Result = "";
   6.117 -		if (this.ContentValues.containsKey(ETAG))
   6.118 -			Result = this.ContentValues.getAsString(ETAG);
   6.119 -		return Result;
   6.120 -	}
   6.121 +        this.mProvider = provider;*/
   6.122 +        //this.setCounterpartUri(calendarUri);
   6.123 +        mAndroidCalendarUri = calendarUri;
   6.124 +    }
   6.125  
   6.126 -	public void setETag(String eTag) {
   6.127 -		this.ContentValues.put(ETAG, eTag);
   6.128 -	}
   6.129 -	
   6.130 -	public Uri getUri() {
   6.131 -		return muri;
   6.132 -	}
   6.133 +    public Calendar getIcsEvent() {
   6.134 +        return mCalendar;
   6.135 +    }
   6.136  
   6.137 -	public void setUri(Uri uri) {
   6.138 -		this.muri = uri;
   6.139 -	}
   6.140 -	
   6.141 -	public Uri getAndroidCalendarUri() {
   6.142 -		return mAndroidCalendarUri;
   6.143 -	}
   6.144 -	
   6.145 -	@Override
   6.146 -	public String toString() {
   6.147 -		return this.getUri().toString();
   6.148 -	}
   6.149 -	
   6.150 -	/**
   6.151 -	 * reads an android event from a given cursor into {@link AndroidEvent#ContentValues}
   6.152 -	 * @param cur the cursor with the event
   6.153 -	 * @return success of this funtion
   6.154 -	 * @see AndroidEvent#ContentValues
   6.155 -	 */
   6.156 -	public boolean readContentValues(Cursor cur) {
   6.157 -		this.setETag(cur.getString(cur.getColumnIndex(ETAG)));
   6.158 +    public String getETag() {
   6.159 +        String Result = "";
   6.160 +        if (this.ContentValues.containsKey(ETAG))
   6.161 +            Result = this.ContentValues.getAsString(ETAG);
   6.162 +        return Result;
   6.163 +    }
   6.164  
   6.165 -		this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE)));
   6.166 -		this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE)));
   6.167 -		this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART)));
   6.168 -		this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND)));
   6.169 -		this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY)));
   6.170 -		this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE)));
   6.171 -		this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID)));
   6.172 -		this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID)));
   6.173 -		//this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read
   6.174 -		this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION)));
   6.175 -		this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION)));
   6.176 -		this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL)));
   6.177 -		
   6.178 -		this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS)));
   6.179 -		
   6.180 -		this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE)));
   6.181 -		this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION)));
   6.182 +    public void setETag(String eTag) {
   6.183 +        this.ContentValues.put(ETAG, eTag);
   6.184 +    }
   6.185  
   6.186 -		this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE)));
   6.187 -		this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE)));
   6.188 -		this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE)));
   6.189 -		this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE)));		
   6.190 -		this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY)));
   6.191 -		this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID)));
   6.192 -		this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA)));
   6.193 -		
   6.194 -		return true;
   6.195 -	}
   6.196 -	
   6.197 -	/**
   6.198 -	 * reads the attendees from a given cursor
   6.199 -	 * @param cur the cursor with the attendees
   6.200 -	 * @return success of this function
   6.201 -	 * @see AndroidEvent#mAttendees
   6.202 -	 */
   6.203 -	public boolean readAttendees(Cursor cur) {
   6.204 -		Attendee attendee = null;
   6.205 -		Organizer organizer = null;
   6.206 -		ParameterList paraList = null;
   6.207 +    public Uri getUri() {
   6.208 +        return muri;
   6.209 +    }
   6.210  
   6.211 -		String Name = "";
   6.212 -		Cn cn = null;
   6.213 +    public void setUri(Uri uri) {
   6.214 +        this.muri = uri;
   6.215 +    }
   6.216  
   6.217 -		String Email = "";
   6.218 +    public Uri getAndroidCalendarUri() {
   6.219 +        return mAndroidCalendarUri;
   6.220 +    }
   6.221  
   6.222 -		int Relationship = 0;
   6.223 -		
   6.224 -		
   6.225 -		int Status = 0;
   6.226 -		PartStat partstat = null;
   6.227 +    @Override
   6.228 +    public String toString() {
   6.229 +        return this.getUri().toString();
   6.230 +    }
   6.231  
   6.232 -		int Type = 0;
   6.233 -		Role role = null;
   6.234 -		
   6.235 -		try {
   6.236 -			while (cur.moveToNext()) {
   6.237 -				Name         = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME));
   6.238 -				Email        = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL));
   6.239 -				Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP));
   6.240 -				Type         = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE));
   6.241 -				Status       = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS));
   6.242 -				
   6.243 -				if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) {
   6.244 -					organizer = new Organizer();
   6.245 -					organizer.setValue("mailto:" + Email);
   6.246 -					paraList = organizer.getParameters();
   6.247 -					mAttendees.add(organizer);
   6.248 -				} else {
   6.249 -					attendee = new Attendee();
   6.250 -					attendee.setValue("mailto:" + Email);
   6.251 -					paraList = attendee.getParameters();
   6.252 -					mAttendees.add(attendee);
   6.253 -				}
   6.254 -				
   6.255 -				Rsvp rsvp = new Rsvp(true);
   6.256 -				paraList.add(rsvp);
   6.257 +    /**
   6.258 +     * reads an android event from a given cursor into {@link AndroidEvent#ContentValues}
   6.259 +     *
   6.260 +     * @param cur the cursor with the event
   6.261 +     * @return success of this funtion
   6.262 +     * @see AndroidEvent#ContentValues
   6.263 +     */
   6.264 +    public boolean readContentValues(Cursor cur) {
   6.265 +        this.setETag(cur.getString(cur.getColumnIndex(ETAG)));
   6.266  
   6.267 -				cn = new Cn(Name);
   6.268 -				paraList.add(cn);
   6.269 -				
   6.270 -				if (Status == Attendees.ATTENDEE_STATUS_INVITED)
   6.271 -					partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
   6.272 -				else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED)
   6.273 -					partstat = new PartStat(PartStat.ACCEPTED.getValue());
   6.274 -				else if (Status == Attendees.ATTENDEE_STATUS_DECLINED)
   6.275 -					partstat = new PartStat(PartStat.DECLINED.getValue());
   6.276 -				else if (Status == Attendees.ATTENDEE_STATUS_NONE)
   6.277 -					partstat = new PartStat(PartStat.COMPLETED.getValue());
   6.278 -				else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE)
   6.279 -					partstat = new PartStat(PartStat.TENTATIVE.getValue());
   6.280 -				else 
   6.281 -					partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
   6.282 -				paraList.add(partstat);
   6.283 +        this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE)));
   6.284 +        this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE)));
   6.285 +        this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART)));
   6.286 +        this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND)));
   6.287 +        this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY)));
   6.288 +        this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE)));
   6.289 +        this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID)));
   6.290 +        this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID)));
   6.291 +        //this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read
   6.292 +        this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION)));
   6.293 +        this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION)));
   6.294 +        this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL)));
   6.295  
   6.296 -				if (Type == Attendees.TYPE_OPTIONAL)
   6.297 -					role = new Role(Role.OPT_PARTICIPANT.getValue());
   6.298 -				else if (Type == Attendees.TYPE_NONE)
   6.299 -					role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required?
   6.300 -				else if (Type == Attendees.TYPE_REQUIRED)
   6.301 -					role = new Role(Role.REQ_PARTICIPANT.getValue());
   6.302 -				else
   6.303 -					role = new Role(Role.NON_PARTICIPANT.getValue());
   6.304 -				paraList.add(role);
   6.305 -			}
   6.306 +        this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS)));
   6.307  
   6.308 -		} catch (URISyntaxException e) {
   6.309 -			e.printStackTrace();
   6.310 -		}
   6.311 -		return true;
   6.312 -	}
   6.313 -	
   6.314 -	/**
   6.315 -	 * reads the reminders from a given cursor
   6.316 -	 * @param cur the cursor with the reminders
   6.317 -	 * @return success of this function
   6.318 -	 */
   6.319 -	public boolean readReminder(Cursor cur) {
   6.320 -		int Method;
   6.321 -		int Minutes;
   6.322 -		VAlarm reminder;
   6.323 -		while (cur.moveToNext()) {
   6.324 -			reminder = new VAlarm();
   6.325 -			Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD));
   6.326 -			Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1;
   6.327 -			
   6.328 -			
   6.329 -			Dur dur = new Dur(0, 0, Minutes, 0);
   6.330 -			Trigger tri = new Trigger(dur);
   6.331 -			Value val = new Value(Duration.DURATION);
   6.332 -			tri.getParameters().add(val);
   6.333 -			reminder.getProperties().add(tri);
   6.334 +        this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE)));
   6.335 +        this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION)));
   6.336  
   6.337 -			Description desc = new Description();
   6.338 -			desc.setValue("caldavsyncadapter standard description");
   6.339 -			reminder.getProperties().add(desc);
   6.340 +        this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE)));
   6.341 +        this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE)));
   6.342 +        this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE)));
   6.343 +        this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE)));
   6.344 +        this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY)));
   6.345 +        this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID)));
   6.346 +        this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA)));
   6.347  
   6.348 +        return true;
   6.349 +    }
   6.350  
   6.351 -			if (Method == Reminders.METHOD_EMAIL)
   6.352 -				reminder.getProperties().add(Action.EMAIL);
   6.353 -			else
   6.354 -				reminder.getProperties().add(Action.DISPLAY);
   6.355 -			
   6.356 -			this.mReminders.add(reminder);
   6.357 -		}
   6.358 -		return true;
   6.359 -	}
   6.360 -	
   6.361 -	/**
   6.362 -	 * generates a new ics-file.
   6.363 -	 * uses {@link AndroidEvent#ContentValues} as source.
   6.364 -	 * this should only be used when a new event has been generated within android.
   6.365 -	 * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter
   6.366 -	 * @return success of the function
   6.367 -	 * @see CalendarEvent#fetchBody()
   6.368 -	 */
   6.369 -	public boolean createIcs(String strUid) {
   6.370 -		boolean Result = false;
   6.371 -		TimeZone timezone = null;
   6.372 -		TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
   6.373 +    /**
   6.374 +     * reads the attendees from a given cursor
   6.375 +     *
   6.376 +     * @param cur the cursor with the attendees
   6.377 +     * @return success of this function
   6.378 +     * @see AndroidEvent#mAttendees
   6.379 +     */
   6.380 +    public boolean readAttendees(Cursor cur) {
   6.381 +        Attendee attendee = null;
   6.382 +        Organizer organizer = null;
   6.383 +        ParameterList paraList = null;
   6.384 +
   6.385 +        String Name = "";
   6.386 +        Cn cn = null;
   6.387 +
   6.388 +        String Email = "";
   6.389 +
   6.390 +        int Relationship = 0;
   6.391 +
   6.392 +
   6.393 +        int Status = 0;
   6.394 +        PartStat partstat = null;
   6.395 +
   6.396 +        int Type = 0;
   6.397 +        Role role = null;
   6.398 +
   6.399 +        try {
   6.400 +            while (cur.moveToNext()) {
   6.401 +                Name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME));
   6.402 +                Email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL));
   6.403 +                Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP));
   6.404 +                Type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE));
   6.405 +                Status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS));
   6.406 +
   6.407 +                if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) {
   6.408 +                    organizer = new Organizer();
   6.409 +                    organizer.setValue("mailto:" + Email);
   6.410 +                    paraList = organizer.getParameters();
   6.411 +                    mAttendees.add(organizer);
   6.412 +                } else {
   6.413 +                    attendee = new Attendee();
   6.414 +                    attendee.setValue("mailto:" + Email);
   6.415 +                    paraList = attendee.getParameters();
   6.416 +                    mAttendees.add(attendee);
   6.417 +                }
   6.418 +
   6.419 +                Rsvp rsvp = new Rsvp(true);
   6.420 +                paraList.add(rsvp);
   6.421 +
   6.422 +                cn = new Cn(Name);
   6.423 +                paraList.add(cn);
   6.424 +
   6.425 +                if (Status == Attendees.ATTENDEE_STATUS_INVITED)
   6.426 +                    partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
   6.427 +                else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED)
   6.428 +                    partstat = new PartStat(PartStat.ACCEPTED.getValue());
   6.429 +                else if (Status == Attendees.ATTENDEE_STATUS_DECLINED)
   6.430 +                    partstat = new PartStat(PartStat.DECLINED.getValue());
   6.431 +                else if (Status == Attendees.ATTENDEE_STATUS_NONE)
   6.432 +                    partstat = new PartStat(PartStat.COMPLETED.getValue());
   6.433 +                else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE)
   6.434 +                    partstat = new PartStat(PartStat.TENTATIVE.getValue());
   6.435 +                else
   6.436 +                    partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
   6.437 +                paraList.add(partstat);
   6.438 +
   6.439 +                if (Type == Attendees.TYPE_OPTIONAL)
   6.440 +                    role = new Role(Role.OPT_PARTICIPANT.getValue());
   6.441 +                else if (Type == Attendees.TYPE_NONE)
   6.442 +                    role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required?
   6.443 +                else if (Type == Attendees.TYPE_REQUIRED)
   6.444 +                    role = new Role(Role.REQ_PARTICIPANT.getValue());
   6.445 +                else
   6.446 +                    role = new Role(Role.NON_PARTICIPANT.getValue());
   6.447 +                paraList.add(role);
   6.448 +            }
   6.449 +
   6.450 +        } catch (URISyntaxException e) {
   6.451 +            e.printStackTrace();
   6.452 +        }
   6.453 +        return true;
   6.454 +    }
   6.455 +
   6.456 +    /**
   6.457 +     * reads the reminders from a given cursor
   6.458 +     *
   6.459 +     * @param cur the cursor with the reminders
   6.460 +     * @return success of this function
   6.461 +     */
   6.462 +    public boolean readReminder(Cursor cur) {
   6.463 +        int Method;
   6.464 +        int Minutes;
   6.465 +        VAlarm reminder;
   6.466 +        while (cur.moveToNext()) {
   6.467 +            reminder = new VAlarm();
   6.468 +            Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD));
   6.469 +            Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1;
   6.470 +
   6.471 +
   6.472 +            Dur dur = new Dur(0, 0, Minutes, 0);
   6.473 +            Trigger tri = new Trigger(dur);
   6.474 +            Value val = new Value(Duration.DURATION);
   6.475 +            tri.getParameters().add(val);
   6.476 +            reminder.getProperties().add(tri);
   6.477 +
   6.478 +            Description desc = new Description();
   6.479 +            desc.setValue("caldavsyncadapter standard description");
   6.480 +            reminder.getProperties().add(desc);
   6.481 +
   6.482 +
   6.483 +            if (Method == Reminders.METHOD_EMAIL)
   6.484 +                reminder.getProperties().add(Action.EMAIL);
   6.485 +            else
   6.486 +                reminder.getProperties().add(Action.DISPLAY);
   6.487 +
   6.488 +            this.mReminders.add(reminder);
   6.489 +        }
   6.490 +        return true;
   6.491 +    }
   6.492 +
   6.493 +    /**
   6.494 +     * generates a new ics-file.
   6.495 +     * uses {@link AndroidEvent#ContentValues} as source.
   6.496 +     * this should only be used when a new event has been generated within android.
   6.497 +     *
   6.498 +     * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter
   6.499 +     * @return success of the function
   6.500 +     * @see CalendarEvent#fetchBody()
   6.501 +     */
   6.502 +    public boolean createIcs(String strUid) {
   6.503 +        boolean Result = false;
   6.504 +        TimeZone timeZone = null;
   6.505 +        TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
   6.506  //TODO: do not simply create the ics-file new. take into account the RAWDATA if available
   6.507  		/* 
   6.508  		 * dtstart=1365598800000
   6.509 @@ -335,232 +342,239 @@
   6.510  		 * _sync_id=null
   6.511  		 * dirty=1
   6.512  		 */
   6.513 -		
   6.514 -		try {
   6.515 -			mCalendar = new Calendar();
   6.516 -			PropertyList propCalendar = mCalendar.getProperties();
   6.517 -			propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
   6.518 -			propCalendar.add(Version.VERSION_2_0);
   6.519 -			propCalendar.add(CalScale.GREGORIAN);
   6.520 -			
   6.521 -			VEvent event = new VEvent();
   6.522 -			mCalendar.getComponents().add(event);
   6.523 -			PropertyList propEvent = event.getProperties();
   6.524  
   6.525 -			// DTSTAMP -> is created by new VEvent() automatical
   6.526 -			//na 
   6.527 -			
   6.528 -			// CREATED
   6.529 -			//na
   6.530 -			
   6.531 -			// LAST-MODIFIED
   6.532 -			//na
   6.533 -			
   6.534 -			// SEQUENCE
   6.535 -			//na
   6.536 -			
   6.537 -			// DTSTART
   6.538 -			long lngStart = this.ContentValues.getAsLong(Events.DTSTART);
   6.539 -			String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE);
   6.540 -			boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY);
   6.541 -			if (lngStart > 0) {
   6.542 -				DtStart dtStart = new DtStart();
   6.543 -				if (allDay) {
   6.544 -					Date dateStart = new Date();
   6.545 -					dateStart.setTime(lngStart);
   6.546 -					dtStart.setDate(dateStart);
   6.547 -				} else {
   6.548 -					DateTime datetimeStart = new DateTime();
   6.549 -					datetimeStart.setTime(lngStart);
   6.550 -					dtStart.setDate(datetimeStart);
   6.551 +        try {
   6.552 +            mCalendar = new Calendar();
   6.553 +            PropertyList propCalendar = mCalendar.getProperties();
   6.554 +            propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
   6.555 +            propCalendar.add(Version.VERSION_2_0);
   6.556 +            propCalendar.add(CalScale.GREGORIAN);
   6.557  
   6.558 -					timezone = registry.getTimeZone(strTZStart);
   6.559 -					dtStart.setTimeZone(timezone);
   6.560 -					
   6.561 -					// no timezone information for allDay events
   6.562 -					mCalendar.getComponents().add(timezone.getVTimeZone());
   6.563 -				}
   6.564 -				propEvent.add(dtStart);
   6.565 -			}
   6.566 -			
   6.567 -			// DTEND
   6.568 -			long lngEnd       = this.ContentValues.getAsLong(Events.DTEND);
   6.569 -			String strTZEnd   = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE);
   6.570 -			if (strTZEnd == null)
   6.571 -				strTZEnd = strTZStart;
   6.572 -			if (lngEnd > 0) {
   6.573 -				DtEnd dtEnd = new DtEnd();
   6.574 -				if (allDay) {
   6.575 -					Date dateEnd = new Date();
   6.576 -					dateEnd.setTime(lngEnd);
   6.577 -					dtEnd.setDate(dateEnd);
   6.578 -				} else {
   6.579 -					DateTime datetimeEnd = new DateTime();
   6.580 -					datetimeEnd.setTime(lngEnd);
   6.581 -					dtEnd.setDate(datetimeEnd);
   6.582 -					if (strTZEnd != null)
   6.583 -						timezone = registry.getTimeZone(strTZEnd);
   6.584 -					dtEnd.setTimeZone(timezone);
   6.585 -				}
   6.586 -				propEvent.add(dtEnd);
   6.587 -			}
   6.588 -			
   6.589 -			// DURATION
   6.590 -			if (this.ContentValues.containsKey(Events.DURATION)) {
   6.591 -				String strDuration = this.ContentValues.getAsString(Events.DURATION);
   6.592 -				if (strDuration != null) {
   6.593 -					Duration duration = new Duration();
   6.594 -					duration.setValue(strDuration);
   6.595 -					
   6.596 -					propEvent.add(duration);
   6.597 -				}
   6.598 -			}
   6.599 +            VEvent event = new VEvent();
   6.600 +            mCalendar.getComponents().add(event);
   6.601 +            PropertyList propEvent = event.getProperties();
   6.602  
   6.603 -			//RRULE
   6.604 -			if (this.ContentValues.containsKey(Events.RRULE)) {
   6.605 -				String strRrule = this.ContentValues.getAsString(Events.RRULE);
   6.606 -				if (strRrule != null) {
   6.607 -					if (!strRrule.equals("")) {
   6.608 -						RRule rrule = new RRule();
   6.609 -						rrule.setValue(strRrule);
   6.610 -						propEvent.add(rrule);
   6.611 -					}
   6.612 -				}
   6.613 -			}
   6.614 -			
   6.615 -			//RDATE
   6.616 -			if (this.ContentValues.containsKey(Events.RDATE)) {
   6.617 -				String strRdate = this.ContentValues.getAsString(Events.RDATE);
   6.618 -				if (strRdate != null) {
   6.619 -					if (!strRdate.equals("")) {
   6.620 -						RDate rdate = new RDate();
   6.621 -						rdate.setValue(strRdate);
   6.622 -						propEvent.add(rdate);
   6.623 -					}
   6.624 -				}
   6.625 -			}
   6.626 -			
   6.627 -			//EXRULE
   6.628 -			if (this.ContentValues.containsKey(Events.EXRULE)) {
   6.629 -				String strExrule = this.ContentValues.getAsString(Events.EXRULE);
   6.630 -				if (strExrule != null) {
   6.631 -					if (!strExrule.equals("")) {
   6.632 -						ExRule exrule = new ExRule();
   6.633 -						exrule.setValue(strExrule);
   6.634 -						propEvent.add(exrule);
   6.635 -					}
   6.636 -				}
   6.637 -			}
   6.638 -			
   6.639 -			//EXDATE
   6.640 -			if (this.ContentValues.containsKey(Events.EXDATE)) {
   6.641 -				String strExdate = this.ContentValues.getAsString(Events.EXDATE);
   6.642 -				if (strExdate != null) {
   6.643 -					if (!strExdate.equals("")) {
   6.644 -						ExDate exdate = new ExDate();
   6.645 -						exdate.setValue(strExdate);
   6.646 -						propEvent.add(exdate);
   6.647 -					}
   6.648 -				}
   6.649 -			}
   6.650 -			
   6.651 -			//SUMMARY
   6.652 -			if (this.ContentValues.containsKey(Events.TITLE)) {
   6.653 -				String strTitle = this.ContentValues.getAsString(Events.TITLE);
   6.654 -				if (strTitle != null) {
   6.655 -					Summary summary = new Summary(strTitle);
   6.656 -					propEvent.add(summary);
   6.657 -				}
   6.658 -			}
   6.659 -			
   6.660 -			//DESCIPTION
   6.661 -			if (this.ContentValues.containsKey(Events.DESCRIPTION)) {
   6.662 -				String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION);
   6.663 -				if (strDescription != null) {
   6.664 -					if (!strDescription.equals("")) {
   6.665 -						Description description = new Description(strDescription);
   6.666 -						propEvent.add(description);
   6.667 -					}
   6.668 -				}
   6.669 -			}
   6.670 -			
   6.671 -			//LOCATION
   6.672 -			if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) {
   6.673 -				String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION);
   6.674 -				if (strLocation != null) {
   6.675 -					if (!strLocation.equals("")) { 
   6.676 -						Location location = new Location(strLocation);
   6.677 -						propEvent.add(location);
   6.678 -					}
   6.679 -				}
   6.680 -			}
   6.681 -			
   6.682 -			//CLASS / ACCESS_LEVEL
   6.683 -			if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) {
   6.684 -				int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL);
   6.685 -				Clazz clazz = new Clazz();
   6.686 -				if (accessLevel == Events.ACCESS_PUBLIC)
   6.687 -					clazz.setValue(Clazz.PUBLIC.getValue());
   6.688 -				else if (accessLevel == Events.ACCESS_PRIVATE)
   6.689 -					clazz.setValue(Clazz.PRIVATE.getValue());
   6.690 -				else if (accessLevel == Events.ACCESS_CONFIDENTIAL)
   6.691 -					clazz.setValue(Clazz.CONFIDENTIAL.getValue());
   6.692 -				else 
   6.693 -					clazz.setValue(Clazz.PUBLIC.getValue());
   6.694 -				
   6.695 -				propEvent.add(clazz);
   6.696 -			}
   6.697 -			
   6.698 -			//STATUS
   6.699 -			if (this.ContentValues.containsKey(Events.STATUS)) {
   6.700 -				int intStatus = this.ContentValues.getAsInteger(Events.STATUS);
   6.701 -				if (intStatus > -1) {
   6.702 -					Status status = new Status();
   6.703 -					if (intStatus == Events.STATUS_CANCELED) 
   6.704 -						status.setValue(Status.VEVENT_CANCELLED.getValue());
   6.705 -					else if (intStatus == Events.STATUS_CONFIRMED)
   6.706 -						status.setValue(Status.VEVENT_CONFIRMED.getValue());
   6.707 -					else if (intStatus == Events.STATUS_TENTATIVE)
   6.708 -						status.setValue(Status.VEVENT_TENTATIVE.getValue());
   6.709 -					
   6.710 -					propEvent.add(status);
   6.711 -				}
   6.712 -			}
   6.713 +            // DTSTAMP -> is created by new VEvent() automatical
   6.714 +            //na
   6.715  
   6.716 -			//UID
   6.717 -			Uid uid = new Uid(strUid);
   6.718 -			propEvent.add(uid);
   6.719 +            // CREATED
   6.720 +            //na
   6.721  
   6.722 -			// Attendees
   6.723 -			if (mAttendees.size() > 0) {
   6.724 -				for (Object objProp: mAttendees) {
   6.725 -					Property prop = (Property) objProp;
   6.726 -					propEvent.add(prop);
   6.727 -				}
   6.728 -			}
   6.729 -			
   6.730 -			// Reminders
   6.731 -			if (mReminders.size() > 0) {
   6.732 -				for (Object objComp: mReminders) {
   6.733 -					Component com = (Component) objComp;
   6.734 -					event.getAlarms().add(com);
   6.735 -				}
   6.736 -			}
   6.737 -			
   6.738 -		} catch (ParseException e) {
   6.739 -			e.printStackTrace();
   6.740 -		}
   6.741 -		
   6.742 -		return Result;
   6.743 -	}
   6.744 -	
   6.745 -	/**
   6.746 -	 * marks the android event as already handled
   6.747 -	 * @return
   6.748 -	 * @see AndroidEvent#cInternalTag
   6.749 -	 * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
   6.750 -	 * @throws RemoteException
   6.751 -	 */
   6.752 +            // LAST-MODIFIED
   6.753 +            //na
   6.754 +
   6.755 +            // SEQUENCE
   6.756 +            //na
   6.757 +
   6.758 +            // DTSTART
   6.759 +            long lngStart = this.ContentValues.getAsLong(Events.DTSTART);
   6.760 +            String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE);
   6.761 +            boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY);
   6.762 +            if (lngStart > 0) {
   6.763 +                DtStart dtStart = new DtStart();
   6.764 +                if (allDay) {
   6.765 +                    Date dateStart = new Date();
   6.766 +                    dateStart.setTime(lngStart);
   6.767 +                    dtStart.setDate(dateStart);
   6.768 +                } else {
   6.769 +                    DateTime datetimeStart = new DateTime();
   6.770 +                    datetimeStart.setTime(lngStart);
   6.771 +                    dtStart.setDate(datetimeStart);
   6.772 +
   6.773 +                    timeZone = registry.getTimeZone(strTZStart);
   6.774 +                    if (timeZone == null) {
   6.775 +                        java.util.TimeZone systemTimeZone = TimeZone.getTimeZone(strTZStart);
   6.776 +                        if (systemTimeZone == null) {
   6.777 +                            systemTimeZone = TimeZone.getDefault();
   6.778 +                        }
   6.779 +                        timeZone = registry.getTimeZone(systemTimeZone.getID());
   6.780 +                    }
   6.781 +                    dtStart.setTimeZone(timeZone);
   6.782 +
   6.783 +                    // no timezone information for allDay events
   6.784 +                    mCalendar.getComponents().add(timeZone.getVTimeZone());
   6.785 +                }
   6.786 +                propEvent.add(dtStart);
   6.787 +            }
   6.788 +
   6.789 +            // DTEND
   6.790 +            long lngEnd = this.ContentValues.getAsLong(Events.DTEND);
   6.791 +            String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE);
   6.792 +            if (strTZEnd == null)
   6.793 +                strTZEnd = strTZStart;
   6.794 +            if (lngEnd > 0) {
   6.795 +                DtEnd dtEnd = new DtEnd();
   6.796 +                if (allDay) {
   6.797 +                    Date dateEnd = new Date();
   6.798 +                    dateEnd.setTime(lngEnd);
   6.799 +                    dtEnd.setDate(dateEnd);
   6.800 +                } else {
   6.801 +                    DateTime datetimeEnd = new DateTime();
   6.802 +                    datetimeEnd.setTime(lngEnd);
   6.803 +                    dtEnd.setDate(datetimeEnd);
   6.804 +                    if (strTZEnd != null)
   6.805 +                        timeZone = registry.getTimeZone(strTZEnd);
   6.806 +                    dtEnd.setTimeZone(timeZone);
   6.807 +                }
   6.808 +                propEvent.add(dtEnd);
   6.809 +            }
   6.810 +
   6.811 +            // DURATION
   6.812 +            if (this.ContentValues.containsKey(Events.DURATION)) {
   6.813 +                String strDuration = this.ContentValues.getAsString(Events.DURATION);
   6.814 +                if (strDuration != null) {
   6.815 +                    Duration duration = new Duration();
   6.816 +                    duration.setValue(strDuration);
   6.817 +
   6.818 +                    propEvent.add(duration);
   6.819 +                }
   6.820 +            }
   6.821 +
   6.822 +            //RRULE
   6.823 +            if (this.ContentValues.containsKey(Events.RRULE)) {
   6.824 +                String strRrule = this.ContentValues.getAsString(Events.RRULE);
   6.825 +                if (strRrule != null) {
   6.826 +                    if (!strRrule.equals("")) {
   6.827 +                        RRule rrule = new RRule();
   6.828 +                        rrule.setValue(strRrule);
   6.829 +                        propEvent.add(rrule);
   6.830 +                    }
   6.831 +                }
   6.832 +            }
   6.833 +
   6.834 +            //RDATE
   6.835 +            if (this.ContentValues.containsKey(Events.RDATE)) {
   6.836 +                String strRdate = this.ContentValues.getAsString(Events.RDATE);
   6.837 +                if (strRdate != null) {
   6.838 +                    if (!strRdate.equals("")) {
   6.839 +                        RDate rdate = new RDate();
   6.840 +                        rdate.setValue(strRdate);
   6.841 +                        propEvent.add(rdate);
   6.842 +                    }
   6.843 +                }
   6.844 +            }
   6.845 +
   6.846 +            //EXRULE
   6.847 +            if (this.ContentValues.containsKey(Events.EXRULE)) {
   6.848 +                String strExrule = this.ContentValues.getAsString(Events.EXRULE);
   6.849 +                if (strExrule != null) {
   6.850 +                    if (!strExrule.equals("")) {
   6.851 +                        ExRule exrule = new ExRule();
   6.852 +                        exrule.setValue(strExrule);
   6.853 +                        propEvent.add(exrule);
   6.854 +                    }
   6.855 +                }
   6.856 +            }
   6.857 +
   6.858 +            //EXDATE
   6.859 +            if (this.ContentValues.containsKey(Events.EXDATE)) {
   6.860 +                String strExdate = this.ContentValues.getAsString(Events.EXDATE);
   6.861 +                if (strExdate != null) {
   6.862 +                    if (!strExdate.equals("")) {
   6.863 +                        ExDate exdate = new ExDate();
   6.864 +                        exdate.setValue(strExdate);
   6.865 +                        propEvent.add(exdate);
   6.866 +                    }
   6.867 +                }
   6.868 +            }
   6.869 +
   6.870 +            //SUMMARY
   6.871 +            if (this.ContentValues.containsKey(Events.TITLE)) {
   6.872 +                String strTitle = this.ContentValues.getAsString(Events.TITLE);
   6.873 +                if (strTitle != null) {
   6.874 +                    Summary summary = new Summary(strTitle);
   6.875 +                    propEvent.add(summary);
   6.876 +                }
   6.877 +            }
   6.878 +
   6.879 +            //DESCIPTION
   6.880 +            if (this.ContentValues.containsKey(Events.DESCRIPTION)) {
   6.881 +                String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION);
   6.882 +                if (strDescription != null) {
   6.883 +                    if (!strDescription.equals("")) {
   6.884 +                        Description description = new Description(strDescription);
   6.885 +                        propEvent.add(description);
   6.886 +                    }
   6.887 +                }
   6.888 +            }
   6.889 +
   6.890 +            //LOCATION
   6.891 +            if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) {
   6.892 +                String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION);
   6.893 +                if (strLocation != null) {
   6.894 +                    if (!strLocation.equals("")) {
   6.895 +                        Location location = new Location(strLocation);
   6.896 +                        propEvent.add(location);
   6.897 +                    }
   6.898 +                }
   6.899 +            }
   6.900 +
   6.901 +            //CLASS / ACCESS_LEVEL
   6.902 +            if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) {
   6.903 +                int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL);
   6.904 +                Clazz clazz = new Clazz();
   6.905 +                if (accessLevel == Events.ACCESS_PUBLIC)
   6.906 +                    clazz.setValue(Clazz.PUBLIC.getValue());
   6.907 +                else if (accessLevel == Events.ACCESS_PRIVATE)
   6.908 +                    clazz.setValue(Clazz.PRIVATE.getValue());
   6.909 +                else if (accessLevel == Events.ACCESS_CONFIDENTIAL)
   6.910 +                    clazz.setValue(Clazz.CONFIDENTIAL.getValue());
   6.911 +                else
   6.912 +                    clazz.setValue(Clazz.PUBLIC.getValue());
   6.913 +
   6.914 +                propEvent.add(clazz);
   6.915 +            }
   6.916 +
   6.917 +            //STATUS
   6.918 +            if (this.ContentValues.containsKey(Events.STATUS)) {
   6.919 +                int intStatus = this.ContentValues.getAsInteger(Events.STATUS);
   6.920 +                if (intStatus > -1) {
   6.921 +                    Status status = new Status();
   6.922 +                    if (intStatus == Events.STATUS_CANCELED)
   6.923 +                        status.setValue(Status.VEVENT_CANCELLED.getValue());
   6.924 +                    else if (intStatus == Events.STATUS_CONFIRMED)
   6.925 +                        status.setValue(Status.VEVENT_CONFIRMED.getValue());
   6.926 +                    else if (intStatus == Events.STATUS_TENTATIVE)
   6.927 +                        status.setValue(Status.VEVENT_TENTATIVE.getValue());
   6.928 +
   6.929 +                    propEvent.add(status);
   6.930 +                }
   6.931 +            }
   6.932 +
   6.933 +            //UID
   6.934 +            Uid uid = new Uid(strUid);
   6.935 +            propEvent.add(uid);
   6.936 +
   6.937 +            // Attendees
   6.938 +            if (mAttendees.size() > 0) {
   6.939 +                for (Object objProp : mAttendees) {
   6.940 +                    Property prop = (Property) objProp;
   6.941 +                    propEvent.add(prop);
   6.942 +                }
   6.943 +            }
   6.944 +
   6.945 +            // Reminders
   6.946 +            if (mReminders.size() > 0) {
   6.947 +                for (Object objComp : mReminders) {
   6.948 +                    Component com = (Component) objComp;
   6.949 +                    event.getAlarms().add(com);
   6.950 +                }
   6.951 +            }
   6.952 +
   6.953 +        } catch (ParseException e) {
   6.954 +            e.printStackTrace();
   6.955 +        }
   6.956 +
   6.957 +        return Result;
   6.958 +    }
   6.959 +
   6.960 +    /**
   6.961 +     * marks the android event as already handled
   6.962 +     * @return
   6.963 +     * @see AndroidEvent#cInternalTag
   6.964 +     * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
   6.965 +     * @throws RemoteException
   6.966 +     */
   6.967  /*	public boolean tagAndroidEvent() throws RemoteException {
   6.968  		
   6.969  		ContentValues values = new ContentValues();
     7.1 --- a/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java	Tue Feb 10 21:55:00 2015 +0100
     7.2 +++ b/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java	Tue Feb 10 22:40:00 2015 +0100
     7.3 @@ -1,6 +1,6 @@
     7.4  /**
     7.5   * Copyright (c) 2012-2013, Gerald Garcia
     7.6 - * 
     7.7 + *
     7.8   * This file is part of Andoid Caldav Sync Adapter Free.
     7.9   *
    7.10   * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
    7.11 @@ -16,24 +16,11 @@
    7.12   * You should have received a copy of the GNU General Public License
    7.13   * along with Andoid Caldav Sync Adapter Free.  
    7.14   * If not, see <http://www.gnu.org/licenses/>.
    7.15 - * 
    7.16 + *
    7.17   */
    7.18  
    7.19  package org.gege.caldavsyncadapter.authenticator;
    7.20  
    7.21 -import java.io.IOException;
    7.22 -import java.io.UnsupportedEncodingException;
    7.23 -import java.net.MalformedURLException;
    7.24 -import java.net.URISyntaxException;
    7.25 -
    7.26 -import javax.xml.parsers.ParserConfigurationException;
    7.27 -
    7.28 -import org.apache.http.conn.HttpHostConnectException;
    7.29 -import org.gege.caldavsyncadapter.R;
    7.30 -import org.gege.caldavsyncadapter.caldav.CaldavFacade;
    7.31 -import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult;
    7.32 -import org.xml.sax.SAXException;
    7.33 -
    7.34  import android.accounts.Account;
    7.35  import android.accounts.AccountManager;
    7.36  import android.animation.Animator;
    7.37 @@ -45,430 +32,480 @@
    7.38  import android.os.AsyncTask;
    7.39  import android.os.Build;
    7.40  import android.os.Bundle;
    7.41 +import android.text.Editable;
    7.42  import android.text.TextUtils;
    7.43 +import android.text.TextWatcher;
    7.44  import android.util.Log;
    7.45  import android.view.KeyEvent;
    7.46  import android.view.Menu;
    7.47  import android.view.View;
    7.48  import android.view.inputmethod.EditorInfo;
    7.49 +import android.widget.CheckBox;
    7.50  import android.widget.EditText;
    7.51  import android.widget.TextView;
    7.52  import android.widget.Toast;
    7.53  
    7.54 +import org.apache.http.conn.HttpHostConnectException;
    7.55 +import org.gege.caldavsyncadapter.Constants;
    7.56 +import org.gege.caldavsyncadapter.R;
    7.57 +import org.gege.caldavsyncadapter.caldav.CaldavFacade;
    7.58 +import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult;
    7.59 +import org.xml.sax.SAXException;
    7.60 +
    7.61 +import java.io.IOException;
    7.62 +import java.io.UnsupportedEncodingException;
    7.63 +import java.net.MalformedURLException;
    7.64 +import java.net.URISyntaxException;
    7.65 +import java.util.Locale;
    7.66 +
    7.67 +import javax.xml.parsers.ParserConfigurationException;
    7.68 +
    7.69  /**
    7.70   * Activity which displays a login screen to the user, offering registration as
    7.71   * well.
    7.72   */
    7.73  public class AuthenticatorActivity extends Activity {
    7.74 -	
    7.75 -	private static final String TAG = "AuthenticatorActivity";
    7.76  
    7.77 -	private static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account";
    7.78 +    private static final String TAG = "AuthenticatorActivity";
    7.79  
    7.80 -	public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY";
    7.81 -	public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME";
    7.82 -	public static final String USER_DATA_VERSION = "USER_DATA_VERSION";
    7.83 -	public static final String CURRENT_USER_DATA_VERSION = "1";
    7.84 -	
    7.85 -	public static final String ACCOUNT_NAME_SPLITTER = "@";
    7.86 -	
    7.87 -	/**
    7.88 -	 * The default email to populate the email field with.
    7.89 -	 */
    7.90 -	public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";
    7.91 +    private static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account";
    7.92  
    7.93 -	/**
    7.94 -	 * Keep track of the login task to ensure we can cancel it if requested.
    7.95 -	 */
    7.96 -	private UserLoginTask mAuthTask = null;
    7.97 +    public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY";
    7.98 +    public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME";
    7.99 +    public static final String USER_DATA_VERSION = "USER_DATA_VERSION";
   7.100 +    public static final String CURRENT_USER_DATA_VERSION = "1";
   7.101  
   7.102 -	// Values for email and password at the time of the login attempt.
   7.103 -	private String mUser;
   7.104 -	private String mPassword;
   7.105 -	private Context mContext;
   7.106 +    public static final String ACCOUNT_NAME_SPLITTER = "@";
   7.107  
   7.108 -	// UI references.
   7.109 -	private EditText mUserView;
   7.110 -	private EditText mPasswordView;
   7.111 -	private View mLoginFormView;
   7.112 -	private View mLoginStatusView;
   7.113 -	private TextView mLoginStatusMessageView;
   7.114 +    /**
   7.115 +     * The default email to populate the email field with.
   7.116 +     */
   7.117 +    public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";
   7.118  
   7.119 -	private AccountManager mAccountManager;
   7.120 +    /**
   7.121 +     * Keep track of the login task to ensure we can cancel it if requested.
   7.122 +     */
   7.123 +    private UserLoginTask mAuthTask = null;
   7.124  
   7.125 -	private String mURL;
   7.126 -	private EditText mURLView;
   7.127 -	
   7.128 -	private String mAccountname;
   7.129 -	private EditText mAccountnameView;
   7.130 -	
   7.131 -	public AuthenticatorActivity() {
   7.132 -		super();
   7.133 -		
   7.134 -	}
   7.135 -	
   7.136 -	@Override
   7.137 -	protected void onCreate(Bundle savedInstanceState) {
   7.138 -		super.onCreate(savedInstanceState);
   7.139 -		
   7.140 -		mAccountManager = AccountManager.get(this);
   7.141 +    // Values for email and password at the time of the login attempt.
   7.142 +    private String mUser;
   7.143 +    private String mPassword;
   7.144 +    private String mTrustAll;
   7.145 +    private Context mContext;
   7.146  
   7.147 -		setContentView(R.layout.activity_authenticator);
   7.148 +    // UI references.
   7.149 +    private EditText mUserView;
   7.150 +    private EditText mPasswordView;
   7.151 +    private View mLoginFormView;
   7.152 +    private View mLoginStatusView;
   7.153 +    private TextView mLoginStatusMessageView;
   7.154 +    private CheckBox mTrustCheckBox;
   7.155  
   7.156 -		// Set up the login form.
   7.157 -		mUser = getIntent().getStringExtra(EXTRA_EMAIL);
   7.158 -		mUserView = (EditText) findViewById(R.id.user);
   7.159 -		mUserView.setText(mUser);
   7.160 -		
   7.161 -		mContext = getBaseContext();
   7.162 +    private AccountManager mAccountManager;
   7.163  
   7.164 -		mPasswordView = (EditText) findViewById(R.id.password);
   7.165 -		mPasswordView
   7.166 -				.setOnEditorActionListener(new TextView.OnEditorActionListener() {
   7.167 -					@Override
   7.168 -					public boolean onEditorAction(TextView textView, int id,
   7.169 -							KeyEvent keyEvent) {
   7.170 -						if (id == R.id.login || id == EditorInfo.IME_NULL) {
   7.171 -							attemptLogin();
   7.172 -							return true;
   7.173 -						}
   7.174 -						return false;
   7.175 -					}
   7.176 -				});
   7.177 +    private String mURL;
   7.178 +    private EditText mURLView;
   7.179  
   7.180 -		
   7.181 -		mURLView = (EditText) findViewById(R.id.url);
   7.182 -		
   7.183 -		mAccountnameView = (EditText) findViewById(R.id.accountname);
   7.184 -		
   7.185 -		mLoginFormView = findViewById(R.id.login_form);
   7.186 -		mLoginStatusView = findViewById(R.id.login_status);
   7.187 -		mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
   7.188 +    private String mAccountname;
   7.189 +    private EditText mAccountnameView;
   7.190  
   7.191 -		findViewById(R.id.sign_in_button).setOnClickListener(
   7.192 -				new View.OnClickListener() {
   7.193 -					@Override
   7.194 -					public void onClick(View view) {
   7.195 -						attemptLogin();
   7.196 -					}
   7.197 -				});
   7.198 -		
   7.199 -		
   7.200 -	}
   7.201 +    public AuthenticatorActivity() {
   7.202 +        super();
   7.203  
   7.204 -	@Override
   7.205 -	public boolean onCreateOptionsMenu(Menu menu) {
   7.206 -		super.onCreateOptionsMenu(menu);
   7.207 -		getMenuInflater().inflate(R.menu.activity_authenticator, menu);
   7.208 -		return true;
   7.209 -	}
   7.210 +    }
   7.211  
   7.212 -	/**
   7.213 -	 * Attempts to sign in or register the account specified by the login form.
   7.214 -	 * If there are form errors (invalid email, missing fields, etc.), the
   7.215 -	 * errors are presented and no actual login attempt is made.
   7.216 -	 */
   7.217 -	public void attemptLogin() {
   7.218 -		if (mAuthTask != null) {
   7.219 -			return;
   7.220 -		}
   7.221 +    @Override
   7.222 +    protected void onCreate(Bundle savedInstanceState) {
   7.223 +        super.onCreate(savedInstanceState);
   7.224  
   7.225 -		// Reset errors.
   7.226 -		mUserView.setError(null);
   7.227 -		mPasswordView.setError(null);
   7.228 +        mAccountManager = AccountManager.get(this);
   7.229  
   7.230 -		// Store values at the time of the login attempt.
   7.231 -		mUser = mUserView.getText().toString();
   7.232 -		mPassword = mPasswordView.getText().toString();
   7.233 -		mURL = mURLView.getText().toString();
   7.234 -		mAccountname = mAccountnameView.getText().toString();
   7.235 +        setContentView(R.layout.activity_authenticator);
   7.236  
   7.237 -		boolean cancel = false;
   7.238 -		View focusView = null;
   7.239 -		
   7.240 -		if (!mAccountname.equals("")) {
   7.241 -			Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE);
   7.242 -			String TestUrl = mAccountManager.getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY);
   7.243 -			if (TestUrl != null) {
   7.244 -				mAccountnameView.setError(getString(R.string.error_account_already_in_use));
   7.245 -				focusView = mAccountnameView;
   7.246 -				cancel = true;
   7.247 -			}
   7.248 -		}
   7.249 +        // Set up the login form.
   7.250 +        mUser = getIntent().getStringExtra(EXTRA_EMAIL);
   7.251 +        mUserView = (EditText) findViewById(R.id.user);
   7.252 +        mUserView.setText(mUser);
   7.253  
   7.254 -		// Check for a valid password.
   7.255 -		if (TextUtils.isEmpty(mPassword)) {
   7.256 -			mPasswordView.setError(getString(R.string.error_field_required));
   7.257 -			focusView = mPasswordView;
   7.258 -			cancel = true;
   7.259 -		} else if (mPassword.length() < 4) {
   7.260 -			mPasswordView.setError(getString(R.string.error_invalid_password));
   7.261 -			focusView = mPasswordView;
   7.262 -			cancel = true;
   7.263 -		}
   7.264 +        mContext = getBaseContext();
   7.265  
   7.266 -		// Check for a valid email address.
   7.267 -		if (TextUtils.isEmpty(mUser)) {
   7.268 -			mUserView.setError(getString(R.string.error_field_required));
   7.269 -			focusView = mUserView;
   7.270 -			cancel = true;
   7.271 -		} 
   7.272 -		//else if (!mUser.contains("@")) {
   7.273 -		//	mUserView.setError(getString(R.string.error_invalid_email));
   7.274 -		//	focusView = mUserView;
   7.275 -		//	cancel = true;
   7.276 -		//}
   7.277 +        mPasswordView = (EditText) findViewById(R.id.password);
   7.278 +        mPasswordView
   7.279 +                .setOnEditorActionListener(new TextView.OnEditorActionListener() {
   7.280 +                    @Override
   7.281 +                    public boolean onEditorAction(TextView textView, int id,
   7.282 +                                                  KeyEvent keyEvent) {
   7.283 +                        if (id == R.id.login || id == EditorInfo.IME_NULL) {
   7.284 +                            attemptLogin();
   7.285 +                            return true;
   7.286 +                        }
   7.287 +                        return false;
   7.288 +                    }
   7.289 +                });
   7.290  
   7.291 -		if (cancel) {
   7.292 -			// There was an error; don't attempt login and focus the first
   7.293 -			// form field with an error.
   7.294 -			focusView.requestFocus();
   7.295 -		} else {
   7.296 -			// Show a progress spinner, and kick off a background task to
   7.297 -			// perform the user login attempt.
   7.298 -			mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
   7.299 -			showProgress(true);
   7.300 -			mAuthTask = new UserLoginTask();
   7.301 -			mAuthTask.execute((Void) null);
   7.302 -		}
   7.303 -	}
   7.304  
   7.305 -	/**
   7.306 -	 * Shows the progress UI and hides the login form.
   7.307 -	 */
   7.308 -	@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
   7.309 -	private void showProgress(final boolean show) {
   7.310 -		// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
   7.311 -		// for very easy animations. If available, use these APIs to fade-in
   7.312 -		// the progress spinner.
   7.313 -		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
   7.314 -			int shortAnimTime = getResources().getInteger(
   7.315 -					android.R.integer.config_shortAnimTime);
   7.316 +        mURLView = (EditText) findViewById(R.id.url);
   7.317 +        // if the URL start with "https" show the option to disable SSL host verification
   7.318 +        mURLView.addTextChangedListener(new TextWatcher() {
   7.319 +            @Override
   7.320 +            public void onTextChanged(CharSequence s, int start, int before, int count) {
   7.321 +                String url = ((EditText) findViewById(R.id.url)).getText().toString();
   7.322 +                int visible = url.toLowerCase(Locale.getDefault())
   7.323 +                        .startsWith("https") ? View.VISIBLE : View.GONE;
   7.324 +                ((CheckBox) findViewById(R.id.trustall)).setVisibility(visible);
   7.325 +            }
   7.326  
   7.327 -			mLoginStatusView.setVisibility(View.VISIBLE);
   7.328 -			mLoginStatusView.animate().setDuration(shortAnimTime)
   7.329 -					.alpha(show ? 1 : 0)
   7.330 -					.setListener(new AnimatorListenerAdapter() {
   7.331 -						@Override
   7.332 -						public void onAnimationEnd(Animator animation) {
   7.333 -							mLoginStatusView.setVisibility(show ? View.VISIBLE
   7.334 -									: View.GONE);
   7.335 -						}
   7.336 -					});
   7.337 +            @Override
   7.338 +            public void beforeTextChanged(CharSequence s, int start, int count,
   7.339 +                                          int after) {
   7.340 +            }
   7.341  
   7.342 -			mLoginFormView.setVisibility(View.VISIBLE);
   7.343 -			mLoginFormView.animate().setDuration(shortAnimTime)
   7.344 -					.alpha(show ? 0 : 1)
   7.345 -					.setListener(new AnimatorListenerAdapter() {
   7.346 -						@Override
   7.347 -						public void onAnimationEnd(Animator animation) {
   7.348 -							mLoginFormView.setVisibility(show ? View.GONE
   7.349 -									: View.VISIBLE);
   7.350 -						}
   7.351 -					});
   7.352 -		} else {
   7.353 -			// The ViewPropertyAnimator APIs are not available, so simply show
   7.354 -			// and hide the relevant UI components.
   7.355 -			mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
   7.356 -			mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
   7.357 -		}
   7.358 -	}
   7.359 +            @Override
   7.360 +            public void afterTextChanged(Editable s) {
   7.361 +            }
   7.362 +        });
   7.363  
   7.364 -	
   7.365 -	protected enum LoginResult {
   7.366 -		 MalformedURLException, 
   7.367 -		 GeneralSecurityException, 
   7.368 -		 UnkonwnException, 
   7.369 -		 WrongCredentials, 
   7.370 -		 InvalidResponse, 
   7.371 -		 WrongUrl, 
   7.372 -		 ConnectionRefused, 
   7.373 -		 Success_Calendar, 
   7.374 -		 Success_Collection, 
   7.375 -		 Account_Already_In_Use
   7.376 -	}
   7.377 -	
   7.378 -	
   7.379 -	/**
   7.380 -	 * Represents an asynchronous login/registration task used to authenticate
   7.381 -	 * the user.
   7.382 -	 */
   7.383 -	public class UserLoginTask extends AsyncTask<Void, Void, LoginResult> {
   7.384 +        mAccountnameView = (EditText) findViewById(R.id.accountname);
   7.385  
   7.386 -		@Override
   7.387 -		protected LoginResult doInBackground(Void... params) {
   7.388 +        mLoginFormView = findViewById(R.id.login_form);
   7.389 +        mLoginStatusView = findViewById(R.id.login_status);
   7.390 +        mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
   7.391  
   7.392 -			TestConnectionResult result = null;
   7.393 -			
   7.394 -			try {
   7.395 -				CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL);
   7.396 -				String version = "";
   7.397 -				try {
   7.398 -					version = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
   7.399 -				} catch (NameNotFoundException e) {
   7.400 -					version = "unknown";
   7.401 -					e.printStackTrace();
   7.402 -				}
   7.403 -				facade.setVersion(version);
   7.404 -				result = facade.testConnection();
   7.405 -				Log.i(TAG, "testConnection status="+result);
   7.406 -			} catch (HttpHostConnectException e) {
   7.407 -				Log.w(TAG,"testConnection", e);
   7.408 -				return LoginResult.ConnectionRefused;
   7.409 -			} catch (MalformedURLException e) {				
   7.410 -				Log.w(TAG,"testConnection", e);
   7.411 -				return LoginResult.MalformedURLException;
   7.412 -			} catch (UnsupportedEncodingException e) {
   7.413 -				Log.w(TAG,"testConnection", e);
   7.414 -				return LoginResult.UnkonwnException;
   7.415 -			} catch (ParserConfigurationException e) {
   7.416 -				Log.w(TAG,"testConnection", e);
   7.417 -				return LoginResult.UnkonwnException;
   7.418 -			} catch (SAXException e) {
   7.419 -				Log.w(TAG,"testConnection", e);
   7.420 -				return LoginResult.InvalidResponse;
   7.421 -			} catch (IOException e) {
   7.422 -				Log.w(TAG,"testConnection", e);
   7.423 -				return LoginResult.UnkonwnException;
   7.424 -			} catch (URISyntaxException e) {
   7.425 -				Log.w(TAG,"testConnection", e);
   7.426 -				return LoginResult.MalformedURLException;
   7.427 -			}
   7.428 +        findViewById(R.id.sign_in_button).setOnClickListener(
   7.429 +                new View.OnClickListener() {
   7.430 +                    @Override
   7.431 +                    public void onClick(View view) {
   7.432 +                        attemptLogin();
   7.433 +                    }
   7.434 +                }
   7.435 +        );
   7.436  
   7.437 -			if (result == null) {
   7.438 -				return LoginResult.UnkonwnException;
   7.439 -			}
   7.440 -			
   7.441 -			switch (result) {
   7.442 -			
   7.443 -			case SUCCESS:
   7.444 -				boolean OldAccount = false;
   7.445 -				LoginResult Result = LoginResult.Success_Calendar; 
   7.446 +        mTrustCheckBox = (CheckBox) findViewById(R.id.trustall);
   7.447  
   7.448 -				if (OldAccount) {
   7.449 -					final Account account = new Account(mUser, ACCOUNT_TYPE);			
   7.450 -					if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
   7.451 -						Log.v(TAG,"new account created");
   7.452 -						mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
   7.453 -					} else {
   7.454 -						Log.v(TAG,"no new account created");
   7.455 -						Result = LoginResult.Account_Already_In_Use;
   7.456 -					}
   7.457 -				} else {
   7.458 -					final Account account; 
   7.459 -					if (mAccountname.equals("")) {
   7.460 -						account = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, ACCOUNT_TYPE);
   7.461 -					} else {
   7.462 -						account = new Account(mAccountname, ACCOUNT_TYPE);
   7.463 -					}
   7.464 -					if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
   7.465 -						Log.v(TAG,"new account created");
   7.466 -						mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
   7.467 -						mAccountManager.setUserData(account, USER_DATA_USERNAME, mUser);
   7.468 -						mAccountManager.setUserData(account, USER_DATA_VERSION, CURRENT_USER_DATA_VERSION);
   7.469 -					} else {
   7.470 -						Log.v(TAG,"no new account created");
   7.471 -						Result = LoginResult.Account_Already_In_Use;
   7.472 -					}
   7.473 -				}
   7.474 -			
   7.475 -				return Result;
   7.476  
   7.477 -			case WRONG_CREDENTIAL:
   7.478 -				return LoginResult.WrongCredentials;
   7.479 -				
   7.480 -			case WRONG_SERVER_STATUS:
   7.481 -				return LoginResult.InvalidResponse;
   7.482 -				
   7.483 -			case WRONG_URL:
   7.484 -				return LoginResult.WrongUrl;
   7.485 -				
   7.486 -			case WRONG_ANSWER:
   7.487 -				return LoginResult.InvalidResponse;
   7.488 -				
   7.489 -			default:
   7.490 -				return LoginResult.UnkonwnException;
   7.491 -				
   7.492 -			}
   7.493 -			
   7.494 -		}
   7.495 -		
   7.496 +    }
   7.497  
   7.498 -		@Override
   7.499 -		protected void onPostExecute(final LoginResult result) {
   7.500 -			mAuthTask = null;
   7.501 -			showProgress(false);
   7.502 +    @Override
   7.503 +    public boolean onCreateOptionsMenu(Menu menu) {
   7.504 +        super.onCreateOptionsMenu(menu);
   7.505 +        return true;
   7.506 +    }
   7.507  
   7.508 -			int duration = Toast.LENGTH_SHORT;
   7.509 -			Toast toast = null;
   7.510 -			
   7.511 -			switch (result) {
   7.512 -				case Success_Calendar:
   7.513 -					toast = Toast.makeText(getApplicationContext(), R.string.success_calendar, duration);
   7.514 -					toast.show();
   7.515 -					finish();
   7.516 -					break;
   7.517 -					
   7.518 -				case Success_Collection:
   7.519 -					toast = Toast.makeText(getApplicationContext(), R.string.success_collection, duration);
   7.520 -					toast.show();
   7.521 -					finish();
   7.522 -					break;
   7.523 -					
   7.524 -				case MalformedURLException:
   7.525 -					
   7.526 -					toast = Toast.makeText(getApplicationContext(), R.string.error_incorrect_url_format, duration);
   7.527 -					toast.show();
   7.528 -					mURLView.setError(getString(R.string.error_incorrect_url_format));
   7.529 -					mURLView.requestFocus();
   7.530 -					break;
   7.531 -				case InvalidResponse:
   7.532 -					toast =  Toast.makeText(getApplicationContext(), R.string.error_invalid_server_answer, duration);
   7.533 -					toast.show();
   7.534 -					mURLView.setError(getString(R.string.error_invalid_server_answer));
   7.535 -					mURLView.requestFocus();
   7.536 -					break;
   7.537 -				case WrongUrl:
   7.538 -					toast =  Toast.makeText(getApplicationContext(), R.string.error_wrong_url, duration);
   7.539 -					toast.show();
   7.540 -					mURLView.setError(getString(R.string.error_wrong_url));
   7.541 -					mURLView.requestFocus();
   7.542 -					break;
   7.543 -					
   7.544 -				case WrongCredentials:
   7.545 -					mPasswordView.setError(getString(R.string.error_incorrect_password));
   7.546 -					mPasswordView.requestFocus();
   7.547 -					break;
   7.548 -					
   7.549 -				case ConnectionRefused:
   7.550 -					toast =  Toast.makeText(getApplicationContext(), R.string.error_connection_refused, duration);
   7.551 -					toast.show();
   7.552 -					mURLView.setError(getString(R.string.error_connection_refused));
   7.553 -					mURLView.requestFocus();
   7.554 -					break;
   7.555 -				case Account_Already_In_Use:
   7.556 -					toast =  Toast.makeText(getApplicationContext(), R.string.error_account_already_in_use, duration);
   7.557 -					toast.show();
   7.558 -					mURLView.setError(getString(R.string.error_account_already_in_use));
   7.559 -					mURLView.requestFocus();
   7.560 -					break;
   7.561 -				default:
   7.562 -					toast =  Toast.makeText(getApplicationContext(), R.string.error_unkown_error, duration);
   7.563 -					toast.show();
   7.564 -					mURLView.setError(getString(R.string.error_unkown_error));
   7.565 -					mURLView.requestFocus();
   7.566 -					break;
   7.567 -				}
   7.568 -				
   7.569 -				
   7.570 -				
   7.571 -			
   7.572 -		}
   7.573 +    /**
   7.574 +     * Attempts to sign in or register the account specified by the login form.
   7.575 +     * If there are form errors (invalid email, missing fields, etc.), the
   7.576 +     * errors are presented and no actual login attempt is made.
   7.577 +     */
   7.578 +    public void attemptLogin() {
   7.579 +        if (mAuthTask != null) {
   7.580 +            return;
   7.581 +        }
   7.582  
   7.583 -		@Override
   7.584 -		protected void onCancelled() {
   7.585 -			mAuthTask = null;
   7.586 -			showProgress(false);
   7.587 -		}
   7.588 -	}
   7.589 -}
   7.590 +        // Reset errors.
   7.591 +        mUserView.setError(null);
   7.592 +        mPasswordView.setError(null);
   7.593 +
   7.594 +        // Store values at the time of the login attempt.
   7.595 +        mUser = mUserView.getText().toString();
   7.596 +        mPassword = mPasswordView.getText().toString();
   7.597 +        mURL = mURLView.getText().toString();
   7.598 +        mAccountname = mAccountnameView.getText().toString();
   7.599 +        mTrustAll = (mTrustCheckBox.isChecked() ? "false" : "true");
   7.600 +        boolean cancel = false;
   7.601 +        View focusView = null;
   7.602 +
   7.603 +        if (!mAccountname.equals("")) {
   7.604 +            Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE);
   7.605 +            String TestUrl = mAccountManager.getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY);
   7.606 +            if (TestUrl != null) {
   7.607 +                mAccountnameView.setError(getString(R.string.error_account_already_in_use));
   7.608 +                focusView = mAccountnameView;
   7.609 +                cancel = true;
   7.610 +            }
   7.611 +        }
   7.612 +
   7.613 +        // Check for a valid password.
   7.614 +        if (TextUtils.isEmpty(mPassword)) {
   7.615 +            mPasswordView.setError(getString(R.string.error_field_required));
   7.616 +            focusView = mPasswordView;
   7.617 +            cancel = true;
   7.618 +        }
   7.619 +
   7.620 +        // Check for a valid email address.
   7.621 +        if (TextUtils.isEmpty(mUser)) {
   7.622 +            mUserView.setError(getString(R.string.error_field_required));
   7.623 +            focusView = mUserView;
   7.624 +            cancel = true;
   7.625 +        }
   7.626 +        //else if (!mUser.contains("@")) {
   7.627 +        //	mUserView.setError(getString(R.string.error_invalid_email));
   7.628 +        //	focusView = mUserView;
   7.629 +        //	cancel = true;
   7.630 +        //}
   7.631 +
   7.632 +        if (cancel) {
   7.633 +            // There was an error; don't attempt login and focus the first
   7.634 +            // form field with an error.
   7.635 +            focusView.requestFocus();
   7.636 +        } else {
   7.637 +            // Show a progress spinner, and kick off a background task to
   7.638 +            // perform the user login attempt.
   7.639 +            mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
   7.640 +            showProgress(true);
   7.641 +            mAuthTask = new UserLoginTask();
   7.642 +            mAuthTask.execute((Void) null);
   7.643 +        }
   7.644 +    }
   7.645 +
   7.646 +    /**
   7.647 +     * Shows the progress UI and hides the login form.
   7.648 +     */
   7.649 +    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
   7.650 +    private void showProgress(final boolean show) {
   7.651 +        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
   7.652 +        // for very easy animations. If available, use these APIs to fade-in
   7.653 +        // the progress spinner.
   7.654 +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
   7.655 +            int shortAnimTime = getResources().getInteger(
   7.656 +                    android.R.integer.config_shortAnimTime);
   7.657 +
   7.658 +            mLoginStatusView.setVisibility(View.VISIBLE);
   7.659 +            mLoginStatusView.animate().setDuration(shortAnimTime)
   7.660 +                    .alpha(show ? 1 : 0)
   7.661 +                    .setListener(new AnimatorListenerAdapter() {
   7.662 +                        @Override
   7.663 +                        public void onAnimationEnd(Animator animation) {
   7.664 +                            mLoginStatusView.setVisibility(show ? View.VISIBLE
   7.665 +                                    : View.GONE);
   7.666 +                        }
   7.667 +                    });
   7.668 +
   7.669 +            mLoginFormView.setVisibility(View.VISIBLE);
   7.670 +            mLoginFormView.animate().setDuration(shortAnimTime)
   7.671 +                    .alpha(show ? 0 : 1)
   7.672 +                    .setListener(new AnimatorListenerAdapter() {
   7.673 +                        @Override
   7.674 +                        public void onAnimationEnd(Animator animation) {
   7.675 +                            mLoginFormView.setVisibility(show ? View.GONE
   7.676 +                                    : View.VISIBLE);
   7.677 +                        }
   7.678 +                    });
   7.679 +        } else {
   7.680 +            // The ViewPropertyAnimator APIs are not available, so simply show
   7.681 +            // and hide the relevant UI components.
   7.682 +            mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
   7.683 +            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
   7.684 +        }
   7.685 +    }
   7.686 +
   7.687 +
   7.688 +    protected enum LoginResult {
   7.689 +        MalformedURLException,
   7.690 +        GeneralSecurityException,
   7.691 +        UnkonwnException,
   7.692 +        WrongCredentials,
   7.693 +        InvalidResponse,
   7.694 +        WrongUrl,
   7.695 +        ConnectionRefused,
   7.696 +        Success_Calendar,
   7.697 +        Success_Collection,
   7.698 +        UNTRUSTED_CERT,
   7.699 +        Account_Already_In_Use
   7.700 +    }
   7.701 +
   7.702 +
   7.703 +    /**
   7.704 +     * Represents an asynchronous login/registration task used to authenticate
   7.705 +     * the user.
   7.706 +     */
   7.707 +    public class UserLoginTask extends AsyncTask<Void, Void, LoginResult> {
   7.708 +
   7.709 +        @Override
   7.710 +        protected LoginResult doInBackground(Void... params) {
   7.711 +
   7.712 +            TestConnectionResult result = null;
   7.713 +
   7.714 +            try {
   7.715 +                CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL, mTrustAll);
   7.716 +                String version = "";
   7.717 +                try {
   7.718 +                    version = mContext.getPackageManager()
   7.719 +                            .getPackageInfo(mContext.getPackageName(), 0).versionName;
   7.720 +                } catch (NameNotFoundException e) {
   7.721 +                    version = "unknown";
   7.722 +                    e.printStackTrace();
   7.723 +                }
   7.724 +                facade.setVersion(version);
   7.725 +                result = facade.testConnection();
   7.726 +                Log.i(TAG, "testConnection status=" + result);
   7.727 +            } catch (HttpHostConnectException e) {
   7.728 +                Log.w(TAG, "testConnection", e);
   7.729 +                return LoginResult.ConnectionRefused;
   7.730 +            } catch (MalformedURLException e) {
   7.731 +                Log.w(TAG, "testConnection", e);
   7.732 +                return LoginResult.MalformedURLException;
   7.733 +            } catch (UnsupportedEncodingException e) {
   7.734 +                Log.w(TAG, "testConnection", e);
   7.735 +                return LoginResult.UnkonwnException;
   7.736 +            } catch (ParserConfigurationException e) {
   7.737 +                Log.w(TAG, "testConnection", e);
   7.738 +                return LoginResult.UnkonwnException;
   7.739 +            } catch (SAXException e) {
   7.740 +                Log.w(TAG, "testConnection", e);
   7.741 +                return LoginResult.InvalidResponse;
   7.742 +            } catch (IOException e) {
   7.743 +                Log.w(TAG, "testConnection", e);
   7.744 +                return LoginResult.UnkonwnException;
   7.745 +            } catch (URISyntaxException e) {
   7.746 +                Log.w(TAG, "testConnection", e);
   7.747 +                return LoginResult.MalformedURLException;
   7.748 +            }
   7.749 +
   7.750 +            if (result == null) {
   7.751 +                return LoginResult.UnkonwnException;
   7.752 +            }
   7.753 +
   7.754 +            switch (result) {
   7.755 +
   7.756 +                case SSL_ERROR:
   7.757 +                    return LoginResult.UNTRUSTED_CERT;
   7.758 +                case SUCCESS:
   7.759 +                    boolean OldAccount = false;
   7.760 +                    LoginResult Result = LoginResult.Success_Calendar;
   7.761 +
   7.762 +                    if (OldAccount) {
   7.763 +                        final Account account = new Account(mUser, ACCOUNT_TYPE);
   7.764 +                        if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
   7.765 +                            Log.v(TAG, "new account created");
   7.766 +                            mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
   7.767 +                        } else {
   7.768 +                            Log.v(TAG, "no new account created");
   7.769 +                            Result = LoginResult.Account_Already_In_Use;
   7.770 +                        }
   7.771 +                    } else {
   7.772 +                        final Account account;
   7.773 +                        if (mAccountname.equals("")) {
   7.774 +                            account = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, ACCOUNT_TYPE);
   7.775 +                        } else {
   7.776 +                            account = new Account(mAccountname, ACCOUNT_TYPE);
   7.777 +                        }
   7.778 +                        if (mAccountManager.addAccountExplicitly(account, mPassword, null)) {
   7.779 +                            Log.v(TAG, "new account created");
   7.780 +                            mAccountManager.setUserData(account, USER_DATA_URL_KEY, mURL);
   7.781 +                            mAccountManager.setUserData(account, USER_DATA_USERNAME, mUser);
   7.782 +                            mAccountManager.setUserData(account, USER_DATA_VERSION, CURRENT_USER_DATA_VERSION);
   7.783 +                            mAccountManager.setUserData(account, Constants.USER_DATA_TRUST_ALL_KEY, mTrustAll);
   7.784 +                        } else {
   7.785 +                            Log.v(TAG, "no new account created");
   7.786 +                            Result = LoginResult.Account_Already_In_Use;
   7.787 +                        }
   7.788 +                    }
   7.789 +
   7.790 +                    return Result;
   7.791 +
   7.792 +                case WRONG_CREDENTIAL:
   7.793 +                    return LoginResult.WrongCredentials;
   7.794 +
   7.795 +                case WRONG_SERVER_STATUS:
   7.796 +                    return LoginResult.InvalidResponse;
   7.797 +
   7.798 +                case WRONG_URL:
   7.799 +                    return LoginResult.WrongUrl;
   7.800 +
   7.801 +                case WRONG_ANSWER:
   7.802 +                    return LoginResult.InvalidResponse;
   7.803 +
   7.804 +                default:
   7.805 +                    return LoginResult.UnkonwnException;
   7.806 +
   7.807 +            }
   7.808 +
   7.809 +        }
   7.810 +
   7.811 +
   7.812 +        @Override
   7.813 +        protected void onPostExecute(final LoginResult result) {
   7.814 +            mAuthTask = null;
   7.815 +            showProgress(false);
   7.816 +
   7.817 +            int duration = Toast.LENGTH_SHORT;
   7.818 +            Toast toast = null;
   7.819 +
   7.820 +            switch (result) {
   7.821 +                case Success_Calendar:
   7.822 +                    toast = Toast.makeText(getApplicationContext(), R.string.success_calendar, duration);
   7.823 +                    toast.show();
   7.824 +                    finish();
   7.825 +                    break;
   7.826 +
   7.827 +                case Success_Collection:
   7.828 +                    toast = Toast.makeText(getApplicationContext(), R.string.success_collection, duration);
   7.829 +                    toast.show();
   7.830 +                    finish();
   7.831 +                    break;
   7.832 +
   7.833 +                case MalformedURLException:
   7.834 +
   7.835 +                    toast = Toast.makeText(getApplicationContext(), R.string.error_incorrect_url_format, duration);
   7.836 +                    toast.show();
   7.837 +                    mURLView.setError(getString(R.string.error_incorrect_url_format));
   7.838 +                    mURLView.requestFocus();
   7.839 +                    break;
   7.840 +                case InvalidResponse:
   7.841 +                    toast = Toast.makeText(getApplicationContext(), R.string.error_invalid_server_answer, duration);
   7.842 +                    toast.show();
   7.843 +                    mURLView.setError(getString(R.string.error_invalid_server_answer));
   7.844 +                    mURLView.requestFocus();
   7.845 +                    break;
   7.846 +                case WrongUrl:
   7.847 +                    toast = Toast.makeText(getApplicationContext(), R.string.error_wrong_url, duration);
   7.848 +                    toast.show();
   7.849 +                    mURLView.setError(getString(R.string.error_wrong_url));
   7.850 +                    mURLView.requestFocus();
   7.851 +                    break;
   7.852 +
   7.853 +                case GeneralSecurityException:
   7.854 +                    break;
   7.855 +                case UnkonwnException:
   7.856 +                    break;
   7.857 +                case WrongCredentials:
   7.858 +                    mPasswordView.setError(getString(R.string.error_incorrect_password));
   7.859 +                    mPasswordView.requestFocus();
   7.860 +                    break;
   7.861 +
   7.862 +                case ConnectionRefused:
   7.863 +                    toast = Toast.makeText(getApplicationContext(), R.string.error_connection_refused, duration);
   7.864 +                    toast.show();
   7.865 +                    mURLView.setError(getString(R.string.error_connection_refused));
   7.866 +                    mURLView.requestFocus();
   7.867 +                    break;
   7.868 +                case UNTRUSTED_CERT:
   7.869 +                    toast = Toast.makeText(getApplicationContext(), getString(R.string.error_untrusted_certificate), duration);
   7.870 +                    toast.show();
   7.871 +                    mURLView.setError(getString(R.string.error_ssl));
   7.872 +                    mURLView.requestFocus();
   7.873 +                    break;
   7.874 +                case Account_Already_In_Use:
   7.875 +                    toast = Toast.makeText(getApplicationContext(), R.string.error_account_already_in_use, duration);
   7.876 +                    toast.show();
   7.877 +                    mURLView.setError(getString(R.string.error_account_already_in_use));
   7.878 +                    mURLView.requestFocus();
   7.879 +                    break;
   7.880 +                default:
   7.881 +                    toast = Toast.makeText(getApplicationContext(), R.string.error_unkown_error, duration);
   7.882 +                    toast.show();
   7.883 +                    mURLView.setError(getString(R.string.error_unkown_error));
   7.884 +                    mURLView.requestFocus();
   7.885 +                    break;
   7.886 +            }
   7.887 +
   7.888 +
   7.889 +        }
   7.890 +
   7.891 +        @Override
   7.892 +        protected void onCancelled() {
   7.893 +            mAuthTask = null;
   7.894 +            showProgress(false);
   7.895 +        }
   7.896 +    }
   7.897 +}
   7.898 \ No newline at end of file
     8.1 --- a/src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java	Tue Feb 10 21:55:00 2015 +0100
     8.2 +++ b/src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java	Tue Feb 10 22:40:00 2015 +0100
     8.3 @@ -1,6 +1,6 @@
     8.4  /**
     8.5   * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger
     8.6 - * 
     8.7 + *
     8.8   * This file is part of Andoid Caldav Sync Adapter Free.
     8.9   *
    8.10   * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
    8.11 @@ -16,31 +16,15 @@
    8.12   * You should have received a copy of the GNU General Public License
    8.13   * along with Andoid Caldav Sync Adapter Free.  
    8.14   * If not, see <http://www.gnu.org/licenses/>.
    8.15 - * 
    8.16 + *
    8.17   */
    8.18  
    8.19  package org.gege.caldavsyncadapter.caldav;
    8.20  
    8.21 -import java.io.BufferedReader;
    8.22 -import java.io.ByteArrayInputStream;
    8.23 -import java.io.FileNotFoundException;
    8.24 -import java.io.IOException;
    8.25 -import java.io.InputStream;
    8.26 -import java.io.InputStreamReader;
    8.27 -import java.io.UnsupportedEncodingException;
    8.28 -import java.net.MalformedURLException;
    8.29 -import java.net.SocketException;
    8.30 -import java.net.URI;
    8.31 -import java.net.URISyntaxException;
    8.32 -import java.net.URL;
    8.33 -import java.util.ArrayList;
    8.34 -import java.util.List;
    8.35 -
    8.36 -import javax.xml.parsers.DocumentBuilder;
    8.37 -import javax.xml.parsers.DocumentBuilderFactory;
    8.38 -import javax.xml.parsers.ParserConfigurationException;
    8.39 -import javax.xml.parsers.SAXParser;
    8.40 -import javax.xml.parsers.SAXParserFactory;
    8.41 +import android.accounts.Account;
    8.42 +import android.content.ContentProviderClient;
    8.43 +import android.content.Context;
    8.44 +import android.util.Log;
    8.45  
    8.46  import org.apache.http.HttpException;
    8.47  import org.apache.http.HttpHost;
    8.48 @@ -76,11 +60,12 @@
    8.49  import org.apache.http.params.HttpProtocolParams;
    8.50  import org.apache.http.protocol.BasicHttpContext;
    8.51  import org.apache.http.protocol.HttpContext;
    8.52 +import org.apache.http.util.EntityUtils;
    8.53  import org.gege.caldavsyncadapter.BuildConfig;
    8.54 +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
    8.55 +import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
    8.56  import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
    8.57  import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource;
    8.58 -import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
    8.59 -import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
    8.60  import org.gege.caldavsyncadapter.caldav.http.HttpPropFind;
    8.61  import org.gege.caldavsyncadapter.caldav.http.HttpReport;
    8.62  import org.gege.caldavsyncadapter.caldav.xml.CalendarHomeHandler;
    8.63 @@ -96,388 +81,410 @@
    8.64  import org.xml.sax.SAXException;
    8.65  import org.xml.sax.XMLReader;
    8.66  
    8.67 -import android.accounts.Account;
    8.68 -import android.content.ContentProviderClient;
    8.69 -import android.content.Context;
    8.70 -import android.util.Log;
    8.71 +import java.io.ByteArrayInputStream;
    8.72 +import java.io.FileNotFoundException;
    8.73 +import java.io.IOException;
    8.74 +import java.io.InputStream;
    8.75 +import java.io.UnsupportedEncodingException;
    8.76 +import java.net.MalformedURLException;
    8.77 +import java.net.SocketException;
    8.78 +import java.net.URI;
    8.79 +import java.net.URISyntaxException;
    8.80 +import java.net.URL;
    8.81 +import java.util.ArrayList;
    8.82 +import java.util.List;
    8.83 +
    8.84 +import javax.net.ssl.SSLException;
    8.85 +import javax.xml.parsers.DocumentBuilder;
    8.86 +import javax.xml.parsers.DocumentBuilderFactory;
    8.87 +import javax.xml.parsers.ParserConfigurationException;
    8.88 +import javax.xml.parsers.SAXParser;
    8.89 +import javax.xml.parsers.SAXParserFactory;
    8.90  
    8.91  public class CaldavFacade {
    8.92 -	private static final String TAG = "CaldavFacade";
    8.93 +    private static final String TAG = "CaldavFacade";
    8.94  
    8.95 -	private final static String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    8.96 +    private final static String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    8.97  
    8.98 -	private String USER_AGENT = "CalDAV Sync Adapter (Android) https://github.com/gggard/AndroidCaldavSyncAdapater";
    8.99 -	private String VERSION = ""; 
   8.100 +    private String USER_AGENT = "CalDAV Sync Adapter (Android) https://github.com/gggard/AndroidCaldavSyncAdapater";
   8.101 +    private String VERSION = "";
   8.102  
   8.103 -	private static HttpClient httpClient;
   8.104 -	private HttpContext mContext = null;
   8.105 -	private AuthState mLastAuthState = null;
   8.106 -	private AuthScope mLastAuthScope = null;
   8.107 -	
   8.108 -	private boolean trustAll = true;
   8.109 +    private static HttpClient httpClient;
   8.110 +    private HttpContext mContext = null;
   8.111 +    private AuthState mLastAuthState = null;
   8.112 +    private AuthScope mLastAuthScope = null;
   8.113  
   8.114 -	private URL url;
   8.115 +    private boolean mTrustAll = true;
   8.116  
   8.117 -	private static HttpHost targetHost;
   8.118 -	
   8.119 -	private int lastStatusCode;
   8.120 -	private String lastETag;
   8.121 -	private String lastDav;
   8.122 +    private URL url;
   8.123  
   8.124 -	private String mstrcHeaderIfMatch = "If-Match";
   8.125 -	private String mstrcHeaderIfNoneMatch = "If-None-Match";
   8.126 -	
   8.127 -	private Account mAccount = null;
   8.128 -	private ContentProviderClient mProvider;
   8.129 -	
   8.130 -	protected HttpClient getHttpClient() {
   8.131 +    private static HttpHost targetHost;
   8.132  
   8.133 -		HttpParams params = new BasicHttpParams();
   8.134 -		params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
   8.135 -		params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
   8.136 -		params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
   8.137 -		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
   8.138 +    private int lastStatusCode;
   8.139 +    private String lastETag;
   8.140 +    private String lastDav;
   8.141  
   8.142 -		SchemeRegistry registry = new SchemeRegistry();
   8.143 -		registry.register(new Scheme("http", new PlainSocketFactory(), 80));
   8.144 -		registry.register(new Scheme("https", (trustAll ? EasySSLSocketFactory.getSocketFactory() : SSLSocketFactory.getSocketFactory()), 443));
   8.145 -		DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params);
   8.146 -		
   8.147 -		return client;
   8.148 -	}
   8.149 +    private String mstrcHeaderIfMatch = "If-Match";
   8.150 +    private String mstrcHeaderIfNoneMatch = "If-None-Match";
   8.151  
   8.152 -	public CaldavFacade(String mUser, String mPassword, String mURL) throws MalformedURLException {
   8.153 -		url = new URL(mURL);
   8.154 +    private Account mAccount = null;
   8.155 +    private ContentProviderClient mProvider;
   8.156  
   8.157 -		httpClient = getHttpClient();
   8.158 -		UsernamePasswordCredentials upc = new UsernamePasswordCredentials(mUser, mPassword);
   8.159 +    protected HttpClient getHttpClient() {
   8.160  
   8.161 -		AuthScope as = null;
   8.162 -		as = new AuthScope(url.getHost(), -1);
   8.163 -		((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials(as, upc);
   8.164 -		
   8.165 -		mContext = new BasicHttpContext();
   8.166 -		CredentialsProvider credProvider = ((AbstractHttpClient) httpClient).getCredentialsProvider();
   8.167 -		mContext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider);
   8.168 -				
   8.169 -		//http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html
   8.170 -		((AbstractHttpClient) httpClient).addRequestInterceptor(preemptiveAuth, 0);
   8.171 +        HttpParams params = new BasicHttpParams();
   8.172 +        params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
   8.173 +        params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
   8.174 +        params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
   8.175 +        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
   8.176  
   8.177 -		String proto = "http";
   8.178 -		int port = 80;
   8.179 +        SchemeRegistry registry = new SchemeRegistry();
   8.180 +        registry.register(new Scheme("http", new PlainSocketFactory(), 80));
   8.181 +        registry.register(new Scheme("https", (mTrustAll ? EasySSLSocketFactory.getSocketFactory() : SSLSocketFactory
   8.182 +                .getSocketFactory()), 443));
   8.183 +        DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params);
   8.184  
   8.185 -		if (url.getProtocol().equalsIgnoreCase("https")) {
   8.186 -			proto = "https";
   8.187 -			if (url.getPort() == -1)
   8.188 -				port = 443;
   8.189 -			else
   8.190 -				port = url.getPort();
   8.191 -		}
   8.192 +        return client;
   8.193 +    }
   8.194  
   8.195 -		if (url.getProtocol().equalsIgnoreCase("http")) {
   8.196 -			proto = "http";
   8.197 -			if (url.getPort() == -1)
   8.198 -				port = 80;
   8.199 -			else
   8.200 -				port = url.getPort();
   8.201 -		}
   8.202 -		targetHost = new HttpHost(url.getHost(), port, proto);
   8.203 -	}
   8.204 -	
   8.205 -	//http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html
   8.206 -	HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
   8.207 -		@Override
   8.208 -	    public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
   8.209 -	        AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
   8.210 +    public CaldavFacade(String mUser, String mPassword, String mURL, String trustAll) throws MalformedURLException {
   8.211 +        url = new URL(mURL);
   8.212  
   8.213 -	        if (authState.getAuthScheme() == null) {
   8.214 -	        	if (mLastAuthState != null) {
   8.215 -	        		Log.d(TAG, "LastAuthState: restored with user " + mLastAuthState.getCredentials().getUserPrincipal().getName());
   8.216 -	        		authState.setAuthScheme(mLastAuthState.getAuthScheme());
   8.217 -	        		authState.setCredentials(mLastAuthState.getCredentials());
   8.218 -	        	} else {
   8.219 -	        		Log.d(TAG, "LastAuthState: nothing to do");
   8.220 -	        	}
   8.221 -	        	if (mLastAuthScope != null) {
   8.222 -	        		authState.setAuthScope(mLastAuthScope);
   8.223 -	        		Log.d(TAG, "LastAuthScope: restored");
   8.224 -	        	} else {
   8.225 -	        		Log.d(TAG, "LastAuthScope: nothing to do");
   8.226 -	        	}
   8.227 -	        } else {
   8.228 -	        	//AuthState and AuthScope have to be saved separate because of the AuthScope within AuthState gets lost, so we save it in a separate var.
   8.229 -	        	mLastAuthState = authState;
   8.230 -	        	Log.d(TAG, "LastAuthState: new with user " + mLastAuthState.getCredentials().getUserPrincipal().getName());
   8.231 -	        	if (authState.getAuthScope() != null) {
   8.232 -	        		mLastAuthScope = authState.getAuthScope();
   8.233 -	        		Log.d(TAG, "LastAuthScope: new");
   8.234 -	        	}
   8.235 -	        }
   8.236 -	    }
   8.237 -	};
   8.238 +        this.mTrustAll = Boolean.valueOf(trustAll);
   8.239  
   8.240 -	public enum TestConnectionResult {
   8.241 -		WRONG_CREDENTIAL, 
   8.242 -		WRONG_URL, 
   8.243 -		WRONG_SERVER_STATUS, 
   8.244 -		WRONG_ANSWER, 
   8.245 -		SUCCESS
   8.246 -	}
   8.247 +        httpClient = getHttpClient();
   8.248 +        UsernamePasswordCredentials upc = new UsernamePasswordCredentials(mUser, mPassword);
   8.249  
   8.250 -	/**
   8.251 -	 * TODO: testConnection should return only an instance of
   8.252 -	 * TestConnectionResult without throwing an exception or only throw checked
   8.253 -	 * exceptions so you don't have to check the result of this function AND
   8.254 -	 * handle the exceptions
   8.255 -	 * @param context 
   8.256 -	 * 
   8.257 -	 * @return {@link TestConnectionResult}
   8.258 -	 * @throws HttpHostConnectException
   8.259 -	 * @throws IOException
   8.260 -	 * @throws URISyntaxException
   8.261 -	 * @throws ParserConfigurationException
   8.262 -	 * @throws SAXException
   8.263 -	 */
   8.264 -	public TestConnectionResult testConnection() throws HttpHostConnectException, IOException, URISyntaxException, ParserConfigurationException, SAXException {
   8.265 -		Log.d(TAG, "start testConnection ");
   8.266 -		try {
   8.267 -			List<DavCalendar> calendars = new ArrayList<DavCalendar>();
   8.268 -			calendars = forceGetCalendarsFromUri(null, url.toURI());
   8.269 -			if (calendars.size() != 0) {
   8.270 -				return TestConnectionResult.SUCCESS;
   8.271 -			}
   8.272 +        AuthScope as = null;
   8.273 +        as = new AuthScope(url.getHost(), -1);
   8.274 +        ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials(as, upc);
   8.275  
   8.276 -			URI userPrincipal = getUserPrincipal();
   8.277 -			List<URI> calendarSets = getCalendarHomes(userPrincipal);
   8.278 -			for (URI calendarSet : calendarSets) {
   8.279 -				List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet);
   8.280 -				calendars.addAll(calendarSetCalendars);
   8.281 -			}
   8.282 -			if (calendarSets.size() == 0) {
   8.283 -				return TestConnectionResult.WRONG_ANSWER;
   8.284 -			}
   8.285 -		} catch (FileNotFoundException e) {
   8.286 -			return TestConnectionResult.WRONG_URL;
   8.287 -		} catch (SocketException e) {
   8.288 -			return TestConnectionResult.WRONG_URL;
   8.289 -		} catch (AuthenticationException e) {
   8.290 -			return TestConnectionResult.WRONG_CREDENTIAL;
   8.291 -		} catch (ClientProtocolException e) {
   8.292 -			return TestConnectionResult.WRONG_SERVER_STATUS;
   8.293 -		} catch (CaldavProtocolException e) {
   8.294 -			return TestConnectionResult.WRONG_ANSWER;
   8.295 -		}
   8.296 -		return TestConnectionResult.SUCCESS;
   8.297 -	}
   8.298 +        mContext = new BasicHttpContext();
   8.299 +        CredentialsProvider credProvider = ((AbstractHttpClient) httpClient).getCredentialsProvider();
   8.300 +        mContext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider);
   8.301  
   8.302 -	/**
   8.303 -	 * @param context May be null if no notification is needed
   8.304 -	 * @param uri
   8.305 -	 * @return
   8.306 -	 * @throws AuthenticationException
   8.307 -	 * @throws FileNotFoundException
   8.308 -	 */
   8.309 -	private List<DavCalendar> forceGetCalendarsFromUri(Context context, URI uri) throws AuthenticationException, FileNotFoundException {
   8.310 -		List<DavCalendar> calendars = new ArrayList<DavCalendar>();
   8.311 -		Exception exception = null;
   8.312 -		try {
   8.313 -			calendars = getCalendarsFromSet(uri);
   8.314 -		} catch (ClientProtocolException e) {
   8.315 -			if (context != null) {
   8.316 -				NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.317 -				//NotificationsHelper.getCurrentSyncLog().addException(e);
   8.318 -			}
   8.319 -			exception = e;
   8.320 -		} catch (FileNotFoundException e) {
   8.321 -			if (context != null) {
   8.322 -				NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.323 -				//NotificationsHelper.getCurrentSyncLog().addException(e);
   8.324 -			}
   8.325 -			throw e;
   8.326 -		} catch (IOException e) {
   8.327 -			if (context != null) {
   8.328 -				NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.329 -				//NotificationsHelper.getCurrentSyncLog().addException(e);
   8.330 -			}
   8.331 -			exception = e;
   8.332 -		} catch (CaldavProtocolException e) {
   8.333 +        //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html
   8.334 +        ((AbstractHttpClient) httpClient).addRequestInterceptor(preemptiveAuth, 0);
   8.335  
   8.336 -			if (context != null) {
   8.337 -				NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.338 -				//NotificationsHelper.getCurrentSyncLog().addException(e);
   8.339 -			}
   8.340 -			exception = e;
   8.341 -		}
   8.342 -		if (exception != null && BuildConfig.DEBUG) {
   8.343 -			Log.e(TAG, "Force get calendars from '" + uri.toString()
   8.344 -					+ "' failed " + exception.getClass().getCanonicalName()
   8.345 -					+ ": " + exception.getMessage());
   8.346 -		}
   8.347 -		return calendars;
   8.348 -	}
   8.349 +        String proto = "http";
   8.350 +        int port = 80;
   8.351  
   8.352 -	private final static String PROPFIND_USER_PRINCIPAL = XML_VERSION +
   8.353 -			"<d:propfind xmlns:d=\"DAV:\">" +
   8.354 -				"<d:prop>" +
   8.355 -					"<d:current-user-principal />" +
   8.356 -					"<d:principal-URL />" +
   8.357 -				"</d:prop>" +
   8.358 -			"</d:propfind>";
   8.359 -	
   8.360 -	private URI getUserPrincipal() throws SocketException,
   8.361 -			ClientProtocolException, AuthenticationException,
   8.362 -			FileNotFoundException, IOException, CaldavProtocolException,
   8.363 -			URISyntaxException {
   8.364 -		URI uri = this.url.toURI();
   8.365 -		HttpPropFind request = createPropFindRequest(uri,
   8.366 -				PROPFIND_USER_PRINCIPAL, 0);
   8.367 -		HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.368 -		checkStatus(response);
   8.369 -		ServerInfoHandler serverInfoHandler = new ServerInfoHandler();
   8.370 -		parseXML(response, serverInfoHandler);
   8.371 -		String userPrincipal = null;
   8.372 -		if (serverInfoHandler.currentUserPrincipal != null) {
   8.373 -			userPrincipal = serverInfoHandler.currentUserPrincipal;
   8.374 -		} else if (serverInfoHandler.principalUrl != null) {
   8.375 -			userPrincipal = serverInfoHandler.principalUrl;
   8.376 -		} else {
   8.377 -			throw new CaldavProtocolException("no principal url found");
   8.378 -		}
   8.379 -		try {
   8.380 -			URI userPrincipalUri = new URI(userPrincipal);
   8.381 -			userPrincipalUri = uri.resolve(userPrincipalUri);
   8.382 -			if (BuildConfig.DEBUG) {
   8.383 -				Log.d(TAG,
   8.384 -						"Found userPrincipal: " + userPrincipalUri.toString());
   8.385 -			}
   8.386 -			return userPrincipalUri;
   8.387 -		} catch (URISyntaxException e) {
   8.388 -			throw new CaldavProtocolException("principal url '" + userPrincipal
   8.389 -					+ "' malformed");
   8.390 -		}
   8.391 -	}
   8.392 +        if (url.getProtocol().equalsIgnoreCase("https")) {
   8.393 +            proto = "https";
   8.394 +            if (url.getPort() == -1)
   8.395 +                port = 443;
   8.396 +            else
   8.397 +                port = url.getPort();
   8.398 +        }
   8.399  
   8.400 -	private final static String PROPFIND_CALENDAR_HOME_SET = XML_VERSION
   8.401 -			+ "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"><d:prop><c:calendar-home-set/></d:prop></d:propfind>";
   8.402 +        if (url.getProtocol().equalsIgnoreCase("http")) {
   8.403 +            proto = "http";
   8.404 +            if (url.getPort() == -1)
   8.405 +                port = 80;
   8.406 +            else
   8.407 +                port = url.getPort();
   8.408 +        }
   8.409 +        targetHost = new HttpHost(url.getHost(), port, proto);
   8.410 +    }
   8.411  
   8.412 -	private List<URI> getCalendarHomes(URI userPrincipal)
   8.413 -			throws ClientProtocolException, IOException,
   8.414 -			AuthenticationException, FileNotFoundException,
   8.415 -			CaldavProtocolException {
   8.416 -		HttpPropFind request = createPropFindRequest(userPrincipal,
   8.417 -				PROPFIND_CALENDAR_HOME_SET, 0);
   8.418 -		HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.419 -		checkStatus(response);
   8.420 -		CalendarHomeHandler calendarHomeHandler = new CalendarHomeHandler(
   8.421 -				userPrincipal);
   8.422 -		parseXML(response, calendarHomeHandler);
   8.423 -		List<URI> result = calendarHomeHandler.calendarHomeSet;
   8.424 -		if (BuildConfig.DEBUG) {
   8.425 -			Log.d(TAG, result.size() + " calendar-home-set found in "
   8.426 -					+ userPrincipal.toString());
   8.427 -		}
   8.428 -		return result;
   8.429 -	}
   8.430 +    //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html
   8.431 +    HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
   8.432 +        @Override
   8.433 +        public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
   8.434 +            AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
   8.435  
   8.436 -	private final static String PROPFIND_CALENDER_LIST = XML_VERSION
   8.437 -			+ "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\" xmlns:ic=\"http://apple.com/ns/ical/\">"
   8.438 -			+ "<d:prop><d:displayname /><d:resourcetype />"
   8.439 -			// +
   8.440 -			// "<d:supported-method-set /><d:supported-report-set /><c:supported-calendar-component-set />"
   8.441 -			// +
   8.442 -			// "<c:calendar-description /><c:calendar-timezone /><c:calendar-free-busy-set />
   8.443 -			+ "<ic:calendar-color />"
   8.444 -			//<ic:calendar-order />"
   8.445 -			+ "<cs:getctag /></d:prop></d:propfind>";
   8.446 +            if (authState.getAuthScheme() == null) {
   8.447 +                if (mLastAuthState != null) {
   8.448 +                    Log.d(TAG, "LastAuthState: restored with user " + mLastAuthState.getCredentials()
   8.449 +                            .getUserPrincipal()
   8.450 +                            .getName());
   8.451 +                    authState.setAuthScheme(mLastAuthState.getAuthScheme());
   8.452 +                    authState.setCredentials(mLastAuthState.getCredentials());
   8.453 +                } else {
   8.454 +                    Log.d(TAG, "LastAuthState: nothing to do");
   8.455 +                }
   8.456 +                if (mLastAuthScope != null) {
   8.457 +                    authState.setAuthScope(mLastAuthScope);
   8.458 +                    Log.d(TAG, "LastAuthScope: restored");
   8.459 +                } else {
   8.460 +                    Log.d(TAG, "LastAuthScope: nothing to do");
   8.461 +                }
   8.462 +            } else {
   8.463 +                //AuthState and AuthScope have to be saved separate because of the AuthScope within AuthState gets lost, so we save it in a separate var.
   8.464 +                mLastAuthState = authState;
   8.465 +                Log.d(TAG, "LastAuthState: new with user " + mLastAuthState.getCredentials()
   8.466 +                        .getUserPrincipal()
   8.467 +                        .getName());
   8.468 +                if (authState.getAuthScope() != null) {
   8.469 +                    mLastAuthScope = authState.getAuthScope();
   8.470 +                    Log.d(TAG, "LastAuthScope: new");
   8.471 +                }
   8.472 +            }
   8.473 +        }
   8.474 +    };
   8.475  
   8.476 -	
   8.477 -	private List<DavCalendar> getCalendarsFromSet(URI calendarSet)
   8.478 -			throws ClientProtocolException, IOException,
   8.479 -			CaldavProtocolException, AuthenticationException,
   8.480 -			FileNotFoundException {
   8.481 -		HttpPropFind request = createPropFindRequest(calendarSet, PROPFIND_CALENDER_LIST, 1);
   8.482 -		HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.483 -		checkStatus(response);
   8.484 -		CalendarsHandler calendarsHandler = new CalendarsHandler(calendarSet);
   8.485 -		parseXML(response, calendarsHandler);
   8.486 -		List<DavCalendar> result = calendarsHandler.calendars;
   8.487 -		if (BuildConfig.DEBUG) {
   8.488 -			Log.i(TAG,
   8.489 -					result.size() + " calendars found in set "
   8.490 -							+ calendarSet.toString());
   8.491 -		}
   8.492 -		return result;
   8.493 -	}
   8.494 -	
   8.495 -	/**
   8.496 -	 * Discover CalDAV Calendars Mentioned in
   8.497 -	 * http://tools.ietf.org/html/draft-daboo-srv-caldav-10#section-6 and
   8.498 -	 * http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Discovery
   8.499 -	 * <ol>
   8.500 -	 * <li>PROPFIND calendar-home-set on url
   8.501 -	 * <li>PROPFIND DAV:current-user-principal or principal-URL on url
   8.502 -	 * <li>PROPFIND calendar-home-set on current-user-principal or principal-URL
   8.503 -	 * <li>PROPFIND displayname, resourcetype, getctag on CalendarHomeSets
   8.504 -	 * </ol>
   8.505 -	 * @param context 
   8.506 -	 * 
   8.507 -	 * @return List of {@link DavCalendar}
   8.508 -	 * @throws ClientProtocolException
   8.509 -	 *             http protocol error
   8.510 -	 * @throws IOException
   8.511 -	 *             Connection lost
   8.512 -	 * @throws URISyntaxException
   8.513 -	 *             url in Constructor malformed
   8.514 -	 * @throws CaldavProtocolException
   8.515 -	 *             caldav protocol error
   8.516 -	 */
   8.517 -	//public Iterable<Calendar> getCalendarList(Context context) throws ClientProtocolException,
   8.518 -	public CalendarList getCalendarList(Context context) throws ClientProtocolException,
   8.519 -			IOException, URISyntaxException, ParserConfigurationException,
   8.520 -			CaldavProtocolException {
   8.521 -		try {
   8.522 -			CalendarList Result = new CalendarList(this.mAccount, this.mProvider, CalendarSource.CalDAV, this.url.toString());
   8.523 -			List<DavCalendar> calendars = new ArrayList<DavCalendar>();
   8.524 -			
   8.525 -			calendars = forceGetCalendarsFromUri(context, this.url.toURI());
   8.526 -			
   8.527 -			if (calendars.size() == 0) {
   8.528 -				// no calendars found, try the home-set
   8.529 -				URI userPrincipal = getUserPrincipal();
   8.530 -				List<URI> calendarSets = getCalendarHomes(userPrincipal);
   8.531 -				for (URI calendarSet : calendarSets) {
   8.532 -					List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet);
   8.533 -					calendars.addAll(calendarSetCalendars);
   8.534 -				}
   8.535 -			}
   8.536 -			for (DavCalendar cal : calendars) {
   8.537 -				Result.addCalendar(cal);
   8.538 -			}
   8.539 -			
   8.540 -			//return calendars;
   8.541 -			return Result;
   8.542 -		} catch (AuthenticationException e) {
   8.543 -			throw new IOException(e);
   8.544 -		}
   8.545 -	}
   8.546 +    public enum TestConnectionResult {
   8.547 +        WRONG_CREDENTIAL,
   8.548 +        WRONG_URL,
   8.549 +        WRONG_SERVER_STATUS,
   8.550 +        WRONG_ANSWER,
   8.551 +        SSL_ERROR,
   8.552 +        SUCCESS
   8.553 +    }
   8.554  
   8.555 -	//public Iterable<CalendarEvent> getCalendarEvents(DavCalendar calendar)
   8.556 -	public ArrayList<CalendarEvent> getCalendarEvents(DavCalendar calendar)
   8.557 -			throws URISyntaxException, ClientProtocolException, IOException,
   8.558 -			ParserConfigurationException, SAXException {
   8.559 +    /**
   8.560 +     * TODO: testConnection should return only an instance of
   8.561 +     * TestConnectionResult without throwing an exception or only throw checked
   8.562 +     * exceptions so you don't have to check the result of this function AND
   8.563 +     * handle the exceptions
   8.564 +     *
   8.565 +     * @return {@link TestConnectionResult}
   8.566 +     * @throws HttpHostConnectException
   8.567 +     * @throws IOException
   8.568 +     * @throws URISyntaxException
   8.569 +     * @throws ParserConfigurationException
   8.570 +     * @throws SAXException
   8.571 +     */
   8.572 +    public TestConnectionResult testConnection() throws IOException, URISyntaxException, ParserConfigurationException, SAXException {
   8.573 +        Log.d(TAG, "start testConnection ");
   8.574 +        try {
   8.575 +            List<DavCalendar> calendars = new ArrayList<DavCalendar>();
   8.576 +            calendars = forceGetCalendarsFromUri(null, url.toURI());
   8.577 +            if (calendars.size() != 0) {
   8.578 +                return TestConnectionResult.SUCCESS;
   8.579 +            }
   8.580  
   8.581 -		ArrayList<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>();
   8.582 +            URI userPrincipal = getUserPrincipal();
   8.583 +            List<URI> calendarSets = getCalendarHomes(userPrincipal);
   8.584 +            for (URI calendarSet : calendarSets) {
   8.585 +                List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet);
   8.586 +                calendars.addAll(calendarSetCalendars);
   8.587 +            }
   8.588 +            if (calendarSets.size() == 0) {
   8.589 +                return TestConnectionResult.WRONG_ANSWER;
   8.590 +            }
   8.591 +        } catch (FileNotFoundException e) {
   8.592 +            return TestConnectionResult.WRONG_URL;
   8.593 +        } catch (SSLException e) {
   8.594 +            return TestConnectionResult.SSL_ERROR;
   8.595 +        } catch (SocketException e) {
   8.596 +            return TestConnectionResult.WRONG_URL;
   8.597 +        } catch (AuthenticationException e) {
   8.598 +            return TestConnectionResult.WRONG_CREDENTIAL;
   8.599 +        } catch (ClientProtocolException e) {
   8.600 +            return TestConnectionResult.WRONG_SERVER_STATUS;
   8.601 +        } catch (CaldavProtocolException e) {
   8.602 +            return TestConnectionResult.WRONG_ANSWER;
   8.603 +        }
   8.604 +        return TestConnectionResult.SUCCESS;
   8.605 +    }
   8.606  
   8.607 -		String requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
   8.608 -				+ "<D:propfind xmlns:D=\"DAV:\">" + "<D:prop>" + "<D:getetag/>"
   8.609 -				+ "</D:prop>" + "</D:propfind>";
   8.610 +    /**
   8.611 +     * @param context May be null if no notification is needed
   8.612 +     * @param uri
   8.613 +     * @return
   8.614 +     * @throws AuthenticationException
   8.615 +     * @throws FileNotFoundException
   8.616 +     */
   8.617 +    private List<DavCalendar> forceGetCalendarsFromUri(Context context, URI uri) throws AuthenticationException, FileNotFoundException {
   8.618 +        List<DavCalendar> calendars = new ArrayList<DavCalendar>();
   8.619 +        Exception exception = null;
   8.620 +        try {
   8.621 +            calendars = getCalendarsFromSet(uri);
   8.622 +        } catch (ClientProtocolException e) {
   8.623 +            if (context != null) {
   8.624 +                NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.625 +                //NotificationsHelper.getCurrentSyncLog().addException(e);
   8.626 +            }
   8.627 +            exception = e;
   8.628 +        } catch (FileNotFoundException e) {
   8.629 +            if (context != null) {
   8.630 +                NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.631 +                //NotificationsHelper.getCurrentSyncLog().addException(e);
   8.632 +            }
   8.633 +            throw e;
   8.634 +        } catch (IOException e) {
   8.635 +            if (context != null) {
   8.636 +                NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.637 +                //NotificationsHelper.getCurrentSyncLog().addException(e);
   8.638 +            }
   8.639 +            exception = e;
   8.640 +        } catch (CaldavProtocolException e) {
   8.641  
   8.642 -		HttpPropFind request = null;
   8.643 -		
   8.644 -		String EventUri;
   8.645 +            if (context != null) {
   8.646 +                NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
   8.647 +                //NotificationsHelper.getCurrentSyncLog().addException(e);
   8.648 +            }
   8.649 +            exception = e;
   8.650 +        }
   8.651 +        if (exception != null && BuildConfig.DEBUG) {
   8.652 +            Log.e(TAG, "Force get calendars from '" + uri.toString()
   8.653 +                    + "' failed " + exception.getClass().getCanonicalName()
   8.654 +                    + ": " + exception.getMessage());
   8.655 +        }
   8.656 +        return calendars;
   8.657 +    }
   8.658 +
   8.659 +    private final static String PROPFIND_USER_PRINCIPAL = XML_VERSION +
   8.660 +            "<d:propfind xmlns:d=\"DAV:\">" +
   8.661 +            "<d:prop>" +
   8.662 +            "<d:current-user-principal />" +
   8.663 +            "<d:principal-URL />" +
   8.664 +            "</d:prop>" +
   8.665 +            "</d:propfind>";
   8.666 +
   8.667 +    private URI getUserPrincipal() throws
   8.668 +            AuthenticationException,
   8.669 +            IOException, CaldavProtocolException,
   8.670 +            URISyntaxException {
   8.671 +        URI uri = this.url.toURI();
   8.672 +        HttpPropFind request = createPropFindRequest(uri,
   8.673 +                PROPFIND_USER_PRINCIPAL, 0);
   8.674 +        HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.675 +        checkStatus(response);
   8.676 +        ServerInfoHandler serverInfoHandler = new ServerInfoHandler();
   8.677 +        parseXML(response, serverInfoHandler);
   8.678 +        String userPrincipal = null;
   8.679 +        if (serverInfoHandler.currentUserPrincipal != null) {
   8.680 +            userPrincipal = serverInfoHandler.currentUserPrincipal;
   8.681 +        } else if (serverInfoHandler.principalUrl != null) {
   8.682 +            userPrincipal = serverInfoHandler.principalUrl;
   8.683 +        } else {
   8.684 +            throw new CaldavProtocolException("no principal url found");
   8.685 +        }
   8.686 +        try {
   8.687 +            URI userPrincipalUri = new URI(userPrincipal);
   8.688 +            userPrincipalUri = uri.resolve(userPrincipalUri);
   8.689 +            if (BuildConfig.DEBUG) {
   8.690 +                Log.d(TAG,
   8.691 +                        "Found userPrincipal: " + userPrincipalUri.toString());
   8.692 +            }
   8.693 +            return userPrincipalUri;
   8.694 +        } catch (URISyntaxException e) {
   8.695 +            throw new CaldavProtocolException("principal url '" + userPrincipal
   8.696 +                    + "' malformed");
   8.697 +        }
   8.698 +    }
   8.699 +
   8.700 +    private final static String PROPFIND_CALENDAR_HOME_SET = XML_VERSION
   8.701 +            + "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"><d:prop><c:calendar-home-set/></d:prop></d:propfind>";
   8.702 +
   8.703 +    private List<URI> getCalendarHomes(URI userPrincipal)
   8.704 +            throws ClientProtocolException, IOException,
   8.705 +            AuthenticationException, FileNotFoundException,
   8.706 +            CaldavProtocolException {
   8.707 +        HttpPropFind request = createPropFindRequest(userPrincipal,
   8.708 +                PROPFIND_CALENDAR_HOME_SET, 0);
   8.709 +        HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.710 +        checkStatus(response);
   8.711 +        CalendarHomeHandler calendarHomeHandler = new CalendarHomeHandler(
   8.712 +                userPrincipal);
   8.713 +        parseXML(response, calendarHomeHandler);
   8.714 +        List<URI> result = calendarHomeHandler.calendarHomeSet;
   8.715 +        if (BuildConfig.DEBUG) {
   8.716 +            Log.d(TAG, result.size() + " calendar-home-set found in "
   8.717 +                    + userPrincipal.toString());
   8.718 +        }
   8.719 +        return result;
   8.720 +    }
   8.721 +
   8.722 +    private final static String PROPFIND_CALENDER_LIST = XML_VERSION
   8.723 +            + "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\" xmlns:ic=\"http://apple.com/ns/ical/\">"
   8.724 +            + "<d:prop><d:displayname /><d:resourcetype />"
   8.725 +            // +
   8.726 +            // "<d:supported-method-set /><d:supported-report-set /><c:supported-calendar-component-set />"
   8.727 +            // +
   8.728 +            // "<c:calendar-description /><c:calendar-timezone /><c:calendar-free-busy-set />
   8.729 +            + "<ic:calendar-color />"
   8.730 +            //<ic:calendar-order />"
   8.731 +            + "<cs:getctag /></d:prop></d:propfind>";
   8.732 +
   8.733 +
   8.734 +    private List<DavCalendar> getCalendarsFromSet(URI calendarSet)
   8.735 +            throws ClientProtocolException, IOException,
   8.736 +            CaldavProtocolException, AuthenticationException,
   8.737 +            FileNotFoundException {
   8.738 +        HttpPropFind request = createPropFindRequest(calendarSet, PROPFIND_CALENDER_LIST, 1);
   8.739 +        HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.740 +        checkStatus(response);
   8.741 +        CalendarsHandler calendarsHandler = new CalendarsHandler(calendarSet);
   8.742 +        parseXML(response, calendarsHandler);
   8.743 +        List<DavCalendar> result = calendarsHandler.calendars;
   8.744 +        if (BuildConfig.DEBUG) {
   8.745 +            Log.i(TAG,
   8.746 +                    result.size() + " calendars found in set "
   8.747 +                            + calendarSet.toString()
   8.748 +            );
   8.749 +        }
   8.750 +        return result;
   8.751 +    }
   8.752 +
   8.753 +    /**
   8.754 +     * Discover CalDAV Calendars Mentioned in
   8.755 +     * http://tools.ietf.org/html/draft-daboo-srv-caldav-10#section-6 and
   8.756 +     * http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Discovery
   8.757 +     * <ol>
   8.758 +     * <li>PROPFIND calendar-home-set on url
   8.759 +     * <li>PROPFIND DAV:current-user-principal or principal-URL on url
   8.760 +     * <li>PROPFIND calendar-home-set on current-user-principal or principal-URL
   8.761 +     * <li>PROPFIND displayname, resourcetype, getctag on CalendarHomeSets
   8.762 +     * </ol>
   8.763 +     *
   8.764 +     * @param context
   8.765 +     * @return List of {@link DavCalendar}
   8.766 +     * @throws ClientProtocolException http protocol error
   8.767 +     * @throws IOException             Connection lost
   8.768 +     * @throws URISyntaxException      url in Constructor malformed
   8.769 +     * @throws CaldavProtocolException caldav protocol error
   8.770 +     */
   8.771 +    //public Iterable<Calendar> getCalendarList(Context context) throws ClientProtocolException,
   8.772 +    public CalendarList getCalendarList(Context context) throws ClientProtocolException,
   8.773 +            IOException, URISyntaxException, ParserConfigurationException,
   8.774 +            CaldavProtocolException {
   8.775 +        try {
   8.776 +            CalendarList Result = new CalendarList(this.mAccount, this.mProvider, CalendarSource.CalDAV, this.url
   8.777 +                    .toString());
   8.778 +            List<DavCalendar> calendars = new ArrayList<DavCalendar>();
   8.779 +
   8.780 +            calendars = forceGetCalendarsFromUri(context, this.url.toURI());
   8.781 +
   8.782 +            if (calendars.size() == 0) {
   8.783 +                // no calendars found, try the home-set
   8.784 +                URI userPrincipal = getUserPrincipal();
   8.785 +                List<URI> calendarSets = getCalendarHomes(userPrincipal);
   8.786 +                for (URI calendarSet : calendarSets) {
   8.787 +                    List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet);
   8.788 +                    calendars.addAll(calendarSetCalendars);
   8.789 +                }
   8.790 +            }
   8.791 +            for (DavCalendar cal : calendars) {
   8.792 +                Result.addCalendar(cal);
   8.793 +            }
   8.794 +
   8.795 +            //return calendars;
   8.796 +            return Result;
   8.797 +        } catch (AuthenticationException e) {
   8.798 +            throw new IOException(e);
   8.799 +        }
   8.800 +    }
   8.801 +
   8.802 +    //public Iterable<CalendarEvent> getCalendarEvents(DavCalendar calendar)
   8.803 +    public ArrayList<CalendarEvent> getCalendarEvents(DavCalendar calendar)
   8.804 +            throws URISyntaxException, ClientProtocolException, IOException,
   8.805 +            ParserConfigurationException, SAXException {
   8.806 +
   8.807 +        ArrayList<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>();
   8.808 +
   8.809 +        String requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
   8.810 +                + "<D:propfind xmlns:D=\"DAV:\">" + "<D:prop>" + "<D:getetag/>"
   8.811 +                + "</D:prop>" + "</D:propfind>";
   8.812 +
   8.813 +        HttpPropFind request = null;
   8.814 +
   8.815 +        String EventUri;
   8.816  
   8.817  		/*request = new HttpPropFind();
   8.818 -		request.setURI(calendar.getURI());
   8.819 +        request.setURI(calendar.getURI());
   8.820  		request.setHeader("Host", targetHost.getHostName());
   8.821  		request.setHeader("Depth", "1");
   8.822  		request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
   8.823 @@ -487,380 +494,358 @@
   8.824  		} catch (UnsupportedEncodingException e) {
   8.825  			throw new AssertionError("UTF-8 is unknown");
   8.826  		}*/
   8.827 -		request = this.createPropFindRequest(calendar.getURI(), requestBody, 1);
   8.828 -		
   8.829 -		Log.d(TAG, "Getting eTag by PROPFIND at " + request.getURI());
   8.830 +        request = this.createPropFindRequest(calendar.getURI(), requestBody, 1);
   8.831  
   8.832 -		HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.833 +        Log.d(TAG, "Getting eTag by PROPFIND at " + request.getURI());
   8.834  
   8.835 -		BufferedReader reader = new BufferedReader(new InputStreamReader(
   8.836 -				response.getEntity().getContent(), "UTF-8"));
   8.837 +        HttpResponse response = httpClient.execute(targetHost, request, mContext);
   8.838 +        String body = EntityUtils.toString(response.getEntity(), "UTF-8");
   8.839  
   8.840 -		String line;
   8.841 -		String body = "";
   8.842 -		do {
   8.843 -			line = reader.readLine();
   8.844 -			if (line != null)
   8.845 -				body += line;
   8.846 -		} while (line != null);
   8.847 +        Log.d(TAG, "HttpResponse status=" + response.getStatusLine()
   8.848 +                + " body= " + body);
   8.849  
   8.850 -		Log.d(TAG, "HttpResponse status=" + response.getStatusLine()
   8.851 -				+ " body= " + body);
   8.852 +        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   8.853 +        factory.setNamespaceAware(true);
   8.854 +        DocumentBuilder builder = factory.newDocumentBuilder();
   8.855 +        Document dom = builder.parse(new InputSource(new ByteArrayInputStream(
   8.856 +                body.getBytes("utf-8"))));
   8.857 +        Element root = dom.getDocumentElement();
   8.858 +        NodeList items = root.getElementsByTagNameNS("*", "getetag");
   8.859  
   8.860 -		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   8.861 -		factory.setNamespaceAware(true);
   8.862 -		DocumentBuilder builder = factory.newDocumentBuilder();
   8.863 -		Document dom = builder.parse(new InputSource(new ByteArrayInputStream(
   8.864 -				body.getBytes("utf-8"))));
   8.865 -		Element root = dom.getDocumentElement();
   8.866 -		NodeList items = root.getElementsByTagNameNS("*", "getetag");
   8.867 +        for (int i = 0; i < items.getLength(); i++) {
   8.868 +            CalendarEvent calendarEvent = new CalendarEvent(this.mAccount, this.mProvider);
   8.869  
   8.870 -		for (int i = 0; i < items.getLength(); i++) {
   8.871 -			CalendarEvent calendarEvent = new CalendarEvent(this.mAccount, this.mProvider);
   8.872 +            Node node = items.item(i);
   8.873  
   8.874 -			Node node = items.item(i);
   8.875 +            if (node.getTextContent().trim().length() == 0)
   8.876 +                continue; // not an event
   8.877  
   8.878 -			if (node.getTextContent().trim().length() == 0)
   8.879 -				continue; // not an event
   8.880 +            calendarEvent.setETag(node.getTextContent().trim());
   8.881 +            //calendarEvent.calendarURL = this.url;
   8.882 +            calendarEvent.calendarURL = calendar.getURI().toURL();
   8.883  
   8.884 -			calendarEvent.setETag(node.getTextContent().trim());
   8.885 -			//calendarEvent.calendarURL = this.url;
   8.886 -			calendarEvent.calendarURL = calendar.getURI().toURL();
   8.887 +            node = node.getParentNode(); // prop
   8.888 +            node = node.getParentNode(); // propstat
   8.889 +            node = node.getParentNode(); // response
   8.890  
   8.891 -			node = node.getParentNode(); // prop
   8.892 -			node = node.getParentNode(); // propstat
   8.893 -			node = node.getParentNode(); // response
   8.894 +            NodeList children = node.getChildNodes();
   8.895 +            for (int j = 0; j < children.getLength(); j++) {
   8.896 +                Node childNode = children.item(j);
   8.897 +                if ((childNode.getLocalName() != null) && (childNode.getLocalName()
   8.898 +                        .equalsIgnoreCase("href"))) {
   8.899 +                    EventUri = childNode.getTextContent().trim();
   8.900 +                    //HINT: bugfix for zimbra calendar: replace("@", "%40")
   8.901 +                    EventUri = EventUri.replace("@", "%40");
   8.902 +                    calendarEvent.setUri(new URI(EventUri));
   8.903 +                }
   8.904 +            }
   8.905  
   8.906 -			NodeList children = node.getChildNodes();
   8.907 -			for (int j = 0; j < children.getLength(); j++) {
   8.908 -				Node childNode = children.item(j);
   8.909 -				if ((childNode.getLocalName()!=null) && (childNode.getLocalName().equalsIgnoreCase("href"))) {
   8.910 -					EventUri = childNode.getTextContent().trim();
   8.911 -					//HINT: bugfix for zimbra calendar: replace("@", "%40")
   8.912 -					EventUri = EventUri.replace("@", "%40");
   8.913 -					calendarEvent.setUri(new URI(EventUri));
   8.914 -				}
   8.915 -			}
   8.916 +            calendarEventList.add(calendarEvent);
   8.917  
   8.918 -			calendarEventList.add(calendarEvent);
   8.919 +        }
   8.920  
   8.921 -		}
   8.922 +        return calendarEventList;
   8.923 +    }
   8.924  
   8.925 -		return calendarEventList;
   8.926 -	}
   8.927 -
   8.928 -	private void parseXML(HttpResponse response, ContentHandler contentHandler)
   8.929 -			throws IOException, CaldavProtocolException {
   8.930 -		InputStream is = response.getEntity().getContent();
   8.931 -		/*BufferedReader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
   8.932 -		String Content = "";
   8.933 +    private void parseXML(HttpResponse response, ContentHandler contentHandler)
   8.934 +            throws IOException, CaldavProtocolException {
   8.935 +        InputStream is = response.getEntity().getContent();
   8.936 +        /*BufferedReader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
   8.937 +        String Content = "";
   8.938  		String Line = bReader.readLine();
   8.939  
   8.940  		while (Line != null) {
   8.941  			Content += Line;
   8.942  			Line = bReader.readLine();
   8.943  		}*/
   8.944 -		
   8.945 -		SAXParserFactory factory = SAXParserFactory.newInstance();
   8.946 -		try {
   8.947 -			SAXParser parser = factory.newSAXParser();
   8.948 -			XMLReader reader = parser.getXMLReader();
   8.949 -			reader.setContentHandler(contentHandler);
   8.950 -			reader.parse(new InputSource(is));
   8.951 -		} catch (ParserConfigurationException e) {
   8.952 -			throw new AssertionError("ParserConfigurationException "
   8.953 -					+ e.getMessage());
   8.954 -		} catch (IllegalStateException e) {
   8.955 -			throw new CaldavProtocolException(e.getMessage());
   8.956 -		} catch (SAXException e) {
   8.957 -			throw new CaldavProtocolException(e.getMessage());
   8.958 -		}
   8.959 -	}
   8.960  
   8.961 -	private void checkStatus(HttpResponse response)
   8.962 -			throws AuthenticationException, FileNotFoundException,
   8.963 -			ClientProtocolException {
   8.964 -		final int statusCode = response.getStatusLine().getStatusCode();
   8.965 -		lastStatusCode = statusCode;
   8.966 -		if (response.containsHeader("ETag"))
   8.967 -			lastETag = response.getFirstHeader("ETag").getValue();
   8.968 -		else
   8.969 -			lastETag = "";
   8.970 -		if (response.containsHeader("DAV"))
   8.971 -			lastDav = response.getFirstHeader("DAV").getValue();
   8.972 -		else
   8.973 -			lastDav = "";
   8.974 -		
   8.975 -		switch (statusCode) {
   8.976 -		case 401:
   8.977 -			throw new AuthenticationException();
   8.978 -		case 404:
   8.979 -			throw new FileNotFoundException();
   8.980 -		case 409: //Conflict
   8.981 -		case 412:
   8.982 -		case 200:
   8.983 -		case 201:
   8.984 -		case 204:
   8.985 -		case 207:
   8.986 -			return;
   8.987 -		default:
   8.988 -			throw new ClientProtocolException("StatusCode: " + statusCode);
   8.989 -		}
   8.990 -	}
   8.991 +        SAXParserFactory factory = SAXParserFactory.newInstance();
   8.992 +        try {
   8.993 +            SAXParser parser = factory.newSAXParser();
   8.994 +            XMLReader reader = parser.getXMLReader();
   8.995 +            reader.setContentHandler(contentHandler);
   8.996 +            reader.parse(new InputSource(is));
   8.997 +        } catch (ParserConfigurationException e) {
   8.998 +            throw new AssertionError("ParserConfigurationException "
   8.999 +                    + e.getMessage());
  8.1000 +        } catch (IllegalStateException e) {
  8.1001 +            throw new CaldavProtocolException(e.getMessage());
  8.1002 +        } catch (SAXException e) {
  8.1003 +            throw new CaldavProtocolException(e.getMessage());
  8.1004 +        }
  8.1005 +    }
  8.1006  
  8.1007 -	private HttpPropFind createPropFindRequest(URI uri, String data, int depth) {
  8.1008 -		HttpPropFind request = new HttpPropFind();
  8.1009 +    private void checkStatus(HttpResponse response)
  8.1010 +            throws AuthenticationException, FileNotFoundException,
  8.1011 +            ClientProtocolException {
  8.1012 +        final int statusCode = response.getStatusLine().getStatusCode();
  8.1013 +        lastStatusCode = statusCode;
  8.1014 +        if (response.containsHeader("ETag"))
  8.1015 +            lastETag = response.getFirstHeader("ETag").getValue();
  8.1016 +        else
  8.1017 +            lastETag = "";
  8.1018 +        if (response.containsHeader("DAV"))
  8.1019 +            lastDav = response.getFirstHeader("DAV").getValue();
  8.1020 +        else
  8.1021 +            lastDav = "";
  8.1022  
  8.1023 -		request.setURI(uri);
  8.1024 -		//request.setHeader("Host", targetHost.getHostName());
  8.1025 -		request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1026 -		request.setHeader("Depth", Integer.toString(depth));
  8.1027 -		request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1028 -		try {
  8.1029 -			request.setEntity(new StringEntity(data, "UTF-8"));
  8.1030 -		} catch (UnsupportedEncodingException e) {
  8.1031 -			throw new AssertionError("UTF-8 is unknown");
  8.1032 -		}
  8.1033 -		return request;
  8.1034 -	}
  8.1035 -	
  8.1036 -	private HttpDelete createDeleteRequest(URI uri) {
  8.1037 -		HttpDelete request = new HttpDelete();
  8.1038 -		request.setURI(uri);
  8.1039 -		//request.setHeader("Host", targetHost.getHostName());
  8.1040 -		request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1041 -		request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1042 -		return request;
  8.1043 -	}
  8.1044 +        switch (statusCode) {
  8.1045 +            case 401:
  8.1046 +                throw new AuthenticationException();
  8.1047 +            case 404:
  8.1048 +                throw new FileNotFoundException();
  8.1049 +            case 409: //Conflict
  8.1050 +            case 412:
  8.1051 +            case 200:
  8.1052 +            case 201:
  8.1053 +            case 204:
  8.1054 +            case 207:
  8.1055 +                return;
  8.1056 +            default:
  8.1057 +                throw new ClientProtocolException("StatusCode: " + statusCode);
  8.1058 +        }
  8.1059 +    }
  8.1060  
  8.1061 -	private HttpPut createPutRequest(URI uri, String data, int depth) {
  8.1062 -		HttpPut request = new HttpPut();
  8.1063 -		request.setURI(uri);
  8.1064 -		//request.setHeader("Host", targetHost.getHostName());
  8.1065 -		request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1066 -		//request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1067 -		request.setHeader("Content-Type", "text/calendar; charset=UTF-8");
  8.1068 -		try {
  8.1069 -			request.setEntity(new StringEntity(data, "UTF-8"));
  8.1070 -			//request.setEntity(new StringEntity(data));
  8.1071 -		} catch (UnsupportedEncodingException e) {
  8.1072 -			throw new AssertionError("UTF-8 is unknown");
  8.1073 -		}
  8.1074 -		return request;
  8.1075 -	}
  8.1076 -	
  8.1077 -	private static HttpReport createReportRequest(URI uri, String data, int depth) {
  8.1078 -		HttpReport request = new HttpReport();
  8.1079 -		request.setURI(uri);
  8.1080 -		//request.setHeader("Host", targetHost.getHostName());
  8.1081 -		request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1082 -		request.setHeader("Depth", Integer.toString(depth));
  8.1083 -		request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1084 -		//request.setHeader("Content-Type", "text/xml;charset=\"UTF-8\"");
  8.1085 -		try {
  8.1086 -			request.setEntity(new StringEntity(data));
  8.1087 -		} catch (UnsupportedEncodingException e) {
  8.1088 -			throw new AssertionError("UTF-8 is unknown");
  8.1089 -		}
  8.1090 -		return request;
  8.1091 -	}
  8.1092 -	
  8.1093 -	public static void fetchEvent_old(CalendarEvent calendarEvent)
  8.1094 -			throws ClientProtocolException, IOException {
  8.1095 -		HttpGet request = null;
  8.1096 +    private HttpPropFind createPropFindRequest(URI uri, String data, int depth) {
  8.1097 +        HttpPropFind request = new HttpPropFind();
  8.1098  
  8.1099 -		request = new HttpGet();
  8.1100 -		request.setURI(calendarEvent.getUri());
  8.1101 -		request.setHeader("Host", targetHost.getHostName());
  8.1102 -		request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1103 +        request.setURI(uri);
  8.1104 +        //request.setHeader("Host", targetHost.getHostName());
  8.1105 +        request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1106 +        request.setHeader("Depth", Integer.toString(depth));
  8.1107 +        request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1108 +        try {
  8.1109 +            request.setEntity(new StringEntity(data, "UTF-8"));
  8.1110 +        } catch (UnsupportedEncodingException e) {
  8.1111 +            throw new AssertionError("UTF-8 is unknown");
  8.1112 +        }
  8.1113 +        return request;
  8.1114 +    }
  8.1115  
  8.1116 -		HttpResponse response = httpClient.execute(targetHost, request);
  8.1117 +    private HttpDelete createDeleteRequest(URI uri) {
  8.1118 +        HttpDelete request = new HttpDelete();
  8.1119 +        request.setURI(uri);
  8.1120 +        //request.setHeader("Host", targetHost.getHostName());
  8.1121 +        request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1122 +        request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1123 +        return request;
  8.1124 +    }
  8.1125  
  8.1126 -		BufferedReader reader = new BufferedReader(new InputStreamReader(
  8.1127 -				response.getEntity().getContent(), "UTF-8"));
  8.1128 +    private HttpPut createPutRequest(URI uri, String data, int depth) {
  8.1129 +        HttpPut request = new HttpPut();
  8.1130 +        request.setURI(uri);
  8.1131 +        //request.setHeader("Host", targetHost.getHostName());
  8.1132 +        request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1133 +        //request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1134 +        request.setHeader("Content-Type", "text/calendar; charset=UTF-8");
  8.1135 +        try {
  8.1136 +            request.setEntity(new StringEntity(data, "UTF-8"));
  8.1137 +            //request.setEntity(new StringEntity(data));
  8.1138 +        } catch (UnsupportedEncodingException e) {
  8.1139 +            throw new AssertionError("UTF-8 is unknown");
  8.1140 +        }
  8.1141 +        return request;
  8.1142 +    }
  8.1143  
  8.1144 -		String line;
  8.1145 -		String body = "";
  8.1146 -		do {
  8.1147 -			line = reader.readLine();
  8.1148 -			if (line != null)
  8.1149 -				body += line + "\n";
  8.1150 -		} while (line != null);
  8.1151 +    private static HttpReport createReportRequest(URI uri, String data, int depth) {
  8.1152 +        HttpReport request = new HttpReport();
  8.1153 +        request.setURI(uri);
  8.1154 +        //request.setHeader("Host", targetHost.getHostName());
  8.1155 +        request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
  8.1156 +        request.setHeader("Depth", Integer.toString(depth));
  8.1157 +        request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1158 +        //request.setHeader("Content-Type", "text/xml;charset=\"UTF-8\"");
  8.1159 +        try {
  8.1160 +            request.setEntity(new StringEntity(data));
  8.1161 +        } catch (UnsupportedEncodingException e) {
  8.1162 +            throw new AssertionError("UTF-8 is unknown");
  8.1163 +        }
  8.1164 +        return request;
  8.1165 +    }
  8.1166  
  8.1167 -		calendarEvent.setICSasString(body);
  8.1168 +    public static void fetchEvent_old(CalendarEvent calendarEvent)
  8.1169 +            throws ClientProtocolException, IOException {
  8.1170 +        HttpGet request = null;
  8.1171  
  8.1172 -		Log.d(TAG, "HttpResponse GET event status=" + response.getStatusLine()
  8.1173 -				+ " body= " + body);
  8.1174 -	}
  8.1175 -	
  8.1176 -	public static boolean getEvent(CalendarEvent calendarEvent) throws ClientProtocolException, IOException {
  8.1177 -		boolean Result = false;
  8.1178 -		HttpReport request = null;
  8.1179 +        request = new HttpGet();
  8.1180 +        request.setURI(calendarEvent.getUri());
  8.1181 +        request.setHeader("Host", targetHost.getHostName());
  8.1182 +        request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
  8.1183  
  8.1184 -		//HINT: bugfix for google calendar: replace("@", "%40")
  8.1185 -		String data = XML_VERSION +
  8.1186 -				"<C:calendar-multiget xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">" +
  8.1187 -					"<D:prop>" +
  8.1188 -						"<D:getetag />" +
  8.1189 -						"<C:calendar-data />" +
  8.1190 -					"</D:prop>" +
  8.1191 -					"<D:href>" + calendarEvent.getUri().getRawPath().replace("@", "%40") + "</D:href>" +
  8.1192 -				"</C:calendar-multiget>";
  8.1193 +        HttpResponse response = httpClient.execute(targetHost, request);
  8.1194 +        String body = EntityUtils.toString(response.getEntity(), "UTF-8");
  8.1195  
  8.1196 -		URI calendarURI = null;
  8.1197 -		try {
  8.1198 -			calendarURI = calendarEvent.calendarURL.toURI();
  8.1199 -		} catch (URISyntaxException e) {
  8.1200 -			e.printStackTrace();
  8.1201 -		}
  8.1202 -		//request = createReportRequest(calendarEvent.getUri(), data, 1);
  8.1203 -		request = createReportRequest(calendarURI, data, 1);
  8.1204 +        calendarEvent.setICSasString(body);
  8.1205  
  8.1206 -		HttpResponse response = httpClient.execute(targetHost, request);
  8.1207 +        Log.d(TAG, "HttpResponse GET event status=" + response.getStatusLine()
  8.1208 +                + " body= " + body);
  8.1209 +    }
  8.1210  
  8.1211 -		BufferedReader reader = new BufferedReader(new InputStreamReader(
  8.1212 -				response.getEntity().getContent(), "UTF-8"));
  8.1213 +    public static boolean getEvent(CalendarEvent calendarEvent) throws ClientProtocolException, IOException {
  8.1214 +        boolean Result = false;
  8.1215 +        HttpReport request = null;
  8.1216  
  8.1217 -		String line;
  8.1218 -		String body = "";
  8.1219 -		do {
  8.1220 -			line = reader.readLine();
  8.1221 -			if (line != null)
  8.1222 -				body += line + "\n";
  8.1223 -		} while (line != null);
  8.1224 +        //HINT: bugfix for google calendar: replace("@", "%40")
  8.1225 +        String data = XML_VERSION +
  8.1226 +                "<C:calendar-multiget xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">" +
  8.1227 +                "<D:prop>" +
  8.1228 +                "<D:getetag />" +
  8.1229 +                "<C:calendar-data />" +
  8.1230 +                "</D:prop>" +
  8.1231 +                "<D:href>" + calendarEvent.getUri().getRawPath().replace("@", "%40") + "</D:href>" +
  8.1232 +                "</C:calendar-multiget>";
  8.1233  
  8.1234 -		if (calendarEvent.setICSasMultiStatus(body))
  8.1235 -			Result = true;
  8.1236 +        URI calendarURI = null;
  8.1237 +        try {
  8.1238 +            calendarURI = calendarEvent.calendarURL.toURI();
  8.1239 +        } catch (URISyntaxException e) {
  8.1240 +            e.printStackTrace();
  8.1241 +        }
  8.1242 +        //request = createReportRequest(calendarEvent.getUri(), data, 1);
  8.1243 +        request = createReportRequest(calendarURI, data, 1);
  8.1244  
  8.1245 -		return Result;
  8.1246 -	}
  8.1247 -	
  8.1248 -		
  8.1249 -	/**
  8.1250 -	 * sends a update event request to the server 
  8.1251 -	 * @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
  8.1252 -	 * @param data the full ical-data for the event
  8.1253 -	 * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to update this version
  8.1254 -	 * @return
  8.1255 -	 */
  8.1256 -	public boolean updateEvent(URI uri, String data, String ETag) {
  8.1257 -		boolean Result = false;
  8.1258 -		
  8.1259 -		try {
  8.1260 -			HttpPut request = createPutRequest(uri, data, 1);
  8.1261 -			request.addHeader(mstrcHeaderIfMatch, ETag);
  8.1262 -			HttpResponse response = httpClient.execute(targetHost, request, mContext);
  8.1263 -			checkStatus(response);
  8.1264 -			if ((lastStatusCode == 200) || (lastStatusCode == 201) || (lastStatusCode == 204)) {
  8.1265 -				Result = true;
  8.1266 -			} else if (lastStatusCode == 412) {
  8.1267 -				//Precondition failed
  8.1268 -				Result = false;
  8.1269 -			} else if (lastStatusCode == 409) {
  8.1270 -				//Conflict
  8.1271 -				Result = false;
  8.1272 -			} else {
  8.1273 -				Log.w(TAG, "Unkown StatusCode during creation of an event");
  8.1274 -			}
  8.1275 -		} catch (ClientProtocolException e) {
  8.1276 -			e.printStackTrace();
  8.1277 -		} catch (IOException e) {
  8.1278 -			e.printStackTrace();
  8.1279 -		} catch (AuthenticationException e) {
  8.1280 -			e.printStackTrace();
  8.1281 -		}
  8.1282 -		return Result;
  8.1283 -	}
  8.1284 -	
  8.1285 -	/**
  8.1286 -	 * sends a create event request to server
  8.1287 -	 * @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
  8.1288 -	 * @param data the full ical-data for the new event
  8.1289 -	 * @return success of this function
  8.1290 -	 */
  8.1291 -	public boolean createEvent(URI uri, String data) {
  8.1292 -		boolean Result = false;
  8.1293 -		
  8.1294 -		try {
  8.1295 -			HttpPut request = createPutRequest(uri, data, 1);
  8.1296 -			request.addHeader(mstrcHeaderIfNoneMatch, "*");
  8.1297 -			HttpResponse response = httpClient.execute(targetHost, request, mContext);
  8.1298 -			checkStatus(response);
  8.1299 -			if (lastStatusCode == 201) {
  8.1300 -				Result = true;
  8.1301 -			} else {
  8.1302 -				Log.w(TAG, "Unkown StatusCode during creation of an event");
  8.1303 -			}
  8.1304 -		} catch (ClientProtocolException e) {
  8.1305 -			e.printStackTrace();
  8.1306 -		} catch (IOException e) {
  8.1307 -			e.printStackTrace();
  8.1308 -		} catch (AuthenticationException e) {
  8.1309 -			e.printStackTrace();
  8.1310 -		}
  8.1311 -		return Result;
  8.1312 -	}
  8.1313 -	
  8.1314 -	/**
  8.1315 -	 * sends a delete event request to the server
  8.1316 -	 * @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
  8.1317 -	 * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to delete this version
  8.1318 -	 * @return success of this function
  8.1319 -	 */
  8.1320 -	public boolean deleteEvent(URI calendarEventUri, String ETag) {
  8.1321 -		boolean Result = false;
  8.1322 -		
  8.1323 -		try {
  8.1324 -			HttpDelete request = createDeleteRequest(calendarEventUri);
  8.1325 -			request.addHeader(mstrcHeaderIfMatch, ETag);
  8.1326 -			HttpResponse response = httpClient.execute(targetHost, request, mContext);
  8.1327 -			checkStatus(response);
  8.1328 -			if ((lastStatusCode == 204) || (lastStatusCode == 200)) {
  8.1329 -				Result = true;
  8.1330 -			} else {
  8.1331 -				Log.w(TAG, "Unkown StatusCode during deletion of an event");
  8.1332 -			}
  8.1333 -		} catch (ClientProtocolException e) {
  8.1334 -			e.printStackTrace();
  8.1335 -		} catch (IOException e) {
  8.1336 -			if (lastStatusCode == 404) {
  8.1337 -				//the event has already been deleted on server side. no action needed
  8.1338 -				Result = true;
  8.1339 -			} else {
  8.1340 -				e.printStackTrace();
  8.1341 -			}
  8.1342 -		} catch (AuthenticationException e) {
  8.1343 -			e.printStackTrace();
  8.1344 -		}
  8.1345 -		
  8.1346 -		return Result;
  8.1347 -	}
  8.1348 -	
  8.1349 -	/**
  8.1350 -	 * returns the ETAG send by the last server response.
  8.1351 -	 * @return the ETAG
  8.1352 -	 */
  8.1353 -	public String getLastETag() {
  8.1354 -		return lastETag;
  8.1355 -	}
  8.1356 -	
  8.1357 -	/**
  8.1358 -	 * returns the DAV-Options send by the last server response.
  8.1359 -	 * @return the DAV-Options
  8.1360 -	 */
  8.1361 -	public String getLastDav() {
  8.1362 -		return lastDav;
  8.1363 -	}
  8.1364 -	
  8.1365 -	public void setVersion(String version) {
  8.1366 -		VERSION = version;
  8.1367 -		((AbstractHttpClient) httpClient).getParams().setParameter(CoreProtocolPNames.USER_AGENT, this.USER_AGENT + " Version:" + VERSION);
  8.1368 -	}
  8.1369 -	
  8.1370 -	public void setAccount(Account account) {
  8.1371 -		this.mAccount = account;
  8.1372 -	}
  8.1373 -	public void setProvider(ContentProviderClient provider) {
  8.1374 -		this.mProvider = provider;
  8.1375 -	}
  8.1376 -}
  8.1377 \ No newline at end of file
  8.1378 +        HttpResponse response = httpClient.execute(targetHost, request);
  8.1379 +        String body = EntityUtils.toString(response.getEntity(), "UTF-8");
  8.1380 +
  8.1381 +        if (calendarEvent.setICSasMultiStatus(body))
  8.1382 +            Result = true;
  8.1383 +
  8.1384 +        return Result;
  8.1385 +    }
  8.1386 +
  8.1387 +
  8.1388 +    /**
  8.1389 +     * sends a update event request to the server
  8.1390 +     *
  8.1391 +     * @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
  8.1392 +     * @param data the full ical-data for the event
  8.1393 +     * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to update this version
  8.1394 +     * @return
  8.1395 +     */
  8.1396 +    public boolean updateEvent(URI uri, String data, String ETag) {
  8.1397 +        boolean Result = false;
  8.1398 +
  8.1399 +        try {
  8.1400 +            HttpPut request = createPutRequest(uri, data, 1);
  8.1401 +            request.addHeader(mstrcHeaderIfMatch, ETag);
  8.1402 +            HttpResponse response = httpClient.execute(targetHost, request, mContext);
  8.1403 +            checkStatus(response);
  8.1404 +            if ((lastStatusCode == 200) || (lastStatusCode == 201) || (lastStatusCode == 204)) {
  8.1405 +                Result = true;
  8.1406 +            } else if (lastStatusCode == 412) {
  8.1407 +                //Precondition failed
  8.1408 +                Result = false;
  8.1409 +            } else if (lastStatusCode == 409) {
  8.1410 +                //Conflict
  8.1411 +                Result = false;
  8.1412 +            } else {
  8.1413 +                Log.w(TAG, "Unkown StatusCode during creation of an event");
  8.1414 +            }
  8.1415 +        } catch (ClientProtocolException e) {
  8.1416 +            e.printStackTrace();
  8.1417 +        } catch (IOException e) {
  8.1418 +            e.printStackTrace();
  8.1419 +        } catch (AuthenticationException e) {
  8.1420 +            e.printStackTrace();
  8.1421 +        }
  8.1422 +        return Result;
  8.1423 +    }
  8.1424 +
  8.1425 +    /**
  8.1426 +     * sends a create event request to server
  8.1427 +     *
  8.1428 +     * @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
  8.1429 +     * @param data the full ical-data for the new event
  8.1430 +     * @return success of this function
  8.1431 +     */
  8.1432 +    public boolean createEvent(URI uri, String data) {
  8.1433 +        boolean Result = false;
  8.1434 +
  8.1435 +        try {
  8.1436 +            HttpPut request = createPutRequest(uri, data, 1);
  8.1437 +            request.addHeader(mstrcHeaderIfNoneMatch, "*");
  8.1438 +            HttpResponse response = httpClient.execute(targetHost, request, mContext);
  8.1439 +            checkStatus(response);
  8.1440 +            if (lastStatusCode == 201) {
  8.1441 +                Result = true;
  8.1442 +            } else {
  8.1443 +                Log.w(TAG, "Unkown StatusCode during creation of an event");
  8.1444 +            }
  8.1445 +        } catch (ClientProtocolException e) {
  8.1446 +            e.printStackTrace();
  8.1447 +        } catch (IOException e) {
  8.1448 +            e.printStackTrace();
  8.1449 +        } catch (AuthenticationException e) {
  8.1450 +            e.printStackTrace();
  8.1451 +        }
  8.1452 +        return Result;
  8.1453 +    }
  8.1454 +
  8.1455 +    /**
  8.1456 +     * sends a delete event request to the server
  8.1457 +     *
  8.1458 +     * @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
  8.1459 +     * @param ETag             the ETAG of this event is send within the "If-Match" Parameter to tell the server only to delete this version
  8.1460 +     * @return success of this function
  8.1461 +     */
  8.1462 +    public boolean deleteEvent(URI calendarEventUri, String ETag) {
  8.1463 +        boolean Result = false;
  8.1464 +
  8.1465 +        try {
  8.1466 +            HttpDelete request = createDeleteRequest(calendarEventUri);
  8.1467 +            request.addHeader(mstrcHeaderIfMatch, ETag);
  8.1468 +            HttpResponse response = httpClient.execute(targetHost, request, mContext);
  8.1469 +            checkStatus(response);
  8.1470 +            if ((lastStatusCode == 204) || (lastStatusCode == 200)) {
  8.1471 +                Result = true;
  8.1472 +            } else {
  8.1473 +                Log.w(TAG, "Unkown StatusCode during deletion of an event");
  8.1474 +            }
  8.1475 +        } catch (ClientProtocolException e) {
  8.1476 +            e.printStackTrace();
  8.1477 +        } catch (IOException e) {
  8.1478 +            if (lastStatusCode == 404) {
  8.1479 +                //the event has already been deleted on server side. no action needed
  8.1480 +                Result = true;
  8.1481 +            } else {
  8.1482 +                e.printStackTrace();
  8.1483 +            }
  8.1484 +        } catch (AuthenticationException e) {
  8.1485 +            e.printStackTrace();
  8.1486 +        }
  8.1487 +
  8.1488 +        return Result;
  8.1489 +    }
  8.1490 +
  8.1491 +    /**
  8.1492 +     * returns the ETAG send by the last server response.
  8.1493 +     *
  8.1494 +     * @return the ETAG
  8.1495 +     */
  8.1496 +    public String getLastETag() {
  8.1497 +        return lastETag;
  8.1498 +    }
  8.1499 +
  8.1500 +    /**
  8.1501 +     * returns the DAV-Options send by the last server response.
  8.1502 +     *
  8.1503 +     * @return the DAV-Options
  8.1504 +     */
  8.1505 +    public String getLastDav() {
  8.1506 +        return lastDav;
  8.1507 +    }
  8.1508 +
  8.1509 +    public void setVersion(String version) {
  8.1510 +        VERSION = version;
  8.1511 +        ((AbstractHttpClient) httpClient).getParams()
  8.1512 +                .setParameter(CoreProtocolPNames.USER_AGENT, this.USER_AGENT + " Version:" + VERSION);
  8.1513 +    }
  8.1514 +
  8.1515 +    public void setAccount(Account account) {
  8.1516 +        this.mAccount = account;
  8.1517 +    }
  8.1518 +
  8.1519 +    public void setProvider(ContentProviderClient provider) {
  8.1520 +        this.mProvider = provider;
  8.1521 +    }
  8.1522 +}
     9.1 --- a/src/org/gege/caldavsyncadapter/caldav/CopyOfEasySSLSocketFactory.java	Tue Feb 10 21:55:00 2015 +0100
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,159 +0,0 @@
     9.4 -/**
     9.5 - * Copyright (c) 2012-2013, Gerald Garcia
     9.6 - * 
     9.7 - * This file is part of Andoid Caldav Sync Adapter Free.
     9.8 - *
     9.9 - * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
    9.10 - * it and/or modify it under the terms of the GNU General Public License 
    9.11 - * as published by the Free Software Foundation, either version 3 of the 
    9.12 - * License, or at your option any later version.
    9.13 - *
    9.14 - * Andoid Caldav Sync Adapter Free is distributed in the hope that 
    9.15 - * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
    9.16 - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    9.17 - * GNU General Public License for more details.
    9.18 - *
    9.19 - * You should have received a copy of the GNU General Public License
    9.20 - * along with Andoid Caldav Sync Adapter Free.  
    9.21 - * If not, see <http://www.gnu.org/licenses/>.
    9.22 - * 
    9.23 - */
    9.24 -
    9.25 -package org.gege.caldavsyncadapter.caldav;
    9.26 -
    9.27 -/*
    9.28 - * Licensed to the Apache Software Foundation (ASF) under one
    9.29 - * or more contributor license agreements.  See the NOTICE file
    9.30 - * distributed with this work for additional information
    9.31 - * regarding copyright ownership.  The ASF licenses this file
    9.32 - * to you under the Apache License, Version 2.0 (the
    9.33 - * "License"); you may not use this file except in compliance
    9.34 - * with the License.  You may obtain a copy of the License at
    9.35 - *
    9.36 - *   http://www.apache.org/licenses/LICENSE-2.0
    9.37 - *
    9.38 - * Unless required by applicable law or agreed to in writing,
    9.39 - * software distributed under the License is distributed on an
    9.40 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    9.41 - * KIND, either express or implied.  See the License for the
    9.42 - * specific language governing permissions and limitations
    9.43 - * under the License.
    9.44 - */
    9.45 -
    9.46 -import java.io.IOException;
    9.47 -import java.net.InetAddress;
    9.48 -import java.net.InetSocketAddress;
    9.49 -import java.net.Socket;
    9.50 -import java.net.UnknownHostException;
    9.51 -
    9.52 -import javax.net.ssl.SSLContext;
    9.53 -import javax.net.ssl.SSLSocket;
    9.54 -import javax.net.ssl.TrustManager;
    9.55 -
    9.56 -import org.apache.http.conn.ConnectTimeoutException;
    9.57 -import org.apache.http.conn.scheme.LayeredSocketFactory;
    9.58 -import org.apache.http.conn.scheme.SocketFactory;
    9.59 -import org.apache.http.params.HttpConnectionParams;
    9.60 -import org.apache.http.params.HttpParams;
    9.61 -
    9.62 -/**
    9.63 - * This socket factory will create ssl socket that accepts self signed
    9.64 - * certificate
    9.65 - * 
    9.66 - * @author olamy
    9.67 - * @version $Id: EasySSLSocketFactory.java 765355 2009-04-15 20:59:07Z evenisse
    9.68 - *          $
    9.69 - * @since 1.2.3
    9.70 - */
    9.71 -public class CopyOfEasySSLSocketFactory implements SocketFactory,
    9.72 -		LayeredSocketFactory {
    9.73 -
    9.74 -	private SSLContext sslcontext = null;
    9.75 -
    9.76 -	private static SSLContext createEasySSLContext() throws IOException {
    9.77 -		try {
    9.78 -			SSLContext context = SSLContext.getInstance("TLS");
    9.79 -			context.init(null, new TrustManager[] { new EasyX509TrustManager(
    9.80 -					null) }, null);
    9.81 -			return context;
    9.82 -		} catch (Exception e) {
    9.83 -			throw new IOException(e.getMessage());
    9.84 -		}
    9.85 -	}
    9.86 -
    9.87 -	private SSLContext getSSLContext() throws IOException {
    9.88 -		if (this.sslcontext == null) {
    9.89 -			this.sslcontext = createEasySSLContext();
    9.90 -		}
    9.91 -		return this.sslcontext;
    9.92 -	}
    9.93 -
    9.94 -	/**
    9.95 -	 * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket,
    9.96 -	 *      java.lang.String, int, java.net.InetAddress, int,
    9.97 -	 *      org.apache.http.params.HttpParams)
    9.98 -	 */
    9.99 -	public Socket connectSocket(Socket sock, String host, int port,
   9.100 -			InetAddress localAddress, int localPort, HttpParams params)
   9.101 -			throws IOException, UnknownHostException, ConnectTimeoutException {
   9.102 -		int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
   9.103 -		int soTimeout = HttpConnectionParams.getSoTimeout(params);
   9.104 -
   9.105 -		InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
   9.106 -		SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
   9.107 -
   9.108 -		if ((localAddress != null) || (localPort > 0)) {
   9.109 -			// we need to bind explicitly
   9.110 -			if (localPort < 0) {
   9.111 -				localPort = 0; // indicates "any"
   9.112 -			}
   9.113 -			InetSocketAddress isa = new InetSocketAddress(localAddress,
   9.114 -					localPort);
   9.115 -			sslsock.bind(isa);
   9.116 -		}
   9.117 -
   9.118 -		sslsock.connect(remoteAddress, connTimeout);
   9.119 -		sslsock.setSoTimeout(soTimeout);
   9.120 -		return sslsock;
   9.121 -
   9.122 -	}
   9.123 -
   9.124 -	/**
   9.125 -	 * @see org.apache.http.conn.scheme.SocketFactory#createSocket()
   9.126 -	 */
   9.127 -	public Socket createSocket() throws IOException {
   9.128 -		return getSSLContext().getSocketFactory().createSocket();
   9.129 -	}
   9.130 -
   9.131 -	/**
   9.132 -	 * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
   9.133 -	 */
   9.134 -	public boolean isSecure(Socket socket) throws IllegalArgumentException {
   9.135 -		return true;
   9.136 -	}
   9.137 -
   9.138 -	/**
   9.139 -	 * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket,
   9.140 -	 *      java.lang.String, int, boolean)
   9.141 -	 */
   9.142 -	public Socket createSocket(Socket socket, String host, int port,
   9.143 -			boolean autoClose) throws IOException, UnknownHostException {
   9.144 -		return getSSLContext().getSocketFactory().createSocket();
   9.145 -	}
   9.146 -
   9.147 -	// -------------------------------------------------------------------
   9.148 -	// javadoc in org.apache.http.conn.scheme.SocketFactory says :
   9.149 -	// Both Object.equals() and Object.hashCode() must be overridden
   9.150 -	// for the correct operation of some connection managers
   9.151 -	// -------------------------------------------------------------------
   9.152 -
   9.153 -	public boolean equals(Object obj) {
   9.154 -		return ((obj != null) && obj.getClass().equals(
   9.155 -				CopyOfEasySSLSocketFactory.class));
   9.156 -	}
   9.157 -
   9.158 -	public int hashCode() {
   9.159 -		return CopyOfEasySSLSocketFactory.class.hashCode();
   9.160 -	}
   9.161 -
   9.162 -}
   9.163 \ No newline at end of file
    10.1 --- a/src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java	Tue Feb 10 21:55:00 2015 +0100
    10.2 +++ b/src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java	Tue Feb 10 22:40:00 2015 +0100
    10.3 @@ -54,7 +54,8 @@
    10.4  	
    10.5      private static final EasySSLSocketFactory DEFAULT_FACTORY = new EasySSLSocketFactory();
    10.6  
    10.7 -    public static EasySSLSocketFactory getSocketFactory() {
    10.8 +    public static EasySSLSocketFactory getSocketFactory
    10.9 +            () {
   10.10          return DEFAULT_FACTORY;
   10.11      }
   10.12  
    11.1 --- a/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java	Tue Feb 10 21:55:00 2015 +0100
    11.2 +++ b/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java	Tue Feb 10 22:40:00 2015 +0100
    11.3 @@ -1,6 +1,6 @@
    11.4  /**
    11.5   * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger
    11.6 - * 
    11.7 + *
    11.8   * This file is part of Andoid Caldav Sync Adapter Free.
    11.9   *
   11.10   * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
   11.11 @@ -16,27 +16,11 @@
   11.12   * You should have received a copy of the GNU General Public License
   11.13   * along with Andoid Caldav Sync Adapter Free.  
   11.14   * If not, see <http://www.gnu.org/licenses/>.
   11.15 - * 
   11.16 + *
   11.17   */
   11.18  
   11.19  package org.gege.caldavsyncadapter.caldav.entities;
   11.20  
   11.21 -import java.io.IOException;
   11.22 -import java.net.URI;
   11.23 -import java.net.URISyntaxException;
   11.24 -import java.util.ArrayList;
   11.25 -
   11.26 -import javax.xml.parsers.ParserConfigurationException;
   11.27 -
   11.28 -import org.apache.http.client.ClientProtocolException;
   11.29 -import org.gege.caldavsyncadapter.CalendarColors;
   11.30 -import org.gege.caldavsyncadapter.Event;
   11.31 -import org.gege.caldavsyncadapter.android.entities.AndroidEvent;
   11.32 -import org.gege.caldavsyncadapter.caldav.CaldavFacade;
   11.33 -import org.gege.caldavsyncadapter.syncadapter.SyncAdapter;
   11.34 -import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper;
   11.35 -import org.xml.sax.SAXException;
   11.36 -
   11.37  import android.accounts.Account;
   11.38  import android.content.ContentProviderClient;
   11.39  import android.content.ContentUris;
   11.40 @@ -49,618 +33,674 @@
   11.41  import android.provider.CalendarContract.Events;
   11.42  import android.util.Log;
   11.43  
   11.44 +import org.apache.http.client.ClientProtocolException;
   11.45 +import org.gege.caldavsyncadapter.CalendarColors;
   11.46 +import org.gege.caldavsyncadapter.Event;
   11.47 +import org.gege.caldavsyncadapter.android.entities.AndroidEvent;
   11.48 +import org.gege.caldavsyncadapter.caldav.CaldavFacade;
   11.49 +import org.gege.caldavsyncadapter.syncadapter.SyncAdapter;
   11.50 +import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper;
   11.51 +import org.xml.sax.SAXException;
   11.52 +
   11.53 +import java.io.IOException;
   11.54 +import java.net.URI;
   11.55 +import java.net.URISyntaxException;
   11.56 +import java.util.ArrayList;
   11.57 +import java.util.regex.Matcher;
   11.58 +import java.util.regex.Pattern;
   11.59 +
   11.60 +import javax.xml.parsers.ParserConfigurationException;
   11.61 +
   11.62  public class DavCalendar {
   11.63 -	public enum CalendarSource {
   11.64 -		undefined, Android, CalDAV
   11.65 -	}
   11.66 -		
   11.67 -	private static final String TAG = "Calendar";
   11.68 -		
   11.69 -	/**
   11.70 -	 * stores the CTAG of a calendar
   11.71 -	 */
   11.72 -	public static String CTAG = Calendars.CAL_SYNC1;
   11.73 -	
   11.74 -	/**
   11.75 -	 * stores the URI of a calendar
   11.76 -	 * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname
   11.77 -	 */
   11.78 -	public static String URI = Calendars._SYNC_ID;
   11.79 -	
   11.80 -	public static String SERVERURL = Calendars.CAL_SYNC2;
   11.81 -	
   11.82 -	private String strCalendarColor = "";
   11.83 -	
   11.84 -	private ArrayList<Uri> mNotifyList = new ArrayList<Uri>(); 
   11.85 +    public enum CalendarSource {
   11.86 +        undefined, Android, CalDAV
   11.87 +    }
   11.88  
   11.89 -	/**
   11.90 -	 * the event transformed into ContentValues
   11.91 -	 */
   11.92 -	public ContentValues ContentValues = new ContentValues();
   11.93 -	
   11.94 -	private Account mAccount = null;
   11.95 -	private ContentProviderClient mProvider = null;
   11.96 -	
   11.97 -	public boolean foundServerSide = false;
   11.98 -	public boolean foundClientSide = false;
   11.99 -	public CalendarSource Source = CalendarSource.undefined;
  11.100 -	
  11.101 -	public String ServerUrl = "";
  11.102 -	
  11.103 -	private ArrayList<CalendarEvent> mCalendarEvents = new ArrayList<CalendarEvent>();
  11.104 -	
  11.105 -	private int mTagCounter = 1;
  11.106 -	
  11.107 -	/**
  11.108 -	 * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname
  11.109 -	 */
  11.110 -	public URI getURI() {
  11.111 -		String strUri = this.getContentValueAsString(DavCalendar.URI);
  11.112 -		URI result = null;
  11.113 -		try {
  11.114 -			result = new URI(strUri);
  11.115 -		} catch (URISyntaxException e) {
  11.116 -			e.printStackTrace();
  11.117 -		}
  11.118 -		return result;
  11.119 -	}
  11.120 +    private static final String TAG = "Calendar";
  11.121  
  11.122 -	/**
  11.123 -	 * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname
  11.124 -	 */
  11.125 -	public void setURI(URI uri) {
  11.126 -		this.setContentValueAsString(DavCalendar.URI, uri.toString());
  11.127 -	}
  11.128 +    /**
  11.129 +     * stores the CTAG of a calendar
  11.130 +     */
  11.131 +    public static String CTAG = Calendars.CAL_SYNC1;
  11.132  
  11.133 -	/**
  11.134 -	 * example: Cleartext Display Name 
  11.135 -	 */
  11.136 -	public String getCalendarDisplayName() {
  11.137 -		return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME);
  11.138 -	}
  11.139 +    /**
  11.140 +     * stores the URI of a calendar
  11.141 +     * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname
  11.142 +     */
  11.143 +    public static String URI = Calendars._SYNC_ID;
  11.144  
  11.145 -	/**
  11.146 -	 * example: Cleartext Display Name 
  11.147 -	 */
  11.148 -	public void setCalendarDisplayName(String displayName) {
  11.149 -		this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName);
  11.150 -	}
  11.151 -	
  11.152 +    public static String SERVERURL = Calendars.CAL_SYNC2;
  11.153  
  11.154 -	/**
  11.155 -	 * example: 1143
  11.156 -	 */
  11.157 -	public void setCTag(String cTag, boolean Update) {
  11.158 -		this.setContentValueAsString(DavCalendar.CTAG, cTag);
  11.159 -		if (Update) {
  11.160 -			//serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag());
  11.161 -			try {
  11.162 -				this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag);
  11.163 -			} catch (RemoteException e) {
  11.164 -				e.printStackTrace();
  11.165 -			}
  11.166 -		}
  11.167 -	}
  11.168 -	
  11.169 -	/**
  11.170 -	 * example: 1143
  11.171 -	 */
  11.172 -	public String getcTag() {
  11.173 -		return this.getContentValueAsString(DavCalendar.CTAG);
  11.174 -	}
  11.175 -	
  11.176 -	/**
  11.177 -	 * example: #FFCCAA 
  11.178 -	 */
  11.179 -	public void setCalendarColorAsString(String color) {
  11.180 -		int maxlen = 6;
  11.181 -		
  11.182 -		this.strCalendarColor = color;
  11.183 -		if (!color.equals("")) {
  11.184 -			String strColor = color.replace("#", "");
  11.185 -			if (strColor.length() > maxlen)
  11.186 -				strColor = strColor.substring(0, maxlen);
  11.187 -			int intColor = Integer.parseInt(strColor, 16);
  11.188 -			this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor);
  11.189 -		}
  11.190 -	}
  11.191 +    private String strCalendarColor = "";
  11.192  
  11.193 -	/**
  11.194 -	 * example: #FFCCAA 
  11.195 -	 */
  11.196 -	public String getCalendarColorAsString() {
  11.197 -		return this.strCalendarColor;
  11.198 -	}
  11.199 +    private ArrayList<Uri> mNotifyList = new ArrayList<Uri>();
  11.200  
  11.201 -	/**
  11.202 -	 * example 12345 
  11.203 -	 */
  11.204 -	public int getCalendarColor() {
  11.205 -		return this.getContentValueAsInt(Calendars.CALENDAR_COLOR);
  11.206 -	}
  11.207 -	
  11.208 -	/**
  11.209 -	 * example 12345 
  11.210 -	 */
  11.211 -	public void setCalendarColor(int color) {
  11.212 -		this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color);
  11.213 -	}
  11.214 +    /**
  11.215 +     * the event transformed into ContentValues
  11.216 +     */
  11.217 +    public ContentValues ContentValues = new ContentValues();
  11.218  
  11.219 -	/**
  11.220 -	 * example: 
  11.221 -	 * 		should be: calendarname
  11.222 -	 * 		but is:    http://caldav.example.com/calendarserver.php/calendars/username/calendarname/
  11.223 -	 */
  11.224 -	public String getCalendarName() {
  11.225 -		return this.getContentValueAsString(Calendars.NAME);
  11.226 -	}
  11.227 +    private Account mAccount = null;
  11.228 +    private ContentProviderClient mProvider = null;
  11.229  
  11.230 -	/**
  11.231 -	 * example: 
  11.232 -	 * 		should be: calendarname
  11.233 -	 * 		but is:    http://caldav.example.com/calendarserver.php/calendars/username/calendarname/
  11.234 -	 */
  11.235 -	public void setCalendarName(String calendarName) {
  11.236 -		this.setContentValueAsString(Calendars.NAME, calendarName);
  11.237 -	}
  11.238 +    public boolean foundServerSide = false;
  11.239 +    public boolean foundClientSide = false;
  11.240 +    public CalendarSource Source = CalendarSource.undefined;
  11.241  
  11.242 -	/**
  11.243 -	 * example: 8
  11.244 -	 */
  11.245 -	public int getAndroidCalendarId() {
  11.246 -		return this.getContentValueAsInt(Calendars._ID);
  11.247 -	}
  11.248 +    public String ServerUrl = "";
  11.249  
  11.250 -	/**
  11.251 -	 * example: 8
  11.252 -	 */
  11.253 -	public void setAndroidCalendarId(int androidCalendarId) {
  11.254 -		this.setContentValueAsInt(Calendars._ID, androidCalendarId);
  11.255 -	}
  11.256 +    private ArrayList<CalendarEvent> mCalendarEvents = new ArrayList<CalendarEvent>();
  11.257  
  11.258 -	/**
  11.259 -	 * example: content://com.android.calendar/calendars/8
  11.260 -	 */
  11.261 -	public Uri getAndroidCalendarUri() {
  11.262 -		return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId());
  11.263 -	}
  11.264 -	
  11.265 -	/**
  11.266 -	 * empty constructor
  11.267 -	 */
  11.268 -	public DavCalendar(CalendarSource source) {
  11.269 -		this.Source = source;
  11.270 -	}
  11.271 -	
  11.272 -	/**
  11.273 -	 * creates an new instance from a cursor
  11.274 -	 * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI
  11.275 -	 */
  11.276 -	public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, CalendarSource source, String serverUrl) {
  11.277 -		this.mAccount = account;
  11.278 -		this.mProvider = provider;
  11.279 -		this.foundClientSide = true;
  11.280 -		this.Source = source;
  11.281 -		this.ServerUrl = serverUrl;
  11.282 +    private int mTagCounter = 1;
  11.283  
  11.284 -		String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID));
  11.285 -		String strName = cur.getString(cur.getColumnIndex(Calendars.NAME));
  11.286 -		String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME));
  11.287 -		String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG));
  11.288 -		String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL));
  11.289 -		int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID));
  11.290 +    /**
  11.291 +     * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname
  11.292 +     */
  11.293 +    public URI getURI() {
  11.294 +        String strUri = this.getContentValueAsString(DavCalendar.URI);
  11.295 +        URI result = null;
  11.296 +        try {
  11.297 +            result = new URI(strUri);
  11.298 +        } catch (URISyntaxException e) {
  11.299 +            e.printStackTrace();
  11.300 +        }
  11.301 +        return result;
  11.302 +    }
  11.303  
  11.304 -		this.setCalendarName(strName);
  11.305 -		this.setCalendarDisplayName(strDisplayName);
  11.306 -		this.setCTag(strCTAG, false);
  11.307 -		this.setAndroidCalendarId(intAndroidCalendarId);
  11.308 -		
  11.309 -		if (strSyncID == null) {
  11.310 -			this.correctSyncID(strName);
  11.311 -			strSyncID = strName;
  11.312 -		}
  11.313 -		if (strServerUrl == null) {
  11.314 -			this.correctServerUrl(serverUrl);
  11.315 -		}
  11.316 -		URI uri = null;
  11.317 -		try {
  11.318 -			uri = new URI(strSyncID);
  11.319 -		} catch (URISyntaxException e) {
  11.320 -			e.printStackTrace();
  11.321 -		}
  11.322 -		this.setURI(uri);
  11.323 -	}
  11.324 -	
  11.325 -	/**
  11.326 -	 * checks a given list of android calendars for a specific android calendar.
  11.327 -	 * this calendar should be a server calendar as it is searched for.
  11.328 -	 * if the calendar is not found, it will be created.
  11.329 -	 * @param androidCalList the list of android calendars
  11.330 -	 * @param context
  11.331 -	 * @return the found android calendar or null of fails
  11.332 -	 * @throws RemoteException
  11.333 -	 */
  11.334 -	public Uri checkAndroidCalendarList(CalendarList androidCalList, android.content.Context context) throws RemoteException {
  11.335 -		Uri androidCalendarUri = null;
  11.336 -		boolean isCalendarExist = false;
  11.337 -		
  11.338 -		DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI());
  11.339 -		if (androidCalendar != null) {
  11.340 -			isCalendarExist = true;
  11.341 -			androidCalendar.foundServerSide = true;
  11.342 -		}
  11.343 -		
  11.344 +    /**
  11.345 +     * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname
  11.346 +     */
  11.347 +    public void setURI(URI uri) {
  11.348 +        this.setContentValueAsString(DavCalendar.URI, uri.toString());
  11.349 +    }
  11.350  
  11.351 -		if (!isCalendarExist) {
  11.352 -			DavCalendar newCal = this.createNewAndroidCalendar(this, androidCalList.getCalendarList().size(), context);
  11.353 -			if (newCal != null) {
  11.354 -				androidCalList.addCalendar(newCal);
  11.355 -				androidCalendarUri = newCal.getAndroidCalendarUri();
  11.356 -			}
  11.357 -		} else {
  11.358 -			androidCalendarUri = androidCalendar.getAndroidCalendarUri();
  11.359 -			if (!this.getCalendarColorAsString().equals("")) {
  11.360 -				//serverCalendar.updateCalendarColor(returnedCalendarUri, serverCalendar);
  11.361 -				this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, this.getCalendarColor());
  11.362 -			}
  11.363 -			if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) && 
  11.364 -				(androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) {
  11.365 -				String serverDisplayName = this.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME);
  11.366 -				String clientDisplayName = androidCalendar.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME);
  11.367 -				if (!serverDisplayName.equals(clientDisplayName))
  11.368 -					this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, serverDisplayName);
  11.369 -			}
  11.370 -		}
  11.371 -		
  11.372 -		return androidCalendarUri;
  11.373 -	}
  11.374 -	
  11.375 -	/**
  11.376 -	 * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI (_SYNC_ID)
  11.377 -	 * @param calendarUri the real calendarUri
  11.378 -	 * @return success of this function
  11.379 -	 */
  11.380 -	private boolean correctSyncID(String calendarUri) {
  11.381 -		boolean Result = false;
  11.382 -		Log.v(TAG, "correcting SyncID for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME));
  11.383 -			
  11.384 -		ContentValues mUpdateValues = new ContentValues();
  11.385 -		mUpdateValues.put(DavCalendar.URI, calendarUri);
  11.386 -		
  11.387 -		try {
  11.388 -			mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null);
  11.389 -			Result = true;
  11.390 -		} catch (RemoteException e) {
  11.391 -			e.printStackTrace();
  11.392 -		}
  11.393 -		
  11.394 -		return Result;
  11.395 -	}
  11.396 -	
  11.397 -	/**
  11.398 -	 * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98)
  11.399 -	 * @param serverUrl the current serverurl
  11.400 -	 * @return success of this function
  11.401 -	 */
  11.402 -	private boolean correctServerUrl(String serverUrl) {
  11.403 -		boolean Result = false;
  11.404 -		Log.v(TAG, "correcting ServerUrl for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME));
  11.405 -			
  11.406 -		ContentValues mUpdateValues = new ContentValues();
  11.407 -		mUpdateValues.put(DavCalendar.SERVERURL, serverUrl);
  11.408 -		
  11.409 -		try {
  11.410 -			mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null);
  11.411 -			Result = true;
  11.412 -		} catch (RemoteException e) {
  11.413 -			e.printStackTrace();
  11.414 -		}
  11.415 -		
  11.416 -		return Result;
  11.417 -	}
  11.418 -	
  11.419 -	/**
  11.420 -	 * creates a new androidCalendar
  11.421 -	 * @param serverCalendar
  11.422 -	 * @param index
  11.423 -	 * @param context
  11.424 -	 * @return the new androidCalendar or null if fails
  11.425 -	 */
  11.426 -	private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, android.content.Context context) {
  11.427 -		Uri newUri = null;
  11.428 -		DavCalendar Result = null;
  11.429 -		
  11.430 -		final ContentValues contentValues = new ContentValues();
  11.431 -		contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString());
  11.432 -		contentValues.put(DavCalendar.SERVERURL, this.ServerUrl);
  11.433 +    /**
  11.434 +     * example: Cleartext Display Name
  11.435 +     */
  11.436 +    public String getCalendarDisplayName() {
  11.437 +        return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME);
  11.438 +    }
  11.439  
  11.440 -		contentValues.put(Calendars.VISIBLE, 1);
  11.441 -		contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName());
  11.442 -		contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name);
  11.443 -		contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type);
  11.444 -		contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name);
  11.445 -		contentValues.put(Calendars.SYNC_EVENTS, 1);
  11.446 -		contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER);
  11.447 -		
  11.448 -		if (!serverCalendar.getCalendarColorAsString().equals("")) {
  11.449 -			contentValues.put(Calendars.CALENDAR_COLOR, serverCalendar.getCalendarColor());
  11.450 -		} else {
  11.451 -			// find a color
  11.452 -			//int index = mList.size();
  11.453 -			index = index % CalendarColors.colors.length;
  11.454 -			contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[index]);
  11.455 -		}
  11.456 +    /**
  11.457 +     * example: Cleartext Display Name
  11.458 +     */
  11.459 +    public void setCalendarDisplayName(String displayName) {
  11.460 +        this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName);
  11.461 +    }
  11.462  
  11.463 -		try {
  11.464 -			newUri = mProvider.insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), contentValues);
  11.465 -		} catch (RemoteException e) {
  11.466 -			e.printStackTrace();
  11.467 -		}
  11.468  
  11.469 -		// it is possible that this calendar already exists but the provider failed to find it within isCalendarExist()
  11.470 -		// the adapter would try to create a new calendar but the provider fails again to create a new calendar.
  11.471 -		if (newUri != null) {
  11.472 -			long newCalendarId = ContentUris.parseId(newUri);
  11.473 +    /**
  11.474 +     * example: 1143
  11.475 +     */
  11.476 +    public void setCTag(String cTag, boolean Update) {
  11.477 +        this.setContentValueAsString(DavCalendar.CTAG, cTag);
  11.478 +        if (Update) {
  11.479 +            //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag());
  11.480 +            try {
  11.481 +                this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag);
  11.482 +            } catch (RemoteException e) {
  11.483 +                e.printStackTrace();
  11.484 +            }
  11.485 +        }
  11.486 +    }
  11.487  
  11.488 -			Cursor cur = null;
  11.489 -			Uri uri = Calendars.CONTENT_URI;   
  11.490 -			String selection = "(" + Calendars._ID +  " = ?)";
  11.491 -			String[] selectionArgs = new String[] {String.valueOf(newCalendarId)}; 
  11.492 +    /**
  11.493 +     * example: 1143
  11.494 +     */
  11.495 +    public String getcTag() {
  11.496 +        return this.getContentValueAsString(DavCalendar.CTAG);
  11.497 +    }
  11.498  
  11.499 -			// Submit the query and get a Cursor object back. 
  11.500 -			try {
  11.501 -				cur = mProvider.query(uri, null, selection, selectionArgs, null);
  11.502 -			} catch (RemoteException e) {
  11.503 -				e.printStackTrace();
  11.504 -			}
  11.505 -			
  11.506 -			if (cur != null) {
  11.507 -				while (cur.moveToNext()) {
  11.508 -					Result = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl);
  11.509 -					Result.foundServerSide = true;
  11.510 -				}
  11.511 -				cur.close();
  11.512 -				//if (Result != null)
  11.513 -				//	this.mList.add(Result);
  11.514 -			}
  11.515 -			Log.i(TAG, "New calendar created : URI=" + Result.getAndroidCalendarUri());
  11.516 -			NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", "new calendar found: " + Result.getCalendarDisplayName());
  11.517 -			mNotifyList.add(Result.getAndroidCalendarUri());
  11.518 -		}
  11.519 -		
  11.520 -		return Result;
  11.521 -	}
  11.522 -	
  11.523 -	/**
  11.524 -	 * there is no corresponding calendar on server side. time to delete this calendar on android side.
  11.525 -	 * @return 
  11.526 -	 */
  11.527 -	public boolean deleteAndroidCalendar() {
  11.528 -		boolean Result = false;
  11.529 -		
  11.530 -		String mSelectionClause = "(" + Calendars._ID + " = ?)";
  11.531 -		int calendarId  = this.getAndroidCalendarId();
  11.532 -		String[] mSelectionArgs = {Long.toString(calendarId)};
  11.533 -		
  11.534 -		int CountDeleted = 0;
  11.535 -		try {
  11.536 -			CountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs);
  11.537 -			Log.i(TAG,"Calendar deleted: " + String.valueOf(calendarId));
  11.538 -			this.mNotifyList.add(this.getAndroidCalendarUri());
  11.539 -			Result = true;
  11.540 -		} catch (RemoteException e) {
  11.541 -			e.printStackTrace();
  11.542 -		}	
  11.543 -		Log.d(TAG, "Android Calendars deleted: " + Integer.toString(CountDeleted));
  11.544 -		
  11.545 -		return Result;
  11.546 -	}
  11.547 +    /**
  11.548 +     * example: #FFCCAA
  11.549 +     */
  11.550 +    public void setCalendarColorAsString(String color) {
  11.551 +        int maxlen = 6;
  11.552  
  11.553 -	/**
  11.554 -	 * updates the android calendar
  11.555 -	 * @param calendarUri the uri of the androidCalendar
  11.556 -	 * @param target must be from android.provider.CalendarContract.Calendars
  11.557 -	 * @param value the new value for the target
  11.558 -	 * @throws RemoteException
  11.559 -	 */
  11.560 -	private void updateAndroidCalendar(Uri calendarUri, String target, int value) throws RemoteException {
  11.561 -		ContentValues mUpdateValues = new ContentValues();
  11.562 -		mUpdateValues.put(target, value);
  11.563 -		
  11.564 -		mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null);
  11.565 -	}
  11.566 +        this.strCalendarColor = color;
  11.567 +        if (!color.equals("")) {
  11.568 +            String strColor = color.replace("#", "");
  11.569 +            if (strColor.length() > maxlen)
  11.570 +                strColor = strColor.substring(0, maxlen);
  11.571 +            int intColor = Integer.parseInt(strColor, 16);
  11.572 +            this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor);
  11.573 +        }
  11.574 +    }
  11.575  
  11.576 -	/**
  11.577 -	 * updates the android calendar
  11.578 -	 * @param calendarUri the uri of the androidCalendar
  11.579 -	 * @param target must be from android.provider.CalendarContract.Calendars
  11.580 -	 * @param value the new value for the target
  11.581 -	 * @throws RemoteException
  11.582 -	 */
  11.583 -	private void updateAndroidCalendar(Uri calendarUri, String target, String value) throws RemoteException {
  11.584 -		ContentValues mUpdateValues = new ContentValues();
  11.585 -		mUpdateValues.put(target, value);
  11.586 -		
  11.587 -		mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null);
  11.588 -	}
  11.589 -	
  11.590 -	/**
  11.591 -	 * marks the android event as already handled
  11.592 -	 * @return
  11.593 -	 * @see AndroidEvent#cInternalTag
  11.594 -	 * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
  11.595 -	 * @throws RemoteException
  11.596 -	 */
  11.597 -	public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException {
  11.598 -		boolean Result = false;
  11.599 -		
  11.600 -		ContentValues values = new ContentValues();
  11.601 -		//values.put(Event.INTERNALTAG, 1);
  11.602 -		values.put(Event.INTERNALTAG, mTagCounter);
  11.603 -		//values.put(Event.INTERNALTAG, String.valueOf(mTagCounter));
  11.604 -		
  11.605 -		int RowCount = this.mProvider.update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), values, null, null);
  11.606 -		//Log.v(TAG,"event tag nr: " + String.valueOf(mTagCounter));
  11.607 -		//Log.v(TAG,"Rows updated: " + String.valueOf(RowCount));
  11.608 -		
  11.609 -		if (RowCount == 1) {
  11.610 -			Result = true;
  11.611 -			mTagCounter += 1;
  11.612 -		} else {
  11.613 -			Log.v(TAG,"EVENT NOT TAGGED!");
  11.614 -		}
  11.615 -		
  11.616 -		return Result;
  11.617 -	} 
  11.618 -	
  11.619 -	/**
  11.620 -	 * removes the tag of all android events
  11.621 -	 * @return
  11.622 -	 * @see AndroidEvent#cInternalTag
  11.623 -	 * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
  11.624 -	 * @throws RemoteException
  11.625 -	 */
  11.626 -	public int untagAndroidEvents() throws RemoteException {
  11.627 -		int RowCount = 0;
  11.628 -		int Steps = 100;
  11.629 -		ContentValues values = new ContentValues();
  11.630 -		values.put(Event.INTERNALTAG, 0);
  11.631 +    /**
  11.632 +     * example: #FFCCAA
  11.633 +     */
  11.634 +    public String getCalendarColorAsString() {
  11.635 +        return this.strCalendarColor;
  11.636 +    }
  11.637  
  11.638 -		for (int i=1; i < this.mTagCounter; i = i + Steps) {
  11.639 -			String mSelectionClause = "(CAST(" + Event.INTERNALTAG +  " AS INT) >= ?) AND (CAST(" + Event.INTERNALTAG +  " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)";
  11.640 -			String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + Steps), Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))};
  11.641 -			RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs);
  11.642 -		}
  11.643 -		/*String mSelectionClause = "(" + Event.INTERNALTAG +  " > ?) AND (" + Events.CALENDAR_ID + " = ?)";
  11.644 -		String[] mSelectionArgs = {"0", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))};
  11.645 +    /**
  11.646 +     * example 12345
  11.647 +     */
  11.648 +    public int getCalendarColor() {
  11.649 +        return this.getContentValueAsInt(Calendars.CALENDAR_COLOR);
  11.650 +    }
  11.651 +
  11.652 +    /**
  11.653 +     * example 12345
  11.654 +     */
  11.655 +    public void setCalendarColor(int color) {
  11.656 +        this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color);
  11.657 +    }
  11.658 +
  11.659 +    /**
  11.660 +     * example:
  11.661 +     * should be: calendarname
  11.662 +     * but is:    http://caldav.example.com/calendarserver.php/calendars/username/calendarname/
  11.663 +     */
  11.664 +    public String getCalendarName() {
  11.665 +        return this.getContentValueAsString(Calendars.NAME);
  11.666 +    }
  11.667 +
  11.668 +    /**
  11.669 +     * example:
  11.670 +     * should be: calendarname
  11.671 +     * but is:    http://caldav.example.com/calendarserver.php/calendars/username/calendarname/
  11.672 +     */
  11.673 +    public void setCalendarName(String calendarName) {
  11.674 +        this.setContentValueAsString(Calendars.NAME, calendarName);
  11.675 +    }
  11.676 +
  11.677 +    /**
  11.678 +     * example: 8
  11.679 +     */
  11.680 +    public int getAndroidCalendarId() {
  11.681 +        return this.getContentValueAsInt(Calendars._ID);
  11.682 +    }
  11.683 +
  11.684 +    /**
  11.685 +     * example: 8
  11.686 +     */
  11.687 +    public void setAndroidCalendarId(int androidCalendarId) {
  11.688 +        this.setContentValueAsInt(Calendars._ID, androidCalendarId);
  11.689 +    }
  11.690 +
  11.691 +    /**
  11.692 +     * example: content://com.android.calendar/calendars/8
  11.693 +     */
  11.694 +    public Uri getAndroidCalendarUri() {
  11.695 +        return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId());
  11.696 +    }
  11.697 +
  11.698 +    /**
  11.699 +     * empty constructor
  11.700 +     */
  11.701 +    public DavCalendar(CalendarSource source) {
  11.702 +        this.Source = source;
  11.703 +    }
  11.704 +
  11.705 +    /**
  11.706 +     * creates an new instance from a cursor
  11.707 +     *
  11.708 +     * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI
  11.709 +     */
  11.710 +    public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, CalendarSource source, String serverUrl) {
  11.711 +        this.mAccount = account;
  11.712 +        this.mProvider = provider;
  11.713 +        this.foundClientSide = true;
  11.714 +        this.Source = source;
  11.715 +        this.ServerUrl = serverUrl;
  11.716 +
  11.717 +        String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID));
  11.718 +        String strName = cur.getString(cur.getColumnIndex(Calendars.NAME));
  11.719 +        String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME));
  11.720 +        String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG));
  11.721 +        String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL));
  11.722 +        String strCalendarColor = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_COLOR));
  11.723 +        int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID));
  11.724 +
  11.725 +        this.setCalendarName(strName);
  11.726 +        this.setCalendarDisplayName(strDisplayName);
  11.727 +        this.setCTag(strCTAG, false);
  11.728 +        this.setAndroidCalendarId(intAndroidCalendarId);
  11.729 +        this.setCalendarColor(Integer.parseInt(strCalendarColor));
  11.730 +
  11.731 +        if (strSyncID == null) {
  11.732 +            this.correctSyncID(strName);
  11.733 +            strSyncID = strName;
  11.734 +        }
  11.735 +        if (strServerUrl == null) {
  11.736 +            this.correctServerUrl(serverUrl);
  11.737 +        }
  11.738 +        URI uri = null;
  11.739 +        try {
  11.740 +            uri = new URI(strSyncID);
  11.741 +        } catch (URISyntaxException e) {
  11.742 +            e.printStackTrace();
  11.743 +        }
  11.744 +        this.setURI(uri);
  11.745 +    }
  11.746 +
  11.747 +    /**
  11.748 +     * checks a given list of android calendars for a specific android calendar.
  11.749 +     * this calendar should be a server calendar as it is searched for.
  11.750 +     * if the calendar is not found, it will be created.
  11.751 +     *
  11.752 +     * @param androidCalList the list of android calendars
  11.753 +     * @param context
  11.754 +     * @return the found android calendar or null of fails
  11.755 +     * @throws RemoteException
  11.756 +     */
  11.757 +    public Uri checkAndroidCalendarList(CalendarList androidCalList, android.content.Context context) throws RemoteException {
  11.758 +        Uri androidCalendarUri = null;
  11.759 +        boolean isCalendarExist = false;
  11.760 +
  11.761 +        DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI());
  11.762 +        if (androidCalendar != null) {
  11.763 +            isCalendarExist = true;
  11.764 +            androidCalendar.foundServerSide = true;
  11.765 +        }
  11.766 +
  11.767 +
  11.768 +        if (!isCalendarExist) {
  11.769 +            DavCalendar newCal = this.createNewAndroidCalendar(this, androidCalList.getCalendarList()
  11.770 +                    .size(), context);
  11.771 +            if (newCal != null) {
  11.772 +                androidCalList.addCalendar(newCal);
  11.773 +                androidCalendarUri = newCal.getAndroidCalendarUri();
  11.774 +            }
  11.775 +        } else {
  11.776 +            androidCalendarUri = androidCalendar.getAndroidCalendarUri();
  11.777 +            if (!this.getCalendarColorAsString().equals("")) {
  11.778 +                this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, getColorAsHex(this.getCalendarColorAsString()));
  11.779 +            }
  11.780 +            if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) &&
  11.781 +                    (androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) {
  11.782 +                String serverDisplayName = this.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME);
  11.783 +                String clientDisplayName = androidCalendar.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME);
  11.784 +                if (!serverDisplayName.equals(clientDisplayName))
  11.785 +                    this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, serverDisplayName);
  11.786 +            }
  11.787 +        }
  11.788 +
  11.789 +        return androidCalendarUri;
  11.790 +    }
  11.791 +
  11.792 +    /**
  11.793 +     * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI (_SYNC_ID)
  11.794 +     *
  11.795 +     * @param calendarUri the real calendarUri
  11.796 +     * @return success of this function
  11.797 +     */
  11.798 +    private boolean correctSyncID(String calendarUri) {
  11.799 +        boolean Result = false;
  11.800 +        Log.v(TAG, "correcting SyncID for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME));
  11.801 +
  11.802 +        ContentValues mUpdateValues = new ContentValues();
  11.803 +        mUpdateValues.put(DavCalendar.URI, calendarUri);
  11.804 +
  11.805 +        try {
  11.806 +            mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null);
  11.807 +            Result = true;
  11.808 +        } catch (RemoteException e) {
  11.809 +            e.printStackTrace();
  11.810 +        }
  11.811 +
  11.812 +        return Result;
  11.813 +    }
  11.814 +
  11.815 +    /**
  11.816 +     * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98)
  11.817 +     *
  11.818 +     * @param serverUrl the current serverurl
  11.819 +     * @return success of this function
  11.820 +     */
  11.821 +    private boolean correctServerUrl(String serverUrl) {
  11.822 +        boolean Result = false;
  11.823 +        Log.v(TAG, "correcting ServerUrl for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME));
  11.824 +
  11.825 +        ContentValues mUpdateValues = new ContentValues();
  11.826 +        mUpdateValues.put(DavCalendar.SERVERURL, serverUrl);
  11.827 +
  11.828 +        try {
  11.829 +            mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null);
  11.830 +            Result = true;
  11.831 +        } catch (RemoteException e) {
  11.832 +            e.printStackTrace();
  11.833 +        }
  11.834 +
  11.835 +        return Result;
  11.836 +    }
  11.837 +
  11.838 +    /**
  11.839 +     * creates a new androidCalendar
  11.840 +     *
  11.841 +     * @param serverCalendar
  11.842 +     * @param index
  11.843 +     * @param context
  11.844 +     * @return the new androidCalendar or null if fails
  11.845 +     */
  11.846 +    private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, android.content.Context context) {
  11.847 +        Uri newUri = null;
  11.848 +        DavCalendar Result = null;
  11.849 +
  11.850 +        final ContentValues contentValues = new ContentValues();
  11.851 +        contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString());
  11.852 +        contentValues.put(DavCalendar.SERVERURL, this.ServerUrl);
  11.853 +
  11.854 +        contentValues.put(Calendars.VISIBLE, 1);
  11.855 +        contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName());
  11.856 +        contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name);
  11.857 +        contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type);
  11.858 +        contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name);
  11.859 +        contentValues.put(Calendars.SYNC_EVENTS, 1);
  11.860 +        contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER);
  11.861 +
  11.862 +        String calendarColorAsString = serverCalendar.getCalendarColorAsString();
  11.863 +        if (!calendarColorAsString.isEmpty()) {
  11.864 +            int color = getColorAsHex(calendarColorAsString);
  11.865 +            contentValues.put(Calendars.CALENDAR_COLOR, color);
  11.866 +        } else {
  11.867 +            // find a color
  11.868 +            //int index = mList.size();
  11.869 +            index = index % CalendarColors.colors.length;
  11.870 +            contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[2]);
  11.871 +        }
  11.872 +
  11.873 +        try {
  11.874 +            newUri = mProvider.insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), contentValues);
  11.875 +        } catch (RemoteException e) {
  11.876 +            e.printStackTrace();
  11.877 +        }
  11.878 +
  11.879 +        // it is possible that this calendar already exists but the provider failed to find it within isCalendarExist()
  11.880 +        // the adapter would try to create a new calendar but the provider fails again to create a new calendar.
  11.881 +        if (newUri != null) {
  11.882 +            long newCalendarId = ContentUris.parseId(newUri);
  11.883 +
  11.884 +            Cursor cur = null;
  11.885 +            Uri uri = Calendars.CONTENT_URI;
  11.886 +            String selection = "(" + Calendars._ID + " = ?)";
  11.887 +            String[] selectionArgs = new String[]{String.valueOf(newCalendarId)};
  11.888 +
  11.889 +            // Submit the query and get a Cursor object back.
  11.890 +            try {
  11.891 +                cur = mProvider.query(uri, null, selection, selectionArgs, null);
  11.892 +            } catch (RemoteException e) {
  11.893 +                e.printStackTrace();
  11.894 +            }
  11.895 +
  11.896 +            if (cur != null) {
  11.897 +                while (cur.moveToNext()) {
  11.898 +                    Result = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl);
  11.899 +                    Result.foundServerSide = true;
  11.900 +                }
  11.901 +                cur.close();
  11.902 +                //if (Result != null)
  11.903 +                //	this.mList.add(Result);
  11.904 +            }
  11.905 +            Log.i(TAG, "New calendar created : URI=" + Result.getAndroidCalendarUri());
  11.906 +            NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", "new calendar found: " + Result
  11.907 +                    .getCalendarDisplayName());
  11.908 +            mNotifyList.add(Result.getAndroidCalendarUri());
  11.909 +        }
  11.910 +
  11.911 +        return Result;
  11.912 +    }
  11.913 +
  11.914 +    private int getColorAsHex(String calendarColorAsString) {
  11.915 +        int color = 0x0000FF00;
  11.916 +        Pattern p = Pattern.compile("#?(\\p{XDigit}{6})(\\p{XDigit}{2})?");
  11.917 +        Matcher m = p.matcher(calendarColorAsString);
  11.918 +        if (m.find()) {
  11.919 +            int color_rgb = Integer.parseInt(m.group(1), 16);
  11.920 +            int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF;
  11.921 +            color = (color_alpha << 24) | color_rgb;
  11.922 +        }
  11.923 +        return color;
  11.924 +    }
  11.925 +
  11.926 +    /**
  11.927 +     * there is no corresponding calendar on server side. time to delete this calendar on android side.
  11.928 +     *
  11.929 +     * @return
  11.930 +     */
  11.931 +    public boolean deleteAndroidCalendar() {
  11.932 +        boolean Result = false;
  11.933 +
  11.934 +        String mSelectionClause = "(" + Calendars._ID + " = ?)";
  11.935 +        int calendarId = this.getAndroidCalendarId();
  11.936 +        String[] mSelectionArgs = {Long.toString(calendarId)};
  11.937 +
  11.938 +        int CountDeleted = 0;
  11.939 +        try {
  11.940 +            CountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs);
  11.941 +            Log.i(TAG, "Calendar deleted: " + String.valueOf(calendarId));
  11.942 +            this.mNotifyList.add(this.getAndroidCalendarUri());
  11.943 +            Result = true;
  11.944 +        } catch (RemoteException e) {
  11.945 +            e.printStackTrace();
  11.946 +        }
  11.947 +        Log.d(TAG, "Android Calendars deleted: " + Integer.toString(CountDeleted));
  11.948 +
  11.949 +        return Result;
  11.950 +    }
  11.951 +
  11.952 +    /**
  11.953 +     * updates the android calendar
  11.954 +     *
  11.955 +     * @param calendarUri the uri of the androidCalendar
  11.956 +     * @param target      must be from android.provider.CalendarContract.Calendars
  11.957 +     * @param value       the new value for the target
  11.958 +     * @throws RemoteException
  11.959 +     */
  11.960 +    private void updateAndroidCalendar(Uri calendarUri, String target, int value) throws RemoteException {
  11.961 +        ContentValues mUpdateValues = new ContentValues();
  11.962 +        mUpdateValues.put(target, value);
  11.963 +
  11.964 +        mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null);
  11.965 +    }
  11.966 +
  11.967 +    /**
  11.968 +     * updates the android calendar
  11.969 +     *
  11.970 +     * @param calendarUri the uri of the androidCalendar
  11.971 +     * @param target      must be from android.provider.CalendarContract.Calendars
  11.972 +     * @param value       the new value for the target
  11.973 +     * @throws RemoteException
  11.974 +     */
  11.975 +    private void updateAndroidCalendar(Uri calendarUri, String target, String value) throws RemoteException {
  11.976 +        ContentValues mUpdateValues = new ContentValues();
  11.977 +        mUpdateValues.put(target, value);
  11.978 +
  11.979 +        mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null);
  11.980 +    }
  11.981 +
  11.982 +    /**
  11.983 +     * marks the android event as already handled
  11.984 +     *
  11.985 +     * @return
  11.986 +     * @throws RemoteException
  11.987 +     * @see AndroidEvent#cInternalTag
  11.988 +     * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
  11.989 +     */
  11.990 +    public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException {
  11.991 +        boolean Result = false;
  11.992 +
  11.993 +        ContentValues values = new ContentValues();
  11.994 +        //values.put(Event.INTERNALTAG, 1);
  11.995 +        values.put(Event.INTERNALTAG, mTagCounter);
  11.996 +        //values.put(Event.INTERNALTAG, String.valueOf(mTagCounter));
  11.997 +
  11.998 +        int RowCount = this.mProvider.update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), values, null, null);
  11.999 +        //Log.v(TAG,"event tag nr: " + String.valueOf(mTagCounter));
 11.1000 +        //Log.v(TAG,"Rows updated: " + String.valueOf(RowCount));
 11.1001 +
 11.1002 +        if (RowCount == 1) {
 11.1003 +            Result = true;
 11.1004 +            mTagCounter += 1;
 11.1005 +        } else {
 11.1006 +            Log.v(TAG, "EVENT NOT TAGGED!");
 11.1007 +        }
 11.1008 +
 11.1009 +        return Result;
 11.1010 +    }
 11.1011 +
 11.1012 +    /**
 11.1013 +     * removes the tag of all android events
 11.1014 +     *
 11.1015 +     * @return
 11.1016 +     * @throws RemoteException
 11.1017 +     * @see AndroidEvent#cInternalTag
 11.1018 +     * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
 11.1019 +     */
 11.1020 +    public int untagAndroidEvents() throws RemoteException {
 11.1021 +        int RowCount = 0;
 11.1022 +        int Steps = 100;
 11.1023 +        ContentValues values = new ContentValues();
 11.1024 +        values.put(Event.INTERNALTAG, 0);
 11.1025 +
 11.1026 +        for (int i = 1; i < this.mTagCounter; i = i + Steps) {
 11.1027 +            String mSelectionClause = "(CAST(" + Event.INTERNALTAG + " AS INT) >= ?) AND (CAST(" + Event.INTERNALTAG + " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)";
 11.1028 +            String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + Steps), Long.toString(ContentUris
 11.1029 +                    .parseId(this.getAndroidCalendarUri()))};
 11.1030 +            RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs);
 11.1031 +        }
 11.1032 +        /*String mSelectionClause = "(" + Event.INTERNALTAG +  " > ?) AND (" + Events.CALENDAR_ID + " = ?)";
 11.1033 +        String[] mSelectionArgs = {"0", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))};
 11.1034  		RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs);*/
 11.1035 -		
 11.1036 -		//Log.d(TAG, "Rows reseted: " + RowCount.toString());
 11.1037 -		return RowCount;
 11.1038 -	}
 11.1039 -	/**
 11.1040 -	 * Events not being tagged are for deletion 
 11.1041 -	 * @return
 11.1042 -	 * @see AndroidEvent#cInternalTag
 11.1043 -	 * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
 11.1044 -	 * @throws RemoteException
 11.1045 -	 */
 11.1046 -	public int deleteUntaggedEvents() throws RemoteException {
 11.1047 -		String mSelectionClause = "(" + Event.INTERNALTAG +  " < ?) AND (" + Events.CALENDAR_ID + " = ?)";
 11.1048 -		String[] mSelectionArgs = {"1", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))};
 11.1049 -		
 11.1050 -		int CountDeleted = this.mProvider.delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), mSelectionClause, mSelectionArgs);	
 11.1051 -		//Log.d(TAG, "Rows deleted: " + CountDeleted.toString());
 11.1052 -		return CountDeleted;
 11.1053 -	}
 11.1054 -	
 11.1055 -	private Uri SyncAdapterCalendar() {
 11.1056 -		return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type);
 11.1057 -	}
 11.1058 -	private Uri SyncAdapter() {
 11.1059 -		return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type);
 11.1060 -	}
 11.1061 -	private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
 11.1062 -	    return uri.buildUpon()
 11.1063 -	        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
 11.1064 -	        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
 11.1065 -	        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
 11.1066 -	}
 11.1067 -	
 11.1068 -	public void setAccount(Account account) {
 11.1069 -		this.mAccount = account;
 11.1070 -	}
 11.1071 -	public void setProvider(ContentProviderClient provider) {
 11.1072 -		this.mProvider = provider;
 11.1073 -	}
 11.1074 -	
 11.1075 -	/**
 11.1076 -	 * general access function to ContentValues
 11.1077 -	 * @param Item the item name from Calendars.*
 11.1078 -	 * @return the value for the item
 11.1079 -	 */
 11.1080 -	private String getContentValueAsString(String Item) {
 11.1081 -		String Result = "";
 11.1082 -		if (this.ContentValues.containsKey(Item))
 11.1083 -			Result = this.ContentValues.getAsString(Item);
 11.1084 -		return Result;
 11.1085 -	}
 11.1086 -	/**
 11.1087 -	 * general access function to ContentValues
 11.1088 -	 * @param Item the item name from Calendars.*
 11.1089 -	 * @return the value for the item
 11.1090 -	 */
 11.1091 -	private int getContentValueAsInt(String Item) {
 11.1092 -		int Result = 0;
 11.1093 -		if (this.ContentValues.containsKey(Item))
 11.1094 -			Result = this.ContentValues.getAsInteger(Item);
 11.1095 -		return Result;
 11.1096 -	}
 11.1097 -	
 11.1098 -	/**
 11.1099 -	 * general access function to ContentValues
 11.1100 -	 * @param Item the item name from Calendars.*
 11.1101 -	 * @param Value the value for the item
 11.1102 -	 * @return success of this function
 11.1103 -	 */
 11.1104 -	private boolean setContentValueAsString(String Item, String Value) {
 11.1105 -		boolean Result = false;
 11.1106 -		
 11.1107 -		if (this.ContentValues.containsKey(Item))
 11.1108 -			this.ContentValues.remove(Item);
 11.1109 -		this.ContentValues.put(Item, Value);
 11.1110 -		
 11.1111 -		return Result;
 11.1112 -	}
 11.1113 -	
 11.1114 -	/**
 11.1115 -	 * general access function to ContentValues
 11.1116 -	 * @param Item the item name from Calendars.*
 11.1117 -	 * @param Value the value for the item
 11.1118 -	 * @return success of this function
 11.1119 -	 */
 11.1120 -	private boolean setContentValueAsInt(String Item, int Value) {
 11.1121 -		boolean Result = false;
 11.1122 -		
 11.1123 -		if (this.ContentValues.containsKey(Item))
 11.1124 -			this.ContentValues.remove(Item);
 11.1125 -		this.ContentValues.put(Item, Value);
 11.1126 -		
 11.1127 -		return Result;
 11.1128 -	}
 11.1129 -	
 11.1130 -	public ArrayList<Uri> getNotifyList() {
 11.1131 -		return this.mNotifyList;
 11.1132 -	}
 11.1133  
 11.1134 -	public ArrayList<CalendarEvent> getCalendarEvents() {
 11.1135 -		return this.mCalendarEvents;
 11.1136 -	}
 11.1137 -	
 11.1138 -	public boolean readCalendarEvents(CaldavFacade facade) {
 11.1139 -		boolean Result = false;
 11.1140 -		
 11.1141 -		try {
 11.1142 -			this.mCalendarEvents = facade.getCalendarEvents(this);
 11.1143 -			Result = true;
 11.1144 -		} catch (ClientProtocolException e) {
 11.1145 -			e.printStackTrace();
 11.1146 -			Result = false;
 11.1147 -		} catch (URISyntaxException e) {
 11.1148 -			e.printStackTrace();
 11.1149 -			Result = false;
 11.1150 -		} catch (IOException e) {
 11.1151 -			e.printStackTrace();
 11.1152 -			Result = false;
 11.1153 -		} catch (ParserConfigurationException e) {
 11.1154 -			e.printStackTrace();
 11.1155 -			Result = false;
 11.1156 -		} catch (SAXException e) {
 11.1157 -			e.printStackTrace();
 11.1158 -			Result = false;
 11.1159 -		}
 11.1160 -		
 11.1161 -		return Result;
 11.1162 -	}
 11.1163 -	
 11.1164 +        //Log.d(TAG, "Rows reseted: " + RowCount.toString());
 11.1165 +        return RowCount;
 11.1166 +    }
 11.1167 +
 11.1168 +    /**
 11.1169 +     * Events not being tagged are for deletion
 11.1170 +     *
 11.1171 +     * @return
 11.1172 +     * @throws RemoteException
 11.1173 +     * @see AndroidEvent#cInternalTag
 11.1174 +     * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
 11.1175 +     */
 11.1176 +    public int deleteUntaggedEvents() throws RemoteException {
 11.1177 +        String mSelectionClause = "(" + Event.INTERNALTAG + " < ?) AND (" + Events.CALENDAR_ID + " = ?)";
 11.1178 +        String[] mSelectionArgs = {"1", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))};
 11.1179 +
 11.1180 +        int CountDeleted = this.mProvider.delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), mSelectionClause, mSelectionArgs);
 11.1181 +        //Log.d(TAG, "Rows deleted: " + CountDeleted.toString());
 11.1182 +        return CountDeleted;
 11.1183 +    }
 11.1184 +
 11.1185 +    private Uri SyncAdapterCalendar() {
 11.1186 +        return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type);
 11.1187 +    }
 11.1188 +
 11.1189 +    private Uri SyncAdapter() {
 11.1190 +        return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type);
 11.1191 +    }
 11.1192 +
 11.1193 +    private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
 11.1194 +        return uri.buildUpon()
 11.1195 +                .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true")
 11.1196 +                .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
 11.1197 +                .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
 11.1198 +    }
 11.1199 +
 11.1200 +    public void setAccount(Account account) {
 11.1201 +        this.mAccount = account;
 11.1202 +    }
 11.1203 +
 11.1204 +    public void setProvider(ContentProviderClient provider) {
 11.1205 +        this.mProvider = provider;
 11.1206 +    }
 11.1207 +
 11.1208 +    /**
 11.1209 +     * general access function to ContentValues
 11.1210 +     *
 11.1211 +     * @param Item the item name from Calendars.*
 11.1212 +     * @return the value for the item
 11.1213 +     */
 11.1214 +    private String getContentValueAsString(String Item) {
 11.1215 +        String Result = "";
 11.1216 +        if (this.ContentValues.containsKey(Item))
 11.1217 +            Result = this.ContentValues.getAsString(Item);
 11.1218 +        return Result;
 11.1219 +    }
 11.1220 +
 11.1221 +    /**
 11.1222 +     * general access function to ContentValues
 11.1223 +     *
 11.1224 +     * @param Item the item name from Calendars.*
 11.1225 +     * @return the value for the item
 11.1226 +     */
 11.1227 +    private int getContentValueAsInt(String Item) {
 11.1228 +        int Result = 0;
 11.1229 +        if (this.ContentValues.containsKey(Item))
 11.1230 +            Result = this.ContentValues.getAsInteger(Item);
 11.1231 +        return Result;
 11.1232 +    }
 11.1233 +
 11.1234 +    /**
 11.1235 +     * general access function to ContentValues
 11.1236 +     *
 11.1237 +     * @param Item  the item name from Calendars.*
 11.1238 +     * @param Value the value for the item
 11.1239 +     * @return success of this function
 11.1240 +     */
 11.1241 +    private boolean setContentValueAsString(String Item, String Value) {
 11.1242 +        boolean Result = false;
 11.1243 +
 11.1244 +        if (this.ContentValues.containsKey(Item))
 11.1245 +            this.ContentValues.remove(Item);
 11.1246 +        this.ContentValues.put(Item, Value);
 11.1247 +
 11.1248 +        return Result;
 11.1249 +    }
 11.1250 +
 11.1251 +    /**
 11.1252 +     * general access function to ContentValues
 11.1253 +     *
 11.1254 +     * @param Item  the item name from Calendars.*
 11.1255 +     * @param Value the value for the item
 11.1256 +     * @return success of this function
 11.1257 +     */
 11.1258 +    private boolean setContentValueAsInt(String Item, int Value) {
 11.1259 +        boolean Result = false;
 11.1260 +
 11.1261 +        if (this.ContentValues.containsKey(Item))
 11.1262 +            this.ContentValues.remove(Item);
 11.1263 +        this.ContentValues.put(Item, Value);
 11.1264 +
 11.1265 +        return Result;
 11.1266 +    }
 11.1267 +
 11.1268 +    public ArrayList<Uri> getNotifyList() {
 11.1269 +        return this.mNotifyList;
 11.1270 +    }
 11.1271 +
 11.1272 +    public ArrayList<CalendarEvent> getCalendarEvents() {
 11.1273 +        return this.mCalendarEvents;
 11.1274 +    }
 11.1275 +
 11.1276 +    public boolean readCalendarEvents(CaldavFacade facade) {
 11.1277 +        boolean Result = false;
 11.1278 +
 11.1279 +        try {
 11.1280 +            this.mCalendarEvents = facade.getCalendarEvents(this);
 11.1281 +            Result = true;
 11.1282 +        } catch (ClientProtocolException e) {
 11.1283 +            e.printStackTrace();
 11.1284 +            Result = false;
 11.1285 +        } catch (URISyntaxException e) {
 11.1286 +            e.printStackTrace();
 11.1287 +            Result = false;
 11.1288 +        } catch (IOException e) {
 11.1289 +            e.printStackTrace();
 11.1290 +            Result = false;
 11.1291 +        } catch (ParserConfigurationException e) {
 11.1292 +            e.printStackTrace();
 11.1293 +            Result = false;
 11.1294 +        } catch (SAXException e) {
 11.1295 +            e.printStackTrace();
 11.1296 +            Result = false;
 11.1297 +        }
 11.1298 +
 11.1299 +        return Result;
 11.1300 +    }
 11.1301 +
 11.1302  }
    12.1 --- a/src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java	Tue Feb 10 21:55:00 2015 +0100
    12.2 +++ b/src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java	Tue Feb 10 22:40:00 2015 +0100
    12.3 @@ -26,6 +26,8 @@
    12.4  
    12.5  public class HttpReport extends HttpEntityEnclosingRequestBase implements HttpUriRequest {
    12.6  
    12.7 +	public static final String USER_DATA_TRUST_ALL_KEY = "USER_DATA_TRUSTALL_KEY";
    12.8 +
    12.9  	@Override
   12.10  	public String getMethod() {
   12.11  		return "REPORT";
    13.1 --- a/src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java	Tue Feb 10 21:55:00 2015 +0100
    13.2 +++ b/src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java	Tue Feb 10 22:40:00 2015 +0100
    13.3 @@ -1,6 +1,6 @@
    13.4  /**
    13.5   * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger
    13.6 - * 
    13.7 + *
    13.8   * This file is part of Andoid Caldav Sync Adapter Free.
    13.9   *
   13.10   * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
   13.11 @@ -16,36 +16,11 @@
   13.12   * You should have received a copy of the GNU General Public License
   13.13   * along with Andoid Caldav Sync Adapter Free.  
   13.14   * If not, see <http://www.gnu.org/licenses/>.
   13.15 - * 
   13.16 + *
   13.17   */
   13.18  
   13.19  package org.gege.caldavsyncadapter.syncadapter;
   13.20  
   13.21 -import java.io.IOException;
   13.22 -import java.net.URI;
   13.23 -//import java.net.MalformedURLException;
   13.24 -import java.net.URISyntaxException;
   13.25 -import java.util.ArrayList;
   13.26 -//import java.security.GeneralSecurityException;
   13.27 -
   13.28 -import javax.xml.parsers.ParserConfigurationException;
   13.29 -
   13.30 -import net.fortuna.ical4j.data.ParserException;
   13.31 -
   13.32 -import org.apache.http.ParseException;
   13.33 -import org.apache.http.client.ClientProtocolException;
   13.34 -import org.gege.caldavsyncadapter.Event;
   13.35 -import org.gege.caldavsyncadapter.android.entities.AndroidEvent;
   13.36 -import org.gege.caldavsyncadapter.authenticator.AuthenticatorActivity;
   13.37 -import org.gege.caldavsyncadapter.caldav.CaldavFacade;
   13.38 -import org.gege.caldavsyncadapter.caldav.CaldavProtocolException;
   13.39 -import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
   13.40 -import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
   13.41 -import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
   13.42 -import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource;
   13.43 -import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper;
   13.44 -import org.xml.sax.SAXException;
   13.45 -
   13.46  import android.accounts.Account;
   13.47  import android.accounts.AccountManager;
   13.48  import android.content.AbstractThreadedSyncAdapter;
   13.49 @@ -66,18 +41,45 @@
   13.50  import android.provider.CalendarContract.Reminders;
   13.51  import android.util.Log;
   13.52  
   13.53 +import net.fortuna.ical4j.data.ParserException;
   13.54 +
   13.55 +import org.apache.http.ParseException;
   13.56 +import org.apache.http.client.ClientProtocolException;
   13.57 +import org.gege.caldavsyncadapter.Constants;
   13.58 +import org.gege.caldavsyncadapter.Event;
   13.59 +import org.gege.caldavsyncadapter.android.entities.AndroidEvent;
   13.60 +import org.gege.caldavsyncadapter.authenticator.AuthenticatorActivity;
   13.61 +import org.gege.caldavsyncadapter.caldav.CaldavFacade;
   13.62 +import org.gege.caldavsyncadapter.caldav.CaldavProtocolException;
   13.63 +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
   13.64 +import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
   13.65 +import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
   13.66 +import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource;
   13.67 +import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper;
   13.68 +import org.xml.sax.SAXException;
   13.69 +
   13.70 +import java.io.IOException;
   13.71 +import java.net.URI;
   13.72 +import java.net.URISyntaxException;
   13.73 +import java.util.ArrayList;
   13.74 +
   13.75 +import javax.xml.parsers.ParserConfigurationException;
   13.76 +
   13.77 +//import java.net.MalformedURLException;
   13.78 +//import java.security.GeneralSecurityException;
   13.79 +
   13.80  public class SyncAdapter extends AbstractThreadedSyncAdapter {
   13.81  
   13.82 -	private static final String TAG = "SyncAdapter";
   13.83 -	private AccountManager mAccountManager;
   13.84 -	private String mVersion = "";
   13.85 -	private int mCountPerformSync = 0;
   13.86 -	private int mCountSyncCanceled = 0;
   13.87 -	private int mCountProviderFailed = 0;
   13.88 -	
   13.89 -	private int mCountProviderFailedMax = 3;
   13.90 +    private static final String TAG = "SyncAdapter";
   13.91 +    private AccountManager mAccountManager;
   13.92 +    private String mVersion = "";
   13.93 +    private int mCountPerformSync = 0;
   13.94 +    private int mCountSyncCanceled = 0;
   13.95 +    private int mCountProviderFailed = 0;
   13.96 +
   13.97 +    private int mCountProviderFailedMax = 3;
   13.98  //	private Context mContext;
   13.99 -	
  13.100 +
  13.101  	
  13.102  /*	private static final String[] CALENDAR_PROJECTION = new String[] {
  13.103  	    Calendars._ID,                           // 0
  13.104 @@ -102,81 +104,87 @@
  13.105  		Events.CALENDAR_ID
  13.106  	};
  13.107  */
  13.108 -	
  13.109 -	// ignore same CTag
  13.110 -	//private static final boolean FORCE_SYNCHRONIZE = false;
  13.111 -	// drop all calendar before synchro
  13.112 -	//private static final boolean DROP_CALENDAR_EVENTS = false;
  13.113 -	
  13.114 -	public SyncAdapter(Context context, boolean autoInitialize) {
  13.115 -		super(context, autoInitialize);
  13.116 -		//android.os.Debug.waitForDebugger();
  13.117 -		mAccountManager = AccountManager.get(context);
  13.118 -		try {
  13.119 -			mVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
  13.120 -		} catch (NameNotFoundException e) {
  13.121 -			e.printStackTrace();
  13.122 -		}
  13.123 +
  13.124 +    // ignore same CTag
  13.125 +    //private static final boolean FORCE_SYNCHRONIZE = false;
  13.126 +    // drop all calendar before synchro
  13.127 +    //private static final boolean DROP_CALENDAR_EVENTS = false;
  13.128 +
  13.129 +    public SyncAdapter(Context context, boolean autoInitialize) {
  13.130 +        super(context, autoInitialize);
  13.131 +        //android.os.Debug.waitForDebugger();
  13.132 +        mAccountManager = AccountManager.get(context);
  13.133 +        try {
  13.134 +            mVersion = context.getPackageManager()
  13.135 +                    .getPackageInfo(context.getPackageName(), 0).versionName;
  13.136 +        } catch (NameNotFoundException e) {
  13.137 +            e.printStackTrace();
  13.138 +        }
  13.139  //		mContext = context;
  13.140 -	}
  13.141 +    }
  13.142  
  13.143 -	@Override
  13.144 -	public void onPerformSync(Account account, Bundle extras, String authority,
  13.145 -			ContentProviderClient provider, SyncResult syncResult) {
  13.146 -		boolean bolError = false;
  13.147 -		
  13.148 -		String url = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_URL_KEY);
  13.149 -		this.mCountPerformSync += 1;
  13.150 -		Log.v(TAG, "onPerformSync() count:" + String.valueOf(this.mCountPerformSync) + " on " + account.name + " with URL " + url);
  13.151 +    @Override
  13.152 +    public void onPerformSync(Account account, Bundle extras, String authority,
  13.153 +                              ContentProviderClient provider, SyncResult syncResult) {
  13.154 +        boolean bolError = false;
  13.155  
  13.156 -		CalendarList serverCalList;
  13.157 -		
  13.158 -		CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url);
  13.159 -		androidCalList.readCalendarFromClient();
  13.160 -		ArrayList<Uri> notifyList = new ArrayList<Uri>();
  13.161 +        String url = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_URL_KEY);
  13.162 +        String trust = mAccountManager.getUserData(account, Constants.USER_DATA_TRUST_ALL_KEY);
  13.163 +        this.mCountPerformSync += 1;
  13.164 +        Log.v(TAG, "onPerformSync() count:" + String.valueOf(this.mCountPerformSync) + " on " + account.name + " with URL " + url);
  13.165  
  13.166 -		try {
  13.167 - 			String Username = "";
  13.168 -			String UserDataVersion = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_VERSION);
  13.169 -			if (UserDataVersion == null) {
  13.170 -				Username = account.name;
  13.171 -			} else {
  13.172 -				Username = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_USERNAME);
  13.173 -			}
  13.174 +        CalendarList serverCalList;
  13.175  
  13.176 -			CaldavFacade facade = new CaldavFacade(Username, mAccountManager.getPassword(account), url);
  13.177 -			facade.setAccount(account);
  13.178 -			facade.setProvider(provider);
  13.179 -			facade.setVersion(mVersion);
  13.180 -			serverCalList = facade.getCalendarList(this.getContext());
  13.181 -			//String davProperties = facade.getLastDav();
  13.182 -			Log.i(TAG, String.valueOf(androidCalList.getCalendarList().size()) + " calendars found at android");
  13.183 -			
  13.184 -			for (DavCalendar serverCalendar : serverCalList.getCalendarList()) {
  13.185 -				Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar.getURI());
  13.186 +        CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url);
  13.187 +        androidCalList.readCalendarFromClient();
  13.188 +        ArrayList<Uri> notifyList = new ArrayList<Uri>();
  13.189  
  13.190 -				Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this.getContext());
  13.191 +        try {
  13.192 +            String Username = "";
  13.193 +            String UserDataVersion = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_VERSION);
  13.194 +            if (UserDataVersion == null) {
  13.195 +                Username = account.name;
  13.196 +            } else {
  13.197 +                Username = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_USERNAME);
  13.198 +            }
  13.199  
  13.200 -				// check if the adapter was able to get an existing calendar or create a new one
  13.201 -				if (androidCalendarUri != null) {
  13.202 -					// the provider seems to work correct, reset the counter
  13.203 -					mCountProviderFailed = 0;
  13.204 -					DavCalendar androidCalendar = androidCalList.getCalendarByAndroidUri(androidCalendarUri);
  13.205 -					
  13.206 -					//if ((FORCE_SYNCHRONIZE) || (androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) {
  13.207 -					if ((androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) {
  13.208 -							Log.d(TAG, "CTag has changed, something to synchronise");
  13.209 -							if (serverCalendar.readCalendarEvents(facade)) {
  13.210 -								this.synchroniseEvents(androidCalendar, serverCalendar, syncResult.stats, notifyList);
  13.211 +            CaldavFacade facade = new CaldavFacade(Username, mAccountManager.getPassword(account), url, trust);
  13.212 +            facade.setAccount(account);
  13.213 +            facade.setProvider(provider);
  13.214 +            facade.setVersion(mVersion);
  13.215 +            serverCalList = facade.getCalendarList(this.getContext());
  13.216 +            //String davProperties = facade.getLastDav();
  13.217 +            Log.i(TAG, String.valueOf(androidCalList.getCalendarList()
  13.218 +                    .size()) + " calendars found at android");
  13.219  
  13.220 -								Log.d(TAG, "Updating stored CTag");
  13.221 -								//serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag());
  13.222 -								androidCalendar.setCTag(serverCalendar.getcTag(), true);
  13.223 -							} else {
  13.224 -								Log.d(TAG, "unable to read events from server calendar");
  13.225 -							}
  13.226 -					} else {
  13.227 -						Log.d(TAG, "CTag has not changed, nothing to do");
  13.228 +            for (DavCalendar serverCalendar : serverCalList.getCalendarList()) {
  13.229 +                Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar
  13.230 +                        .getURI());
  13.231 +
  13.232 +                Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this
  13.233 +                        .getContext());
  13.234 +
  13.235 +                // check if the adapter was able to get an existing calendar or create a new one
  13.236 +                if (androidCalendarUri != null) {
  13.237 +                    // the provider seems to work correct, reset the counter
  13.238 +                    mCountProviderFailed = 0;
  13.239 +                    DavCalendar androidCalendar = androidCalList.getCalendarByAndroidUri(androidCalendarUri);
  13.240 +
  13.241 +                    //if ((FORCE_SYNCHRONIZE) || (androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) {
  13.242 +                    if ((androidCalendar.getcTag() == null) || (!androidCalendar.getcTag()
  13.243 +                            .equals(serverCalendar.getcTag()))) {
  13.244 +                        Log.d(TAG, "CTag has changed, something to synchronise");
  13.245 +                        if (serverCalendar.readCalendarEvents(facade)) {
  13.246 +                            this.synchroniseEvents(androidCalendar, serverCalendar, syncResult.stats, notifyList);
  13.247 +
  13.248 +                            Log.d(TAG, "Updating stored CTag");
  13.249 +                            //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag());
  13.250 +                            androidCalendar.setCTag(serverCalendar.getcTag(), true);
  13.251 +                        } else {
  13.252 +                            Log.d(TAG, "unable to read events from server calendar");
  13.253 +                        }
  13.254 +                    } else {
  13.255 +                        Log.d(TAG, "CTag has not changed, nothing to do");
  13.256  	
  13.257  						/* this is unnecessary. "SkippedEntries" are:
  13.258  						 * Counter for tracking how many entries, either from the server or the local store, 
  13.259 @@ -196,52 +204,53 @@
  13.260  				        int count = countCursor.getInt(0);
  13.261  				        syncResult.stats.numSkippedEntries += count;
  13.262  				        countCursor.close();*/
  13.263 -						
  13.264 -					}
  13.265 -					
  13.266 -					this.checkDirtyAndroidEvents(provider, account, androidCalendarUri, facade, serverCalendar.getURI(), syncResult.stats, notifyList);
  13.267 -				} else {
  13.268 -					// this happens if the data provider failes to get an existing or create a new calendar
  13.269 -					mCountProviderFailed += 1;
  13.270 -					Log.e(TAG, "failed to get an existing or create a new calendar");
  13.271 -					syncResult.stats.numIoExceptions += 1;
  13.272 -					if (mCountProviderFailed >= mCountProviderFailedMax) {
  13.273 -						// see issue #96
  13.274 -						NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "are you using CyanogenMod in Incognito Mode?");
  13.275 -					} else {
  13.276 -						NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "the provider failed to get an existing or create a new calendar");
  13.277 -					}
  13.278 -					bolError = true;
  13.279 -				}
  13.280 -			}
  13.281 -			
  13.282 -			if (!bolError) {
  13.283 -				// check whether a calendar is not synced -> delete it at android
  13.284 -				androidCalList.deleteCalendarOnClientSideOnly(this.getContext());
  13.285 -			}
  13.286 -			
  13.287 -			// notify the ContentResolver
  13.288 -			for (Uri uri : androidCalList.getNotifyList()) {
  13.289 -				this.getContext().getContentResolver().notifyChange(uri, null);
  13.290 -			}
  13.291 -			for (Uri uri : serverCalList.getNotifyList()) {
  13.292 -				this.getContext().getContentResolver().notifyChange(uri, null);
  13.293 -			}
  13.294 -			for (Uri uri : notifyList) {
  13.295 -				this.getContext().getContentResolver().notifyChange(uri, null);
  13.296 -			}
  13.297 -			
  13.298 -			//Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString());
  13.299 -			//Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString());
  13.300 -			Log.i(TAG,"Entries:                       " + String.valueOf(syncResult.stats.numEntries));
  13.301 -			Log.i(TAG,"Rows inserted:                 " + String.valueOf(syncResult.stats.numInserts));
  13.302 -			Log.i(TAG,"Rows updated:                  " + String.valueOf(syncResult.stats.numUpdates));
  13.303 -			Log.i(TAG,"Rows deleted:                  " + String.valueOf(syncResult.stats.numDeletes));
  13.304 -			Log.i(TAG,"Rows skipped:                  " + String.valueOf(syncResult.stats.numSkippedEntries));
  13.305 -			Log.i(TAG,"Io Exceptions:                 " + String.valueOf(syncResult.stats.numIoExceptions));
  13.306 -			Log.i(TAG,"Parse Exceptions:              " + String.valueOf(syncResult.stats.numParseExceptions));
  13.307 -			Log.i(TAG,"Auth Exceptions:               " + String.valueOf(syncResult.stats.numAuthExceptions));
  13.308 -			Log.i(TAG,"Conflict Detected Exceptions:  " + String.valueOf(syncResult.stats.numConflictDetectedExceptions));
  13.309 +
  13.310 +                    }
  13.311 +
  13.312 +                    this.checkDirtyAndroidEvents(provider, account, androidCalendarUri, facade, serverCalendar
  13.313 +                            .getURI(), syncResult.stats, notifyList);
  13.314 +                } else {
  13.315 +                    // this happens if the data provider failes to get an existing or create a new calendar
  13.316 +                    mCountProviderFailed += 1;
  13.317 +                    Log.e(TAG, "failed to get an existing or create a new calendar");
  13.318 +                    syncResult.stats.numIoExceptions += 1;
  13.319 +                    if (mCountProviderFailed >= mCountProviderFailedMax) {
  13.320 +                        // see issue #96
  13.321 +                        NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "are you using CyanogenMod in Incognito Mode?");
  13.322 +                    } else {
  13.323 +                        NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "the provider failed to get an existing or create a new calendar");
  13.324 +                    }
  13.325 +                    bolError = true;
  13.326 +                }
  13.327 +            }
  13.328 +
  13.329 +            if (!bolError) {
  13.330 +                // check whether a calendar is not synced -> delete it at android
  13.331 +                androidCalList.deleteCalendarOnClientSideOnly(this.getContext());
  13.332 +            }
  13.333 +
  13.334 +            // notify the ContentResolver
  13.335 +            for (Uri uri : androidCalList.getNotifyList()) {
  13.336 +                this.getContext().getContentResolver().notifyChange(uri, null);
  13.337 +            }
  13.338 +            for (Uri uri : serverCalList.getNotifyList()) {
  13.339 +                this.getContext().getContentResolver().notifyChange(uri, null);
  13.340 +            }
  13.341 +            for (Uri uri : notifyList) {
  13.342 +                this.getContext().getContentResolver().notifyChange(uri, null);
  13.343 +            }
  13.344 +
  13.345 +            //Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString());
  13.346 +            //Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString());
  13.347 +            Log.i(TAG, "Entries:                       " + String.valueOf(syncResult.stats.numEntries));
  13.348 +            Log.i(TAG, "Rows inserted:                 " + String.valueOf(syncResult.stats.numInserts));
  13.349 +            Log.i(TAG, "Rows updated:                  " + String.valueOf(syncResult.stats.numUpdates));
  13.350 +            Log.i(TAG, "Rows deleted:                  " + String.valueOf(syncResult.stats.numDeletes));
  13.351 +            Log.i(TAG, "Rows skipped:                  " + String.valueOf(syncResult.stats.numSkippedEntries));
  13.352 +            Log.i(TAG, "Io Exceptions:                 " + String.valueOf(syncResult.stats.numIoExceptions));
  13.353 +            Log.i(TAG, "Parse Exceptions:              " + String.valueOf(syncResult.stats.numParseExceptions));
  13.354 +            Log.i(TAG, "Auth Exceptions:               " + String.valueOf(syncResult.stats.numAuthExceptions));
  13.355 +            Log.i(TAG, "Conflict Detected Exceptions:  " + String.valueOf(syncResult.stats.numConflictDetectedExceptions));
  13.356  
  13.357  		/*} catch (final AuthenticatorException e) {
  13.358              syncResult.stats.numParseExceptions++;
  13.359 @@ -260,119 +269,125 @@
  13.360          } catch (final ParseException e) {
  13.361              syncResult.stats.numParseExceptions++;
  13.362              Log.e(TAG, "ParseException", e);
  13.363 -            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (parsing)", e.getMessage());
  13.364 +            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (parsing)", e
  13.365 +                    .getMessage());
  13.366              //NotificationsHelper.getCurrentSyncLog().addException(e);
  13.367          /*} catch (final JSONException e) {
  13.368              syncResult.stats.numParseExceptions++;
  13.369              Log.e(TAG, "JSONException", e);*/
  13.370 -		} catch (Exception e) {
  13.371 -			Log.e(TAG, "Updating calendar exception " + e.getClass().getName(), e);
  13.372 +        } catch (Exception e) {
  13.373 +            Log.e(TAG, "Updating calendar exception " + e.getClass().getName(), e);
  13.374              syncResult.stats.numParseExceptions++;
  13.375 -            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (general)", e.getMessage());
  13.376 +            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (general)", e
  13.377 +                    .getMessage());
  13.378              //NotificationsHelper.getCurrentSyncLog().addException(e);
  13.379 -			//throw new RuntimeException(e);
  13.380 -		}
  13.381 -	}
  13.382 +            //throw new RuntimeException(e);
  13.383 +        }
  13.384 +    }
  13.385  
  13.386 -	public void onSyncCanceled () {
  13.387 -		//TODO: implement SyncCanceled
  13.388 -		this.mCountSyncCanceled += 1;
  13.389 -		Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled));
  13.390 -	}
  13.391 +    public void onSyncCanceled() {
  13.392 +        //TODO: implement SyncCanceled
  13.393 +        this.mCountSyncCanceled += 1;
  13.394 +        Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled));
  13.395 +    }
  13.396  
  13.397 -	
  13.398 -	/**
  13.399 -	 * both calender event and android event have been found.
  13.400 -	 * server wins always at the moment.
  13.401 -	 * @param androidCalendar
  13.402 -	 * @param serverCalendar
  13.403 -	 * @param stats
  13.404 -	 * @param notifyList
  13.405 -	 * @throws ClientProtocolException
  13.406 -	 * @throws URISyntaxException
  13.407 -	 * @throws IOException
  13.408 -	 * @throws ParserConfigurationException
  13.409 -	 * @throws SAXException
  13.410 -	 * @throws RemoteException
  13.411 -	 * @throws CaldavProtocolException
  13.412 -	 * @throws ParserException
  13.413 -	 * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent)
  13.414 -	 * @see SyncAdapter#tagAndroidEvent(ContentProviderClient, Account, AndroidEvent)
  13.415 -	 * @see SyncAdapter#untagAndroidEvents(ContentProviderClient, Account, Uri)
  13.416 -	 * @see SyncAdapter#deleteUntaggedEvents(ContentProviderClient, Account, Uri)
  13.417 -	 */
  13.418 -	private void synchroniseEvents(
  13.419 -				DavCalendar androidCalendar, 
  13.420 -				DavCalendar serverCalendar, 
  13.421 -				SyncStats stats, 
  13.422 -				ArrayList<Uri> notifyList
  13.423 -			) throws ClientProtocolException, URISyntaxException, IOException, ParserConfigurationException, SAXException, RemoteException, CaldavProtocolException, ParserException {
  13.424 +
  13.425 +    /**
  13.426 +     * both calender event and android event have been found.
  13.427 +     * server wins always at the moment.
  13.428 +     *
  13.429 +     * @param androidCalendar
  13.430 +     * @param serverCalendar
  13.431 +     * @param stats
  13.432 +     * @param notifyList
  13.433 +     * @throws ClientProtocolException
  13.434 +     * @throws URISyntaxException
  13.435 +     * @throws IOException
  13.436 +     * @throws ParserConfigurationException
  13.437 +     * @throws SAXException
  13.438 +     * @throws RemoteException
  13.439 +     * @throws CaldavProtocolException
  13.440 +     * @throws ParserException
  13.441 +     * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent)
  13.442 +     * @see SyncAdapter#tagAndroidEvent(ContentProviderClient, Account, AndroidEvent)
  13.443 +     * @see SyncAdapter#untagAndroidEvents(ContentProviderClient, Account, Uri)
  13.444 +     * @see SyncAdapter#deleteUntaggedEvents(ContentProviderClient, Account, Uri)
  13.445 +     */
  13.446 +    private void synchroniseEvents(
  13.447 +            DavCalendar androidCalendar,
  13.448 +            DavCalendar serverCalendar,
  13.449 +            SyncStats stats,
  13.450 +            ArrayList<Uri> notifyList
  13.451 +    ) throws ClientProtocolException, URISyntaxException, IOException, ParserConfigurationException, SAXException, RemoteException, CaldavProtocolException, ParserException {
  13.452  		
  13.453  		/*if (DROP_CALENDAR_EVENTS) {
  13.454  			dropAllEvents(account, provider, androidCalendar.getAndroidCalendarUri());
  13.455  		}*/
  13.456 -		
  13.457 -		int rowInsert = 0;
  13.458 -		int rowUpdate = 0;
  13.459 -		int rowTag = 0;
  13.460 -		int rowDelete = 0;
  13.461 -		int rowUntag = 0;
  13.462 -		int rowSkip = 0;
  13.463 -		
  13.464 -		for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) {
  13.465 -			try {
  13.466 -				AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
  13.467 -				
  13.468 -				Log.i(TAG, "Event " + calendarEvent.getUri().toString()+ " androidUri="+androidEvent);
  13.469 -				
  13.470 -				if (androidEvent == null) {
  13.471 +
  13.472 +        int rowInsert = 0;
  13.473 +        int rowUpdate = 0;
  13.474 +        int rowTag = 0;
  13.475 +        int rowDelete = 0;
  13.476 +        int rowUntag = 0;
  13.477 +        int rowSkip = 0;
  13.478 +
  13.479 +        for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) {
  13.480 +            try {
  13.481 +                AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
  13.482 +
  13.483 +                Log.i(TAG, "Event " + calendarEvent.getUri()
  13.484 +                        .toString() + " androidUri=" + androidEvent);
  13.485 +
  13.486 +                if (androidEvent == null) {
  13.487  					/* new android event */
  13.488 -					if (calendarEvent.createAndroidEvent(androidCalendar)) {
  13.489 -						rowInsert += 1;
  13.490 -						androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
  13.491 -						notifyList.add(androidEvent.getUri());
  13.492 -					} else {
  13.493 -						rowSkip += 1;
  13.494 -					}
  13.495 -				} else {
  13.496 +                    if (calendarEvent.createAndroidEvent(androidCalendar)) {
  13.497 +                        rowInsert += 1;
  13.498 +                        androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
  13.499 +                        notifyList.add(androidEvent.getUri());
  13.500 +                    } else {
  13.501 +                        rowSkip += 1;
  13.502 +                    }
  13.503 +                } else {
  13.504  					/* the android exists */
  13.505 -					String androidETag = androidEvent.getETag();
  13.506 -					if (androidETag == null)
  13.507 -						androidETag = "";
  13.508 -					Log.d(TAG, "Event compare: " + androidETag + " <> " + calendarEvent.getETag().toString());
  13.509 -					if ((androidEvent.getETag() == null) || (!androidETag.equals(calendarEvent.getETag()))) {
  13.510 +                    String androidETag = androidEvent.getETag();
  13.511 +                    if (androidETag == null)
  13.512 +                        androidETag = "";
  13.513 +                    Log.d(TAG, "Event compare: " + androidETag + " <> " + calendarEvent.getETag()
  13.514 +                            .toString());
  13.515 +                    if ((androidEvent.getETag() == null) || (!androidETag.equals(calendarEvent.getETag()))) {
  13.516  						/* the android event is getting updated */
  13.517 -						if (calendarEvent.updateAndroidEvent(androidEvent)) {
  13.518 -							rowUpdate += 1;
  13.519 -							notifyList.add(androidEvent.getUri());
  13.520 -						} else {
  13.521 -							rowSkip += 1;
  13.522 -						}
  13.523 -					}
  13.524 -				}
  13.525 -				if (androidEvent != null)
  13.526 -					//if (androidEvent.tagAndroidEvent())
  13.527 -					if (androidCalendar.tagAndroidEvent(androidEvent))
  13.528 -						rowTag += 1;
  13.529 -				
  13.530 -				
  13.531 -			} catch (ParserException ex) {
  13.532 -				Log.e(TAG, "Parser exception", ex);
  13.533 -				stats.numParseExceptions++;
  13.534 +                        if (calendarEvent.updateAndroidEvent(androidEvent)) {
  13.535 +                            rowUpdate += 1;
  13.536 +                            notifyList.add(androidEvent.getUri());
  13.537 +                        } else {
  13.538 +                            rowSkip += 1;
  13.539 +                        }
  13.540 +                    }
  13.541 +                }
  13.542 +                if (androidEvent != null)
  13.543 +                    //if (androidEvent.tagAndroidEvent())
  13.544 +                    if (androidCalendar.tagAndroidEvent(androidEvent))
  13.545 +                        rowTag += 1;
  13.546  
  13.547 -	            NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (parsing)", ex.getMessage());
  13.548 -	            //NotificationsHelper.getCurrentSyncLog().addException(ex);
  13.549 -			} catch (CaldavProtocolException ex) {
  13.550 -				Log.e(TAG, "Caldav exception", ex);
  13.551 -				stats.numParseExceptions++;
  13.552  
  13.553 -	            NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage());
  13.554 -	            //NotificationsHelper.getCurrentSyncLog().addException(ex);
  13.555 -			}
  13.556 -		}
  13.557 -		
  13.558 -		rowDelete = androidCalendar.deleteUntaggedEvents();
  13.559 -		rowUntag = androidCalendar.untagAndroidEvents();
  13.560 +            } catch (ParserException ex) {
  13.561 +                Log.e(TAG, "Parser exception", ex);
  13.562 +                stats.numParseExceptions++;
  13.563 +
  13.564 +                NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (parsing)", ex
  13.565 +                        .getMessage());
  13.566 +                //NotificationsHelper.getCurrentSyncLog().addException(ex);
  13.567 +            } catch (CaldavProtocolException ex) {
  13.568 +                Log.e(TAG, "Caldav exception", ex);
  13.569 +                stats.numParseExceptions++;
  13.570 +
  13.571 +                NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage());
  13.572 +                //NotificationsHelper.getCurrentSyncLog().addException(ex);
  13.573 +            }
  13.574 +        }
  13.575 +
  13.576 +        rowDelete = androidCalendar.deleteUntaggedEvents();
  13.577 +        rowUntag = androidCalendar.untagAndroidEvents();
  13.578  
  13.579  		/*Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString());
  13.580  		Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString());
  13.581 @@ -380,188 +395,192 @@
  13.582  		Log.i(TAG,"Rows updated:  " + String.valueOf(rowUpdate));
  13.583  		Log.i(TAG,"Rows deleted:  " + String.valueOf(rowDelete));
  13.584  		Log.i(TAG,"Rows skipped:  " + String.valueOf(rowSkip));*/
  13.585 -		Log.i(TAG,"Rows tagged:   " + String.valueOf(rowTag));
  13.586 -		Log.i(TAG,"Rows untagged: " + String.valueOf(rowUntag));
  13.587 -		
  13.588 -		stats.numInserts += rowInsert;
  13.589 -		stats.numUpdates += rowUpdate;
  13.590 -		stats.numDeletes += rowDelete;
  13.591 -		stats.numSkippedEntries += rowSkip;
  13.592 -		stats.numEntries += rowInsert + rowUpdate + rowDelete;
  13.593 +        Log.i(TAG, "Rows tagged:   " + String.valueOf(rowTag));
  13.594 +        Log.i(TAG, "Rows untagged: " + String.valueOf(rowUntag));
  13.595  
  13.596 -	}
  13.597 -	
  13.598 -	/**
  13.599 -	 * checks the android events for the dirty flag.
  13.600 -	 * the flag is set by android when the event has been changed. 
  13.601 -	 * the dirty flag is removed when an android event has been updated from calendar event
  13.602 -	 * @param provider
  13.603 -	 * @param account
  13.604 -	 * @param calendarUri
  13.605 -	 * @param facade
  13.606 -	 * @param caldavCalendarUri
  13.607 -	 * @param stats
  13.608 -	 * @param notifyList
  13.609 -	 * @return count of dirty events
  13.610 -	 */
  13.611 -	private int checkDirtyAndroidEvents(
  13.612 -				ContentProviderClient provider, 
  13.613 -				Account account, 
  13.614 -				Uri calendarUri, 
  13.615 -				CaldavFacade facade, 
  13.616 -				URI caldavCalendarUri, 
  13.617 -				SyncStats stats, 
  13.618 -				ArrayList<Uri> notifyList
  13.619 -			) {
  13.620 -		Cursor curEvent = null;
  13.621 -		Cursor curAttendee = null;
  13.622 -		Cursor curReminder = null;
  13.623 -		Long EventID;
  13.624 -		Long CalendarID;
  13.625 -		AndroidEvent androidEvent = null;
  13.626 -		int rowDirty = 0;
  13.627 -		int rowInsert = 0;
  13.628 -		int rowUpdate = 0;
  13.629 -		int rowDelete = 0;
  13.630 -		
  13.631 -		try {
  13.632 -			CalendarID = ContentUris.parseId(calendarUri);
  13.633 -			String selection = "(" + Events.DIRTY + " = ?) AND (" + Events.CALENDAR_ID + " = ?)";
  13.634 -			String[] selectionArgs = new String[] {"1", CalendarID.toString()}; 
  13.635 -			curEvent = provider.query(Events.CONTENT_URI, null, selection, selectionArgs, null);
  13.636 -			
  13.637 -			while (curEvent.moveToNext()) {
  13.638 -				EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID));
  13.639 -				Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID);
  13.640 -				
  13.641 -				//androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri);
  13.642 -				androidEvent = new AndroidEvent(returnedUri, calendarUri);
  13.643 -				androidEvent.readContentValues(curEvent);
  13.644 -				
  13.645 -				selection = "(" + Attendees.EVENT_ID + " = ?)";
  13.646 -				selectionArgs = new String[] {String.valueOf(EventID)};
  13.647 -				curAttendee = provider.query(Attendees.CONTENT_URI, null, selection, selectionArgs, null);
  13.648 -				selection = "(" + Reminders.EVENT_ID + " = ?)";
  13.649 -				selectionArgs = new String[] {String.valueOf(EventID)};
  13.650 -				curReminder = provider.query(Reminders.CONTENT_URI, null, selection, selectionArgs, null);
  13.651 -				androidEvent.readAttendees(curAttendee);
  13.652 -				androidEvent.readReminder(curReminder);
  13.653 -				curAttendee.close();
  13.654 -				curReminder.close();
  13.655 -				
  13.656 -				String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID);
  13.657 -				
  13.658 -				boolean Deleted = false;
  13.659 -				int intDeleted = 0;
  13.660 -				intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED));
  13.661 -				Deleted = (intDeleted == 1);
  13.662 +        stats.numInserts += rowInsert;
  13.663 +        stats.numUpdates += rowUpdate;
  13.664 +        stats.numDeletes += rowDelete;
  13.665 +        stats.numSkippedEntries += rowSkip;
  13.666 +        stats.numEntries += rowInsert + rowUpdate + rowDelete;
  13.667  
  13.668 -				if (SyncID == null) {
  13.669 -					// new Android event
  13.670 -					String newGUID = java.util.UUID.randomUUID().toString() + "-caldavsyncadapter";
  13.671 -					String calendarPath = caldavCalendarUri.getPath();
  13.672 -					if (!calendarPath.endsWith("/"))
  13.673 -						calendarPath += "/";
  13.674 +    }
  13.675  
  13.676 -					SyncID = calendarPath + newGUID + ".ics";
  13.677 -					
  13.678 -					androidEvent.createIcs(newGUID);
  13.679 -					
  13.680 -					if (facade.createEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString())) {
  13.681 -						//HINT: bugfix for google calendar replace("@", "%40")
  13.682 -						if (SyncID.contains("@"))
  13.683 -							SyncID = SyncID.replace("@", "%40");
  13.684 -						ContentValues values = new ContentValues();
  13.685 -						values.put(Events._SYNC_ID, SyncID);
  13.686 +    /**
  13.687 +     * checks the android events for the dirty flag.
  13.688 +     * the flag is set by android when the event has been changed.
  13.689 +     * the dirty flag is removed when an android event has been updated from calendar event
  13.690 +     *
  13.691 +     * @param provider
  13.692 +     * @param account
  13.693 +     * @param calendarUri
  13.694 +     * @param facade
  13.695 +     * @param caldavCalendarUri
  13.696 +     * @param stats
  13.697 +     * @param notifyList
  13.698 +     * @return count of dirty events
  13.699 +     */
  13.700 +    private int checkDirtyAndroidEvents(
  13.701 +            ContentProviderClient provider,
  13.702 +            Account account,
  13.703 +            Uri calendarUri,
  13.704 +            CaldavFacade facade,
  13.705 +            URI caldavCalendarUri,
  13.706 +            SyncStats stats,
  13.707 +            ArrayList<Uri> notifyList
  13.708 +    ) {
  13.709 +        Cursor curEvent = null;
  13.710 +        Cursor curAttendee = null;
  13.711 +        Cursor curReminder = null;
  13.712 +        Long EventID;
  13.713 +        Long CalendarID;
  13.714 +        AndroidEvent androidEvent = null;
  13.715 +        int rowDirty = 0;
  13.716 +        int rowInsert = 0;
  13.717 +        int rowUpdate = 0;
  13.718 +        int rowDelete = 0;
  13.719  
  13.720 -						//google doesn't send the etag after creation
  13.721 -						//HINT: my SabreDAV send always the same etag after putting a new event
  13.722 -						//String LastETag = facade.getLastETag();
  13.723 -						//if (!LastETag.equals("")) {
  13.724 -						//	values.put(Event.ETAG, LastETag);
  13.725 -						//} else {
  13.726 -							//so get the etag with a new REPORT
  13.727 -							CalendarEvent calendarEvent = new CalendarEvent(account, provider);
  13.728 -							calendarEvent.calendarURL = caldavCalendarUri.toURL();
  13.729 -							URI SyncURI = new URI(SyncID);
  13.730 -							calendarEvent.setUri(SyncURI);
  13.731 -							CaldavFacade.getEvent(calendarEvent);
  13.732 -							values.put(Event.ETAG, calendarEvent.getETag());
  13.733 -						//}
  13.734 -						values.put(Event.UID, newGUID);
  13.735 -						values.put(Events.DIRTY, 0);
  13.736 -						values.put(Event.RAWDATA, androidEvent.getIcsEvent().toString());
  13.737 -						
  13.738 -						int rowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), values, null, null);
  13.739 -						if (rowCount == 1) {
  13.740 -							rowInsert += 1;
  13.741 -							notifyList.add(androidEvent.getUri());
  13.742 -						}
  13.743 -					}
  13.744 -				} else if (Deleted) {
  13.745 -					// deleted Android event
  13.746 -					if (facade.deleteEvent(URI.create(SyncID), androidEvent.getETag())) {
  13.747 -						String mSelectionClause = "(" + Events._ID +  "= ?)";
  13.748 -						String[] mSelectionArgs = {String.valueOf(EventID)};
  13.749 -						
  13.750 -						int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs);	
  13.751 -						
  13.752 -						if (countDeleted == 1) {
  13.753 -							rowDelete += 1;
  13.754 -							notifyList.add(androidEvent.getUri());
  13.755 -						}
  13.756 -					}
  13.757 -				} else {
  13.758 -					//update the android event to the server
  13.759 -					String uid = androidEvent.getUID();
  13.760 -					if ((uid == null) || (uid.equals(""))) {
  13.761 -						//COMPAT: this is needed because in the past, the UID was not stored in the android event
  13.762 -						CalendarEvent calendarEvent = new CalendarEvent(account, provider);
  13.763 -						URI syncURI = new URI(SyncID);
  13.764 -						calendarEvent.setUri(syncURI);
  13.765 -						calendarEvent.calendarURL = caldavCalendarUri.toURL();
  13.766 -						if (calendarEvent.fetchBody()) {
  13.767 -							calendarEvent.readContentValues();
  13.768 -							uid = calendarEvent.getUID();
  13.769 -						}
  13.770 -					}
  13.771 -					if (uid != null) {
  13.772 -						androidEvent.createIcs(uid);
  13.773 -							
  13.774 -						if (facade.updateEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString(), androidEvent.getETag())) {
  13.775 -							selection = "(" + Events._ID + "= ?)";
  13.776 -							selectionArgs = new String[] {EventID.toString()};
  13.777 -							androidEvent.ContentValues.put(Events.DIRTY, 0);
  13.778 +        try {
  13.779 +            CalendarID = ContentUris.parseId(calendarUri);
  13.780 +            String selection = "(" + Events.DIRTY + " = ?) AND (" + Events.CALENDAR_ID + " = ?)";
  13.781 +            String[] selectionArgs = new String[]{"1", CalendarID.toString()};
  13.782 +            curEvent = provider.query(Events.CONTENT_URI, null, selection, selectionArgs, null);
  13.783  
  13.784 -							//google doesn't send the etag after update
  13.785 -							String LastETag = facade.getLastETag();
  13.786 -							if (!LastETag.equals("")) {
  13.787 -								androidEvent.ContentValues.put(Event.ETAG, LastETag);
  13.788 -							} else {
  13.789 -								//so get the etag with a new REPORT
  13.790 -								CalendarEvent calendarEvent = new CalendarEvent(account, provider);
  13.791 -								calendarEvent.calendarURL = caldavCalendarUri.toURL();
  13.792 -								URI SyncURI = new URI(SyncID);
  13.793 -								calendarEvent.setUri(SyncURI);
  13.794 -								CaldavFacade.getEvent(calendarEvent);
  13.795 -								androidEvent.ContentValues.put(Event.ETAG, calendarEvent.getETag());
  13.796 -							}
  13.797 -							androidEvent.ContentValues.put(Event.RAWDATA, androidEvent.getIcsEvent().toString());
  13.798 -							int RowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), androidEvent.ContentValues, null, null);
  13.799 -			
  13.800 -							if (RowCount == 1) {
  13.801 -								rowUpdate += 1;
  13.802 -								notifyList.add(androidEvent.getUri());
  13.803 -							}
  13.804 -						} else {
  13.805 -							rowDirty += 1;
  13.806 -						}
  13.807 -					} else {
  13.808 -						rowDirty += 1;
  13.809 -					}
  13.810 -				}
  13.811 -			}
  13.812 -			curEvent.close();
  13.813 +            while (curEvent.moveToNext()) {
  13.814 +                EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID));
  13.815 +                Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID);
  13.816 +
  13.817 +                //androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri);
  13.818 +                androidEvent = new AndroidEvent(returnedUri, calendarUri);
  13.819 +                androidEvent.readContentValues(curEvent);
  13.820 +
  13.821 +                selection = "(" + Attendees.EVENT_ID + " = ?)";
  13.822 +                selectionArgs = new String[]{String.valueOf(EventID)};
  13.823 +                curAttendee = provider.query(Attendees.CONTENT_URI, null, selection, selectionArgs, null);
  13.824 +                selection = "(" + Reminders.EVENT_ID + " = ?)";
  13.825 +                selectionArgs = new String[]{String.valueOf(EventID)};
  13.826 +                curReminder = provider.query(Reminders.CONTENT_URI, null, selection, selectionArgs, null);
  13.827 +                androidEvent.readAttendees(curAttendee);
  13.828 +                androidEvent.readReminder(curReminder);
  13.829 +                curAttendee.close();
  13.830 +                curReminder.close();
  13.831 +
  13.832 +                String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID);
  13.833 +
  13.834 +                boolean Deleted = false;
  13.835 +                int intDeleted = 0;
  13.836 +                intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED));
  13.837 +                Deleted = (intDeleted == 1);
  13.838 +
  13.839 +                if (SyncID == null) {
  13.840 +                    // new Android event
  13.841 +                    String newGUID = java.util.UUID.randomUUID().toString() + "-caldavsyncadapter";
  13.842 +                    String calendarPath = caldavCalendarUri.getPath();
  13.843 +                    if (!calendarPath.endsWith("/"))
  13.844 +                        calendarPath += "/";
  13.845 +
  13.846 +                    SyncID = calendarPath + newGUID + ".ics";
  13.847 +
  13.848 +                    androidEvent.createIcs(newGUID);
  13.849 +
  13.850 +                    if (facade.createEvent(URI.create(SyncID), androidEvent.getIcsEvent()
  13.851 +                            .toString())) {
  13.852 +                        //HINT: bugfix for google calendar replace("@", "%40")
  13.853 +                        if (SyncID.contains("@"))
  13.854 +                            SyncID = SyncID.replace("@", "%40");
  13.855 +                        ContentValues values = new ContentValues();
  13.856 +                        values.put(Events._SYNC_ID, SyncID);
  13.857 +
  13.858 +                        //google doesn't send the etag after creation
  13.859 +                        //HINT: my SabreDAV send always the same etag after putting a new event
  13.860 +                        //String LastETag = facade.getLastETag();
  13.861 +                        //if (!LastETag.equals("")) {
  13.862 +                        //	values.put(Event.ETAG, LastETag);
  13.863 +                        //} else {
  13.864 +                        //so get the etag with a new REPORT
  13.865 +                        CalendarEvent calendarEvent = new CalendarEvent(account, provider);
  13.866 +                        calendarEvent.calendarURL = caldavCalendarUri.toURL();
  13.867 +                        URI SyncURI = new URI(SyncID);
  13.868 +                        calendarEvent.setUri(SyncURI);
  13.869 +                        CaldavFacade.getEvent(calendarEvent);
  13.870 +                        values.put(Event.ETAG, calendarEvent.getETag());
  13.871 +                        //}
  13.872 +                        values.put(Event.UID, newGUID);
  13.873 +                        values.put(Events.DIRTY, 0);
  13.874 +                        values.put(Event.RAWDATA, androidEvent.getIcsEvent().toString());
  13.875 +
  13.876 +                        int rowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), values, null, null);
  13.877 +                        if (rowCount == 1) {
  13.878 +                            rowInsert += 1;
  13.879 +                            notifyList.add(androidEvent.getUri());
  13.880 +                        }
  13.881 +                    }
  13.882 +                } else if (Deleted) {
  13.883 +                    // deleted Android event
  13.884 +                    if (facade.deleteEvent(URI.create(SyncID), androidEvent.getETag())) {
  13.885 +                        String mSelectionClause = "(" + Events._ID + "= ?)";
  13.886 +                        String[] mSelectionArgs = {String.valueOf(EventID)};
  13.887 +
  13.888 +                        int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs);
  13.889 +
  13.890 +                        if (countDeleted == 1) {
  13.891 +                            rowDelete += 1;
  13.892 +                            notifyList.add(androidEvent.getUri());
  13.893 +                        }
  13.894 +                    }
  13.895 +                } else {
  13.896 +                    //update the android event to the server
  13.897 +                    String uid = androidEvent.getUID();
  13.898 +                    if ((uid == null) || (uid.equals(""))) {
  13.899 +                        //COMPAT: this is needed because in the past, the UID was not stored in the android event
  13.900 +                        CalendarEvent calendarEvent = new CalendarEvent(account, provider);
  13.901 +                        URI syncURI = new URI(SyncID);
  13.902 +                        calendarEvent.setUri(syncURI);
  13.903 +                        calendarEvent.calendarURL = caldavCalendarUri.toURL();
  13.904 +                        if (calendarEvent.fetchBody()) {
  13.905 +                            calendarEvent.readContentValues();
  13.906 +                            uid = calendarEvent.getUID();
  13.907 +                        }
  13.908 +                    }
  13.909 +                    if (uid != null) {
  13.910 +                        androidEvent.createIcs(uid);
  13.911 +
  13.912 +                        if (facade.updateEvent(URI.create(SyncID), androidEvent.getIcsEvent()
  13.913 +                                .toString(), androidEvent.getETag())) {
  13.914 +                            selection = "(" + Events._ID + "= ?)";
  13.915 +                            selectionArgs = new String[]{EventID.toString()};
  13.916 +                            androidEvent.ContentValues.put(Events.DIRTY, 0);
  13.917 +
  13.918 +                            //google doesn't send the etag after update
  13.919 +                            String LastETag = facade.getLastETag();
  13.920 +                            if (!LastETag.equals("")) {
  13.921 +                                androidEvent.ContentValues.put(Event.ETAG, LastETag);
  13.922 +                            } else {
  13.923 +                                //so get the etag with a new REPORT
  13.924 +                                CalendarEvent calendarEvent = new CalendarEvent(account, provider);
  13.925 +                                calendarEvent.calendarURL = caldavCalendarUri.toURL();
  13.926 +                                URI SyncURI = new URI(SyncID);
  13.927 +                                calendarEvent.setUri(SyncURI);
  13.928 +                                CaldavFacade.getEvent(calendarEvent);
  13.929 +                                androidEvent.ContentValues.put(Event.ETAG, calendarEvent.getETag());
  13.930 +                            }
  13.931 +                            androidEvent.ContentValues.put(Event.RAWDATA, androidEvent.getIcsEvent()
  13.932 +                                    .toString());
  13.933 +                            int RowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), androidEvent.ContentValues, null, null);
  13.934 +
  13.935 +                            if (RowCount == 1) {
  13.936 +                                rowUpdate += 1;
  13.937 +                                notifyList.add(androidEvent.getUri());
  13.938 +                            }
  13.939 +                        } else {
  13.940 +                            rowDirty += 1;
  13.941 +                        }
  13.942 +                    } else {
  13.943 +                        rowDirty += 1;
  13.944 +                    }
  13.945 +                }
  13.946 +            }
  13.947 +            curEvent.close();
  13.948  
  13.949  			/*if ((rowInsert > 0) || (rowUpdate > 0) || (rowDelete > 0) || (rowDirty > 0)) {
  13.950  				Log.i(TAG,"Android Rows inserted: " + String.valueOf(rowInsert));
  13.951 @@ -569,33 +588,33 @@
  13.952  				Log.i(TAG,"Android Rows deleted:  " + String.valueOf(rowDelete));
  13.953  				Log.i(TAG,"Android Rows dirty:    " + String.valueOf(rowDirty));
  13.954  			}*/
  13.955 -			
  13.956 -			stats.numInserts += rowInsert;
  13.957 -			stats.numUpdates += rowUpdate;
  13.958 -			stats.numDeletes += rowDelete;
  13.959 -			stats.numSkippedEntries += rowDirty;
  13.960 -			stats.numEntries += rowInsert + rowUpdate + rowDelete;
  13.961 -		} catch (RemoteException e) {
  13.962 -			e.printStackTrace();
  13.963 -		} catch (URISyntaxException e) {
  13.964 -			// TODO Automatisch generierter Erfassungsblock
  13.965 -			e.printStackTrace();
  13.966 -		} catch (ClientProtocolException e) {
  13.967 -			// TODO Automatisch generierter Erfassungsblock
  13.968 -			e.printStackTrace();
  13.969 -		} catch (IOException e) {
  13.970 -			// TODO Automatisch generierter Erfassungsblock
  13.971 -			e.printStackTrace();
  13.972 -		} catch (CaldavProtocolException e) {
  13.973 -			// TODO Automatisch generierter Erfassungsblock
  13.974 -			e.printStackTrace();
  13.975 -		} catch (ParserException e) {
  13.976 -			// TODO Automatisch generierter Erfassungsblock
  13.977 -			e.printStackTrace();
  13.978 -		}
  13.979 -		
  13.980 -		return rowDirty;
  13.981 -	}
  13.982 +
  13.983 +            stats.numInserts += rowInsert;
  13.984 +            stats.numUpdates += rowUpdate;
  13.985 +            stats.numDeletes += rowDelete;
  13.986 +            stats.numSkippedEntries += rowDirty;
  13.987 +            stats.numEntries += rowInsert + rowUpdate + rowDelete;
  13.988 +        } catch (RemoteException e) {
  13.989 +            e.printStackTrace();
  13.990 +        } catch (URISyntaxException e) {
  13.991 +            // TODO Automatisch generierter Erfassungsblock
  13.992 +            e.printStackTrace();
  13.993 +        } catch (ClientProtocolException e) {
  13.994 +            // TODO Automatisch generierter Erfassungsblock
  13.995 +            e.printStackTrace();
  13.996 +        } catch (IOException e) {
  13.997 +            // TODO Automatisch generierter Erfassungsblock
  13.998 +            e.printStackTrace();
  13.999 +        } catch (CaldavProtocolException e) {
 13.1000 +            // TODO Automatisch generierter Erfassungsblock
 13.1001 +            e.printStackTrace();
 13.1002 +        } catch (ParserException e) {
 13.1003 +            // TODO Automatisch generierter Erfassungsblock
 13.1004 +            e.printStackTrace();
 13.1005 +        }
 13.1006 +
 13.1007 +        return rowDirty;
 13.1008 +    }
 13.1009  	
 13.1010  /*	private Account UpgradeAccount(Account OldAccount) {
 13.1011  		String Username = OldAccount.name;
 13.1012 @@ -624,13 +643,13 @@
 13.1013  				        selection, selectionArgs);
 13.1014  		
 13.1015  	}*/
 13.1016 -	
 13.1017 -	private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
 13.1018 -	    return uri.buildUpon()
 13.1019 -	        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
 13.1020 -	        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
 13.1021 -	        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
 13.1022 -	 }
 13.1023 +
 13.1024 +    private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
 13.1025 +        return uri.buildUpon()
 13.1026 +                .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true")
 13.1027 +                .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
 13.1028 +                .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
 13.1029 +    }
 13.1030  
 13.1031  }
 13.1032  

mercurial