From: Tobias Hößl Date: Sat, 4 Aug 2012 08:46:11 +0000 (+0000) Subject: Move friendica-specific parts into an own subdirectory X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=b8234a1cb8d6603bf527fa12f6be9062b35efa8d;p=friendica-addons.git Move friendica-specific parts into an own subdirectory --- diff --git a/dav/FriendicaACLPlugin.inc.php b/dav/FriendicaACLPlugin.inc.php deleted file mode 100644 index 6bb8fc99..00000000 --- a/dav/FriendicaACLPlugin.inc.php +++ /dev/null @@ -1,31 +0,0 @@ -get_baseurl()); -$path = "/"; -if (isset($uri["path"]) && strlen($uri["path"]) > 1) { - $path = $uri["path"] . "/"; -} - -define("CALDAV_SQL_DB", ""); -define("CALDAV_SQL_PREFIX", "dav_"); -define("CALDAV_URL_PREFIX", $path . "dav/"); -define("DAV_APPNAME", "Friendica"); - -define("CALDAV_NAMESPACE_PRIVATE", 1); -define("CALDAV_FRIENDICA_MINE", "friendica-mine"); -define("CALDAV_FRIENDICA_CONTACTS", "friendica-contacts"); - -$GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"] = array(CALDAV_FRIENDICA_MINE, CALDAV_FRIENDICA_CONTACTS); -$GLOBALS["CALDAV_PRIVATE_SYSTEM_BACKENDS"] = array("Sabre_CalDAV_Backend_Friendica"); - -define("CARDDAV_NAMESPACE_PRIVATE", 1); -define("CARDDAV_FRIENDICA_CONTACT", "friendica"); -$GLOBALS["CARDDAV_PRIVATE_SYSTEM_ADDRESSBOOKS"] = array(CARDDAV_FRIENDICA_CONTACT); -$GLOBALS["CARDDAV_PRIVATE_SYSTEM_BACKENDS"] = array("Sabre_CardDAV_Backend_Friendica"); - -$GLOBALS["CALDAV_ACL_PLUGIN_CLASS"] = "Sabre_DAVACL_Plugin_Friendica"; - -define("CALDAV_MAX_YEAR", date("Y") + 5); - -/** - * @return int - */ -function getCurMicrotime() -{ - list($usec, $sec) = explode(" ", microtime()); - return sprintf("%14.0f", $sec * 10000 + $usec * 10000); -} // function getCurMicrotime - -/** - * - */ -function debug_time() -{ - $cur = getCurMicrotime(); - if ($GLOBALS["debug_time_last"] > 0) { - echo "Zeit: " . ($cur - $GLOBALS["debug_time_last"]) . "
\n"; - } - $GLOBALS["debug_time_last"] = $cur; -} - - -/** - * @param string $username - * @return int|null - */ -function dav_compat_username2id($username = "") -{ - $x = q("SELECT `uid` FROM `user` WHERE `nickname`='%s' AND `account_removed` = 0 AND `account_expired` = 0", dbesc($username)); - if (count($x) == 1) return $x[0]["uid"]; - return null; -} - -/** - * @param int $id - * @return string - */ -function dav_compat_id2username($id = 0) -{ - $x = q("SELECT `nickname` FROM `user` WHERE `uid` = %i AND `account_removed` = 0 AND `account_expired` = 0", IntVal($id)); - if (count($x) == 1) return $x[0]["nickname"]; - return ""; -} - -/** - * @return int - */ -function dav_compat_get_curr_user_id() -{ - $a = get_app(); - return IntVal($a->user["uid"]); -} - - -/** - * @param string $principalUri - * @return int|null - */ -function dav_compat_principal2uid($principalUri = "") -{ - if (strlen($principalUri) == 0) return null; - if ($principalUri[0] == "/") $principalUri = substr($principalUri, 1); - if (strpos($principalUri, "principals/users/") !== 0) return null; - $username = substr($principalUri, strlen("principals/users/")); - return dav_compat_username2id($username); -} - -/** - * @param string $principalUri - * @return array|null - */ -function dav_compat_principal2namespace($principalUri = "") -{ - if (strlen($principalUri) == 0) return null; - if ($principalUri[0] == "/") $principalUri = substr($principalUri, 1); - - if (strpos($principalUri, "principals/users/") !== 0) return null; - $username = substr($principalUri, strlen("principals/users/")); - return array("namespace" => CALDAV_NAMESPACE_PRIVATE, "namespace_id" => dav_compat_username2id($username)); -} - - -/** - * @return string - */ -function dav_compat_currentUserPrincipal() -{ - $a = get_app(); - return "principals/users/" . strtolower($a->user["nickname"]); -} - - -/** - * @param string $name - * @return null|string - */ -function dav_compat_getRequestVar($name = "") -{ - if (isset($_REQUEST[$name])) return $_REQUEST[$name]; - else return null; -} - -/** - * @param $text - * @return null|string - */ -function dav_compat_parse_text_serverside($text) -{ - return dav_compat_getRequestVar($text); -} - -/** - * @param string $uri - */ -function dav_compat_redirect($uri = "") -{ - goaway($uri); -} - - -/** - * @return null|int - */ -function dav_compat_get_max_private_calendars() -{ - return null; -} - -/** - * @return string - */ -function dav_compat_get_hostname() { - $a = get_app(); - return $a->get_hostname(); -} - -/** - * @param int $namespace - * @param int $namespace_id - * @param string $uri - * @param array $calendar - * @return Sabre_CalDAV_Backend_Common - * @throws Exception - */ -function wdcal_calendar_factory($namespace, $namespace_id, $uri, $calendar = null) -{ - switch ($namespace) { - case CALDAV_NAMESPACE_PRIVATE: - if ($uri == CALDAV_FRIENDICA_MINE || $uri == CALDAV_FRIENDICA_CONTACTS) return Sabre_CalDAV_Backend_Friendica::getInstance(); - else return Sabre_CalDAV_Backend_Private::getInstance(); - } - throw new Exception("Calendar Namespace not found"); -} - -/** - * @param int $calendar_id - * @return Sabre_CalDAV_Backend_Common - * @throws Exception - */ -function wdcal_calendar_factory_by_id($calendar_id) -{ - $calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendar_id); - return wdcal_calendar_factory($calendar["namespace"], $calendar["namespace_id"], $calendar["uri"], $calendar); -} - -/** - * @param int $user_id - * @param bool $withcheck - * @return array - */ -function wdcal_create_std_calendars_get_statements($user_id, $withcheck = true) -{ - $stms = array(); - $a = get_app(); - $uris = array( - 'private' => t("Private Calendar"), - CALDAV_FRIENDICA_MINE => t("Friendica Events: Mine"), - CALDAV_FRIENDICA_CONTACTS => t("Friendica Events: Contacts"), - ); - foreach ($uris as $uri => $name) { - $cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($uri)); - if (count($cals) == 0 || !$withcheck) $stms[] = - sprintf("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `displayname`, `timezone`, `ctag`, `uri`, `has_vevent`, `has_vtodo`) - VALUES (%d, %d, '%s', '%s', 1, '%s', 1, 0)", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($name), dbesc($a->timezone), dbesc($uri)); - } - return $stms; -} - -/** - */ -function wdcal_create_std_calendars() -{ - $a = get_app(); - if (!local_user()) return; - - $privates = q("SELECT COUNT(*) num FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); - if ($privates[0]["num"] > 0) return; - - $stms = wdcal_create_std_calendars_get_statements($a->user["uid"]); - foreach ($stms as $stmt) q($stmt); -} - - - - -/** - * @param int $user_id - * @param bool $withcheck - * @return array - */ -function wdcal_create_std_addressbooks_get_statements($user_id, $withcheck = true) -{ - $stms = array(); - $a = get_app(); - $uris = array( - 'private' => t("Private Addresses"), - CARDDAV_FRIENDICA_CONTACT => t("Friendica Contacts"), - ); - foreach ($uris as $uri => $name) { - $cals = q("SELECT * FROM %s%saddressbooks WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($uri)); - if (count($cals) == 0 || !$withcheck) $stms[] = - sprintf("INSERT INTO %s%saddressbooks (`namespace`, `namespace_id`, `displayname`, `ctag`, `uri`) - VALUES (%d, %d, '%s', 1, '%s')", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CARDDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($name), dbesc($uri)); - } - return $stms; -} - -/** - */ -function wdcal_create_std_addressbooks() -{ - $a = get_app(); - if (!local_user()) return; - - $privates = q("SELECT COUNT(*) num FROM %s%addressbooks WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CARDDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); - if ($privates[0]["num"] > 0) return; - - $stms = wdcal_create_std_addressbooks_get_statements($a->user["uid"]); - foreach ($stms as $stmt) q($stmt); -} diff --git a/dav/database-init.inc.php b/dav/database-init.inc.php deleted file mode 100644 index 7c0d23a3..00000000 --- a/dav/database-init.inc.php +++ /dev/null @@ -1,270 +0,0 @@ -q($st); - if ($db->error) $errors[] = $db->error; - } - - return $errors; -} - -/** - * @return array - */ -function dav_upgrade_tables() -{ - $ver = dav_check_tables(); - if (!in_array($ver, array(1))) return array("Unknown error"); - - $stms = dav_get_update_statements($ver); - $errors = array(); - - global $db; - foreach ($stms as $st) { - $db->q($st); - if ($db->error) $errors[] = $db->error; - } - - return $errors; -} \ No newline at end of file diff --git a/dav/dav.php b/dav/dav.php index 05916d01..40040dfe 100644 --- a/dav/dav.php +++ b/dav/dav.php @@ -8,5 +8,5 @@ $_v = explode(".", phpversion()); if ($_v[0] > 5 || ($_v[0] == 5 && $_v[1] >= 3)) { - require(__DIR__ . "/main.php"); + require(__DIR__ . "/friendica/main.php"); } \ No newline at end of file diff --git a/dav/dav_caldav_backend_virtual_friendica.inc.php b/dav/dav_caldav_backend_virtual_friendica.inc.php deleted file mode 100644 index d2810b4f..00000000 --- a/dav/dav_caldav_backend_virtual_friendica.inc.php +++ /dev/null @@ -1,253 +0,0 @@ - 0"; - break; - default: - throw new Sabre_DAV_Exception_NotFound(); - } - - $r = q("SELECT * FROM `event` WHERE `uid` = %d " . $sql_where . " ORDER BY `start`", IntVal($calendar["namespace_id"])); - - foreach ($r as $row) { - $uid = $calendar["uri"] . "-" . $row["id"]; - $vevent = dav_create_empty_vevent($uid); - $component = dav_get_eventComponent($vevent); - - if ($row["adjust"]) { - $start = datetime_convert('UTC', date_default_timezone_get(), $row["start"]); - $finish = datetime_convert('UTC', date_default_timezone_get(), $row["finish"]); - } else { - $start = $row["start"]; - $finish = $row["finish"]; - } - - $summary = ($row["summary"] != "" ? $row["summary"] : $row["desc"]); - $desc = ($row["summary"] != "" ? $row["desc"] : ""); - $component->add("SUMMARY", icalendar_sanitize_string($summary)); - $component->add("LOCATION", icalendar_sanitize_string($row["location"])); - $component->add("DESCRIPTION", icalendar_sanitize_string($desc)); - - $ts_start = wdcal_mySql2PhpTime($start); - $ts_end = wdcal_mySql2PhpTime($start); - - $allday = (strpos($start, "00:00:00") !== false && strpos($finish, "00:00:00") !== false); - $type = ($allday ? Sabre_VObject_Property_DateTime::DATE : Sabre_VObject_Property_DateTime::LOCALTZ); - - $datetime_start = new Sabre_VObject_Property_DateTime("DTSTART"); - $datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_start)), $type); - $datetime_end = new Sabre_VObject_Property_DateTime("DTEND"); - $datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_end)), $type); - - $component->add($datetime_start); - $component->add($datetime_end); - - $data = $vevent->serialize(); - - q("INSERT INTO %s%scal_virtual_object_cache (`calendar_id`, `data_uri`, `data_summary`, `data_location`, `data_start`, `data_end`, `data_allday`, `data_type`, - `calendardata`, `size`, `etag`) VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', %d, '%s')", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId, dbesc($uid), dbesc($summary), dbesc($row["location"]), dbesc($row["start"]), dbesc($row["finish"]), - ($allday ? 1 : 0), dbesc(($row["type"] == "birthday" ? "birthday" : "")), dbesc($data), strlen($data), md5($data)); - - } - - } - - - /** - * @param array $row - * @param array $calendar - * @param string $base_path - * @return array - */ - private function jqcal2wdcal($row, $calendar, $base_path) - { - if ($row["adjust"]) { - $start = datetime_convert('UTC', date_default_timezone_get(), $row["start"]); - $finish = datetime_convert('UTC', date_default_timezone_get(), $row["finish"]); - } else { - $start = $row["start"]; - $finish = $row["finish"]; - } - - $allday = (strpos($start, "00:00:00") !== false && strpos($finish, "00:00:00") !== false); - - $summary = (($row["summary"]) ? $row["summary"] : substr(preg_replace("/\[[^\]]*\]/", "", $row["desc"]), 0, 100)); - - return array( - "jq_id" => $row["id"], - "ev_id" => $row["id"], - "summary" => escape_tags($summary), - "start" => wdcal_mySql2PhpTime($start), - "end" => wdcal_mySql2PhpTime($finish), - "is_allday" => ($allday ? 1 : 0), - "is_moredays" => (substr($start, 0, 10) != substr($finish, 0, 10)), - "is_recurring" => ($row["type"] == "birthday"), - "color" => "7878ff", - "is_editable" => 0, - "is_editable_quick" => 0, - "location" => $row["location"], - "attendees" => '', - "has_notification" => 0, - "url_detail" => $base_path . "/events/event/" . $row["id"], - "url_edit" => "", - "special_type" => ($row["type"] == "birthday" ? "birthday" : ""), - ); - } - - - /** - * @param int $calendarId - * @param string $date_from - * @param string $date_to - * @param string $base_path - * @throws Sabre_DAV_Exception_NotFound - * @return array - */ - public function listItemsByRange($calendarId, $date_from, $date_to, $base_path) - { - $calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendarId); - - if ($calendar["namespace"] != CALDAV_NAMESPACE_PRIVATE) throw new Sabre_DAV_Exception_NotFound(); - - switch ($calendar["uri"]) { - case CALDAV_FRIENDICA_MINE: - $sql_where = " AND cid = 0"; - break; - case CALDAV_FRIENDICA_CONTACTS: - $sql_where = " AND cid > 0"; - break; - default: - throw new Sabre_DAV_Exception_NotFound(); - } - - if ($date_from != "") { - if (is_numeric($date_from)) $sql_where .= " AND `finish` >= '" . date("Y-m-d H:i:s", $date_from) . "'"; - else $sql_where .= " AND `finish` >= '" . dbesc($date_from) . "'"; - } - if ($date_to != "") { - if (is_numeric($date_to)) $sql_where .= " AND `start` <= '" . date("Y-m-d H:i:s", $date_to) . "'"; - else $sql_where .= " AND `start` <= '" . dbesc($date_to) . "'"; - } - $ret = array(); - - $r = q("SELECT * FROM `event` WHERE `uid` = %d " . $sql_where . " ORDER BY `start`", IntVal($calendar["namespace_id"])); - - $a = get_app(); - foreach ($r as $row) { - $r = $this->jqcal2wdcal($row, $calendar, $a->get_baseurl()); - $r["calendar_id"] = $calendar["id"]; - $ret[] = $r; - } - - return $ret; - } - - - /** - * Returns a list of calendars for a principal. - * - * Every project is an array with the following keys: - * * id, a unique id that will be used by other functions to modify the - * calendar. This can be the same as the uri or a database key. - * * uri, which the basename of the uri with which the calendar is - * accessed. - * * principaluri. The owner of the calendar. Almost always the same as - * principalUri passed to this method. - * - * Furthermore it can contain webdav properties in clark notation. A very - * common one is '{DAV:}displayname'. - * - * @param string $principalUri - * @return array - */ - public function getCalendarsForUser($principalUri) - { - $n = dav_compat_principal2namespace($principalUri); - if ($n["namespace"] != $this->getNamespace()) return array(); - - $cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $this->getNamespace(), IntVal($n["namespace_id"])); - $ret = array(); - foreach ($cals as $cal) { - if (!in_array($cal["uri"], $GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"])) continue; - - $dat = array( - "id" => $cal["id"], - "uri" => $cal["uri"], - "principaluri" => $principalUri, - '{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag'] ? $cal['ctag'] : '0', - '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array("VEVENT")), - "calendar_class" => "Sabre_CalDAV_Calendar_Virtual", - ); - foreach ($this->propertyMap as $key=> $field) $dat[$key] = $cal[$field]; - - $ret[] = $dat; - } - - return $ret; - } - - /** - * @param int $calendar_id - * @param int $calendarobject_id - * @return string - */ - function getItemDetailRedirect($calendar_id, $calendarobject_id) - { - $a = get_app(); - $item = q("SELECT `id` FROM `item` WHERE `event-id` = %d AND `uid` = %d AND deleted = 0", IntVal($calendarobject_id), $a->user["uid"]); - if (count($item) == 0) return "/events/"; - return "/display/" . $a->user["nickname"] . "/" . IntVal($item[0]["id"]); - - } -} diff --git a/dav/dav_carddav_backend_virtual_friendica.inc.php b/dav/dav_carddav_backend_virtual_friendica.inc.php deleted file mode 100644 index 3d7e0974..00000000 --- a/dav/dav_carddav_backend_virtual_friendica.inc.php +++ /dev/null @@ -1,205 +0,0 @@ - $books[0]["id"], - 'uri' => "friendica", - 'principaluri' => $principalUri, - '{DAV:}displayname' => t("Friendica-Contacts"), - '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => t("Your Friendica-Contacts"), - '{http://calendarserver.org/ns/}getctag' => $ctag, - '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data' => - new Sabre_CardDAV_Property_SupportedAddressData(), - ); - - return $addressBooks; - - } - - /** - * @static - * @param array $contact - * @return array - */ - private static function dav_contactarr2vcardsource($contact) - { - $name = explode(" ", $contact["name"]); - $first_name = $last_name = ""; - $middle_name = array(); - $num = count($name); - for ($i = 0; $i < $num && $first_name == ""; $i++) if ($name[$i] != "") { - $first_name = $name[$i]; - unset($name[$i]); - } - for ($i = $num - 1; $i >= 0 && $last_name == ""; $i--) if (isset($name[$i]) && $name[$i] != "") { - $last_name = $name[$i]; - unset($name[$i]); - } - foreach ($name as $n) if ($n != "") $middle_name[] = $n; - $vcarddata = new vcard_source_data($first_name, implode(" ", $middle_name), $last_name); - $vcarddata->homepages[] = new vcard_source_data_homepage("pref", $contact["url"]); - $vcarddata->last_update = ($contact["last-update"] > 0 ? $contact["last-update"] : $contact["created"]); - - $photo = q("SELECT * FROM photo WHERE `contact-id` = %d ORDER BY scale DESC", $contact["id"]); //prefer size 80x80 - if ($photo && count($photo) > 0) { - $photodata = new vcard_source_data_photo(); - $photodata->width = $photo[0]["width"]; - $photodata->height = $photo[0]["height"]; - $photodata->type = "JPEG"; - $photodata->binarydata = $photo[0]["data"]; - $vcarddata->photo = $photodata; - } - - switch ($contact["network"]) { - case "face": - $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("facebook", $contact["notify"], "http://www.facebook.com/" . $contact["notify"]); - break; - case "dfrn": - $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("dfrn", $contact["nick"], $contact["url"]); - break; - case "twitter": - $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("twitter", $contact["nick"], "http://twitter.com/" . $contact["nick"]); // @TODO Stimmt das? - break; - } - - $vcard = vcard_source_compile($vcarddata); - return array( - "id" => $contact["id"], - "carddata" => $vcard, - "uri" => $contact["id"] . ".vcf", - "lastmodified" => wdcal_mySql2PhpTime($vcarddata->last_update), - "etag" => md5($vcard), - "size" => strlen($vcard), - ); - - } - - /** - * @static - * @param int $addressbookId - * @throws Sabre_DAV_Exception_NotFound - */ - static protected function createCache_internal($addressbookId) { - //$notin = (count($exclude_ids) > 0 ? " AND id NOT IN (" . implode(", ", $exclude_ids) . ") " : ""); - $addressbook = q("SELECT * FROM %s%saddressbooks WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($addressbookId)); - if (count($addressbook) != 1 || $addressbook[0]["namespace"] != CARDDAV_NAMESPACE_PRIVATE) throw new Sabre_DAV_Exception_NotFound(); - $contacts = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0 ORDER BY `name` ASC", $addressbook[0]["namespace_id"]); - - $retdata = array(); - foreach ($contacts as $contact) { - $x = static::dav_contactarr2vcardsource($contact); - q("INSERT INTO %s%saddressbookobjects (`addressbook_id`, `contact`, `carddata`, `uri`, `lastmodified`, `etag`, `size`) VALUES (%d, %d, '%s', '%s', NOW(), '%s', %d)", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $addressbookId, $contact["id"], dbesc($x["carddata"]), dbesc($x["uri"]), dbesc($x["etag"]), $x["size"] - ); - } - } - - - /** - * Updates a card. - * - * The addressbook id will be passed as the first argument. This is the - * same id as it is returned from the getAddressbooksForUser method. - * - * The cardUri is a base uri, and doesn't include the full path. The - * cardData argument is the vcard body, and is passed as a string. - * - * It is possible to return an ETag from this method. This ETag should - * match that of the updated resource, and must be enclosed with double - * quotes (that is: the string itself must contain the actual quotes). - * - * You should only return the ETag if you store the carddata as-is. If a - * subsequent GET request on the same card does not have the same body, - * byte-by-byte and you did return an ETag here, clients tend to get - * confused. - * - * If you don't return an ETag, you can just return null. - * - * @param string $addressBookId - * @param string $cardUri - * @param string $cardData - * @throws Sabre_DAV_Exception_Forbidden - * @return string|null - */ - public function updateCard($addressBookId, $cardUri, $cardData) - { - $x = explode("-", $addressBookId); - - $etag = md5($cardData); - q("UPDATE %s%scards SET carddata = '%s', lastmodified = %d, etag = '%s', size = %d, manually_edited = 1 WHERE uri = '%s' AND namespace = %d AND namespace_id =%d", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($cardData), time(), $etag, strlen($cardData), dbesc($cardUri), IntVal($x[10]), IntVal($x[1]) - ); - q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1])); - - return '"' . $etag . '"'; - } - - /** - * Deletes a card - * - * @param string $addressBookId - * @param string $cardUri - * @throws Sabre_DAV_Exception_Forbidden - * @return bool - */ - public function deleteCard($addressBookId, $cardUri) - { - $x = explode("-", $addressBookId); - - q("UPDATE %s%scards SET manually_deleted = 1 WHERE namespace = %d AND namespace_id = %d AND uri = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($cardUri)); - q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1])); - - return true; - } -} diff --git a/dav/dav_friendica_auth.inc.php b/dav/dav_friendica_auth.inc.php deleted file mode 100644 index acc33fa1..00000000 --- a/dav/dav_friendica_auth.inc.php +++ /dev/null @@ -1,93 +0,0 @@ -currentUser); - } - - /** - * @return null|string - */ - public function getCurrentUser() { - return $this->currentUser; - } - - /** - * Authenticates the user based on the current request. - * - * If authentication is successful, true must be returned. - * If authentication fails, an exception must be thrown. - * - * @param Sabre_DAV_Server $server - * @param string $realm - * @throws Sabre_DAV_Exception_NotAuthenticated - * @return bool - */ - public function authenticate(Sabre_DAV_Server $server, $realm) { - - $a = get_app(); - if (isset($a->user["uid"])) { - $this->currentUser = strtolower($a->user["nickname"]); - return true; - } - - $auth = new Sabre_HTTP_BasicAuth(); - $auth->setHTTPRequest($server->httpRequest); - $auth->setHTTPResponse($server->httpResponse); - $auth->setRealm($realm); - $userpass = $auth->getUserPass(); - if (!$userpass) { - $auth->requireLogin(); - throw new Sabre_DAV_Exception_NotAuthenticated('No basic authentication headers were found'); - } - - // Authenticates the user - if (!$this->validateUserPass($userpass[0],$userpass[1])) { - $auth->requireLogin(); - throw new Sabre_DAV_Exception_NotAuthenticated('Username or password does not match'); - } - $this->currentUser = strtolower($userpass[0]); - return true; - } - - - /** - * @param string $username - * @param string $password - * @return bool - */ - protected function validateUserPass($username, $password) { - $encrypted = hash('whirlpool',trim($password)); - $r = q("SELECT COUNT(*) anz FROM `user` WHERE `nickname` = '%s' AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `verified` = 1 LIMIT 1", - dbesc(trim($username)), - dbesc($encrypted) - ); - return ($r[0]["anz"] == 1); - } - -} diff --git a/dav/dav_friendica_principal.inc.php b/dav/dav_friendica_principal.inc.php deleted file mode 100644 index 780bcd24..00000000 --- a/dav/dav_friendica_principal.inc.php +++ /dev/null @@ -1,218 +0,0 @@ -authBackend = &$authBackend; - - } - - - /** - * @var Sabre_DAVACL_IPrincipalBackend|null - */ - private static $intstance = null; - - /** - * @static - * @return Sabre_DAVACL_IPrincipalBackend - */ - public static function &getInstance() { - if (is_null(self::$intstance)) { - $authBackend = Sabre_DAV_Auth_Backend_Std::getInstance(); - self::$intstance = new Sabre_DAVACL_PrincipalBackend_Std($authBackend); - } - return self::$intstance; - } - - /** - * Returns a list of principals based on a prefix. - * - * This prefix will often contain something like 'principals'. You are only - * expected to return principals that are in this base path. - * - * You are expected to return at least a 'uri' for every user, you can - * return any additional properties if you wish so. Common properties are: - * {DAV:}displayname - * {http://sabredav.org/ns}email-address - This is a custom SabreDAV - * field that's actualy injected in a number of other properties. If - * you have an email address, use this property. - * - * @param string $prefixPath - * @return array - */ - public function getPrincipalsByPrefix($prefixPath) - { - - // This backend only support principals in one collection - if ($prefixPath !== $this->prefix) return array(); - - $users = array(); - - $r = q("SELECT `nickname` FROM `user` WHERE `nickname` = '%s'", escape_tags($this->authBackend->getCurrentUser()) ); - foreach ($r as $t) { - $users[] = array( - 'uri' => $this->prefix . '/' . strtolower($t['nickname']), - '{DAV:}displayname' => $t['nickname'], - ); - } - - return $users; - - } - - /** - * Returns a specific principal, specified by it's path. - * The returned structure should be the exact same as from - * getPrincipalsByPrefix. - * - * @param string $path - * @return array - */ - public function getPrincipalByPath($path) - { - - list($prefixPath, $userName) = Sabre_DAV_URLUtil::splitPath($path); - - // This backend only support principals in one collection - if ($prefixPath !== $this->prefix) return null; - - $r = q("SELECT `nickname` FROM `user` WHERE `nickname` = '%s'", escape_tags($userName) ); - if (count($r) == 0) return array(); - - return array( - 'uri' => $this->prefix . '/' . strtolower($r[0]['nickname']), - '{DAV:}displayname' => $r[0]['nickname'], - ); - - } - - - function getGroupMemberSet($principal) - { - return array(); - } - - function getGroupMembership($principal) - { - return array(); - } - - - /** - * Updates the list of group members for a group principal. - * - * The principals should be passed as a list of uri's. - * - * @param string $principal - * @param array $members - * @throws Sabre_DAV_Exception - * @return void - */ - public function setGroupMemberSet($principal, array $members) - { - throw new Sabre_DAV_Exception('Operation not supported'); - } - - /** - * Updates one ore more webdav properties on a principal. - * - * The list of mutations is supplied as an array. Each key in the array is - * a propertyname, such as {DAV:}displayname. - * - * Each value is the actual value to be updated. If a value is null, it - * must be deleted. - * - * This method should be atomic. It must either completely succeed, or - * completely fail. Success and failure can simply be returned as 'true' or - * 'false'. - * - * It is also possible to return detailed failure information. In that case - * an array such as this should be returned: - * - * array( - * 200 => array( - * '{DAV:}prop1' => null, - * ), - * 201 => array( - * '{DAV:}prop2' => null, - * ), - * 403 => array( - * '{DAV:}prop3' => null, - * ), - * 424 => array( - * '{DAV:}prop4' => null, - * ), - * ); - * - * In this previous example prop1 was successfully updated or deleted, and - * prop2 was succesfully created. - * - * prop3 failed to update due to '403 Forbidden' and because of this prop4 - * also could not be updated with '424 Failed dependency'. - * - * This last example was actually incorrect. While 200 and 201 could appear - * in 1 response, if there's any error (403) the other properties should - * always fail with 423 (failed dependency). - * - * But anyway, if you don't want to scratch your head over this, just - * return true or false. - * - * @param string $path - * @param array $mutations - * @return array|bool - */ - function updatePrincipal($path, $mutations) - { - // TODO: Implement updatePrincipal() method. - } - - /** - * This method is used to search for principals matching a set of - * properties. - * - * This search is specifically used by RFC3744's principal-property-search - * REPORT. You should at least allow searching on - * http://sabredav.org/ns}email-address. - * - * The actual search should be a unicode-non-case-sensitive search. The - * keys in searchProperties are the WebDAV property names, while the values - * are the property values to search on. - * - * If multiple properties are being searched on, the search should be - * AND'ed. - * - * This method should simply return an array with full principal uri's. - * - * If somebody attempted to search on a property the backend does not - * support, you should simply return 0 results. - * - * You can also just return 0 results if you choose to not support - * searching at all, but keep in mind that this may stop certain features - * from working. - * - * @param string $prefixPath - * @param array $searchProperties - * @return array - */ - function searchPrincipals($prefixPath, array $searchProperties) - { - // TODO: Implement searchPrincipals() method. - } -} diff --git a/dav/friendica/FriendicaACLPlugin.inc.php b/dav/friendica/FriendicaACLPlugin.inc.php new file mode 100644 index 00000000..6bb8fc99 --- /dev/null +++ b/dav/friendica/FriendicaACLPlugin.inc.php @@ -0,0 +1,31 @@ +get_baseurl()); +$path = "/"; +if (isset($uri["path"]) && strlen($uri["path"]) > 1) { + $path = $uri["path"] . "/"; +} + +define("CALDAV_SQL_DB", ""); +define("CALDAV_SQL_PREFIX", "dav_"); +define("CALDAV_URL_PREFIX", $path . "dav/"); +define("DAV_APPNAME", "Friendica"); + +define("CALDAV_NAMESPACE_PRIVATE", 1); +define("CALDAV_FRIENDICA_MINE", "friendica-mine"); +define("CALDAV_FRIENDICA_CONTACTS", "friendica-contacts"); + +$GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"] = array(CALDAV_FRIENDICA_MINE, CALDAV_FRIENDICA_CONTACTS); +$GLOBALS["CALDAV_PRIVATE_SYSTEM_BACKENDS"] = array("Sabre_CalDAV_Backend_Friendica"); + +define("CARDDAV_NAMESPACE_PRIVATE", 1); +define("CARDDAV_FRIENDICA_CONTACT", "friendica"); +$GLOBALS["CARDDAV_PRIVATE_SYSTEM_ADDRESSBOOKS"] = array(CARDDAV_FRIENDICA_CONTACT); +$GLOBALS["CARDDAV_PRIVATE_SYSTEM_BACKENDS"] = array("Sabre_CardDAV_Backend_Friendica"); + +$GLOBALS["CALDAV_ACL_PLUGIN_CLASS"] = "Sabre_DAVACL_Plugin_Friendica"; + +define("CALDAV_MAX_YEAR", date("Y") + 5); + +/** + * @return int + */ +function getCurMicrotime() +{ + list($usec, $sec) = explode(" ", microtime()); + return sprintf("%14.0f", $sec * 10000 + $usec * 10000); +} // function getCurMicrotime + +/** + * + */ +function debug_time() +{ + $cur = getCurMicrotime(); + if ($GLOBALS["debug_time_last"] > 0) { + echo "Zeit: " . ($cur - $GLOBALS["debug_time_last"]) . "
\n"; + } + $GLOBALS["debug_time_last"] = $cur; +} + + +/** + * @param string $username + * @return int|null + */ +function dav_compat_username2id($username = "") +{ + $x = q("SELECT `uid` FROM `user` WHERE `nickname`='%s' AND `account_removed` = 0 AND `account_expired` = 0", dbesc($username)); + if (count($x) == 1) return $x[0]["uid"]; + return null; +} + +/** + * @param int $id + * @return string + */ +function dav_compat_id2username($id = 0) +{ + $x = q("SELECT `nickname` FROM `user` WHERE `uid` = %i AND `account_removed` = 0 AND `account_expired` = 0", IntVal($id)); + if (count($x) == 1) return $x[0]["nickname"]; + return ""; +} + +/** + * @return int + */ +function dav_compat_get_curr_user_id() +{ + $a = get_app(); + return IntVal($a->user["uid"]); +} + + +/** + * @param string $principalUri + * @return int|null + */ +function dav_compat_principal2uid($principalUri = "") +{ + if (strlen($principalUri) == 0) return null; + if ($principalUri[0] == "/") $principalUri = substr($principalUri, 1); + if (strpos($principalUri, "principals/users/") !== 0) return null; + $username = substr($principalUri, strlen("principals/users/")); + return dav_compat_username2id($username); +} + +/** + * @param string $principalUri + * @return array|null + */ +function dav_compat_principal2namespace($principalUri = "") +{ + if (strlen($principalUri) == 0) return null; + if ($principalUri[0] == "/") $principalUri = substr($principalUri, 1); + + if (strpos($principalUri, "principals/users/") !== 0) return null; + $username = substr($principalUri, strlen("principals/users/")); + return array("namespace" => CALDAV_NAMESPACE_PRIVATE, "namespace_id" => dav_compat_username2id($username)); +} + + +/** + * @return string + */ +function dav_compat_currentUserPrincipal() +{ + $a = get_app(); + return "principals/users/" . strtolower($a->user["nickname"]); +} + + +/** + * @param string $name + * @return null|string + */ +function dav_compat_getRequestVar($name = "") +{ + if (isset($_REQUEST[$name])) return $_REQUEST[$name]; + else return null; +} + +/** + * @param $text + * @return null|string + */ +function dav_compat_parse_text_serverside($text) +{ + return dav_compat_getRequestVar($text); +} + +/** + * @param string $uri + */ +function dav_compat_redirect($uri = "") +{ + goaway($uri); +} + + +/** + * @return null|int + */ +function dav_compat_get_max_private_calendars() +{ + return null; +} + +/** + * @return string + */ +function dav_compat_get_hostname() { + $a = get_app(); + return $a->get_hostname(); +} + +/** + * @param int $namespace + * @param int $namespace_id + * @param string $uri + * @param array $calendar + * @return Sabre_CalDAV_Backend_Common + * @throws Exception + */ +function wdcal_calendar_factory($namespace, $namespace_id, $uri, $calendar = null) +{ + switch ($namespace) { + case CALDAV_NAMESPACE_PRIVATE: + if ($uri == CALDAV_FRIENDICA_MINE || $uri == CALDAV_FRIENDICA_CONTACTS) return Sabre_CalDAV_Backend_Friendica::getInstance(); + else return Sabre_CalDAV_Backend_Private::getInstance(); + } + throw new Exception("Calendar Namespace not found"); +} + +/** + * @param int $calendar_id + * @return Sabre_CalDAV_Backend_Common + * @throws Exception + */ +function wdcal_calendar_factory_by_id($calendar_id) +{ + $calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendar_id); + return wdcal_calendar_factory($calendar["namespace"], $calendar["namespace_id"], $calendar["uri"], $calendar); +} + +/** + * @param int $user_id + * @param bool $withcheck + * @return array + */ +function wdcal_create_std_calendars_get_statements($user_id, $withcheck = true) +{ + $stms = array(); + $a = get_app(); + $uris = array( + 'private' => t("Private Calendar"), + CALDAV_FRIENDICA_MINE => t("Friendica Events: Mine"), + CALDAV_FRIENDICA_CONTACTS => t("Friendica Events: Contacts"), + ); + foreach ($uris as $uri => $name) { + $cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($uri)); + if (count($cals) == 0 || !$withcheck) $stms[] = + sprintf("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `displayname`, `timezone`, `ctag`, `uri`, `has_vevent`, `has_vtodo`) + VALUES (%d, %d, '%s', '%s', 1, '%s', 1, 0)", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($name), dbesc($a->timezone), dbesc($uri)); + } + return $stms; +} + +/** + */ +function wdcal_create_std_calendars() +{ + $a = get_app(); + if (!local_user()) return; + + $privates = q("SELECT COUNT(*) num FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); + if ($privates[0]["num"] > 0) return; + + $stms = wdcal_create_std_calendars_get_statements($a->user["uid"]); + foreach ($stms as $stmt) q($stmt); +} + + + + +/** + * @param int $user_id + * @param bool $withcheck + * @return array + */ +function wdcal_create_std_addressbooks_get_statements($user_id, $withcheck = true) +{ + $stms = array(); + $a = get_app(); + $uris = array( + 'private' => t("Private Addresses"), + CARDDAV_FRIENDICA_CONTACT => t("Friendica Contacts"), + ); + foreach ($uris as $uri => $name) { + $cals = q("SELECT * FROM %s%saddressbooks WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($uri)); + if (count($cals) == 0 || !$withcheck) $stms[] = + sprintf("INSERT INTO %s%saddressbooks (`namespace`, `namespace_id`, `displayname`, `ctag`, `uri`) + VALUES (%d, %d, '%s', 1, '%s')", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CARDDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($name), dbesc($uri)); + } + return $stms; +} + +/** + */ +function wdcal_create_std_addressbooks() +{ + $a = get_app(); + if (!local_user()) return; + + $privates = q("SELECT COUNT(*) num FROM %s%addressbooks WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CARDDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); + if ($privates[0]["num"] > 0) return; + + $stms = wdcal_create_std_addressbooks_get_statements($a->user["uid"]); + foreach ($stms as $stmt) q($stmt); +} diff --git a/dav/friendica/database-init.inc.php b/dav/friendica/database-init.inc.php new file mode 100644 index 00000000..7c0d23a3 --- /dev/null +++ b/dav/friendica/database-init.inc.php @@ -0,0 +1,270 @@ +q($st); + if ($db->error) $errors[] = $db->error; + } + + return $errors; +} + +/** + * @return array + */ +function dav_upgrade_tables() +{ + $ver = dav_check_tables(); + if (!in_array($ver, array(1))) return array("Unknown error"); + + $stms = dav_get_update_statements($ver); + $errors = array(); + + global $db; + foreach ($stms as $st) { + $db->q($st); + if ($db->error) $errors[] = $db->error; + } + + return $errors; +} \ No newline at end of file diff --git a/dav/friendica/dav_caldav_backend_virtual_friendica.inc.php b/dav/friendica/dav_caldav_backend_virtual_friendica.inc.php new file mode 100644 index 00000000..d2810b4f --- /dev/null +++ b/dav/friendica/dav_caldav_backend_virtual_friendica.inc.php @@ -0,0 +1,253 @@ + 0"; + break; + default: + throw new Sabre_DAV_Exception_NotFound(); + } + + $r = q("SELECT * FROM `event` WHERE `uid` = %d " . $sql_where . " ORDER BY `start`", IntVal($calendar["namespace_id"])); + + foreach ($r as $row) { + $uid = $calendar["uri"] . "-" . $row["id"]; + $vevent = dav_create_empty_vevent($uid); + $component = dav_get_eventComponent($vevent); + + if ($row["adjust"]) { + $start = datetime_convert('UTC', date_default_timezone_get(), $row["start"]); + $finish = datetime_convert('UTC', date_default_timezone_get(), $row["finish"]); + } else { + $start = $row["start"]; + $finish = $row["finish"]; + } + + $summary = ($row["summary"] != "" ? $row["summary"] : $row["desc"]); + $desc = ($row["summary"] != "" ? $row["desc"] : ""); + $component->add("SUMMARY", icalendar_sanitize_string($summary)); + $component->add("LOCATION", icalendar_sanitize_string($row["location"])); + $component->add("DESCRIPTION", icalendar_sanitize_string($desc)); + + $ts_start = wdcal_mySql2PhpTime($start); + $ts_end = wdcal_mySql2PhpTime($start); + + $allday = (strpos($start, "00:00:00") !== false && strpos($finish, "00:00:00") !== false); + $type = ($allday ? Sabre_VObject_Property_DateTime::DATE : Sabre_VObject_Property_DateTime::LOCALTZ); + + $datetime_start = new Sabre_VObject_Property_DateTime("DTSTART"); + $datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_start)), $type); + $datetime_end = new Sabre_VObject_Property_DateTime("DTEND"); + $datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_end)), $type); + + $component->add($datetime_start); + $component->add($datetime_end); + + $data = $vevent->serialize(); + + q("INSERT INTO %s%scal_virtual_object_cache (`calendar_id`, `data_uri`, `data_summary`, `data_location`, `data_start`, `data_end`, `data_allday`, `data_type`, + `calendardata`, `size`, `etag`) VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', %d, '%s')", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId, dbesc($uid), dbesc($summary), dbesc($row["location"]), dbesc($row["start"]), dbesc($row["finish"]), + ($allday ? 1 : 0), dbesc(($row["type"] == "birthday" ? "birthday" : "")), dbesc($data), strlen($data), md5($data)); + + } + + } + + + /** + * @param array $row + * @param array $calendar + * @param string $base_path + * @return array + */ + private function jqcal2wdcal($row, $calendar, $base_path) + { + if ($row["adjust"]) { + $start = datetime_convert('UTC', date_default_timezone_get(), $row["start"]); + $finish = datetime_convert('UTC', date_default_timezone_get(), $row["finish"]); + } else { + $start = $row["start"]; + $finish = $row["finish"]; + } + + $allday = (strpos($start, "00:00:00") !== false && strpos($finish, "00:00:00") !== false); + + $summary = (($row["summary"]) ? $row["summary"] : substr(preg_replace("/\[[^\]]*\]/", "", $row["desc"]), 0, 100)); + + return array( + "jq_id" => $row["id"], + "ev_id" => $row["id"], + "summary" => escape_tags($summary), + "start" => wdcal_mySql2PhpTime($start), + "end" => wdcal_mySql2PhpTime($finish), + "is_allday" => ($allday ? 1 : 0), + "is_moredays" => (substr($start, 0, 10) != substr($finish, 0, 10)), + "is_recurring" => ($row["type"] == "birthday"), + "color" => "7878ff", + "is_editable" => 0, + "is_editable_quick" => 0, + "location" => $row["location"], + "attendees" => '', + "has_notification" => 0, + "url_detail" => $base_path . "/events/event/" . $row["id"], + "url_edit" => "", + "special_type" => ($row["type"] == "birthday" ? "birthday" : ""), + ); + } + + + /** + * @param int $calendarId + * @param string $date_from + * @param string $date_to + * @param string $base_path + * @throws Sabre_DAV_Exception_NotFound + * @return array + */ + public function listItemsByRange($calendarId, $date_from, $date_to, $base_path) + { + $calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendarId); + + if ($calendar["namespace"] != CALDAV_NAMESPACE_PRIVATE) throw new Sabre_DAV_Exception_NotFound(); + + switch ($calendar["uri"]) { + case CALDAV_FRIENDICA_MINE: + $sql_where = " AND cid = 0"; + break; + case CALDAV_FRIENDICA_CONTACTS: + $sql_where = " AND cid > 0"; + break; + default: + throw new Sabre_DAV_Exception_NotFound(); + } + + if ($date_from != "") { + if (is_numeric($date_from)) $sql_where .= " AND `finish` >= '" . date("Y-m-d H:i:s", $date_from) . "'"; + else $sql_where .= " AND `finish` >= '" . dbesc($date_from) . "'"; + } + if ($date_to != "") { + if (is_numeric($date_to)) $sql_where .= " AND `start` <= '" . date("Y-m-d H:i:s", $date_to) . "'"; + else $sql_where .= " AND `start` <= '" . dbesc($date_to) . "'"; + } + $ret = array(); + + $r = q("SELECT * FROM `event` WHERE `uid` = %d " . $sql_where . " ORDER BY `start`", IntVal($calendar["namespace_id"])); + + $a = get_app(); + foreach ($r as $row) { + $r = $this->jqcal2wdcal($row, $calendar, $a->get_baseurl()); + $r["calendar_id"] = $calendar["id"]; + $ret[] = $r; + } + + return $ret; + } + + + /** + * Returns a list of calendars for a principal. + * + * Every project is an array with the following keys: + * * id, a unique id that will be used by other functions to modify the + * calendar. This can be the same as the uri or a database key. + * * uri, which the basename of the uri with which the calendar is + * accessed. + * * principaluri. The owner of the calendar. Almost always the same as + * principalUri passed to this method. + * + * Furthermore it can contain webdav properties in clark notation. A very + * common one is '{DAV:}displayname'. + * + * @param string $principalUri + * @return array + */ + public function getCalendarsForUser($principalUri) + { + $n = dav_compat_principal2namespace($principalUri); + if ($n["namespace"] != $this->getNamespace()) return array(); + + $cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $this->getNamespace(), IntVal($n["namespace_id"])); + $ret = array(); + foreach ($cals as $cal) { + if (!in_array($cal["uri"], $GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"])) continue; + + $dat = array( + "id" => $cal["id"], + "uri" => $cal["uri"], + "principaluri" => $principalUri, + '{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag'] ? $cal['ctag'] : '0', + '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array("VEVENT")), + "calendar_class" => "Sabre_CalDAV_Calendar_Virtual", + ); + foreach ($this->propertyMap as $key=> $field) $dat[$key] = $cal[$field]; + + $ret[] = $dat; + } + + return $ret; + } + + /** + * @param int $calendar_id + * @param int $calendarobject_id + * @return string + */ + function getItemDetailRedirect($calendar_id, $calendarobject_id) + { + $a = get_app(); + $item = q("SELECT `id` FROM `item` WHERE `event-id` = %d AND `uid` = %d AND deleted = 0", IntVal($calendarobject_id), $a->user["uid"]); + if (count($item) == 0) return "/events/"; + return "/display/" . $a->user["nickname"] . "/" . IntVal($item[0]["id"]); + + } +} diff --git a/dav/friendica/dav_carddav_backend_virtual_friendica.inc.php b/dav/friendica/dav_carddav_backend_virtual_friendica.inc.php new file mode 100644 index 00000000..3d7e0974 --- /dev/null +++ b/dav/friendica/dav_carddav_backend_virtual_friendica.inc.php @@ -0,0 +1,205 @@ + $books[0]["id"], + 'uri' => "friendica", + 'principaluri' => $principalUri, + '{DAV:}displayname' => t("Friendica-Contacts"), + '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => t("Your Friendica-Contacts"), + '{http://calendarserver.org/ns/}getctag' => $ctag, + '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data' => + new Sabre_CardDAV_Property_SupportedAddressData(), + ); + + return $addressBooks; + + } + + /** + * @static + * @param array $contact + * @return array + */ + private static function dav_contactarr2vcardsource($contact) + { + $name = explode(" ", $contact["name"]); + $first_name = $last_name = ""; + $middle_name = array(); + $num = count($name); + for ($i = 0; $i < $num && $first_name == ""; $i++) if ($name[$i] != "") { + $first_name = $name[$i]; + unset($name[$i]); + } + for ($i = $num - 1; $i >= 0 && $last_name == ""; $i--) if (isset($name[$i]) && $name[$i] != "") { + $last_name = $name[$i]; + unset($name[$i]); + } + foreach ($name as $n) if ($n != "") $middle_name[] = $n; + $vcarddata = new vcard_source_data($first_name, implode(" ", $middle_name), $last_name); + $vcarddata->homepages[] = new vcard_source_data_homepage("pref", $contact["url"]); + $vcarddata->last_update = ($contact["last-update"] > 0 ? $contact["last-update"] : $contact["created"]); + + $photo = q("SELECT * FROM photo WHERE `contact-id` = %d ORDER BY scale DESC", $contact["id"]); //prefer size 80x80 + if ($photo && count($photo) > 0) { + $photodata = new vcard_source_data_photo(); + $photodata->width = $photo[0]["width"]; + $photodata->height = $photo[0]["height"]; + $photodata->type = "JPEG"; + $photodata->binarydata = $photo[0]["data"]; + $vcarddata->photo = $photodata; + } + + switch ($contact["network"]) { + case "face": + $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("facebook", $contact["notify"], "http://www.facebook.com/" . $contact["notify"]); + break; + case "dfrn": + $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("dfrn", $contact["nick"], $contact["url"]); + break; + case "twitter": + $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("twitter", $contact["nick"], "http://twitter.com/" . $contact["nick"]); // @TODO Stimmt das? + break; + } + + $vcard = vcard_source_compile($vcarddata); + return array( + "id" => $contact["id"], + "carddata" => $vcard, + "uri" => $contact["id"] . ".vcf", + "lastmodified" => wdcal_mySql2PhpTime($vcarddata->last_update), + "etag" => md5($vcard), + "size" => strlen($vcard), + ); + + } + + /** + * @static + * @param int $addressbookId + * @throws Sabre_DAV_Exception_NotFound + */ + static protected function createCache_internal($addressbookId) { + //$notin = (count($exclude_ids) > 0 ? " AND id NOT IN (" . implode(", ", $exclude_ids) . ") " : ""); + $addressbook = q("SELECT * FROM %s%saddressbooks WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($addressbookId)); + if (count($addressbook) != 1 || $addressbook[0]["namespace"] != CARDDAV_NAMESPACE_PRIVATE) throw new Sabre_DAV_Exception_NotFound(); + $contacts = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0 ORDER BY `name` ASC", $addressbook[0]["namespace_id"]); + + $retdata = array(); + foreach ($contacts as $contact) { + $x = static::dav_contactarr2vcardsource($contact); + q("INSERT INTO %s%saddressbookobjects (`addressbook_id`, `contact`, `carddata`, `uri`, `lastmodified`, `etag`, `size`) VALUES (%d, %d, '%s', '%s', NOW(), '%s', %d)", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $addressbookId, $contact["id"], dbesc($x["carddata"]), dbesc($x["uri"]), dbesc($x["etag"]), $x["size"] + ); + } + } + + + /** + * Updates a card. + * + * The addressbook id will be passed as the first argument. This is the + * same id as it is returned from the getAddressbooksForUser method. + * + * The cardUri is a base uri, and doesn't include the full path. The + * cardData argument is the vcard body, and is passed as a string. + * + * It is possible to return an ETag from this method. This ETag should + * match that of the updated resource, and must be enclosed with double + * quotes (that is: the string itself must contain the actual quotes). + * + * You should only return the ETag if you store the carddata as-is. If a + * subsequent GET request on the same card does not have the same body, + * byte-by-byte and you did return an ETag here, clients tend to get + * confused. + * + * If you don't return an ETag, you can just return null. + * + * @param string $addressBookId + * @param string $cardUri + * @param string $cardData + * @throws Sabre_DAV_Exception_Forbidden + * @return string|null + */ + public function updateCard($addressBookId, $cardUri, $cardData) + { + $x = explode("-", $addressBookId); + + $etag = md5($cardData); + q("UPDATE %s%scards SET carddata = '%s', lastmodified = %d, etag = '%s', size = %d, manually_edited = 1 WHERE uri = '%s' AND namespace = %d AND namespace_id =%d", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($cardData), time(), $etag, strlen($cardData), dbesc($cardUri), IntVal($x[10]), IntVal($x[1]) + ); + q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1])); + + return '"' . $etag . '"'; + } + + /** + * Deletes a card + * + * @param string $addressBookId + * @param string $cardUri + * @throws Sabre_DAV_Exception_Forbidden + * @return bool + */ + public function deleteCard($addressBookId, $cardUri) + { + $x = explode("-", $addressBookId); + + q("UPDATE %s%scards SET manually_deleted = 1 WHERE namespace = %d AND namespace_id = %d AND uri = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($cardUri)); + q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1])); + + return true; + } +} diff --git a/dav/friendica/dav_friendica_auth.inc.php b/dav/friendica/dav_friendica_auth.inc.php new file mode 100644 index 00000000..acc33fa1 --- /dev/null +++ b/dav/friendica/dav_friendica_auth.inc.php @@ -0,0 +1,93 @@ +currentUser); + } + + /** + * @return null|string + */ + public function getCurrentUser() { + return $this->currentUser; + } + + /** + * Authenticates the user based on the current request. + * + * If authentication is successful, true must be returned. + * If authentication fails, an exception must be thrown. + * + * @param Sabre_DAV_Server $server + * @param string $realm + * @throws Sabre_DAV_Exception_NotAuthenticated + * @return bool + */ + public function authenticate(Sabre_DAV_Server $server, $realm) { + + $a = get_app(); + if (isset($a->user["uid"])) { + $this->currentUser = strtolower($a->user["nickname"]); + return true; + } + + $auth = new Sabre_HTTP_BasicAuth(); + $auth->setHTTPRequest($server->httpRequest); + $auth->setHTTPResponse($server->httpResponse); + $auth->setRealm($realm); + $userpass = $auth->getUserPass(); + if (!$userpass) { + $auth->requireLogin(); + throw new Sabre_DAV_Exception_NotAuthenticated('No basic authentication headers were found'); + } + + // Authenticates the user + if (!$this->validateUserPass($userpass[0],$userpass[1])) { + $auth->requireLogin(); + throw new Sabre_DAV_Exception_NotAuthenticated('Username or password does not match'); + } + $this->currentUser = strtolower($userpass[0]); + return true; + } + + + /** + * @param string $username + * @param string $password + * @return bool + */ + protected function validateUserPass($username, $password) { + $encrypted = hash('whirlpool',trim($password)); + $r = q("SELECT COUNT(*) anz FROM `user` WHERE `nickname` = '%s' AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `verified` = 1 LIMIT 1", + dbesc(trim($username)), + dbesc($encrypted) + ); + return ($r[0]["anz"] == 1); + } + +} diff --git a/dav/friendica/dav_friendica_principal.inc.php b/dav/friendica/dav_friendica_principal.inc.php new file mode 100644 index 00000000..780bcd24 --- /dev/null +++ b/dav/friendica/dav_friendica_principal.inc.php @@ -0,0 +1,218 @@ +authBackend = &$authBackend; + + } + + + /** + * @var Sabre_DAVACL_IPrincipalBackend|null + */ + private static $intstance = null; + + /** + * @static + * @return Sabre_DAVACL_IPrincipalBackend + */ + public static function &getInstance() { + if (is_null(self::$intstance)) { + $authBackend = Sabre_DAV_Auth_Backend_Std::getInstance(); + self::$intstance = new Sabre_DAVACL_PrincipalBackend_Std($authBackend); + } + return self::$intstance; + } + + /** + * Returns a list of principals based on a prefix. + * + * This prefix will often contain something like 'principals'. You are only + * expected to return principals that are in this base path. + * + * You are expected to return at least a 'uri' for every user, you can + * return any additional properties if you wish so. Common properties are: + * {DAV:}displayname + * {http://sabredav.org/ns}email-address - This is a custom SabreDAV + * field that's actualy injected in a number of other properties. If + * you have an email address, use this property. + * + * @param string $prefixPath + * @return array + */ + public function getPrincipalsByPrefix($prefixPath) + { + + // This backend only support principals in one collection + if ($prefixPath !== $this->prefix) return array(); + + $users = array(); + + $r = q("SELECT `nickname` FROM `user` WHERE `nickname` = '%s'", escape_tags($this->authBackend->getCurrentUser()) ); + foreach ($r as $t) { + $users[] = array( + 'uri' => $this->prefix . '/' . strtolower($t['nickname']), + '{DAV:}displayname' => $t['nickname'], + ); + } + + return $users; + + } + + /** + * Returns a specific principal, specified by it's path. + * The returned structure should be the exact same as from + * getPrincipalsByPrefix. + * + * @param string $path + * @return array + */ + public function getPrincipalByPath($path) + { + + list($prefixPath, $userName) = Sabre_DAV_URLUtil::splitPath($path); + + // This backend only support principals in one collection + if ($prefixPath !== $this->prefix) return null; + + $r = q("SELECT `nickname` FROM `user` WHERE `nickname` = '%s'", escape_tags($userName) ); + if (count($r) == 0) return array(); + + return array( + 'uri' => $this->prefix . '/' . strtolower($r[0]['nickname']), + '{DAV:}displayname' => $r[0]['nickname'], + ); + + } + + + function getGroupMemberSet($principal) + { + return array(); + } + + function getGroupMembership($principal) + { + return array(); + } + + + /** + * Updates the list of group members for a group principal. + * + * The principals should be passed as a list of uri's. + * + * @param string $principal + * @param array $members + * @throws Sabre_DAV_Exception + * @return void + */ + public function setGroupMemberSet($principal, array $members) + { + throw new Sabre_DAV_Exception('Operation not supported'); + } + + /** + * Updates one ore more webdav properties on a principal. + * + * The list of mutations is supplied as an array. Each key in the array is + * a propertyname, such as {DAV:}displayname. + * + * Each value is the actual value to be updated. If a value is null, it + * must be deleted. + * + * This method should be atomic. It must either completely succeed, or + * completely fail. Success and failure can simply be returned as 'true' or + * 'false'. + * + * It is also possible to return detailed failure information. In that case + * an array such as this should be returned: + * + * array( + * 200 => array( + * '{DAV:}prop1' => null, + * ), + * 201 => array( + * '{DAV:}prop2' => null, + * ), + * 403 => array( + * '{DAV:}prop3' => null, + * ), + * 424 => array( + * '{DAV:}prop4' => null, + * ), + * ); + * + * In this previous example prop1 was successfully updated or deleted, and + * prop2 was succesfully created. + * + * prop3 failed to update due to '403 Forbidden' and because of this prop4 + * also could not be updated with '424 Failed dependency'. + * + * This last example was actually incorrect. While 200 and 201 could appear + * in 1 response, if there's any error (403) the other properties should + * always fail with 423 (failed dependency). + * + * But anyway, if you don't want to scratch your head over this, just + * return true or false. + * + * @param string $path + * @param array $mutations + * @return array|bool + */ + function updatePrincipal($path, $mutations) + { + // TODO: Implement updatePrincipal() method. + } + + /** + * This method is used to search for principals matching a set of + * properties. + * + * This search is specifically used by RFC3744's principal-property-search + * REPORT. You should at least allow searching on + * http://sabredav.org/ns}email-address. + * + * The actual search should be a unicode-non-case-sensitive search. The + * keys in searchProperties are the WebDAV property names, while the values + * are the property values to search on. + * + * If multiple properties are being searched on, the search should be + * AND'ed. + * + * This method should simply return an array with full principal uri's. + * + * If somebody attempted to search on a property the backend does not + * support, you should simply return 0 results. + * + * You can also just return 0 results if you choose to not support + * searching at all, but keep in mind that this may stop certain features + * from working. + * + * @param string $prefixPath + * @param array $searchProperties + * @return array + */ + function searchPrincipals($prefixPath, array $searchProperties) + { + // TODO: Implement searchPrincipals() method. + } +} diff --git a/dav/friendica/layout.fnk.php b/dav/friendica/layout.fnk.php new file mode 100644 index 00000000..5b65ec24 --- /dev/null +++ b/dav/friendica/layout.fnk.php @@ -0,0 +1,535 @@ +page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; + + $a->page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; + + $a->page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; + + $a->page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; + + $a->page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; + + switch (get_config("system", "language")) { + case "de": + $a->page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; + break; + default: + $a->page['htmlhead'] .= '' . "\r\n"; + } + + $a->page['htmlhead'] .= '' . "\r\n"; + $a->page['htmlhead'] .= '' . "\r\n"; +} + + + +/** + * @param int $calendar_id + */ +function wdcal_print_user_ics($calendar_id) +{ + $calendar_id = IntVal($calendar_id); + + $a = get_app(); + header("Content-type: text/plain"); + + $str = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\n"; + $cals = q("SELECT * FROM %s%scalendars WHERE `id` = %d AND `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendar_id, CALDAV_NAMESPACE_PRIVATE, $a->user["uid"]); + if (count($cals) > 0) { + $objs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d ORDER BY `firstOccurence`", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendar_id); + + foreach ($objs as $obj) { + preg_match("/BEGIN:VEVENT(.*)END:VEVENT/siu", $obj["calendardata"], $matches); + $str2 = preg_replace("/([^\\r])\\n/siu", "\\1\r\n", $matches[0]); + $str2 = preg_replace("/MAILTO:.*[^:a-z0-9_\+äöüß\\n\\n@-]+.*(:|\\r\\n[^ ])/siU", "\\1", $str2); + $str .= $str2 . "\r\n"; + } + } + $str .= "END:VCALENDAR\r\n"; + + echo $str; + killme(); +} + + +/** + * @param int $calendar_id + * @return string + */ +function wdcal_import_user_ics($calendar_id) { + $a = get_app(); + $calendar_id = IntVal($calendar_id); + $o = ""; + + $server = dav_create_server(true, true, false); + $calendar = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_WRITE); + if (!$calendar) goaway($a->get_baseurl() . "/dav/wdcal/"); + + if (isset($_REQUEST["save"])) { + check_form_security_token_redirectOnErr('/dav/settings/', 'icsimport'); + + if ($_FILES["ics_file"]["tmp_name"] != "" && is_uploaded_file($_FILES["ics_file"]["tmp_name"])) try { + $text = file_get_contents($_FILES["ics_file"]["tmp_name"]); + + /** @var Sabre_VObject_Component_VCalendar $vObject */ + $vObject = Sabre_VObject_Reader::read($text); + $comp = $vObject->getComponents(); + $imported = array(); + foreach ($comp as $c) try { + /** @var Sabre_VObject_Component_VEvent $c */ + $uid = $c->__get("UID")->value; + if (!isset($imported[$uid])) $imported[$uid] = ""; + $imported[$uid] .= $c->serialize(); + } catch (Exception $e) { + notice(t("Something went wrong when trying to import the file. Sorry. Maybe some events were imported anyway.")); + } + + if (isset($_REQUEST["overwrite"])) { + $children = $calendar->getChildren(); + foreach ($children as $child) { + /** @var Sabre_CalDAV_CalendarObject $child */ + $child->delete(); + } + $i = 1; + } else { + $i = 0; + $children = $calendar->getChildren(); + foreach ($children as $child) { + /** @var Sabre_CalDAV_CalendarObject $child */ + $name = $child->getName(); + if (preg_match("/import\-([0-9]+)\.ics/siu", $name, $matches)) { + if ($matches[1] > $i) $i = $matches[1]; + }; + } + $i++; + } + + foreach ($imported as $object) try { + + $str = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\n"; + $str .= trim($object); + $str .= "\r\nEND:VCALENDAR\r\n"; + + $calendar->createFile("import-" . $i . ".ics", $str); + $i++; + } catch (Exception $e) { + notice(t("Something went wrong when trying to import the file. Sorry.")); + } + + $o = t("The ICS-File has been imported."); + } catch (Exception $e) { + notice(t("Something went wrong when trying to import the file. Sorry. Maybe some events were imported anyway.")); + } else { + notice(t("No file was uploaded.")); + } + } + + + $o .= "" . t("Go back to the calendar") . "

"; + + $num = q("SELECT COUNT(*) num FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendar_id); + + $o .= "

