/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.io.caldav.internal; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.conn.ssl.AllowAllHostnameVerifier; import org.apache.http.conn.ssl.SSLContextBuilder; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.HttpClientBuilder; import org.joda.time.DateTimeZone; import org.openhab.io.caldav.CalDavEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.sardine.Sardine; import com.github.sardine.impl.SardineImpl; import net.fortuna.ical4j.data.CalendarOutputter; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.TimeZone; import net.fortuna.ical4j.model.TimeZoneRegistry; import net.fortuna.ical4j.model.TimeZoneRegistryFactory; import net.fortuna.ical4j.model.ValidationException; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.property.Clazz; import net.fortuna.ical4j.model.property.Description; import net.fortuna.ical4j.model.property.DtEnd; import net.fortuna.ical4j.model.property.DtStart; import net.fortuna.ical4j.model.property.LastModified; import net.fortuna.ical4j.model.property.ProdId; import net.fortuna.ical4j.model.property.Summary; import net.fortuna.ical4j.model.property.Uid; import net.fortuna.ical4j.model.property.Version; public final class Util { private static final String HTTP_URL_PREFIX = "http://"; private static final Logger log = LoggerFactory.getLogger(Util.class); private Util() { } public static Calendar createCalendar(CalDavEvent calDavEvent, DateTimeZone timeZone) { TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); TimeZone timezone = registry.getTimeZone(timeZone.getID()); Calendar calendar = new Calendar(); calendar.getProperties().add(Version.VERSION_2_0); calendar.getProperties().add(new ProdId("openHAB")); VEvent vEvent = new VEvent(); vEvent.getProperties().add(new Summary(calDavEvent.getName())); vEvent.getProperties().add(new Description(calDavEvent.getContent())); final DtStart dtStart = new DtStart(new net.fortuna.ical4j.model.DateTime(calDavEvent.getStart().toDate())); dtStart.setTimeZone(timezone); vEvent.getProperties().add(dtStart); final DtEnd dtEnd = new DtEnd(new net.fortuna.ical4j.model.DateTime(calDavEvent.getEnd().toDate())); dtEnd.setTimeZone(timezone); vEvent.getProperties().add(dtEnd); vEvent.getProperties().add(new Uid(calDavEvent.getId())); vEvent.getProperties().add(Clazz.PUBLIC); vEvent.getProperties() .add(new LastModified(new net.fortuna.ical4j.model.DateTime(calDavEvent.getLastChanged().toDate()))); calendar.getComponents().add(vEvent); return calendar; } public static File getCachePath(String calendarKey) { return new File(CalDavLoaderImpl.CACHE_PATH + "/" + calendarKey); } public static String getFilename(String name) { name = FilenameUtils.getBaseName(name); name = name.replaceAll("[^a-zA-Z0-9-_]", "_"); return name; } public static File getCacheFile(String calendarId, String filename) { return new File(getCachePath(calendarId), filename + ".ics"); } public static void storeToDisk(String calendarId, String filename, Calendar calendar) { File cacheFile = getCacheFile(calendarId, filename); try { FileOutputStream fout = new FileOutputStream(cacheFile); CalendarOutputter outputter = new CalendarOutputter(); outputter.setValidating(false); outputter.output(calendar, fout); fout.flush(); fout.close(); } catch (IOException e) { log.error("cannot store event '{}' to disk (path={}): {}", filename, cacheFile.getAbsoluteFile(), e.getMessage()); } catch (ValidationException e) { log.error("cannot store event '{}' to disk (path={}): {}", filename, cacheFile.getAbsoluteFile(), e.getMessage()); } } public static Sardine getConnection(CalDavConfig config) { if (config.isDisableCertificateVerification()) { if (config.getUrl().startsWith(HTTP_URL_PREFIX)) { log.error("do not use '{}' if no ssl is used", CalDavLoaderImpl.PROP_DISABLE_CERTIFICATE_VERIFICATION); } log.trace("connecting to caldav '{}' with disabled certificate verification (url={}, username={}, password={})", config.getKey(), config.getUrl(), config.getUsername(), config.getPassword()); HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().setHostnameVerifier(new AllowAllHostnameVerifier()); try { httpClientBuilder.setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build()); } catch (KeyManagementException e) { log.error("error verifying certificate", e); } catch (NoSuchAlgorithmException e) { log.error("error verifying certificate", e); } catch (KeyStoreException e) { log.error("error verifying certificate", e); } if (StringUtils.isEmpty(config.getUsername()) && StringUtils.isEmpty(config.getPassword())) { log.trace("connecting without credentials for '{}'", config.getKey()); return new SardineImpl(httpClientBuilder); } else { return new SardineImpl(httpClientBuilder, config.getUsername(), config.getPassword()); } } else { log.trace("connecting to caldav '{}' (url={}, username={}, password={})", config.getKey(), config.getUrl(), config.getUsername(), config.getPassword()); if (StringUtils.isEmpty(config.getUsername()) && StringUtils.isEmpty(config.getPassword())) { log.trace("connecting without credentials for '{}'", config.getKey()); return new SardineImpl(); } else { return new SardineImpl(config.getUsername(), config.getPassword()); } } } }