src/org/gege/caldavsyncadapter/caldav/CaldavFacade.java

changeset 8
ec8af0e3fbc2
parent 0
fb9019fb1bf7
equal deleted inserted replaced
0:3f1788c95ffe 1:7dba98d9fcec
1 /** 1 /**
2 * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger 2 * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger
3 * 3 *
4 * This file is part of Andoid Caldav Sync Adapter Free. 4 * This file is part of Andoid Caldav Sync Adapter Free.
5 * 5 *
6 * Andoid Caldav Sync Adapter Free is free software: you can redistribute 6 * Andoid Caldav Sync Adapter Free is free software: you can redistribute
7 * it and/or modify it under the terms of the GNU General Public License 7 * it and/or modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, either version 3 of the 8 * as published by the Free Software Foundation, either version 3 of the
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 * 15 *
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with Andoid Caldav Sync Adapter Free. 17 * along with Andoid Caldav Sync Adapter Free.
18 * If not, see <http://www.gnu.org/licenses/>. 18 * If not, see <http://www.gnu.org/licenses/>.
19 * 19 *
20 */ 20 */
21 21
22 package org.gege.caldavsyncadapter.caldav; 22 package org.gege.caldavsyncadapter.caldav;
23 23
24 import java.io.BufferedReader; 24 import android.accounts.Account;
25 import java.io.ByteArrayInputStream; 25 import android.content.ContentProviderClient;
26 import java.io.FileNotFoundException; 26 import android.content.Context;
27 import java.io.IOException; 27 import android.util.Log;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.io.UnsupportedEncodingException;
31 import java.net.MalformedURLException;
32 import java.net.SocketException;
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.net.URL;
36 import java.util.ArrayList;
37 import java.util.List;
38
39 import javax.xml.parsers.DocumentBuilder;
40 import javax.xml.parsers.DocumentBuilderFactory;
41 import javax.xml.parsers.ParserConfigurationException;
42 import javax.xml.parsers.SAXParser;
43 import javax.xml.parsers.SAXParserFactory;
44 28
45 import org.apache.http.HttpException; 29 import org.apache.http.HttpException;
46 import org.apache.http.HttpHost; 30 import org.apache.http.HttpHost;
47 import org.apache.http.HttpRequest; 31 import org.apache.http.HttpRequest;
48 import org.apache.http.HttpRequestInterceptor; 32 import org.apache.http.HttpRequestInterceptor;
74 import org.apache.http.params.CoreProtocolPNames; 58 import org.apache.http.params.CoreProtocolPNames;
75 import org.apache.http.params.HttpParams; 59 import org.apache.http.params.HttpParams;
76 import org.apache.http.params.HttpProtocolParams; 60 import org.apache.http.params.HttpProtocolParams;
77 import org.apache.http.protocol.BasicHttpContext; 61 import org.apache.http.protocol.BasicHttpContext;
78 import org.apache.http.protocol.HttpContext; 62 import org.apache.http.protocol.HttpContext;
63 import org.apache.http.util.EntityUtils;
79 import org.gege.caldavsyncadapter.BuildConfig; 64 import org.gege.caldavsyncadapter.BuildConfig;
65 import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
66 import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
80 import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; 67 import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
81 import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; 68 import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource;
82 import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
83 import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
84 import org.gege.caldavsyncadapter.caldav.http.HttpPropFind; 69 import org.gege.caldavsyncadapter.caldav.http.HttpPropFind;
85 import org.gege.caldavsyncadapter.caldav.http.HttpReport; 70 import org.gege.caldavsyncadapter.caldav.http.HttpReport;
86 import org.gege.caldavsyncadapter.caldav.xml.CalendarHomeHandler; 71 import org.gege.caldavsyncadapter.caldav.xml.CalendarHomeHandler;
87 import org.gege.caldavsyncadapter.caldav.xml.CalendarsHandler; 72 import org.gege.caldavsyncadapter.caldav.xml.CalendarsHandler;
88 import org.gege.caldavsyncadapter.caldav.xml.ServerInfoHandler; 73 import org.gege.caldavsyncadapter.caldav.xml.ServerInfoHandler;
94 import org.xml.sax.ContentHandler; 79 import org.xml.sax.ContentHandler;
95 import org.xml.sax.InputSource; 80 import org.xml.sax.InputSource;
96 import org.xml.sax.SAXException; 81 import org.xml.sax.SAXException;
97 import org.xml.sax.XMLReader; 82 import org.xml.sax.XMLReader;
98 83
99 import android.accounts.Account; 84 import java.io.ByteArrayInputStream;
100 import android.content.ContentProviderClient; 85 import java.io.FileNotFoundException;
101 import android.content.Context; 86 import java.io.IOException;
102 import android.util.Log; 87 import java.io.InputStream;
88 import java.io.UnsupportedEncodingException;
89 import java.net.MalformedURLException;
90 import java.net.SocketException;
91 import java.net.URI;
92 import java.net.URISyntaxException;
93 import java.net.URL;
94 import java.util.ArrayList;
95 import java.util.List;
96
97 import javax.net.ssl.SSLException;
98 import javax.xml.parsers.DocumentBuilder;
99 import javax.xml.parsers.DocumentBuilderFactory;
100 import javax.xml.parsers.ParserConfigurationException;
101 import javax.xml.parsers.SAXParser;
102 import javax.xml.parsers.SAXParserFactory;
103 103
104 public class CaldavFacade { 104 public class CaldavFacade {
105 private static final String TAG = "CaldavFacade"; 105 private static final String TAG = "CaldavFacade";
106 106
107 private final static String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 107 private final static String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
108 108
109 private String USER_AGENT = "CalDAV Sync Adapter (Android) https://github.com/gggard/AndroidCaldavSyncAdapater"; 109 private String USER_AGENT = "CalDAV Sync Adapter (Android) https://github.com/gggard/AndroidCaldavSyncAdapater";
110 private String VERSION = ""; 110 private String VERSION = "";
111 111
112 private static HttpClient httpClient; 112 private static HttpClient httpClient;
113 private HttpContext mContext = null; 113 private HttpContext mContext = null;
114 private AuthState mLastAuthState = null; 114 private AuthState mLastAuthState = null;
115 private AuthScope mLastAuthScope = null; 115 private AuthScope mLastAuthScope = null;
116 116
117 private boolean trustAll = true; 117 private boolean mTrustAll = true;
118 118
119 private URL url; 119 private URL url;
120 120
121 private static HttpHost targetHost; 121 private static HttpHost targetHost;
122 122
123 private int lastStatusCode; 123 private int lastStatusCode;
124 private String lastETag; 124 private String lastETag;
125 private String lastDav; 125 private String lastDav;
126 126
127 private String mstrcHeaderIfMatch = "If-Match"; 127 private String mstrcHeaderIfMatch = "If-Match";
128 private String mstrcHeaderIfNoneMatch = "If-None-Match"; 128 private String mstrcHeaderIfNoneMatch = "If-None-Match";
129 129
130 private Account mAccount = null; 130 private Account mAccount = null;
131 private ContentProviderClient mProvider; 131 private ContentProviderClient mProvider;
132 132
133 protected HttpClient getHttpClient() { 133 protected HttpClient getHttpClient() {
134 134
135 HttpParams params = new BasicHttpParams(); 135 HttpParams params = new BasicHttpParams();
136 params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); 136 params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
137 params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); 137 params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
138 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); 138 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
139 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 139 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
140 140
141 SchemeRegistry registry = new SchemeRegistry(); 141 SchemeRegistry registry = new SchemeRegistry();
142 registry.register(new Scheme("http", new PlainSocketFactory(), 80)); 142 registry.register(new Scheme("http", new PlainSocketFactory(), 80));
143 registry.register(new Scheme("https", (trustAll ? EasySSLSocketFactory.getSocketFactory() : SSLSocketFactory.getSocketFactory()), 443)); 143 registry.register(new Scheme("https", (mTrustAll ? EasySSLSocketFactory.getSocketFactory() : SSLSocketFactory
144 DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params); 144 .getSocketFactory()), 443));
145 145 DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params);
146 return client; 146
147 } 147 return client;
148 148 }
149 public CaldavFacade(String mUser, String mPassword, String mURL) throws MalformedURLException { 149
150 url = new URL(mURL); 150 public CaldavFacade(String mUser, String mPassword, String mURL, String trustAll) throws MalformedURLException {
151 151 url = new URL(mURL);
152 httpClient = getHttpClient(); 152
153 UsernamePasswordCredentials upc = new UsernamePasswordCredentials(mUser, mPassword); 153 this.mTrustAll = Boolean.valueOf(trustAll);
154 154
155 AuthScope as = null; 155 httpClient = getHttpClient();
156 as = new AuthScope(url.getHost(), -1); 156 UsernamePasswordCredentials upc = new UsernamePasswordCredentials(mUser, mPassword);
157 ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials(as, upc); 157
158 158 AuthScope as = null;
159 mContext = new BasicHttpContext(); 159 as = new AuthScope(url.getHost(), -1);
160 CredentialsProvider credProvider = ((AbstractHttpClient) httpClient).getCredentialsProvider(); 160 ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials(as, upc);
161 mContext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider); 161
162 162 mContext = new BasicHttpContext();
163 //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html 163 CredentialsProvider credProvider = ((AbstractHttpClient) httpClient).getCredentialsProvider();
164 ((AbstractHttpClient) httpClient).addRequestInterceptor(preemptiveAuth, 0); 164 mContext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider);
165 165
166 String proto = "http"; 166 //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html
167 int port = 80; 167 ((AbstractHttpClient) httpClient).addRequestInterceptor(preemptiveAuth, 0);
168 168
169 if (url.getProtocol().equalsIgnoreCase("https")) { 169 String proto = "http";
170 proto = "https"; 170 int port = 80;
171 if (url.getPort() == -1) 171
172 port = 443; 172 if (url.getProtocol().equalsIgnoreCase("https")) {
173 else 173 proto = "https";
174 port = url.getPort(); 174 if (url.getPort() == -1)
175 } 175 port = 443;
176 176 else
177 if (url.getProtocol().equalsIgnoreCase("http")) { 177 port = url.getPort();
178 proto = "http"; 178 }
179 if (url.getPort() == -1) 179
180 port = 80; 180 if (url.getProtocol().equalsIgnoreCase("http")) {
181 else 181 proto = "http";
182 port = url.getPort(); 182 if (url.getPort() == -1)
183 } 183 port = 80;
184 targetHost = new HttpHost(url.getHost(), port, proto); 184 else
185 } 185 port = url.getPort();
186 186 }
187 //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html 187 targetHost = new HttpHost(url.getHost(), port, proto);
188 HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() { 188 }
189 @Override 189
190 public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { 190 //http://dlinsin.blogspot.de/2009/08/http-basic-authentication-with-android.html
191 AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); 191 HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
192 192 @Override
193 if (authState.getAuthScheme() == null) { 193 public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
194 if (mLastAuthState != null) { 194 AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
195 Log.d(TAG, "LastAuthState: restored with user " + mLastAuthState.getCredentials().getUserPrincipal().getName()); 195
196 authState.setAuthScheme(mLastAuthState.getAuthScheme()); 196 if (authState.getAuthScheme() == null) {
197 authState.setCredentials(mLastAuthState.getCredentials()); 197 if (mLastAuthState != null) {
198 } else { 198 Log.d(TAG, "LastAuthState: restored with user " + mLastAuthState.getCredentials()
199 Log.d(TAG, "LastAuthState: nothing to do"); 199 .getUserPrincipal()
200 } 200 .getName());
201 if (mLastAuthScope != null) { 201 authState.setAuthScheme(mLastAuthState.getAuthScheme());
202 authState.setAuthScope(mLastAuthScope); 202 authState.setCredentials(mLastAuthState.getCredentials());
203 Log.d(TAG, "LastAuthScope: restored"); 203 } else {
204 } else { 204 Log.d(TAG, "LastAuthState: nothing to do");
205 Log.d(TAG, "LastAuthScope: nothing to do"); 205 }
206 } 206 if (mLastAuthScope != null) {
207 } else { 207 authState.setAuthScope(mLastAuthScope);
208 //AuthState and AuthScope have to be saved separate because of the AuthScope within AuthState gets lost, so we save it in a separate var. 208 Log.d(TAG, "LastAuthScope: restored");
209 mLastAuthState = authState; 209 } else {
210 Log.d(TAG, "LastAuthState: new with user " + mLastAuthState.getCredentials().getUserPrincipal().getName()); 210 Log.d(TAG, "LastAuthScope: nothing to do");
211 if (authState.getAuthScope() != null) { 211 }
212 mLastAuthScope = authState.getAuthScope(); 212 } else {
213 Log.d(TAG, "LastAuthScope: new"); 213 //AuthState and AuthScope have to be saved separate because of the AuthScope within AuthState gets lost, so we save it in a separate var.
214 } 214 mLastAuthState = authState;
215 } 215 Log.d(TAG, "LastAuthState: new with user " + mLastAuthState.getCredentials()
216 } 216 .getUserPrincipal()
217 }; 217 .getName());
218 218 if (authState.getAuthScope() != null) {
219 public enum TestConnectionResult { 219 mLastAuthScope = authState.getAuthScope();
220 WRONG_CREDENTIAL, 220 Log.d(TAG, "LastAuthScope: new");
221 WRONG_URL, 221 }
222 WRONG_SERVER_STATUS, 222 }
223 WRONG_ANSWER, 223 }
224 SUCCESS 224 };
225 } 225
226 226 public enum TestConnectionResult {
227 /** 227 WRONG_CREDENTIAL,
228 * TODO: testConnection should return only an instance of 228 WRONG_URL,
229 * TestConnectionResult without throwing an exception or only throw checked 229 WRONG_SERVER_STATUS,
230 * exceptions so you don't have to check the result of this function AND 230 WRONG_ANSWER,
231 * handle the exceptions 231 SSL_ERROR,
232 * @param context 232 SUCCESS
233 * 233 }
234 * @return {@link TestConnectionResult} 234
235 * @throws HttpHostConnectException 235 /**
236 * @throws IOException 236 * TODO: testConnection should return only an instance of
237 * @throws URISyntaxException 237 * TestConnectionResult without throwing an exception or only throw checked
238 * @throws ParserConfigurationException 238 * exceptions so you don't have to check the result of this function AND
239 * @throws SAXException 239 * handle the exceptions
240 */ 240 *
241 public TestConnectionResult testConnection() throws HttpHostConnectException, IOException, URISyntaxException, ParserConfigurationException, SAXException { 241 * @return {@link TestConnectionResult}
242 Log.d(TAG, "start testConnection "); 242 * @throws HttpHostConnectException
243 try { 243 * @throws IOException
244 List<DavCalendar> calendars = new ArrayList<DavCalendar>(); 244 * @throws URISyntaxException
245 calendars = forceGetCalendarsFromUri(null, url.toURI()); 245 * @throws ParserConfigurationException
246 if (calendars.size() != 0) { 246 * @throws SAXException
247 return TestConnectionResult.SUCCESS; 247 */
248 } 248 public TestConnectionResult testConnection() throws IOException, URISyntaxException, ParserConfigurationException, SAXException {
249 249 Log.d(TAG, "start testConnection ");
250 URI userPrincipal = getUserPrincipal(); 250 try {
251 List<URI> calendarSets = getCalendarHomes(userPrincipal); 251 List<DavCalendar> calendars = new ArrayList<DavCalendar>();
252 for (URI calendarSet : calendarSets) { 252 calendars = forceGetCalendarsFromUri(null, url.toURI());
253 List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet); 253 if (calendars.size() != 0) {
254 calendars.addAll(calendarSetCalendars); 254 return TestConnectionResult.SUCCESS;
255 } 255 }
256 if (calendarSets.size() == 0) { 256
257 return TestConnectionResult.WRONG_ANSWER; 257 URI userPrincipal = getUserPrincipal();
258 } 258 List<URI> calendarSets = getCalendarHomes(userPrincipal);
259 } catch (FileNotFoundException e) { 259 for (URI calendarSet : calendarSets) {
260 return TestConnectionResult.WRONG_URL; 260 List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet);
261 } catch (SocketException e) { 261 calendars.addAll(calendarSetCalendars);
262 return TestConnectionResult.WRONG_URL; 262 }
263 } catch (AuthenticationException e) { 263 if (calendarSets.size() == 0) {
264 return TestConnectionResult.WRONG_CREDENTIAL; 264 return TestConnectionResult.WRONG_ANSWER;
265 } catch (ClientProtocolException e) { 265 }
266 return TestConnectionResult.WRONG_SERVER_STATUS; 266 } catch (FileNotFoundException e) {
267 } catch (CaldavProtocolException e) { 267 return TestConnectionResult.WRONG_URL;
268 return TestConnectionResult.WRONG_ANSWER; 268 } catch (SSLException e) {
269 } 269 return TestConnectionResult.SSL_ERROR;
270 return TestConnectionResult.SUCCESS; 270 } catch (SocketException e) {
271 } 271 return TestConnectionResult.WRONG_URL;
272 272 } catch (AuthenticationException e) {
273 /** 273 return TestConnectionResult.WRONG_CREDENTIAL;
274 * @param context May be null if no notification is needed 274 } catch (ClientProtocolException e) {
275 * @param uri 275 return TestConnectionResult.WRONG_SERVER_STATUS;
276 * @return 276 } catch (CaldavProtocolException e) {
277 * @throws AuthenticationException 277 return TestConnectionResult.WRONG_ANSWER;
278 * @throws FileNotFoundException 278 }
279 */ 279 return TestConnectionResult.SUCCESS;
280 private List<DavCalendar> forceGetCalendarsFromUri(Context context, URI uri) throws AuthenticationException, FileNotFoundException { 280 }
281 List<DavCalendar> calendars = new ArrayList<DavCalendar>(); 281
282 Exception exception = null; 282 /**
283 try { 283 * @param context May be null if no notification is needed
284 calendars = getCalendarsFromSet(uri); 284 * @param uri
285 } catch (ClientProtocolException e) { 285 * @return
286 if (context != null) { 286 * @throws AuthenticationException
287 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); 287 * @throws FileNotFoundException
288 //NotificationsHelper.getCurrentSyncLog().addException(e); 288 */
289 } 289 private List<DavCalendar> forceGetCalendarsFromUri(Context context, URI uri) throws AuthenticationException, FileNotFoundException {
290 exception = e; 290 List<DavCalendar> calendars = new ArrayList<DavCalendar>();
291 } catch (FileNotFoundException e) { 291 Exception exception = null;
292 if (context != null) { 292 try {
293 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); 293 calendars = getCalendarsFromSet(uri);
294 //NotificationsHelper.getCurrentSyncLog().addException(e); 294 } catch (ClientProtocolException e) {
295 } 295 if (context != null) {
296 throw e; 296 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
297 } catch (IOException e) { 297 //NotificationsHelper.getCurrentSyncLog().addException(e);
298 if (context != null) { 298 }
299 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); 299 exception = e;
300 //NotificationsHelper.getCurrentSyncLog().addException(e); 300 } catch (FileNotFoundException e) {
301 } 301 if (context != null) {
302 exception = e; 302 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
303 } catch (CaldavProtocolException e) { 303 //NotificationsHelper.getCurrentSyncLog().addException(e);
304 304 }
305 if (context != null) { 305 throw e;
306 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage()); 306 } catch (IOException e) {
307 //NotificationsHelper.getCurrentSyncLog().addException(e); 307 if (context != null) {
308 } 308 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
309 exception = e; 309 //NotificationsHelper.getCurrentSyncLog().addException(e);
310 } 310 }
311 if (exception != null && BuildConfig.DEBUG) { 311 exception = e;
312 Log.e(TAG, "Force get calendars from '" + uri.toString() 312 } catch (CaldavProtocolException e) {
313 + "' failed " + exception.getClass().getCanonicalName() 313
314 + ": " + exception.getMessage()); 314 if (context != null) {
315 } 315 NotificationsHelper.signalSyncErrors(context, "Caldav sync problem", e.getMessage());
316 return calendars; 316 //NotificationsHelper.getCurrentSyncLog().addException(e);
317 } 317 }
318 318 exception = e;
319 private final static String PROPFIND_USER_PRINCIPAL = XML_VERSION + 319 }
320 "<d:propfind xmlns:d=\"DAV:\">" + 320 if (exception != null && BuildConfig.DEBUG) {
321 "<d:prop>" + 321 Log.e(TAG, "Force get calendars from '" + uri.toString()
322 "<d:current-user-principal />" + 322 + "' failed " + exception.getClass().getCanonicalName()
323 "<d:principal-URL />" + 323 + ": " + exception.getMessage());
324 "</d:prop>" + 324 }
325 "</d:propfind>"; 325 return calendars;
326 326 }
327 private URI getUserPrincipal() throws SocketException, 327
328 ClientProtocolException, AuthenticationException, 328 private final static String PROPFIND_USER_PRINCIPAL = XML_VERSION +
329 FileNotFoundException, IOException, CaldavProtocolException, 329 "<d:propfind xmlns:d=\"DAV:\">" +
330 URISyntaxException { 330 "<d:prop>" +
331 URI uri = this.url.toURI(); 331 "<d:current-user-principal />" +
332 HttpPropFind request = createPropFindRequest(uri, 332 "<d:principal-URL />" +
333 PROPFIND_USER_PRINCIPAL, 0); 333 "</d:prop>" +
334 HttpResponse response = httpClient.execute(targetHost, request, mContext); 334 "</d:propfind>";
335 checkStatus(response); 335
336 ServerInfoHandler serverInfoHandler = new ServerInfoHandler(); 336 private URI getUserPrincipal() throws
337 parseXML(response, serverInfoHandler); 337 AuthenticationException,
338 String userPrincipal = null; 338 IOException, CaldavProtocolException,
339 if (serverInfoHandler.currentUserPrincipal != null) { 339 URISyntaxException {
340 userPrincipal = serverInfoHandler.currentUserPrincipal; 340 URI uri = this.url.toURI();
341 } else if (serverInfoHandler.principalUrl != null) { 341 HttpPropFind request = createPropFindRequest(uri,
342 userPrincipal = serverInfoHandler.principalUrl; 342 PROPFIND_USER_PRINCIPAL, 0);
343 } else { 343 HttpResponse response = httpClient.execute(targetHost, request, mContext);
344 throw new CaldavProtocolException("no principal url found"); 344 checkStatus(response);
345 } 345 ServerInfoHandler serverInfoHandler = new ServerInfoHandler();
346 try { 346 parseXML(response, serverInfoHandler);
347 URI userPrincipalUri = new URI(userPrincipal); 347 String userPrincipal = null;
348 userPrincipalUri = uri.resolve(userPrincipalUri); 348 if (serverInfoHandler.currentUserPrincipal != null) {
349 if (BuildConfig.DEBUG) { 349 userPrincipal = serverInfoHandler.currentUserPrincipal;
350 Log.d(TAG, 350 } else if (serverInfoHandler.principalUrl != null) {
351 "Found userPrincipal: " + userPrincipalUri.toString()); 351 userPrincipal = serverInfoHandler.principalUrl;
352 } 352 } else {
353 return userPrincipalUri; 353 throw new CaldavProtocolException("no principal url found");
354 } catch (URISyntaxException e) { 354 }
355 throw new CaldavProtocolException("principal url '" + userPrincipal 355 try {
356 + "' malformed"); 356 URI userPrincipalUri = new URI(userPrincipal);
357 } 357 userPrincipalUri = uri.resolve(userPrincipalUri);
358 } 358 if (BuildConfig.DEBUG) {
359 359 Log.d(TAG,
360 private final static String PROPFIND_CALENDAR_HOME_SET = XML_VERSION 360 "Found userPrincipal: " + userPrincipalUri.toString());
361 + "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"><d:prop><c:calendar-home-set/></d:prop></d:propfind>"; 361 }
362 362 return userPrincipalUri;
363 private List<URI> getCalendarHomes(URI userPrincipal) 363 } catch (URISyntaxException e) {
364 throws ClientProtocolException, IOException, 364 throw new CaldavProtocolException("principal url '" + userPrincipal
365 AuthenticationException, FileNotFoundException, 365 + "' malformed");
366 CaldavProtocolException { 366 }
367 HttpPropFind request = createPropFindRequest(userPrincipal, 367 }
368 PROPFIND_CALENDAR_HOME_SET, 0); 368
369 HttpResponse response = httpClient.execute(targetHost, request, mContext); 369 private final static String PROPFIND_CALENDAR_HOME_SET = XML_VERSION
370 checkStatus(response); 370 + "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"><d:prop><c:calendar-home-set/></d:prop></d:propfind>";
371 CalendarHomeHandler calendarHomeHandler = new CalendarHomeHandler( 371
372 userPrincipal); 372 private List<URI> getCalendarHomes(URI userPrincipal)
373 parseXML(response, calendarHomeHandler); 373 throws ClientProtocolException, IOException,
374 List<URI> result = calendarHomeHandler.calendarHomeSet; 374 AuthenticationException, FileNotFoundException,
375 if (BuildConfig.DEBUG) { 375 CaldavProtocolException {
376 Log.d(TAG, result.size() + " calendar-home-set found in " 376 HttpPropFind request = createPropFindRequest(userPrincipal,
377 + userPrincipal.toString()); 377 PROPFIND_CALENDAR_HOME_SET, 0);
378 } 378 HttpResponse response = httpClient.execute(targetHost, request, mContext);
379 return result; 379 checkStatus(response);
380 } 380 CalendarHomeHandler calendarHomeHandler = new CalendarHomeHandler(
381 381 userPrincipal);
382 private final static String PROPFIND_CALENDER_LIST = XML_VERSION 382 parseXML(response, calendarHomeHandler);
383 + "<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/\">" 383 List<URI> result = calendarHomeHandler.calendarHomeSet;
384 + "<d:prop><d:displayname /><d:resourcetype />" 384 if (BuildConfig.DEBUG) {
385 // + 385 Log.d(TAG, result.size() + " calendar-home-set found in "
386 // "<d:supported-method-set /><d:supported-report-set /><c:supported-calendar-component-set />" 386 + userPrincipal.toString());
387 // + 387 }
388 // "<c:calendar-description /><c:calendar-timezone /><c:calendar-free-busy-set /> 388 return result;
389 + "<ic:calendar-color />" 389 }
390 //<ic:calendar-order />" 390
391 + "<cs:getctag /></d:prop></d:propfind>"; 391 private final static String PROPFIND_CALENDER_LIST = XML_VERSION
392 392 + "<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/\">"
393 393 + "<d:prop><d:displayname /><d:resourcetype />"
394 private List<DavCalendar> getCalendarsFromSet(URI calendarSet) 394 // +
395 throws ClientProtocolException, IOException, 395 // "<d:supported-method-set /><d:supported-report-set /><c:supported-calendar-component-set />"
396 CaldavProtocolException, AuthenticationException, 396 // +
397 FileNotFoundException { 397 // "<c:calendar-description /><c:calendar-timezone /><c:calendar-free-busy-set />
398 HttpPropFind request = createPropFindRequest(calendarSet, PROPFIND_CALENDER_LIST, 1); 398 + "<ic:calendar-color />"
399 HttpResponse response = httpClient.execute(targetHost, request, mContext); 399 //<ic:calendar-order />"
400 checkStatus(response); 400 + "<cs:getctag /></d:prop></d:propfind>";
401 CalendarsHandler calendarsHandler = new CalendarsHandler(calendarSet); 401
402 parseXML(response, calendarsHandler); 402
403 List<DavCalendar> result = calendarsHandler.calendars; 403 private List<DavCalendar> getCalendarsFromSet(URI calendarSet)
404 if (BuildConfig.DEBUG) { 404 throws ClientProtocolException, IOException,
405 Log.i(TAG, 405 CaldavProtocolException, AuthenticationException,
406 result.size() + " calendars found in set " 406 FileNotFoundException {
407 + calendarSet.toString()); 407 HttpPropFind request = createPropFindRequest(calendarSet, PROPFIND_CALENDER_LIST, 1);
408 } 408 HttpResponse response = httpClient.execute(targetHost, request, mContext);
409 return result; 409 checkStatus(response);
410 } 410 CalendarsHandler calendarsHandler = new CalendarsHandler(calendarSet);
411 411 parseXML(response, calendarsHandler);
412 /** 412 List<DavCalendar> result = calendarsHandler.calendars;
413 * Discover CalDAV Calendars Mentioned in 413 if (BuildConfig.DEBUG) {
414 * http://tools.ietf.org/html/draft-daboo-srv-caldav-10#section-6 and 414 Log.i(TAG,
415 * http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Discovery 415 result.size() + " calendars found in set "
416 * <ol> 416 + calendarSet.toString()
417 * <li>PROPFIND calendar-home-set on url 417 );
418 * <li>PROPFIND DAV:current-user-principal or principal-URL on url 418 }
419 * <li>PROPFIND calendar-home-set on current-user-principal or principal-URL 419 return result;
420 * <li>PROPFIND displayname, resourcetype, getctag on CalendarHomeSets 420 }
421 * </ol> 421
422 * @param context 422 /**
423 * 423 * Discover CalDAV Calendars Mentioned in
424 * @return List of {@link DavCalendar} 424 * http://tools.ietf.org/html/draft-daboo-srv-caldav-10#section-6 and
425 * @throws ClientProtocolException 425 * http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Discovery
426 * http protocol error 426 * <ol>
427 * @throws IOException 427 * <li>PROPFIND calendar-home-set on url
428 * Connection lost 428 * <li>PROPFIND DAV:current-user-principal or principal-URL on url
429 * @throws URISyntaxException 429 * <li>PROPFIND calendar-home-set on current-user-principal or principal-URL
430 * url in Constructor malformed 430 * <li>PROPFIND displayname, resourcetype, getctag on CalendarHomeSets
431 * @throws CaldavProtocolException 431 * </ol>
432 * caldav protocol error 432 *
433 */ 433 * @param context
434 //public Iterable<Calendar> getCalendarList(Context context) throws ClientProtocolException, 434 * @return List of {@link DavCalendar}
435 public CalendarList getCalendarList(Context context) throws ClientProtocolException, 435 * @throws ClientProtocolException http protocol error
436 IOException, URISyntaxException, ParserConfigurationException, 436 * @throws IOException Connection lost
437 CaldavProtocolException { 437 * @throws URISyntaxException url in Constructor malformed
438 try { 438 * @throws CaldavProtocolException caldav protocol error
439 CalendarList Result = new CalendarList(this.mAccount, this.mProvider, CalendarSource.CalDAV, this.url.toString()); 439 */
440 List<DavCalendar> calendars = new ArrayList<DavCalendar>(); 440 //public Iterable<Calendar> getCalendarList(Context context) throws ClientProtocolException,
441 441 public CalendarList getCalendarList(Context context) throws ClientProtocolException,
442 calendars = forceGetCalendarsFromUri(context, this.url.toURI()); 442 IOException, URISyntaxException, ParserConfigurationException,
443 443 CaldavProtocolException {
444 if (calendars.size() == 0) { 444 try {
445 // no calendars found, try the home-set 445 CalendarList Result = new CalendarList(this.mAccount, this.mProvider, CalendarSource.CalDAV, this.url
446 URI userPrincipal = getUserPrincipal(); 446 .toString());
447 List<URI> calendarSets = getCalendarHomes(userPrincipal); 447 List<DavCalendar> calendars = new ArrayList<DavCalendar>();
448 for (URI calendarSet : calendarSets) { 448
449 List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet); 449 calendars = forceGetCalendarsFromUri(context, this.url.toURI());
450 calendars.addAll(calendarSetCalendars); 450
451 } 451 if (calendars.size() == 0) {
452 } 452 // no calendars found, try the home-set
453 for (DavCalendar cal : calendars) { 453 URI userPrincipal = getUserPrincipal();
454 Result.addCalendar(cal); 454 List<URI> calendarSets = getCalendarHomes(userPrincipal);
455 } 455 for (URI calendarSet : calendarSets) {
456 456 List<DavCalendar> calendarSetCalendars = getCalendarsFromSet(calendarSet);
457 //return calendars; 457 calendars.addAll(calendarSetCalendars);
458 return Result; 458 }
459 } catch (AuthenticationException e) { 459 }
460 throw new IOException(e); 460 for (DavCalendar cal : calendars) {
461 } 461 Result.addCalendar(cal);
462 } 462 }
463 463
464 //public Iterable<CalendarEvent> getCalendarEvents(DavCalendar calendar) 464 //return calendars;
465 public ArrayList<CalendarEvent> getCalendarEvents(DavCalendar calendar) 465 return Result;
466 throws URISyntaxException, ClientProtocolException, IOException, 466 } catch (AuthenticationException e) {
467 ParserConfigurationException, SAXException { 467 throw new IOException(e);
468 468 }
469 ArrayList<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>(); 469 }
470 470
471 String requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 471 //public Iterable<CalendarEvent> getCalendarEvents(DavCalendar calendar)
472 + "<D:propfind xmlns:D=\"DAV:\">" + "<D:prop>" + "<D:getetag/>" 472 public ArrayList<CalendarEvent> getCalendarEvents(DavCalendar calendar)
473 + "</D:prop>" + "</D:propfind>"; 473 throws URISyntaxException, ClientProtocolException, IOException,
474 474 ParserConfigurationException, SAXException {
475 HttpPropFind request = null; 475
476 476 ArrayList<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>();
477 String EventUri; 477
478 String requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
479 + "<D:propfind xmlns:D=\"DAV:\">" + "<D:prop>" + "<D:getetag/>"
480 + "</D:prop>" + "</D:propfind>";
481
482 HttpPropFind request = null;
483
484 String EventUri;
478 485
479 /*request = new HttpPropFind(); 486 /*request = new HttpPropFind();
480 request.setURI(calendar.getURI()); 487 request.setURI(calendar.getURI());
481 request.setHeader("Host", targetHost.getHostName()); 488 request.setHeader("Host", targetHost.getHostName());
482 request.setHeader("Depth", "1"); 489 request.setHeader("Depth", "1");
483 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 490 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
484 491
485 try { 492 try {
486 request.setEntity(new StringEntity(requestBody, "UTF-8")); 493 request.setEntity(new StringEntity(requestBody, "UTF-8"));
487 } catch (UnsupportedEncodingException e) { 494 } catch (UnsupportedEncodingException e) {
488 throw new AssertionError("UTF-8 is unknown"); 495 throw new AssertionError("UTF-8 is unknown");
489 }*/ 496 }*/
490 request = this.createPropFindRequest(calendar.getURI(), requestBody, 1); 497 request = this.createPropFindRequest(calendar.getURI(), requestBody, 1);
491 498
492 Log.d(TAG, "Getting eTag by PROPFIND at " + request.getURI()); 499 Log.d(TAG, "Getting eTag by PROPFIND at " + request.getURI());
493 500
494 HttpResponse response = httpClient.execute(targetHost, request, mContext); 501 HttpResponse response = httpClient.execute(targetHost, request, mContext);
495 502 String body = EntityUtils.toString(response.getEntity(), "UTF-8");
496 BufferedReader reader = new BufferedReader(new InputStreamReader( 503
497 response.getEntity().getContent(), "UTF-8")); 504 Log.d(TAG, "HttpResponse status=" + response.getStatusLine()
498 505 + " body= " + body);
499 String line; 506
500 String body = ""; 507 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
501 do { 508 factory.setNamespaceAware(true);
502 line = reader.readLine(); 509 DocumentBuilder builder = factory.newDocumentBuilder();
503 if (line != null) 510 Document dom = builder.parse(new InputSource(new ByteArrayInputStream(
504 body += line; 511 body.getBytes("utf-8"))));
505 } while (line != null); 512 Element root = dom.getDocumentElement();
506 513 NodeList items = root.getElementsByTagNameNS("*", "getetag");
507 Log.d(TAG, "HttpResponse status=" + response.getStatusLine() 514
508 + " body= " + body); 515 for (int i = 0; i < items.getLength(); i++) {
509 516 CalendarEvent calendarEvent = new CalendarEvent(this.mAccount, this.mProvider);
510 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 517
511 factory.setNamespaceAware(true); 518 Node node = items.item(i);
512 DocumentBuilder builder = factory.newDocumentBuilder(); 519
513 Document dom = builder.parse(new InputSource(new ByteArrayInputStream( 520 if (node.getTextContent().trim().length() == 0)
514 body.getBytes("utf-8")))); 521 continue; // not an event
515 Element root = dom.getDocumentElement(); 522
516 NodeList items = root.getElementsByTagNameNS("*", "getetag"); 523 calendarEvent.setETag(node.getTextContent().trim());
517 524 //calendarEvent.calendarURL = this.url;
518 for (int i = 0; i < items.getLength(); i++) { 525 calendarEvent.calendarURL = calendar.getURI().toURL();
519 CalendarEvent calendarEvent = new CalendarEvent(this.mAccount, this.mProvider); 526
520 527 node = node.getParentNode(); // prop
521 Node node = items.item(i); 528 node = node.getParentNode(); // propstat
522 529 node = node.getParentNode(); // response
523 if (node.getTextContent().trim().length() == 0) 530
524 continue; // not an event 531 NodeList children = node.getChildNodes();
525 532 for (int j = 0; j < children.getLength(); j++) {
526 calendarEvent.setETag(node.getTextContent().trim()); 533 Node childNode = children.item(j);
527 //calendarEvent.calendarURL = this.url; 534 if ((childNode.getLocalName() != null) && (childNode.getLocalName()
528 calendarEvent.calendarURL = calendar.getURI().toURL(); 535 .equalsIgnoreCase("href"))) {
529 536 EventUri = childNode.getTextContent().trim();
530 node = node.getParentNode(); // prop 537 //HINT: bugfix for zimbra calendar: replace("@", "%40")
531 node = node.getParentNode(); // propstat 538 EventUri = EventUri.replace("@", "%40");
532 node = node.getParentNode(); // response 539 calendarEvent.setUri(new URI(EventUri));
533 540 }
534 NodeList children = node.getChildNodes(); 541 }
535 for (int j = 0; j < children.getLength(); j++) { 542
536 Node childNode = children.item(j); 543 calendarEventList.add(calendarEvent);
537 if ((childNode.getLocalName()!=null) && (childNode.getLocalName().equalsIgnoreCase("href"))) { 544
538 EventUri = childNode.getTextContent().trim(); 545 }
539 //HINT: bugfix for zimbra calendar: replace("@", "%40") 546
540 EventUri = EventUri.replace("@", "%40"); 547 return calendarEventList;
541 calendarEvent.setUri(new URI(EventUri)); 548 }
542 } 549
543 } 550 private void parseXML(HttpResponse response, ContentHandler contentHandler)
544 551 throws IOException, CaldavProtocolException {
545 calendarEventList.add(calendarEvent); 552 InputStream is = response.getEntity().getContent();
546 553 /*BufferedReader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
547 } 554 String Content = "";
548
549 return calendarEventList;
550 }
551
552 private void parseXML(HttpResponse response, ContentHandler contentHandler)
553 throws IOException, CaldavProtocolException {
554 InputStream is = response.getEntity().getContent();
555 /*BufferedReader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
556 String Content = "";
557 String Line = bReader.readLine(); 555 String Line = bReader.readLine();
558 556
559 while (Line != null) { 557 while (Line != null) {
560 Content += Line; 558 Content += Line;
561 Line = bReader.readLine(); 559 Line = bReader.readLine();
562 }*/ 560 }*/
563 561
564 SAXParserFactory factory = SAXParserFactory.newInstance(); 562 SAXParserFactory factory = SAXParserFactory.newInstance();
565 try { 563 try {
566 SAXParser parser = factory.newSAXParser(); 564 SAXParser parser = factory.newSAXParser();
567 XMLReader reader = parser.getXMLReader(); 565 XMLReader reader = parser.getXMLReader();
568 reader.setContentHandler(contentHandler); 566 reader.setContentHandler(contentHandler);
569 reader.parse(new InputSource(is)); 567 reader.parse(new InputSource(is));
570 } catch (ParserConfigurationException e) { 568 } catch (ParserConfigurationException e) {
571 throw new AssertionError("ParserConfigurationException " 569 throw new AssertionError("ParserConfigurationException "
572 + e.getMessage()); 570 + e.getMessage());
573 } catch (IllegalStateException e) { 571 } catch (IllegalStateException e) {
574 throw new CaldavProtocolException(e.getMessage()); 572 throw new CaldavProtocolException(e.getMessage());
575 } catch (SAXException e) { 573 } catch (SAXException e) {
576 throw new CaldavProtocolException(e.getMessage()); 574 throw new CaldavProtocolException(e.getMessage());
577 } 575 }
578 } 576 }
579 577
580 private void checkStatus(HttpResponse response) 578 private void checkStatus(HttpResponse response)
581 throws AuthenticationException, FileNotFoundException, 579 throws AuthenticationException, FileNotFoundException,
582 ClientProtocolException { 580 ClientProtocolException {
583 final int statusCode = response.getStatusLine().getStatusCode(); 581 final int statusCode = response.getStatusLine().getStatusCode();
584 lastStatusCode = statusCode; 582 lastStatusCode = statusCode;
585 if (response.containsHeader("ETag")) 583 if (response.containsHeader("ETag"))
586 lastETag = response.getFirstHeader("ETag").getValue(); 584 lastETag = response.getFirstHeader("ETag").getValue();
587 else 585 else
588 lastETag = ""; 586 lastETag = "";
589 if (response.containsHeader("DAV")) 587 if (response.containsHeader("DAV"))
590 lastDav = response.getFirstHeader("DAV").getValue(); 588 lastDav = response.getFirstHeader("DAV").getValue();
591 else 589 else
592 lastDav = ""; 590 lastDav = "";
593 591
594 switch (statusCode) { 592 switch (statusCode) {
595 case 401: 593 case 401:
596 throw new AuthenticationException(); 594 throw new AuthenticationException();
597 case 404: 595 case 404:
598 throw new FileNotFoundException(); 596 throw new FileNotFoundException();
599 case 409: //Conflict 597 case 409: //Conflict
600 case 412: 598 case 412:
601 case 200: 599 case 200:
602 case 201: 600 case 201:
603 case 204: 601 case 204:
604 case 207: 602 case 207:
605 return; 603 return;
606 default: 604 default:
607 throw new ClientProtocolException("StatusCode: " + statusCode); 605 throw new ClientProtocolException("StatusCode: " + statusCode);
608 } 606 }
609 } 607 }
610 608
611 private HttpPropFind createPropFindRequest(URI uri, String data, int depth) { 609 private HttpPropFind createPropFindRequest(URI uri, String data, int depth) {
612 HttpPropFind request = new HttpPropFind(); 610 HttpPropFind request = new HttpPropFind();
613 611
614 request.setURI(uri); 612 request.setURI(uri);
615 //request.setHeader("Host", targetHost.getHostName()); 613 //request.setHeader("Host", targetHost.getHostName());
616 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); 614 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
617 request.setHeader("Depth", Integer.toString(depth)); 615 request.setHeader("Depth", Integer.toString(depth));
618 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 616 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
619 try { 617 try {
620 request.setEntity(new StringEntity(data, "UTF-8")); 618 request.setEntity(new StringEntity(data, "UTF-8"));
621 } catch (UnsupportedEncodingException e) { 619 } catch (UnsupportedEncodingException e) {
622 throw new AssertionError("UTF-8 is unknown"); 620 throw new AssertionError("UTF-8 is unknown");
623 } 621 }
624 return request; 622 return request;
625 } 623 }
626 624
627 private HttpDelete createDeleteRequest(URI uri) { 625 private HttpDelete createDeleteRequest(URI uri) {
628 HttpDelete request = new HttpDelete(); 626 HttpDelete request = new HttpDelete();
629 request.setURI(uri); 627 request.setURI(uri);
630 //request.setHeader("Host", targetHost.getHostName()); 628 //request.setHeader("Host", targetHost.getHostName());
631 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); 629 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
632 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 630 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
633 return request; 631 return request;
634 } 632 }
635 633
636 private HttpPut createPutRequest(URI uri, String data, int depth) { 634 private HttpPut createPutRequest(URI uri, String data, int depth) {
637 HttpPut request = new HttpPut(); 635 HttpPut request = new HttpPut();
638 request.setURI(uri); 636 request.setURI(uri);
639 //request.setHeader("Host", targetHost.getHostName()); 637 //request.setHeader("Host", targetHost.getHostName());
640 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); 638 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
641 //request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 639 //request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
642 request.setHeader("Content-Type", "text/calendar; charset=UTF-8"); 640 request.setHeader("Content-Type", "text/calendar; charset=UTF-8");
643 try { 641 try {
644 request.setEntity(new StringEntity(data, "UTF-8")); 642 request.setEntity(new StringEntity(data, "UTF-8"));
645 //request.setEntity(new StringEntity(data)); 643 //request.setEntity(new StringEntity(data));
646 } catch (UnsupportedEncodingException e) { 644 } catch (UnsupportedEncodingException e) {
647 throw new AssertionError("UTF-8 is unknown"); 645 throw new AssertionError("UTF-8 is unknown");
648 } 646 }
649 return request; 647 return request;
650 } 648 }
651 649
652 private static HttpReport createReportRequest(URI uri, String data, int depth) { 650 private static HttpReport createReportRequest(URI uri, String data, int depth) {
653 HttpReport request = new HttpReport(); 651 HttpReport request = new HttpReport();
654 request.setURI(uri); 652 request.setURI(uri);
655 //request.setHeader("Host", targetHost.getHostName()); 653 //request.setHeader("Host", targetHost.getHostName());
656 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); 654 request.setHeader("Host", targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort()));
657 request.setHeader("Depth", Integer.toString(depth)); 655 request.setHeader("Depth", Integer.toString(depth));
658 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 656 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
659 //request.setHeader("Content-Type", "text/xml;charset=\"UTF-8\""); 657 //request.setHeader("Content-Type", "text/xml;charset=\"UTF-8\"");
660 try { 658 try {
661 request.setEntity(new StringEntity(data)); 659 request.setEntity(new StringEntity(data));
662 } catch (UnsupportedEncodingException e) { 660 } catch (UnsupportedEncodingException e) {
663 throw new AssertionError("UTF-8 is unknown"); 661 throw new AssertionError("UTF-8 is unknown");
664 } 662 }
665 return request; 663 return request;
666 } 664 }
667 665
668 public static void fetchEvent_old(CalendarEvent calendarEvent) 666 public static void fetchEvent_old(CalendarEvent calendarEvent)
669 throws ClientProtocolException, IOException { 667 throws ClientProtocolException, IOException {
670 HttpGet request = null; 668 HttpGet request = null;
671 669
672 request = new HttpGet(); 670 request = new HttpGet();
673 request.setURI(calendarEvent.getUri()); 671 request.setURI(calendarEvent.getUri());
674 request.setHeader("Host", targetHost.getHostName()); 672 request.setHeader("Host", targetHost.getHostName());
675 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 673 request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\"");
676 674
677 HttpResponse response = httpClient.execute(targetHost, request); 675 HttpResponse response = httpClient.execute(targetHost, request);
678 676 String body = EntityUtils.toString(response.getEntity(), "UTF-8");
679 BufferedReader reader = new BufferedReader(new InputStreamReader( 677
680 response.getEntity().getContent(), "UTF-8")); 678 calendarEvent.setICSasString(body);
681 679
682 String line; 680 Log.d(TAG, "HttpResponse GET event status=" + response.getStatusLine()
683 String body = ""; 681 + " body= " + body);
684 do { 682 }
685 line = reader.readLine(); 683
686 if (line != null) 684 public static boolean getEvent(CalendarEvent calendarEvent) throws ClientProtocolException, IOException {
687 body += line + "\n"; 685 boolean Result = false;
688 } while (line != null); 686 HttpReport request = null;
689 687
690 calendarEvent.setICSasString(body); 688 //HINT: bugfix for google calendar: replace("@", "%40")
691 689 String data = XML_VERSION +
692 Log.d(TAG, "HttpResponse GET event status=" + response.getStatusLine() 690 "<C:calendar-multiget xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">" +
693 + " body= " + body); 691 "<D:prop>" +
694 } 692 "<D:getetag />" +
695 693 "<C:calendar-data />" +
696 public static boolean getEvent(CalendarEvent calendarEvent) throws ClientProtocolException, IOException { 694 "</D:prop>" +
697 boolean Result = false; 695 "<D:href>" + calendarEvent.getUri().getRawPath().replace("@", "%40") + "</D:href>" +
698 HttpReport request = null; 696 "</C:calendar-multiget>";
699 697
700 //HINT: bugfix for google calendar: replace("@", "%40") 698 URI calendarURI = null;
701 String data = XML_VERSION + 699 try {
702 "<C:calendar-multiget xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">" + 700 calendarURI = calendarEvent.calendarURL.toURI();
703 "<D:prop>" + 701 } catch (URISyntaxException e) {
704 "<D:getetag />" + 702 e.printStackTrace();
705 "<C:calendar-data />" + 703 }
706 "</D:prop>" + 704 //request = createReportRequest(calendarEvent.getUri(), data, 1);
707 "<D:href>" + calendarEvent.getUri().getRawPath().replace("@", "%40") + "</D:href>" + 705 request = createReportRequest(calendarURI, data, 1);
708 "</C:calendar-multiget>"; 706
709 707 HttpResponse response = httpClient.execute(targetHost, request);
710 URI calendarURI = null; 708 String body = EntityUtils.toString(response.getEntity(), "UTF-8");
711 try { 709
712 calendarURI = calendarEvent.calendarURL.toURI(); 710 if (calendarEvent.setICSasMultiStatus(body))
713 } catch (URISyntaxException e) { 711 Result = true;
714 e.printStackTrace(); 712
715 } 713 return Result;
716 //request = createReportRequest(calendarEvent.getUri(), data, 1); 714 }
717 request = createReportRequest(calendarURI, data, 1); 715
718 716
719 HttpResponse response = httpClient.execute(targetHost, request); 717 /**
720 718 * sends a update event request to the server
721 BufferedReader reader = new BufferedReader(new InputStreamReader( 719 *
722 response.getEntity().getContent(), "UTF-8")); 720 * @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
723 721 * @param data the full ical-data for the event
724 String line; 722 * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to update this version
725 String body = ""; 723 * @return
726 do { 724 */
727 line = reader.readLine(); 725 public boolean updateEvent(URI uri, String data, String ETag) {
728 if (line != null) 726 boolean Result = false;
729 body += line + "\n"; 727
730 } while (line != null); 728 try {
731 729 HttpPut request = createPutRequest(uri, data, 1);
732 if (calendarEvent.setICSasMultiStatus(body)) 730 request.addHeader(mstrcHeaderIfMatch, ETag);
733 Result = true; 731 HttpResponse response = httpClient.execute(targetHost, request, mContext);
734 732 checkStatus(response);
735 return Result; 733 if ((lastStatusCode == 200) || (lastStatusCode == 201) || (lastStatusCode == 204)) {
736 } 734 Result = true;
737 735 } else if (lastStatusCode == 412) {
738 736 //Precondition failed
739 /** 737 Result = false;
740 * sends a update event request to the server 738 } else if (lastStatusCode == 409) {
741 * @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 739 //Conflict
742 * @param data the full ical-data for the event 740 Result = false;
743 * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to update this version 741 } else {
744 * @return 742 Log.w(TAG, "Unkown StatusCode during creation of an event");
745 */ 743 }
746 public boolean updateEvent(URI uri, String data, String ETag) { 744 } catch (ClientProtocolException e) {
747 boolean Result = false; 745 e.printStackTrace();
748 746 } catch (IOException e) {
749 try { 747 e.printStackTrace();
750 HttpPut request = createPutRequest(uri, data, 1); 748 } catch (AuthenticationException e) {
751 request.addHeader(mstrcHeaderIfMatch, ETag); 749 e.printStackTrace();
752 HttpResponse response = httpClient.execute(targetHost, request, mContext); 750 }
753 checkStatus(response); 751 return Result;
754 if ((lastStatusCode == 200) || (lastStatusCode == 201) || (lastStatusCode == 204)) { 752 }
755 Result = true; 753
756 } else if (lastStatusCode == 412) { 754 /**
757 //Precondition failed 755 * sends a create event request to server
758 Result = false; 756 *
759 } else if (lastStatusCode == 409) { 757 * @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
760 //Conflict 758 * @param data the full ical-data for the new event
761 Result = false; 759 * @return success of this function
762 } else { 760 */
763 Log.w(TAG, "Unkown StatusCode during creation of an event"); 761 public boolean createEvent(URI uri, String data) {
764 } 762 boolean Result = false;
765 } catch (ClientProtocolException e) { 763
766 e.printStackTrace(); 764 try {
767 } catch (IOException e) { 765 HttpPut request = createPutRequest(uri, data, 1);
768 e.printStackTrace(); 766 request.addHeader(mstrcHeaderIfNoneMatch, "*");
769 } catch (AuthenticationException e) { 767 HttpResponse response = httpClient.execute(targetHost, request, mContext);
770 e.printStackTrace(); 768 checkStatus(response);
771 } 769 if (lastStatusCode == 201) {
772 return Result; 770 Result = true;
773 } 771 } else {
774 772 Log.w(TAG, "Unkown StatusCode during creation of an event");
775 /** 773 }
776 * sends a create event request to server 774 } catch (ClientProtocolException e) {
777 * @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 775 e.printStackTrace();
778 * @param data the full ical-data for the new event 776 } catch (IOException e) {
779 * @return success of this function 777 e.printStackTrace();
780 */ 778 } catch (AuthenticationException e) {
781 public boolean createEvent(URI uri, String data) { 779 e.printStackTrace();
782 boolean Result = false; 780 }
783 781 return Result;
784 try { 782 }
785 HttpPut request = createPutRequest(uri, data, 1); 783
786 request.addHeader(mstrcHeaderIfNoneMatch, "*"); 784 /**
787 HttpResponse response = httpClient.execute(targetHost, request, mContext); 785 * sends a delete event request to the server
788 checkStatus(response); 786 *
789 if (lastStatusCode == 201) { 787 * @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
790 Result = true; 788 * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to delete this version
791 } else { 789 * @return success of this function
792 Log.w(TAG, "Unkown StatusCode during creation of an event"); 790 */
793 } 791 public boolean deleteEvent(URI calendarEventUri, String ETag) {
794 } catch (ClientProtocolException e) { 792 boolean Result = false;
795 e.printStackTrace(); 793
796 } catch (IOException e) { 794 try {
797 e.printStackTrace(); 795 HttpDelete request = createDeleteRequest(calendarEventUri);
798 } catch (AuthenticationException e) { 796 request.addHeader(mstrcHeaderIfMatch, ETag);
799 e.printStackTrace(); 797 HttpResponse response = httpClient.execute(targetHost, request, mContext);
800 } 798 checkStatus(response);
801 return Result; 799 if ((lastStatusCode == 204) || (lastStatusCode == 200)) {
802 } 800 Result = true;
803 801 } else {
804 /** 802 Log.w(TAG, "Unkown StatusCode during deletion of an event");
805 * sends a delete event request to the server 803 }
806 * @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 804 } catch (ClientProtocolException e) {
807 * @param ETag the ETAG of this event is send within the "If-Match" Parameter to tell the server only to delete this version 805 e.printStackTrace();
808 * @return success of this function 806 } catch (IOException e) {
809 */ 807 if (lastStatusCode == 404) {
810 public boolean deleteEvent(URI calendarEventUri, String ETag) { 808 //the event has already been deleted on server side. no action needed
811 boolean Result = false; 809 Result = true;
812 810 } else {
813 try { 811 e.printStackTrace();
814 HttpDelete request = createDeleteRequest(calendarEventUri); 812 }
815 request.addHeader(mstrcHeaderIfMatch, ETag); 813 } catch (AuthenticationException e) {
816 HttpResponse response = httpClient.execute(targetHost, request, mContext); 814 e.printStackTrace();
817 checkStatus(response); 815 }
818 if ((lastStatusCode == 204) || (lastStatusCode == 200)) { 816
819 Result = true; 817 return Result;
820 } else { 818 }
821 Log.w(TAG, "Unkown StatusCode during deletion of an event"); 819
822 } 820 /**
823 } catch (ClientProtocolException e) { 821 * returns the ETAG send by the last server response.
824 e.printStackTrace(); 822 *
825 } catch (IOException e) { 823 * @return the ETAG
826 if (lastStatusCode == 404) { 824 */
827 //the event has already been deleted on server side. no action needed 825 public String getLastETag() {
828 Result = true; 826 return lastETag;
829 } else { 827 }
830 e.printStackTrace(); 828
831 } 829 /**
832 } catch (AuthenticationException e) { 830 * returns the DAV-Options send by the last server response.
833 e.printStackTrace(); 831 *
834 } 832 * @return the DAV-Options
835 833 */
836 return Result; 834 public String getLastDav() {
837 } 835 return lastDav;
838 836 }
839 /** 837
840 * returns the ETAG send by the last server response. 838 public void setVersion(String version) {
841 * @return the ETAG 839 VERSION = version;
842 */ 840 ((AbstractHttpClient) httpClient).getParams()
843 public String getLastETag() { 841 .setParameter(CoreProtocolPNames.USER_AGENT, this.USER_AGENT + " Version:" + VERSION);
844 return lastETag; 842 }
845 } 843
846 844 public void setAccount(Account account) {
847 /** 845 this.mAccount = account;
848 * returns the DAV-Options send by the last server response. 846 }
849 * @return the DAV-Options 847
850 */ 848 public void setProvider(ContentProviderClient provider) {
851 public String getLastDav() { 849 this.mProvider = provider;
852 return lastDav; 850 }
853 }
854
855 public void setVersion(String version) {
856 VERSION = version;
857 ((AbstractHttpClient) httpClient).getParams().setParameter(CoreProtocolPNames.USER_AGENT, this.USER_AGENT + " Version:" + VERSION);
858 }
859
860 public void setAccount(Account account) {
861 this.mAccount = account;
862 }
863 public void setProvider(ContentProviderClient provider) {
864 this.mProvider = provider;
865 }
866 } 851 }

mercurial