" . t("Import a ICS-file") . "

"; + $o .= '
'; + $o .= "\n"; + $o .= "
\n"; + if ($num[0]["num"] > 0) $o .= "
\n"; + $o .= ""; + $o .= '
'; + + return $o; +} + + +/** + * @param array|Sabre_CalDAV_Calendar[] $calendars + * @param array|int[] $calendars_selected + * @param string $data_feed_url + * @param string $view + * @param int $theme + * @param int $height_diff + * @param bool $readonly + * @param string $curr_day + * @param array $add_params + * @param bool $show_nav + * @return string + */ +function wdcal_printCalendar($calendars, $calendars_selected, $data_feed_url, $view = "week", $theme = 0, $height_diff = 175, $readonly = false, $curr_day = "", $add_params = array(), $show_nav = true) +{ + + $a = get_app(); + $localization = wdcal_local::getInstanceByUser($a->user["uid"]); + + if (count($calendars_selected) == 0) foreach ($calendars as $c) { + $prop = $c->getProperties(array("id")); + $calendars_selected[] = $prop["id"]; + } + + $opts = array( + "view" => $view, + "theme" => $theme, + "readonly" => $readonly, + "height_diff" => $height_diff, + "weekstartday" => $localization->getFirstDayOfWeek(), + "data_feed_url" => $data_feed_url, + "date_format_dm1" => $localization->dateformat_js_dm1(), + "date_format_dm2" => $localization->dateformat_js_dm2(), + "date_format_dm3" => $localization->dateformat_js_dm3(), + "date_format_full" => $localization->dateformat_datepicker_js(), + "baseurl" => $a->get_baseurl() . "/dav/wdcal/", + ); + + $x = ' + + +
+
Available Calendars:'; + + foreach ($calendars as $cal) { + $cal_id = $cal->getProperties(array("id", DAV_DISPLAYNAME)); + $x .= '
+
+ +
'; + + if ($show_nav) { + + $x .= '
+ + +
+
+
' . t("Today") . '
+
+
+ +
+
+
+
+
+
+ +
+
+
+
' . t("Reload") . '
+
+
+
+ +
+
+ +
+
+ + ' . t("Date") . ' +
+
+
+
+ '; + } + $x .= ' +
+
+
+
+
+'; + + return $x; +} + + +/** + * @param int $calendar_id + * @param int $calendarobject_id + * @return string + */ +function wdcal_getDetailPage($calendar_id, $calendarobject_id) +{ + $a = get_app(); + + try { + $details = null; + $server = dav_create_server(true, true, false); + $cal = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_READ); + $obj = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($calendarobject_id); + dav_get_current_user_calendarobject($server, $cal, $obj["uri"], DAV_ACL_READ); // Check permissions + + $calbackend = wdcal_calendar_factory_by_id($calendar_id); + $redirect = $calbackend->getItemDetailRedirect($calendar_id, $calendarobject_id); + + if ($redirect !== null) goaway($a->get_baseurl() . $redirect); + + $details = $obj; + } catch (Exception $e) { + info(t("Error") . ": " . $e); + goaway($a->get_baseurl() . "/dav/wdcal/"); + } + + return print_r($details, true); +} + + +/** + * @param int $calendar_id + * @param int $uri + * @return string + */ +function wdcal_getEditPage($calendar_id, $uri) +{ + $a = get_app(); + $localization = wdcal_local::getInstanceByUser($a->user["uid"]); + + return wdcal_getEditPage_str($localization, $a->get_baseurl(), $calendar_id, $uri); +} + +/** + * @return string + */ +function wdcal_getNewPage() +{ + $a = get_app(); + $localization = wdcal_local::getInstanceByUser($a->user["uid"]); + + return wdcal_getEditPage_str($localization, $a->get_baseurl(), 0, 0); +} + + +/** + * @param App $a + * @return string + */ +function wdcal_getSettingsPage(&$a) +{ + + if (!local_user()) { + notice(t('Permission denied.') . EOL); + return ''; + } + + if (isset($_REQUEST["save"])) { + check_form_security_token_redirectOnErr('/dav/settings/', 'calprop'); + set_pconfig($a->user["uid"], "dav", "dateformat", $_REQUEST["wdcal_date_format"]); + info(t('The new values have been saved.')); + } + + if (isset($_REQUEST["save_cals"])) { + check_form_security_token_redirectOnErr('/dav/settings/', 'calprop'); + + $r = q("SELECT * FROM %s%scalendars WHERE `namespace` = " . CALDAV_NAMESPACE_PRIVATE . " AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($a->user["uid"])); + foreach ($r as $cal) { + $backend = wdcal_calendar_factory($cal["namespace"], $cal["namespace_id"], $cal["uri"], $cal); + $change_sql = ""; + $col = substr($_REQUEST["color"][$cal["id"]], 1); + if (strtolower($col) != strtolower($cal["calendarcolor"])) $change_sql .= ", `calendarcolor` = '" . dbesc($col) . "'"; + if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual")) { + if ($_REQUEST["uri"][$cal["id"]] != $cal["uri"]) $change_sql .= ", `uri` = '" . dbesc($_REQUEST["uri"][$cal["id"]]) . "'"; + if ($_REQUEST["name"][$cal["id"]] != $cal["displayname"]) $change_sql .= ", `displayname` = '" . dbesc($_REQUEST["name"][$cal["id"]]) . "'"; + } + if ($change_sql != "") { + q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 $change_sql WHERE `id` = %d AND `namespace_id` = %d AND `namespace_id` = %d", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $cal["id"], CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); + info(t('The calendar has been updated.')); + } + } + + if (isset($_REQUEST["uri"]["new"]) && $_REQUEST["uri"]["new"] != "" && $_REQUEST["name"]["new"] && $_REQUEST["name"]["new"] != "") { + $order = q("SELECT MAX(`calendarorder`) ord FROM %s%scalendars WHERE `namespace_id` = %d AND `namespace_id` = %d", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); + $neworder = $order[0]["ord"] + 1; + q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `calendarorder`, `calendarcolor`, `displayname`, `timezone`, `uri`, `has_vevent`, `ctag`) + VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', 1, 1)", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"]), $neworder, dbesc(strtolower(substr($_REQUEST["color"]["new"], 1))), + dbesc($_REQUEST["name"]["new"]), dbesc($a->timezone), dbesc($_REQUEST["uri"]["new"]) + ); + info(t('The new calendar has been created.')); + } + } + + if (isset($_REQUEST["remove_cal"])) { + check_form_security_token_redirectOnErr('/dav/settings/', 'del_cal', 't'); + + $c = q("SELECT * FROM %s%scalendars WHERE `id` = %d AND `namespace_id` = %d AND `namespace_id` = %d", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"]), CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); + if (count($c) != 1) killme(); + + $calobjs = q("SELECT `id` FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"])); + + $newcal = q("SELECT * FROM %s%scalendars WHERE `id` != %d AND `namespace_id` = %d AND `namespace_id` = %d ORDER BY `calendarcolor` LIMIT 0,1", + CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"]), CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); + if (count($newcal) != 1) killme(); + + q("UPDATE %s%scalendarobjects SET `calendar_id` = %d WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($newcal[0]["id"]), IntVal($c[0]["id"])); + + foreach ($calobjs as $calobj) renderCalDavEntry_calobj_id($calobj["id"]); + + q("DELETE FROM %s%scalendars WHERE `id` = %s", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"])); + q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 WHERE `id` = " . CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $newcal[0]["id"]); + + info(t('The calendar has been deleted.')); + } + + $o = ""; + + $o .= "" . t("Go back to the calendar") . "

