diff options
Diffstat (limited to 'webmail/plugins/carddav/carddav.php')
| -rw-r--r-- | webmail/plugins/carddav/carddav.php | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/webmail/plugins/carddav/carddav.php b/webmail/plugins/carddav/carddav.php new file mode 100644 index 0000000..3c40012 --- /dev/null +++ b/webmail/plugins/carddav/carddav.php @@ -0,0 +1,619 @@ +<?php + +/** + * Include required CardDAV classes + */ +require_once dirname(__FILE__) . '/carddav_backend.php'; +require_once dirname(__FILE__) . '/carddav_addressbook.php'; + +/** + * Roundcube CardDAV implementation + * + * This is a CardDAV implementation for roundcube 0.6 or higher. It allows every user to add + * multiple CardDAV server in their settings. The CardDAV contacts (vCards) will be synchronized + * automaticly with their addressbook. + * + * @author Christian Putzke <christian.putzke@graviox.de> + * @copyright Christian Putzke @ Graviox Studios + * @since 06.09.2011 + * @link http://www.graviox.de/ + * @link https://twitter.com/graviox/ + * @version 0.5.1 + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + * + */ + +class carddav extends rcube_plugin +{ + /** + * Roundcube CardDAV version + * + * @constant string + */ + const VERSION = '0.5.1'; + + /** + * Tasks where the CardDAV plugin is loaded + * + * @var string + */ + public $task = 'settings|addressbook|mail'; + + /** + * CardDAV addressbook + * + * @var string + */ + protected $carddav_addressbook = 'carddav_addressbook'; + + /** + * Init CardDAV plugin - register actions, include scripts, load texts, add hooks + * + * @return void + */ + public function init() + { + $rcmail = rcmail::get_instance(); + $skin_path = $this->local_skin_path(); + + if (!is_dir($skin_path)) + { + $skin_path = 'skins/default'; + } + + $this->add_texts('localization/', true); + $this->include_stylesheet($skin_path . '/carddav.css'); + + switch ($rcmail->task) + { + case 'settings': + $this->register_action('plugin.carddav-server', array($this, 'carddav_server')); + $this->register_action('plugin.carddav-server-save', array($this, 'carddav_server_save')); + $this->register_action('plugin.carddav-server-delete', array($this, 'carddav_server_delete')); + $this->include_script('carddav_settings.js'); + $this->include_script('jquery.base64.js'); + break; + + case 'addressbook': + if ($this->carddav_server_available()) + { + $this->register_action('plugin.carddav-addressbook-sync', array($this, 'carddav_addressbook_sync')); + $this->include_script('carddav_addressbook.js'); + $this->add_hook('addressbooks_list', array($this, 'get_carddav_addressbook_sources')); + $this->add_hook('addressbook_get', array($this, 'get_carddav_addressbook')); + + $this->add_button(array( + 'command' => 'plugin.carddav-addressbook-sync', + 'imagepas' => $skin_path . '/sync_pas.png', + 'imageact' => $skin_path . '/sync_act.png', + 'width' => 32, + 'height' => 32, + 'title' => 'carddav.addressbook_sync' + ), 'toolbar'); + } + break; + + case 'mail': + if ($this->carddav_server_available()) + { + $this->add_hook('addressbooks_list', array($this, 'get_carddav_addressbook_sources')); + $this->add_hook('addressbook_get', array($this, 'get_carddav_addressbook')); + + $sources = (array) $rcmail->config->get('autocomplete_addressbooks', array('sql')); + $servers = $this->get_carddav_server(); + + foreach ($servers as $server) + { + if (!in_array($this->carddav_addressbook . $server['carddav_server_id'], $sources)) + { + $sources[] = $this->carddav_addressbook . $server['carddav_server_id']; + $rcmail->config->set('autocomplete_addressbooks', $sources); + } + } + } + break; + } + } + + /** + * Extend the original local_skin_path method with the default skin path as fallback + * + * @param boolean $include_plugins_directory Include plugins directory + * @return string $skin_path Roundcubes skin path + */ + public function local_skin_path($include_plugins_directory = false) + { + $skin_path = parent::local_skin_path(); + + if (!is_dir($skin_path)) + { + $skin_path = 'skins/default'; + } + + if ($include_plugins_directory === true) + { + $skin_path = 'plugins/carddav/' . $skin_path; + } + + return $skin_path; + } + + /** + * Get all CardDAV servers from the current user + * + * @param boolean $carddav_server_id CardDAV server id to load a single CardDAV server + * @return array CardDAV server array with label, url, username, password (encrypted) + */ + public function get_carddav_server($carddav_server_id = false) + { + $servers = array(); + $rcmail = rcmail::get_instance(); + $user_id = $rcmail->user->data['user_id']; + + $query = " + SELECT + * + FROM + ".get_table_name('carddav_server')." + WHERE + user_id = ? + ".($carddav_server_id !== false ? " AND carddav_server_id = ?" : null)." + "; + + $result = $rcmail->db->query($query, $user_id, $carddav_server_id); + + while($server = $rcmail->db->fetch_assoc($result)) + { + $servers[] = $server; + } + + return $servers; + } + + /** + * Render available CardDAV server list in HTML + * + * @return string HTML rendered CardDAV server list + */ + protected function get_carddav_server_list() + { + $servers = $this->get_carddav_server(); + + if (!empty($servers)) + { + $skin_path = $this->local_skin_path(true); + $content = html::div(array('class' => 'carddav_headline'), $this->gettext('settings_server')); + $table = new html_table(array( + 'cols' => 6, + 'class' => 'carddav_server_list' + )); + + $table->add_header(array('width' => '13%'), $this->gettext('settings_label')); + $table->add_header(array('width' => '36%'), $this->gettext('server')); + $table->add_header(array('width' => '13%'), $this->gettext('username')); + $table->add_header(array('width' => '13%'), $this->gettext('password')); + $table->add_header(array('width' => '13%'), $this->gettext('settings_read_only')); + $table->add_header(array('width' => '13%'), null); + + foreach ($servers as $server) + { + // $rcmail->output->button() seems not to work within ajax requests so we build the button manually + $delete_submit = '<input + type="button" + value="'.$this->gettext('delete').'" + onclick="return rcmail.command(\'plugin.carddav-server-delete\', \''.$server['carddav_server_id'].'\', this)" + class="button mainaction" + />'; + + $table->add(array(), $server['label']); + $table->add(array(), $server['url']); + $table->add(array(), $server['username']); + $table->add(array(), '**********'); + $table->add(array(), ($server['read_only'] ? html::img($skin_path . '/checked.png') : null)); + $table->add(array(), $delete_submit); + } + + $content .= html::div(array('class' => 'carddav_container'), $table->show()); + return $content; + } + else + { + return null; + } + } + + /** + * Get CardDAV addressbook instance + * + * @param array $addressbook Array with all available addressbooks + * @return array Array with all available addressbooks + */ + public function get_carddav_addressbook($addressbook) + { + $servers = $this->get_carddav_server(); + + foreach ($servers as $server) + { + if ($addressbook['id'] === $this->carddav_addressbook . $server['carddav_server_id']) + { + $addressbook['instance'] = new carddav_addressbook($server['carddav_server_id'], $server['label'], ($server['read_only'] == 1 ? true : false)); + } + } + + return $addressbook; + } + + /** + * Get CardDAV addressbook source + * + * @param array $addressbook Array with all available addressbooks sources + * @return array Array with all available addressbooks sources + */ + public function get_carddav_addressbook_sources($addressbook) + { + $servers = $this->get_carddav_server(); + + foreach ($servers as $server) + { + $carddav_addressbook = new carddav_addressbook($server['carddav_server_id'], $server['label'], ($server['read_only'] == 1 ? true : false)); + + $addressbook['sources'][$this->carddav_addressbook . $server['carddav_server_id']] = array( + 'id' => $this->carddav_addressbook . $server['carddav_server_id'], + 'name' => $server['label'], + 'readonly' => $carddav_addressbook->readonly, + 'groups' => $carddav_addressbook->groups + ); + } + + return $addressbook; + } + + /** + * Check if CURL is installed or not + * + * @return boolean + */ + private function check_curl_installed() + { + if (function_exists('curl_init')) + { + return true; + } + else + { + return false; + } + } + + /** + * Synchronize CardDAV addressbook + * + * @param boolean $carddav_server_id CardDAV server id to synchronize a single CardDAV server + * @param boolean $ajax Within a ajax request or not + * @return void + */ + public function carddav_addressbook_sync($carddav_server_id = false, $ajax = true) + { + $servers = $this->get_carddav_server(); + $result = false; + + foreach ($servers as $server) + { + if ($carddav_server_id === false || $carddav_server_id == $server['carddav_server_id']) + { + $carddav_addressbook = new carddav_addressbook($server['carddav_server_id'], $server['label'], ($server['read_only'] == 1 ? true : false)); + $result = $carddav_addressbook->carddav_addressbook_sync($server); + } + } + + if ($ajax === true) + { + $rcmail = rcmail::get_instance(); + + if ($result === true) + { + $rcmail->output->command('plugin.carddav_addressbook_message', array( + 'message' => $this->gettext('addressbook_synced'), + 'check' => true + )); + } + else + { + $rcmail->output->command('plugin.carddav_addressbook_message', array( + 'message' => $this->gettext('addressbook_sync_failed'), + 'check' => false + )); + } + } + } + + /** + * Render CardDAV server settings + * + * @return void + */ + public function carddav_server() + { + $rcmail = rcmail::get_instance(); + $this->register_handler('plugin.body', array($this, 'carddav_server_form')); + $rcmail->output->set_pagetitle($this->gettext('settings')); + $rcmail->output->send('plugin'); + } + + /** + * Check if CardDAV server are available in the local database + * + * @return boolean If CardDAV-Server are available in the local database return true else false + */ + protected function carddav_server_available() + { + $rcmail = rcmail::get_instance(); + $user_id = $rcmail->user->data['user_id']; + + $query = " + SELECT + * + FROM + ".get_table_name('carddav_server')." + WHERE + user_id = ? + "; + + $result = $rcmail->db->query($query, $user_id); + + if ($rcmail->db->num_rows($result)) + { + return true; + } + else + { + return false; + } + } + + /** + * Check if it's possible to connect to the CardDAV server + * + * @return boolean + */ + public function carddav_server_check_connection() + { + $url = parse_input_value(base64_decode($_POST['_server_url'])); + $username = parse_input_value(base64_decode($_POST['_username'])); + $password = parse_input_value(base64_decode($_POST['_password'])); + + $carddav_backend = new carddav_backend($url); + $carddav_backend->set_auth($username, $password); + + return $carddav_backend->check_connection(); + } + + /** + * Render CardDAV server settings formular and register JavaScript actions + * + * @return string HTML CardDAV server formular + */ + public function carddav_server_form() + { + $rcmail = rcmail::get_instance(); + $boxcontent = null; + + if ($this->check_curl_installed()) + { + $input_label = new html_inputfield(array( + 'name' => '_label', + 'id' => '_label', + 'size' => '17' + )); + + $input_server_url = new html_inputfield(array( + 'name' => '_server_url', + 'id' => '_server_url', + 'size' => '44' + )); + + $input_username = new html_inputfield(array( + 'name' => '_username', + 'id' => '_username', + 'size' => '17' + )); + + $input_password = new html_passwordfield(array( + 'name' => '_password', + 'id' => '_password', + 'size' => '17' + )); + + $input_read_only = new html_checkbox(array( + 'name' => '_read_only', + 'id' => '_read_only', + 'value' => 1 + )); + + $input_submit = $rcmail->output->button(array( + 'command' => 'plugin.carddav-server-save', + 'type' => 'input', + 'class' => 'button mainaction', + 'label' => 'save' + )); + + $table = new html_table(array( + 'cols' => 6, + 'class' => 'carddav_server_list' + )); + + $table->add_header(array('width' => '13%'), $this->gettext('settings_label')); + $table->add_header(array('width' => '35%'), $this->gettext('server')); + $table->add_header(array('width' => '13%'), $this->gettext('username')); + $table->add_header(array('width' => '13%'), $this->gettext('password')); + $table->add_header(array('width' => '13%'), $this->gettext('settings_read_only')); + $table->add_header(array('width' => '13%'), null); + + $table->add(array(), $input_label->show()); + $table->add(array(), $input_server_url->show()); + $table->add(array(), $input_username->show()); + $table->add(array(), $input_password->show()); + $table->add(array(), $input_read_only->show()); + $table->add(array(), $input_submit); + + $boxcontent .= html::div(array('class' => 'carddav_headline'), $this->gettext('settings_server_form')); + $boxcontent .= html::div(array('class' => 'carddav_container'), $table->show());; + } + else + { + $rcmail->output->show_message($this->gettext('settings_curl_not_installed'), 'error'); + } + + $output = html::div( + array('class' => 'box carddav'), + html::div(array('class' => 'boxtitle'), $this->gettext('settings')). + html::div(array('class' => 'boxcontent', 'id' => 'carddav_server_list'), $this->get_carddav_server_list()). + html::div(array('class' => 'boxcontent'), $boxcontent). + html::div(array('class' => 'boxcontent'), $this->get_carddav_url_list()) + ); + + return $output; + } + + /** + * Render a CardDAV server example URL list + * + * @return string $content HTML CardDAV server example URL list + */ + public function get_carddav_url_list() + { + $content = null; + + $table = new html_table(array( + 'cols' => 2, + 'class' => 'carddav_server_list' + )); + + $table->add(array(), 'DAViCal'); + $table->add(array(), 'https://example.com/{resource|principal|username}/{collection}/'); + + $table->add(array(), 'Apple Addressbook Server'); + $table->add(array(), 'https://example.com/addressbooks/users/{resource|principal|username}/{collection}/'); + + $table->add(array(), 'memotoo'); + $table->add(array(), 'https://sync.memotoo.com/cardDAV/'); + + $table->add(array(), 'SabreDAV'); + $table->add(array(), 'https://example.com/addressbooks/{resource|principal|username}/{collection}/'); + + $table->add(array(), 'ownCloud'); + $table->add(array(), 'https://example.com/apps/contacts/carddav.php/addressbooks/{resource|principal|username}/{collection}/'); + + $table->add(array(), 'SOGo'); + $table->add(array(), 'https://example.com/SOGo/dav/{resource|principal|username}/Contacts/{collection}/'); + + $content .= html::div(array('class' => 'carddav_headline example_server_list'), $this->gettext('settings_example_server_list')); + $content .= html::div(array('class' => 'carddav_container'), $table->show()); + + return $content; + } + + /** + * Save CardDAV server and execute first CardDAV contact sync + * + * @return void + */ + public function carddav_server_save() + { + $rcmail = rcmail::get_instance(); + + if ($this->carddav_server_check_connection()) + { + $user_id = $rcmail->user->data['user_id']; + $url = parse_input_value(base64_decode($_POST['_server_url'])); + $username = parse_input_value(base64_decode($_POST['_username'])); + $password = parse_input_value(base64_decode($_POST['_password'])); + $label = parse_input_value(base64_decode($_POST['_label'])); + $read_only = (int) parse_input_value(base64_decode($_POST['_read_only'])); + + $query = " + INSERT INTO + ".get_table_name('carddav_server')." (user_id, url, username, password, label, read_only) + VALUES + (?, ?, ?, ?, ?, ?) + "; + + $rcmail->db->query($query, $user_id, $url, $username, $rcmail->encrypt($password), $label, $read_only); + + if ($rcmail->db->affected_rows()) + { + $this->carddav_addressbook_sync($rcmail->db->insert_id(), false); + + $rcmail->output->command('plugin.carddav_server_message', array( + 'server_list' => $this->get_carddav_server_list(), + 'message' => $this->gettext('settings_saved'), + 'check' => true + )); + } + else + { + $rcmail->output->command('plugin.carddav_server_message', array( + 'message' => $this->gettext('settings_save_failed'), + 'check' => false + )); + } + } + else + { + $rcmail->output->command('plugin.carddav_server_message', array( + 'message' => $this->gettext('settings_no_connection'), + 'check' => false + )); + } + } + + /** + * Delete CardDAV server and all related local contacts + * + * @return void + */ + public function carddav_server_delete() + { + $rcmail = rcmail::get_instance(); + $user_id = $rcmail->user->data['user_id']; + $carddav_server_id = parse_input_value(base64_decode($_POST['_carddav_server_id'])); + + $query = " + DELETE FROM + ".get_table_name('carddav_server')." + WHERE + user_id = ? + AND + carddav_server_id = ? + "; + + $rcmail->db->query($query, $user_id, $carddav_server_id); + + if ($rcmail->db->affected_rows()) + { + $rcmail->output->command('plugin.carddav_server_message', array( + 'server_list' => $this->get_carddav_server_list(), + 'message' => $this->gettext('settings_deleted'), + 'check' => true + )); + } + else + { + $rcmail->output->command('plugin.carddav_server_message', array( + 'message' => $this->gettext('settings_delete_failed'), + 'check' => false + )); + } + } + + /** + * Extended write log with pre defined logfile name and add version before the message content + * + * @param string $message Error log message + * @return void + */ + public function write_log($message) + { + write_log('CardDAV', 'v' . self::VERSION . ' | ' . $message); + } +} |
