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 } |