"; + + $o .= '

' . t('Calendar Settings') . '

'; + + $current_format = wdcal_local::getInstanceByUser($a->user["uid"]); + $o .= '
'; + $o .= "\n"; + + $o .= '
'; + + $o .= '
'; + + $o .= ''; + $o .= '
'; + + + $o .= '

' . t('Calendars') . '

'; + $o .= '
'; + $o .= "\n"; + $o .= ""; + + $r = q("SELECT * FROM %s%scalendars WHERE `namespace` = " . CALDAV_NAMESPACE_PRIVATE . " AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($a->user["uid"])); + $private_max = 0; + $num_non_virtual = 0; + foreach ($r as $x) { + $backend = wdcal_calendar_factory($x["namespace"], $x["namespace_id"], $x["uri"], $x); + if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual")) $num_non_virtual++; + } + foreach ($r as $x) { + $p = explode("private-", $x["uri"]); + if (count($p) == 2 && $p[1] > $private_max) $private_max = $p[1]; + + $backend = wdcal_calendar_factory($x["namespace"], $x["namespace_id"], $x["uri"], $x); + $disabled = (is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual") ? "disabled" : ""); + $o .= ""; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= "\n"; + $o .= "\n"; + } + + $private_max++; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= ""; + $o .= "\n"; + + $o .= "
TypeColorNameURI (for CalDAV)ICS
" . escape_tags($backend->getBackendTypeName()) . "Export"; + if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual") && $num_non_virtual > 1) $o .= " / Import"; + $o .= ""; + if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual") && $num_non_virtual > 1) $o .= "Delete"; + $o .= "
"; + $o .= "
[" . t("Create a new calendar") . "]
"; + $o .= ''; + $o .= '
'; + $baseurl = $a->get_baseurl(); + $o .= ""; + + + $o .= "

" . t("Limitations") . "

"; + + $o .= "- The native friendica events are embedded as read-only, half-transparent in the calendar.
"; + + $o .= "

" . t("Warning") . "

"; + + $o .= "This plugin still is in a very early stage of development. Expect major bugs!
"; + + $o .= "

" . t("Synchronization (iPhone, Thunderbird Lightning, Android, ...)") . "

"; + + $o .= 'This plugin enables synchronization of your dates and contacts with CalDAV- and CardDAV-enabled programs or devices.
+ As an example, the instructions how to set up two-way synchronization with an iPhone/iPodTouch are provided below.
+ Unfortunately, Android does not have native support for CalDAV or CardDAV, so an app has to be installed.
+ On desktops, the Lightning-extension to Mozilla Thunderbird should be able to use this plugin as a backend.

'; + + $o .= '

' . t('Synchronizing this calendar with the iPhone') . '

'; + + $o .= ""; + + $o .= '

' . t('Synchronizing your Friendica-Contacts with the iPhone') . '

'; + + $o .= ""; + + return $o; +} + diff --git a/dav/friendica/main.php b/dav/friendica/main.php new file mode 100644 index 00000000..602bda6d --- /dev/null +++ b/dav/friendica/main.php @@ -0,0 +1,348 @@ +argc >= 2 && $a->argv[1] == "wdcal") { + + if ($a->argc >= 3 && $a->argv[2] == "feed") { + wdcal_print_feed($a->get_baseurl() . "/dav/wdcal/"); + killme(); + } + return; + } + if ($a->argc >= 2 && $a->argv[1] == "getExceptionDates") { + echo wdcal_getEditPage_exception_selector(); + killme(); + } + + if ($a->argc >= 2 && $a->argv[1] == "settings") { + return; + } + + + if (isset($_REQUEST["test"])) { + renderAllCalDavEntries(); + } + + + $server = dav_create_server(); + + $browser = new Sabre_DAV_Browser_Plugin(); + $server->addPlugin($browser); + + $server->exec(); + + killme(); +} + +/** + * @return string + */ +function dav_content() +{ + $a = get_app(); + if (!isset($a->user["uid"]) || $a->user["uid"] == 0) { + return login(); + } + + $x = ""; + try { + if ($a->argv[1] == "settings") { + return wdcal_getSettingsPage($a); + } elseif ($a->argv[1] == "wdcal") { + if (isset($a->argv[2]) && strlen($a->argv[2]) > 0) { + if ($a->argv[2] == "new") { + $o = ""; + if (isset($_REQUEST["save"])) { + check_form_security_token_redirectOnErr($a->get_baseurl() . "/dav/wdcal/", "caledit"); + $ret = wdcal_postEditPage("new", "", $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/"); + if ($ret["ok"]) notice($ret["msg"]); + else info($ret["msg"]); + goaway($a->get_baseurl() . "/dav/wdcal/"); + } + $o .= wdcal_getNewPage(); + return $o; + } else { + $calendar_id = IntVal($a->argv[2]); + if (isset($a->argv[3]) && $a->argv[3] == "ics-export") { + wdcal_print_user_ics($calendar_id); + } elseif (isset($a->argv[3]) && $a->argv[3] == "ics-import") { + return wdcal_import_user_ics($calendar_id); + } elseif (isset($a->argv[3]) && $a->argv[3] > 0) { + if (isset($a->argv[4]) && $a->argv[4] == "edit") { + $o = ""; + if (isset($_REQUEST["save"])) { + check_form_security_token_redirectOnErr($a->get_baseurl() . "/dav/wdcal/", "caledit"); + $ret = wdcal_postEditPage($a->argv[3], $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/"); + if ($ret["ok"]) notice($ret["msg"]); + else info($ret["msg"]); + goaway($a->get_baseurl() . "/dav/wdcal/"); + } + $o .= wdcal_getEditPage($calendar_id, $a->argv[3]); + return $o; + } else { + return wdcal_getDetailPage($calendar_id, $a->argv[3]); + } + } else { + // @TODO Edit Calendar + } + } + } else { + $server = dav_create_server(true, true, false); + $cals = dav_get_current_user_calendars($server, DAV_ACL_READ); + $x = wdcal_printCalendar($cals, array(), $a->get_baseurl() . "/dav/wdcal/feed/", "week", 0, 200); + } + } + } catch (DAVVersionMismatchException $e) { + $x = t("The current version of this plugin has not been set up correctly. Please contact the system administrator of your installation of friendica to fix this."); + } + return $x; +} + + +/** + * @param App $a + * @param object $b + */ +function dav_event_created_hook(&$a, &$b) +{ + dav_include_files(); + // @TODO Updating the cache instead of completely invalidating and rebuilding it + Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS); + Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE); +} + +/** + * @param App $a + * @param object $b + */ +function dav_event_updated_hook(&$a, &$b) +{ + dav_include_files(); + // @TODO Updating the cache instead of completely invalidating and rebuilding it + Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS); + Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE); +} + +/** + * @param App $a + * @param object $b + */ +function dav_profile_tabs_hook(&$a, &$b) +{ + $b["tabs"][] = array( + "label" => t('Calendar'), + "url" => $a->get_baseurl() . "/dav/wdcal/", + "sel" => "", + "title" => t('Extended calendar with CalDAV-support'), + ); +} + + +/** + * @param App $a + * @param object $b + */ +function dav_cron(&$a, &$b) +{ + dav_include_files(); + + $r = q("SELECT * FROM %s%snotifications WHERE `notified` = 0 AND `alert_date` <= NOW()", CALDAV_SQL_DB, CALDAV_SQL_PREFIX); + foreach ($r as $not) { + q("UPDATE %s%snotifications SET `notified` = 1 WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $not["id"]); + $event = q("SELECT * FROM %s%sjqcalendar WHERE `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $not["calendarobject_id"]); + $calendar = q("SELECT * FROM %s%scalendars WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $not["calendar_id"]); + $users = array(); + if (count($calendar) != 1 || count($event) == 0) continue; + switch ($calendar[0]["namespace"]) { + case CALDAV_NAMESPACE_PRIVATE: + $user = q("SELECT * FROM user WHERE `uid` = %d AND `blocked` = 0", $calendar[0]["namespace_id"]); + if (count($user) != 1) continue; + $users[] = $user[0]; + break; + } + switch ($not["action"]) { + case "email": + case "display": // @TODO implement "Display" + foreach ($users as $user) { + $find = array("%to%", "%event%", "%url%"); + $repl = array($user["username"], $event[0]["Summary"], $a->get_baseurl() . "/dav/wdcal/" . $calendar[0]["id"] . "/" . $not["calendarobject_id"] . "/"); + $text_text = str_replace($find, $repl, "Hi %to%!\n\nThe event \"%event%\" is about to begin:\n%url%"); + $text_html = str_replace($find, $repl, "Hi %to%!
\n
\nThe event \"%event%\" is about to begin:
\n%url%"); + $params = array( + 'fromName' => FRIENDICA_PLATFORM, + 'fromEmail' => t('noreply') . '@' . $a->get_hostname(), + 'replyTo' => t('noreply') . '@' . $a->get_hostname(), + 'toEmail' => $user["email"], + 'messageSubject' => t("Notification: " . $event[0]["Summary"]), + 'htmlVersion' => $text_html, + 'textVersion' => $text_text, + 'additionalMailHeader' => "", + ); + require_once('include/enotify.php'); + enotify::send($params); + } + break; + } + } +} + + +/** + * @param App $a + * @param null|object $o + */ +function dav_plugin_admin_post(&$a = null, &$o = null) +{ + check_form_security_token_redirectOnErr('/admin/plugins/dav', 'dav_admin_save'); + + dav_include_files(); + require_once(__DIR__ . "/database-init.inc.php"); + + if (isset($_REQUEST["install"])) { + $errs = dav_create_tables(); + if (count($errs) == 0) info(t('The database tables have been installed.') . EOL); + else notice(t("An error occurred during the installation.") . EOL); + } + if (isset($_REQUEST["upgrade"])) { + $errs = dav_upgrade_tables(); + if (count($errs) == 0) { + renderAllCalDavEntries(); + info(t('The database tables have been updated.') . EOL); + } + else notice(t("An error occurred during the update.") . EOL); + } +} + +/** + * @param App $a + * @param string $o + */ +function dav_plugin_admin(&$a, &$o) +{ + dav_include_files(); + require_once(__DIR__ . "/database-init.inc.php"); + + $dbstatus = dav_check_tables(); + + $o = ''; + $o .= '' . t("No system-wide settings yet.") . '

'; + + + $o .= '

' . t('Database status') . '

'; + switch ($dbstatus) { + case 0: + $o .= t('Installed'); + break; + case 1: + $o .= "" . t('Upgrade needed') . "
" . t("Please back up all calendar data (the tables beginning with dav_*) before proceeding. While all calendar events should be converted to the new database structure, it's always safe to have a backup. Below, you can have a look at the database-queries that will be made when pressing the 'update'-button.") . "

"; + break; + case -1: + $o .= t('Not installed') . "

"; + break; + case -2: + default: + $o .= t('Unknown') . "

" . t("Something really went wrong. I cannot recover from this state automatically, sorry. Please go to the database backend, back up the data, and delete all tables beginning with 'dav_' manually. Afterwards, this installation routine should be able to reinitialize the tables automatically."); + break; + } + $o .= "

"; + + $o .= "

" . t("Troubleshooting") . "

"; + $o .= "

" . t("Manual creation of the database tables:") . "

"; + $o .= "" . t("Show SQL-statements") . ""; +} diff --git a/dav/friendica/wdcal.css b/dav/friendica/wdcal.css new file mode 100644 index 00000000..18c25c58 --- /dev/null +++ b/dav/friendica/wdcal.css @@ -0,0 +1,43 @@ + +div.colorPicker-picker { display: inline-block; } +.colorPicker-palette { font-size: 12px; } +.animexxcalendar label, .colorPicker-palette label { background: none; border: none; padding: 0; margin: 0; box-shadow: none; display: inline; font-size: 14px; } +.animexxcalendar input, .colorPicker-palette input { font-size: 14px; } + + +.ui-datepicker { width: 200px; } +.ui-datepicker * { font-size: 12px; line-height: 12px; } +.ui-datepicker th { padding: 10px 2px; } +.ui-datepicker select.ui-datepicker-year { min-width: 0; width: 50px !important; } +#cal_start_time, #cal_end_time { width: 5em; margin-left: 1em; } +#cal_start_date, #cal_end_date { width: 6em;} + + +label.block { + background: none repeat scroll 0 0 #CCCCCC; + border: 1px solid #EEEEEC; + box-shadow: 3px 3px 5px 0 #111111; + color: #111111; + display: inline-block; + font-size: small; + margin: 0 10px 1em 0; + padding: 3px 5px; + width: 38%; + vertical-align: top; +} + +label.plain { + background: none; + border: none; + box-shadow: none; + color: black; + display: inline; + margin: 0; + padding: 0; +} + +.rec_exceptions { display: inline-block; } +.rec_exceptions_holder { display: inline-block; } +.rec_exceptions .remover { } +#rec_until_count { width: 50px; } +#rec_until_date { width: 100px; } \ No newline at end of file diff --git a/dav/layout.fnk.php b/dav/layout.fnk.php deleted file mode 100644 index 597e773d..00000000 --- a/dav/layout.fnk.php +++ /dev/null @@ -1,535 +0,0 @@ -page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; - - $a->page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; - - $a->page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; - - $a->page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; - - $a->page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; - - switch (get_config("system", "language")) { - case "de": - $a->page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; - break; - default: - $a->page['htmlhead'] .= '' . "\r\n"; - } - - $a->page['htmlhead'] .= '' . "\r\n"; - $a->page['htmlhead'] .= '' . "\r\n"; -} - - - -/** - * @param int $calendar_id - */ -function wdcal_print_user_ics($calendar_id) -{ - $calendar_id = IntVal($calendar_id); - - $a = get_app(); - header("Content-type: text/plain"); - - $str = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\n"; - $cals = q("SELECT * FROM %s%scalendars WHERE `id` = %d AND `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendar_id, CALDAV_NAMESPACE_PRIVATE, $a->user["uid"]); - if (count($cals) > 0) { - $objs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d ORDER BY `firstOccurence`", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendar_id); - - foreach ($objs as $obj) { - preg_match("/BEGIN:VEVENT(.*)END:VEVENT/siu", $obj["calendardata"], $matches); - $str2 = preg_replace("/([^\\r])\\n/siu", "\\1\r\n", $matches[0]); - $str2 = preg_replace("/MAILTO:.*[^:a-z0-9_\+äöüß\\n\\n@-]+.*(:|\\r\\n[^ ])/siU", "\\1", $str2); - $str .= $str2 . "\r\n"; - } - } - $str .= "END:VCALENDAR\r\n"; - - echo $str; - killme(); -} - - -/** - * @param int $calendar_id - * @return string - */ -function wdcal_import_user_ics($calendar_id) { - $a = get_app(); - $calendar_id = IntVal($calendar_id); - $o = ""; - - $server = dav_create_server(true, true, false); - $calendar = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_WRITE); - if (!$calendar) goaway($a->get_baseurl() . "/dav/wdcal/"); - - if (isset($_REQUEST["save"])) { - check_form_security_token_redirectOnErr('/dav/settings/', 'icsimport'); - - if ($_FILES["ics_file"]["tmp_name"] != "" && is_uploaded_file($_FILES["ics_file"]["tmp_name"])) try { - $text = file_get_contents($_FILES["ics_file"]["tmp_name"]); - - /** @var Sabre_VObject_Component_VCalendar $vObject */ - $vObject = Sabre_VObject_Reader::read($text); - $comp = $vObject->getComponents(); - $imported = array(); - foreach ($comp as $c) try { - /** @var Sabre_VObject_Component_VEvent $c */ - $uid = $c->__get("UID")->value; - if (!isset($imported[$uid])) $imported[$uid] = ""; - $imported[$uid] .= $c->serialize(); - } catch (Exception $e) { - notice(t("Something went wrong when trying to import the file. Sorry. Maybe some events were imported anyway.")); - } - - if (isset($_REQUEST["overwrite"])) { - $children = $calendar->getChildren(); - foreach ($children as $child) { - /** @var Sabre_CalDAV_CalendarObject $child */ - $child->delete(); - } - $i = 1; - } else { - $i = 0; - $children = $calendar->getChildren(); - foreach ($children as $child) { - /** @var Sabre_CalDAV_CalendarObject $child */ - $name = $child->getName(); - if (preg_match("/import\-([0-9]+)\.ics/siu", $name, $matches)) { - if ($matches[1] > $i) $i = $matches[1]; - }; - } - $i++; - } - - foreach ($imported as $object) try { - - $str = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\n"; - $str .= trim($object); - $str .= "\r\nEND:VCALENDAR\r\n"; - - $calendar->createFile("import-" . $i . ".ics", $str); - $i++; - } catch (Exception $e) { - notice(t("Something went wrong when trying to import the file. Sorry.")); - } - - $o = t("The ICS-File has been imported."); - } catch (Exception $e) { - notice(t("Something went wrong when trying to import the file. Sorry. Maybe some events were imported anyway.")); - } else { - notice(t("No file was uploaded.")); - } - } - - - $o .= "" . t("Go back to the calendar") . "

"; - - $num = q("SELECT COUNT(*) num FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendar_id); - - $o .= "

" . t("Import a ICS-file") . "

"; - $o .= '
'; - $o .= "\n"; - $o .= "
\n"; - if ($num[0]["num"] > 0) $o .= "
\n"; - $o .= ""; - $o .= '
'; - - return $o; -} - - -/** - * @param array|Sabre_CalDAV_Calendar[] $calendars - * @param array|int[] $calendars_selected - * @param string $data_feed_url - * @param string $view - * @param int $theme - * @param int $height_diff - * @param bool $readonly - * @param string $curr_day - * @param array $add_params - * @param bool $show_nav - * @return string - */ -function wdcal_printCalendar($calendars, $calendars_selected, $data_feed_url, $view = "week", $theme = 0, $height_diff = 175, $readonly = false, $curr_day = "", $add_params = array(), $show_nav = true) -{ - - $a = get_app(); - $localization = wdcal_local::getInstanceByUser($a->user["uid"]); - - if (count($calendars_selected) == 0) foreach ($calendars as $c) { - $prop = $c->getProperties(array("id")); - $calendars_selected[] = $prop["id"]; - } - - $opts = array( - "view" => $view, - "theme" => $theme, - "readonly" => $readonly, - "height_diff" => $height_diff, - "weekstartday" => $localization->getFirstDayOfWeek(), - "data_feed_url" => $data_feed_url, - "date_format_dm1" => $localization->dateformat_js_dm1(), - "date_format_dm2" => $localization->dateformat_js_dm2(), - "date_format_dm3" => $localization->dateformat_js_dm3(), - "date_format_full" => $localization->dateformat_datepicker_js(), - "baseurl" => $a->get_baseurl() . "/dav/wdcal/", - ); - - $x = ' - - -
-
Available Calendars:'; - - foreach ($calendars as $cal) { - $cal_id = $cal->getProperties(array("id", DAV_DISPLAYNAME)); - $x .= '
-
- -
'; - - if ($show_nav) { - - $x .= '
- - -
-
-
' . t("Today") . '
-
-
- -
-
-
-
-
-
- -
-
-
-
' . t("Reload") . '
-
-
-
- -
-
- -
-
- - ' . t("Date") . ' -
-
-
-
- '; - } - $x .= ' -
-
-
-
-
-'; - - return $x; -} - - -/** - * @param int $calendar_id - * @param int $calendarobject_id - * @return string - */ -function wdcal_getDetailPage($calendar_id, $calendarobject_id) -{ - $a = get_app(); - - try { - $details = null; - $server = dav_create_server(true, true, false); - $cal = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_READ); - $obj = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($calendarobject_id); - dav_get_current_user_calendarobject($server, $cal, $obj["uri"], DAV_ACL_READ); // Check permissions - - $calbackend = wdcal_calendar_factory_by_id($calendar_id); - $redirect = $calbackend->getItemDetailRedirect($calendar_id, $calendarobject_id); - - if ($redirect !== null) goaway($a->get_baseurl() . $redirect); - - $details = $obj; - } catch (Exception $e) { - info(t("Error") . ": " . $e); - goaway($a->get_baseurl() . "/dav/wdcal/"); - } - - return print_r($details, true); -} - - -/** - * @param int $calendar_id - * @param int $uri - * @return string - */ -function wdcal_getEditPage($calendar_id, $uri) -{ - $a = get_app(); - $localization = wdcal_local::getInstanceByUser($a->user["uid"]); - - return wdcal_getEditPage_str($localization, $a->get_baseurl(), $calendar_id, $uri); -} - -/** - * @return string - */ -function wdcal_getNewPage() -{ - $a = get_app(); - $localization = wdcal_local::getInstanceByUser($a->user["uid"]); - - return wdcal_getEditPage_str($localization, $a->get_baseurl(), 0, 0); -} - - -/** - * @param App $a - * @return string - */ -function wdcal_getSettingsPage(&$a) -{ - - if (!local_user()) { - notice(t('Permission denied.') . EOL); - return ''; - } - - if (isset($_REQUEST["save"])) { - check_form_security_token_redirectOnErr('/dav/settings/', 'calprop'); - set_pconfig($a->user["uid"], "dav", "dateformat", $_REQUEST["wdcal_date_format"]); - info(t('The new values have been saved.')); - } - - if (isset($_REQUEST["save_cals"])) { - check_form_security_token_redirectOnErr('/dav/settings/', 'calprop'); - - $r = q("SELECT * FROM %s%scalendars WHERE `namespace` = " . CALDAV_NAMESPACE_PRIVATE . " AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($a->user["uid"])); - foreach ($r as $cal) { - $backend = wdcal_calendar_factory($cal["namespace"], $cal["namespace_id"], $cal["uri"], $cal); - $change_sql = ""; - $col = substr($_REQUEST["color"][$cal["id"]], 1); - if (strtolower($col) != strtolower($cal["calendarcolor"])) $change_sql .= ", `calendarcolor` = '" . dbesc($col) . "'"; - if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual")) { - if ($_REQUEST["uri"][$cal["id"]] != $cal["uri"]) $change_sql .= ", `uri` = '" . dbesc($_REQUEST["uri"][$cal["id"]]) . "'"; - if ($_REQUEST["name"][$cal["id"]] != $cal["displayname"]) $change_sql .= ", `displayname` = '" . dbesc($_REQUEST["name"][$cal["id"]]) . "'"; - } - if ($change_sql != "") { - q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 $change_sql WHERE `id` = %d AND `namespace_id` = %d AND `namespace_id` = %d", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $cal["id"], CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); - info(t('The calendar has been updated.')); - } - } - - if (isset($_REQUEST["uri"]["new"]) && $_REQUEST["uri"]["new"] != "" && $_REQUEST["name"]["new"] && $_REQUEST["name"]["new"] != "") { - $order = q("SELECT MAX(`calendarorder`) ord FROM %s%scalendars WHERE `namespace_id` = %d AND `namespace_id` = %d", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); - $neworder = $order[0]["ord"] + 1; - q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `calendarorder`, `calendarcolor`, `displayname`, `timezone`, `uri`, `has_vevent`, `ctag`) - VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', 1, 1)", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"]), $neworder, dbesc(strtolower(substr($_REQUEST["color"]["new"], 1))), - dbesc($_REQUEST["name"]["new"]), dbesc($a->timezone), dbesc($_REQUEST["uri"]["new"]) - ); - info(t('The new calendar has been created.')); - } - } - - if (isset($_REQUEST["remove_cal"])) { - check_form_security_token_redirectOnErr('/dav/settings/', 'del_cal', 't'); - - $c = q("SELECT * FROM %s%scalendars WHERE `id` = %d AND `namespace_id` = %d AND `namespace_id` = %d", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"]), CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); - if (count($c) != 1) killme(); - - $calobjs = q("SELECT `id` FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"])); - - $newcal = q("SELECT * FROM %s%scalendars WHERE `id` != %d AND `namespace_id` = %d AND `namespace_id` = %d ORDER BY `calendarcolor` LIMIT 0,1", - CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"]), CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"])); - if (count($newcal) != 1) killme(); - - q("UPDATE %s%scalendarobjects SET `calendar_id` = %d WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($newcal[0]["id"]), IntVal($c[0]["id"])); - - foreach ($calobjs as $calobj) renderCalDavEntry_calobj_id($calobj["id"]); - - q("DELETE FROM %s%scalendars WHERE `id` = %s", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["remove_cal"])); - q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 WHERE `id` = " . CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $newcal[0]["id"]); - - info(t('The calendar has been deleted.')); - } - - $o = ""; - - $o .= "" . t("Go back to the calendar") . "

"; - - $o .= '

' . t('Calendar Settings') . '

'; - - $current_format = wdcal_local::getInstanceByUser($a->user["uid"]); - $o .= '
'; - $o .= "\n"; - - $o .= '
'; - - $o .= '
'; - - $o .= ''; - $o .= '
'; - - - $o .= '

' . t('Calendars') . '

'; - $o .= '
'; - $o .= "\n"; - $o .= ""; - - $r = q("SELECT * FROM %s%scalendars WHERE `namespace` = " . CALDAV_NAMESPACE_PRIVATE . " AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($a->user["uid"])); - $private_max = 0; - $num_non_virtual = 0; - foreach ($r as $x) { - $backend = wdcal_calendar_factory($x["namespace"], $x["namespace_id"], $x["uri"], $x); - if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual")) $num_non_virtual++; - } - foreach ($r as $x) { - $p = explode("private-", $x["uri"]); - if (count($p) == 2 && $p[1] > $private_max) $private_max = $p[1]; - - $backend = wdcal_calendar_factory($x["namespace"], $x["namespace_id"], $x["uri"], $x); - $disabled = (is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual") ? "disabled" : ""); - $o .= ""; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= "\n"; - $o .= "\n"; - } - - $private_max++; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= ""; - $o .= "\n"; - - $o .= "
TypeColorNameURI (for CalDAV)ICS
" . escape_tags($backend->getBackendTypeName()) . "Export"; - if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual") && $num_non_virtual > 1) $o .= " / Import"; - $o .= ""; - if (!is_subclass_of($backend, "Sabre_CalDAV_Backend_Virtual") && $num_non_virtual > 1) $o .= "Delete"; - $o .= "
"; - $o .= "
[" . t("Create a new calendar") . "]
"; - $o .= ''; - $o .= '
'; - $baseurl = $a->get_baseurl(); - $o .= ""; - - - $o .= "

" . t("Limitations") . "

"; - - $o .= "- The native friendica events are embedded as read-only, half-transparent in the calendar.
"; - - $o .= "

" . t("Warning") . "

"; - - $o .= "This plugin still is in a very early stage of development. Expect major bugs!
"; - - $o .= "

" . t("Synchronization (iPhone, Thunderbird Lightning, Android, ...)") . "

"; - - $o .= 'This plugin enables synchronization of your dates and contacts with CalDAV- and CardDAV-enabled programs or devices.
- As an example, the instructions how to set up two-way synchronization with an iPhone/iPodTouch are provided below.
- Unfortunately, Android does not have native support for CalDAV or CardDAV, so an app has to be installed.
- On desktops, the Lightning-extension to Mozilla Thunderbird should be able to use this plugin as a backend.

'; - - $o .= '

' . t('Synchronizing this calendar with the iPhone') . '

'; - - $o .= ""; - - $o .= '

' . t('Synchronizing your Friendica-Contacts with the iPhone') . '

'; - - $o .= ""; - - return $o; -} - diff --git a/dav/main.php b/dav/main.php deleted file mode 100644 index c36d0084..00000000 --- a/dav/main.php +++ /dev/null @@ -1,348 +0,0 @@ -argc >= 2 && $a->argv[1] == "wdcal") { - - if ($a->argc >= 3 && $a->argv[2] == "feed") { - wdcal_print_feed($a->get_baseurl() . "/dav/wdcal/"); - killme(); - } - return; - } - if ($a->argc >= 2 && $a->argv[1] == "getExceptionDates") { - echo wdcal_getEditPage_exception_selector(); - killme(); - } - - if ($a->argc >= 2 && $a->argv[1] == "settings") { - return; - } - - - if (isset($_REQUEST["test"])) { - renderAllCalDavEntries(); - } - - - $server = dav_create_server(); - - $browser = new Sabre_DAV_Browser_Plugin(); - $server->addPlugin($browser); - - $server->exec(); - - killme(); -} - -/** - * @return string - */ -function dav_content() -{ - $a = get_app(); - if (!isset($a->user["uid"]) || $a->user["uid"] == 0) { - return login(); - } - - $x = ""; - try { - if ($a->argv[1] == "settings") { - return wdcal_getSettingsPage($a); - } elseif ($a->argv[1] == "wdcal") { - if (isset($a->argv[2]) && strlen($a->argv[2]) > 0) { - if ($a->argv[2] == "new") { - $o = ""; - if (isset($_REQUEST["save"])) { - check_form_security_token_redirectOnErr($a->get_baseurl() . "/dav/wdcal/", "caledit"); - $ret = wdcal_postEditPage("new", "", $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/"); - if ($ret["ok"]) notice($ret["msg"]); - else info($ret["msg"]); - goaway($a->get_baseurl() . "/dav/wdcal/"); - } - $o .= wdcal_getNewPage(); - return $o; - } else { - $calendar_id = IntVal($a->argv[2]); - if (isset($a->argv[3]) && $a->argv[3] == "ics-export") { - wdcal_print_user_ics($calendar_id); - } elseif (isset($a->argv[3]) && $a->argv[3] == "ics-import") { - return wdcal_import_user_ics($calendar_id); - } elseif (isset($a->argv[3]) && $a->argv[3] > 0) { - if (isset($a->argv[4]) && $a->argv[4] == "edit") { - $o = ""; - if (isset($_REQUEST["save"])) { - check_form_security_token_redirectOnErr($a->get_baseurl() . "/dav/wdcal/", "caledit"); - $ret = wdcal_postEditPage($a->argv[3], $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/"); - if ($ret["ok"]) notice($ret["msg"]); - else info($ret["msg"]); - goaway($a->get_baseurl() . "/dav/wdcal/"); - } - $o .= wdcal_getEditPage($calendar_id, $a->argv[3]); - return $o; - } else { - return wdcal_getDetailPage($calendar_id, $a->argv[3]); - } - } else { - // @TODO Edit Calendar - } - } - } else { - $server = dav_create_server(true, true, false); - $cals = dav_get_current_user_calendars($server, DAV_ACL_READ); - $x = wdcal_printCalendar($cals, array(), $a->get_baseurl() . "/dav/wdcal/feed/", "week", 0, 200); - } - } - } catch (DAVVersionMismatchException $e) { - $x = t("The current version of this plugin has not been set up correctly. Please contact the system administrator of your installation of friendica to fix this."); - } - return $x; -} - - -/** - * @param App $a - * @param object $b - */ -function dav_event_created_hook(&$a, &$b) -{ - dav_include_files(); - // @TODO Updating the cache instead of completely invalidating and rebuilding it - Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS); - Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE); -} - -/** - * @param App $a - * @param object $b - */ -function dav_event_updated_hook(&$a, &$b) -{ - dav_include_files(); - // @TODO Updating the cache instead of completely invalidating and rebuilding it - Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS); - Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE); -} - -/** - * @param App $a - * @param object $b - */ -function dav_profile_tabs_hook(&$a, &$b) -{ - $b["tabs"][] = array( - "label" => t('Calendar'), - "url" => $a->get_baseurl() . "/dav/wdcal/", - "sel" => "", - "title" => t('Extended calendar with CalDAV-support'), - ); -} - - -/** - * @param App $a - * @param object $b - */ -function dav_cron(&$a, &$b) -{ - dav_include_files(); - - $r = q("SELECT * FROM %s%snotifications WHERE `notified` = 0 AND `alert_date` <= NOW()", CALDAV_SQL_DB, CALDAV_SQL_PREFIX); - foreach ($r as $not) { - q("UPDATE %s%snotifications SET `notified` = 1 WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $not["id"]); - $event = q("SELECT * FROM %s%sjqcalendar WHERE `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $not["calendarobject_id"]); - $calendar = q("SELECT * FROM %s%scalendars WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $not["calendar_id"]); - $users = array(); - if (count($calendar) != 1 || count($event) == 0) continue; - switch ($calendar[0]["namespace"]) { - case CALDAV_NAMESPACE_PRIVATE: - $user = q("SELECT * FROM user WHERE `uid` = %d AND `blocked` = 0", $calendar[0]["namespace_id"]); - if (count($user) != 1) continue; - $users[] = $user[0]; - break; - } - switch ($not["action"]) { - case "email": - case "display": // @TODO implement "Display" - foreach ($users as $user) { - $find = array("%to%", "%event%", "%url%"); - $repl = array($user["username"], $event[0]["Summary"], $a->get_baseurl() . "/dav/wdcal/" . $calendar[0]["id"] . "/" . $not["calendarobject_id"] . "/"); - $text_text = str_replace($find, $repl, "Hi %to%!\n\nThe event \"%event%\" is about to begin:\n%url%"); - $text_html = str_replace($find, $repl, "Hi %to%!
\n
\nThe event \"%event%\" is about to begin:
\n%url%"); - $params = array( - 'fromName' => FRIENDICA_PLATFORM, - 'fromEmail' => t('noreply') . '@' . $a->get_hostname(), - 'replyTo' => t('noreply') . '@' . $a->get_hostname(), - 'toEmail' => $user["email"], - 'messageSubject' => t("Notification: " . $event[0]["Summary"]), - 'htmlVersion' => $text_html, - 'textVersion' => $text_text, - 'additionalMailHeader' => "", - ); - require_once('include/enotify.php'); - enotify::send($params); - } - break; - } - } -} - - -/** - * @param App $a - * @param null|object $o - */ -function dav_plugin_admin_post(&$a = null, &$o = null) -{ - check_form_security_token_redirectOnErr('/admin/plugins/dav', 'dav_admin_save'); - - dav_include_files(); - require_once(__DIR__ . "/database-init.inc.php"); - - if (isset($_REQUEST["install"])) { - $errs = dav_create_tables(); - if (count($errs) == 0) info(t('The database tables have been installed.') . EOL); - else notice(t("An error occurred during the installation.") . EOL); - } - if (isset($_REQUEST["upgrade"])) { - $errs = dav_upgrade_tables(); - if (count($errs) == 0) { - renderAllCalDavEntries(); - info(t('The database tables have been updated.') . EOL); - } - else notice(t("An error occurred during the update.") . EOL); - } -} - -/** - * @param App $a - * @param string $o - */ -function dav_plugin_admin(&$a, &$o) -{ - dav_include_files(); - require_once(__DIR__ . "/database-init.inc.php"); - - $dbstatus = dav_check_tables(); - - $o = ''; - $o .= '' . t("No system-wide settings yet.") . '

'; - - - $o .= '

' . t('Database status') . '

'; - switch ($dbstatus) { - case 0: - $o .= t('Installed'); - break; - case 1: - $o .= "" . t('Upgrade needed') . "
" . t("Please back up all calendar data (the tables beginning with dav_*) before proceeding. While all calendar events should be converted to the new database structure, it's always safe to have a backup. Below, you can have a look at the database-queries that will be made when pressing the 'update'-button.") . "

"; - break; - case -1: - $o .= t('Not installed') . "

"; - break; - case -2: - default: - $o .= t('Unknown') . "

" . t("Something really went wrong. I cannot recover from this state automatically, sorry. Please go to the database backend, back up the data, and delete all tables beginning with 'dav_' manually. Afterwards, this installation routine should be able to reinitialize the tables automatically."); - break; - } - $o .= "

"; - - $o .= "

" . t("Troubleshooting") . "

"; - $o .= "

" . t("Manual creation of the database tables:") . "

"; - $o .= "" . t("Show SQL-statements") . ""; -} diff --git a/dav/wdcal.css b/dav/wdcal.css deleted file mode 100644 index 18c25c58..00000000 --- a/dav/wdcal.css +++ /dev/null @@ -1,43 +0,0 @@ - -div.colorPicker-picker { display: inline-block; } -.colorPicker-palette { font-size: 12px; } -.animexxcalendar label, .colorPicker-palette label { background: none; border: none; padding: 0; margin: 0; box-shadow: none; display: inline; font-size: 14px; } -.animexxcalendar input, .colorPicker-palette input { font-size: 14px; } - - -.ui-datepicker { width: 200px; } -.ui-datepicker * { font-size: 12px; line-height: 12px; } -.ui-datepicker th { padding: 10px 2px; } -.ui-datepicker select.ui-datepicker-year { min-width: 0; width: 50px !important; } -#cal_start_time, #cal_end_time { width: 5em; margin-left: 1em; } -#cal_start_date, #cal_end_date { width: 6em;} - - -label.block { - background: none repeat scroll 0 0 #CCCCCC; - border: 1px solid #EEEEEC; - box-shadow: 3px 3px 5px 0 #111111; - color: #111111; - display: inline-block; - font-size: small; - margin: 0 10px 1em 0; - padding: 3px 5px; - width: 38%; - vertical-align: top; -} - -label.plain { - background: none; - border: none; - box-shadow: none; - color: black; - display: inline; - margin: 0; - padding: 0; -} - -.rec_exceptions { display: inline-block; } -.rec_exceptions_holder { display: inline-block; } -.rec_exceptions .remover { } -#rec_until_count { width: 50px; } -#rec_until_date { width: 100px; } \ No newline at end of file