Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1822496
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
26 KB
Subscribers
None
View Options
diff --git a/action/ajax.php b/action/ajax.php
--- a/action/ajax.php
+++ b/action/ajax.php
@@ -1,123 +1,199 @@
<?php
/**
* DokuWiki DAVCard PlugIn - Ajax component
*/
if(!defined('DOKU_INC')) die();
class action_plugin_davcard_ajax extends DokuWiki_Action_Plugin {
/**
* @var helper_plugin_davcard
*/
private $hlp = null;
function __construct() {
$this->hlp =& plugin_load('helper','davcard');
}
function register(Doku_Event_Handler $controller) {
$controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call_unknown');
}
function handle_ajax_call_unknown(&$event, $param) {
if($event->data != 'plugin_davcard') return;
$event->preventDefault();
$event->stopPropagation();
global $INPUT;
$action = trim($INPUT->post->str('action'));
$id = trim($INPUT->post->str('id'));
$page = trim($INPUT->post->str('page'));
$params = $INPUT->post->arr('params');
if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
$user = $_SERVER['REMOTE_USER'];
else
$user = null;
if(!checkSecurityToken())
{
echo "CSRF Attack.";
return;
}
$data = array();
$data['result'] = false;
$data['html'] = $this->getLang('unknown_error');
// Parse the requested action
switch($action)
{
// Add a new Contact
case 'newContact':
if($this->hlp->addContactEntryToAddressbookForPage($id, $user, $params) === true)
{
$data['result'] = true;
}
else
{
$data['result'] = false;
$data['html'] = $this->getLang('error_adding');
}
break;
// Edit a contact
case 'editContact':
break;
// Delete a Contact
case 'deleteContact':
break;
// Get AJAX popup
case 'getContactAjax':
$contactdata = $this->hlp->getContactByUri($id, $params['uri']);
+ $cardpattern = $this->getConf('popup_content');
+ echo '<div class="plugin_davcard_popup_container">';
foreach($contactdata['photo'] as $type => $photodata)
{
+ echo '<div class="plugin_davcard_popup_image">';
$type = strtolower($type);
$imgdata = base64_encode($photodata);
$pattern = '/^(?:[;\/?:@&=+$,]|(?:[^\W_]|[-_.!~*\()\[\] ])|(?:%[\da-fA-F]{2}))*$/';
// PNG images
if($type == 'png')
{
$imgdata = 'data:image/png;base64,'.$imgdata;
echo '<img src="'.$imgdata.'" alt="contact image" />';
}
// JPEG images
elseif(($type == 'jpeg') || ($type == 'jpg'))
{
$imgdata = 'data:image/jpeg;base64,'.$imgdata;
echo '<img src="'.$imgdata.'" alt="contact image" />';
}
// GIF images
elseif($type == 'gif')
{
$imgdata = 'data:image/gif;base64,'.$imgdata;
echo '<img src="'.$imgdata.'" alt="contact image" />';
}
// URLs (no type given)
elseif(preg_match( $pattern, $string ) == 1)
{
echo '<img src="'.$photodata.'" alt="contact image" />';
}
+ echo '</div>';
}
+ echo '<div class="plugin_davcard_popup_content">';
+ $contactname = explode(';', $contactdata['structuredname']);
+ if(count($contactname) > 1)
+ {
+ $cardpattern = str_replace('<DCLASTNAME>', $contactname[0], $cardpattern);
+ $cardpattern = str_replace('<DCFIRSTNAME>', $contactname[1], $cardpattern);
+ }
+ if(count($contactdata['addr']) > 0)
+ {
+ foreach($contactdata['addr'] as $type => $addr)
+ {
+ $type = strtolower($type);
+ if($type == 'work')
+ $prefix = 'WORK';
+ else
+ $prefix = 'PRIVATE';
+ $cardpattern = str_replace('<DC'.$prefix.'STREET>', $addr[2], $cardpattern);
+ $cardpattern = str_replace('<DC'.$prefix.'CITY>', $addr[3], $cardpattern);
+ $cardpattern = str_replace('<DC'.$prefix.'ZIP>', $addr[5], $cardpattern);
+ $cardpattern = str_replace('<DC'.$prefix.'COUNTRY>', $addr[6], $cardpattern);
+ }
+ }
+ if(count($contactdata['tel']) > 0)
+ {
+ $telArr = array();
+ foreach($contactdata['tel'] as $type => $tel)
+ {
+ $type = strtolower($type);
+ $telArr[] = $this->getLang('tel'.strtolower($type)).': '.$tel;
+ }
+ $telStr = implode(' \\\\ ', $telArr);
+ $cardpattern = str_replace('<DCPHONE>', $telStr, $cardpattern);
+ }
+ if(count($contactdata['mail']) > 0)
+ {
+ $mailArr = array();
+ foreach($contactdata['mail'] as $type => $mail)
+ {
+ $mailArr[] = '[['.$mail.']]';
+ }
+ $mailStr = implode(' \\\\ ', $mailArr);
+ $cardpattern = str_replace('<DCEMAIL>', $mailStr, $cardpattern);
+ }
+ if($contactdata['birthday'] != '')
+ {
+ $date = DateTime::createFromFormat('Ymd', $contactdata['birthday']);
+ $dateStr = $date->format($this->getConf('date_format'));
+ $cardpattern = str_replace('<DCBIRTHDAY>', $dateStr, $cardpattern);
+ }
+ if($contactdata['note'] != '')
+ {
+ $notestr = str_replace('\n', ' \\ ', $contactdata['note']);
+ $cardpattern = str_replace('<DCNOTE>', $notestr, $cardpattern);
+ }
+ if($contactdata['title'] != '')
+ {
+ $cardpattern = str_replace('<DCTITLE>', $contactdata['title'], $cardpattern);
+ }
+ if($contactdata['url'] != '')
+ {
+ $url = $contactdata['url'];
+ if(strpos($url, '://') === false)
+ $url = 'http://'.$url;
+ $url = '[['.$url.']]';
+ $cardpattern = str_replace('<DCWEBSITE>', $url, $cardpattern);
+ }
+
+ $replace_match = '/^.*<DC.*>.*$(?:\r\n|\n)?/m';
+ $cardpattern = preg_replace($replace_match, '', $cardpattern);
+ echo $this->render_text($cardpattern);
+ echo '</div>';
+ echo '</div>';
return;
break;
}
// If we are still here, JSON output is requested
//json library of DokuWiki
require_once DOKU_INC . 'inc/JSON.php';
$json = new JSON();
//set content type
header('Content-Type: application/json');
echo $json->encode($data);
}
}
diff --git a/conf/default.php b/conf/default.php
--- a/conf/default.php
+++ b/conf/default.php
@@ -1,8 +1,18 @@
<?php
/**
* Default settings for the davcard plugin
*
* @author Andreas Boehler <dev@aboehler.at>
*/
$conf['default_client_id'] = '';
+$conf['popup_content'] = '| **Name** | <DCFIRSTNAME> <DCLASTNAME> |
+| **Title** | <DCTITLE> |
+| **Address (Work)** | <DCWORKSTREET> \\\\ <DCWORKZIP> <DCWORKCITY> |
+| **Address (Private)** | <DCPRIVATESTREET> \\\\ <DCPRIVATEZIP> <DCPRIVATECITY> |
+| **Phone** | <DCPHONE> |
+| **E-Mail** | <DCEMAIL> |
+| **Website** | <DCWEBSITE> |
+| **Birthday** | <DCBIRTHDAY> |
+| **Note** | <DCNOTE>';
+$conf['date_format'] = 'Y-m-d';
diff --git a/conf/metadata.php b/conf/metadata.php
--- a/conf/metadata.php
+++ b/conf/metadata.php
@@ -1,8 +1,10 @@
<?php
/**
* Options for the davcard plugin
*
* @author Andreas Boehler <dev@aboehler.at>
*/
$meta['default_client_id'] = array('string');
+$meta['popup_content'] = array('');
+$meta['date_format'] = array('string');
diff --git a/helper.php b/helper.php
--- a/helper.php
+++ b/helper.php
@@ -1,423 +1,452 @@
<?php
/**
* Helper Class for the DAVCard plugin
* This helper does the actual work.
*
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
class helper_plugin_davcard extends DokuWiki_Plugin {
protected $sqlite = null;
/**
* Constructor to load the configuration
*/
public function helper_plugin_davcard() {
$this->sqlite =& plugin_load('helper', 'sqlite');
global $conf;
if(!$this->sqlite)
{
if($conf['allowdebug'])
dbglog('This plugin requires the sqlite plugin. Please install it.');
msg('This plugin requires the sqlite plugin. Please install it.');
return;
}
if(!$this->sqlite->init('davcard', DOKU_PLUGIN.'davcard/db/'))
{
if($conf['allowdebug'])
dbglog('Error initialising the SQLite DB for DAVCard');
return;
}
}
private function getContactByDetails($id, $type, $params = array())
{
if(strpos($id, 'webdav://') === 0)
{
$wdc =& plugin_load('helper', 'webdavclient');
if(is_null($wdc))
return $this->getLang('no_wdc');
$connectionId = str_replace('webdav://', '', $id);
$settings = $wdc->getConnection($connectionId);
if($settings === false)
return array('formattedname' => $this->getLang('settings_not_found'));
if($settings['type'] !== 'contacts')
return array('formattedname' => $this->getLang('wrong_type'));
$entries = $wdc->getAddressbookEntries($connectionId);
foreach($entries as $entry)
{
switch($type)
{
case 'structuredname':
$contactdata = explode(';', strtolower($entry['structuredname']));
if(count($contactdata) < 2) // We need at least first and lat name
return array('formattedname' => $this->getLang('contact_not_found'));
if(($params['lastname'] != '') &&
($contactdata[0] === $params['lastname'])
|| $params['lastname'] === '')
{
// last name matched or no last name given
if(($params['firstname'] != '') &&
($contactdata[1] === $params['firstname'])
|| $params['firstname'] === '')
{
// first name matched too or no first name given
$info = $this->parseVcard($entry['contactdata'], $entry['uri']);
return $info;
}
}
break;
case 'formattedname':
if(trim(strtolower($entry['formattedname'])) == $params['formattedname'])
{
$info = $this->parseVcard($entry['contactdata'], $entry['uri']);
return $info;
}
break;
case 'email':
$info = $this->parseVcard($entry['contactdata'], $entry['uri']);
foreach($info['mail'] as $key => $mail)
{
if($mail === strtolower($params['email']))
return $info;
}
break;
}
}
}
return array('formattedname' => $this->getLang('contact_not_found'));
}
public function getContactByStructuredName($id, $firstname = '', $lastname = '')
{
return $this->getContactByDetails($id, 'structuredname',
array('firstname' => strtolower($firstname), 'lastname' => strtolower($lastname)));
}
public function getContactByEmail($id, $email)
{
// FIXME: Maybe it's a good idea to save the e-mail in the database as well!
return $this->getContactByDetails($id, 'email', array('email' => strtolower($email)));
}
public function getContactByFormattedName($id, $name)
{
return $this->getContactByDetails($id, 'formattedname', array('formattedname' => strtolower($name)));
}
public function getContactByUri($id, $uri)
{
if(strpos($id, 'webdav://') === 0)
{
$wdc =& plugin_load('helper', 'webdavclient');
if(is_null($wdc))
return $this->getLang('no_wdc');
$connectionId = str_replace('webdav://', '', $id);
$settings = $wdc->getConnection($connectionId);
if($settings === false)
return array('formattedname' => $this->getLang('settings_not_found'));
if($settings['type'] !== 'contacts')
return array('formattedname' => $this->getLang('wrong_type'));
$row = $wdc->getAddressbookEntryByUri($connectionId, $uri);
if($row === false)
return array('formattedname' => $this->getLang('contact_not_found'));
$info = $this->parseVcard($row['contactdata'], $row['uri']);
return $info;
}
return array('formattedname' => $this->getLang('contact_not_found'));
}
public function setAddressbookNameForPage($name, $description, $id = null, $userid = null)
{
if(is_null($id))
{
global $ID;
$id = $ID;
}
if(is_null($userid))
{
if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
{
$userid = $_SERVER['REMOTE_USER'];
}
else
{
$userid = uniqid('davcard-');
}
}
$bookid = $this->getAddressbookIdForPage($id);
if($bookid === false)
return $this->createAddressbookForPage($name, $description, $id, $userid);
$query = "UPDATE addressbooks SET displayname = ?, description = ? WHERE id = ?";
$res = $this->sqlite->query($query, $name, $description, $bookid);
if($res !== false)
return true;
return false;
}
public function getAddressbookIdForPage($id = null)
{
if(is_null($id))
{
global $ID;
$id = $ID;
}
$query = "SELECT addressbookid FROM pagetoaddressbookmapping WHERE page = ?";
$res = $this->sqlite->query($query, $id);
$row = $this->sqlite->res2row($res);
if(isset($row['addressbookid']))
{
$calid = $row['addressbookid'];
return $calid;
}
return false;
}
public function createAddressbookForPage($name, $description, $id = null, $userid = null)
{
if(is_null($id))
{
global $ID;
$id = $ID;
}
if(is_null($userid))
{
if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
{
$userid = $_SERVER['REMOTE_USER'];
}
else
{
$userid = uniqid('davcard-');
}
}
$values = array('principals/'.$userid,
$name,
str_replace(array('/', ' ', ':'), '_', $id),
$description,
1);
$query = "INSERT INTO addressbooks (principaluri, displayname, uri, description, synctoken) ".
"VALUES (?, ?, ?, ?, ?)";
$res = $this->sqlite->query($query, $values);
if($res === false)
return false;
// Get the new addressbook ID
$query = "SELECT id FROM addressbooks WHERE principaluri = ? AND displayname = ? AND ".
"uri = ? AND description = ? AND synctoken = ?";
$res = $this->sqlite->query($query, $values);
$row = $this->sqlite->res2row($res);
// Update the pagetocalendarmapping table with the new calendar ID
if(isset($row['id']))
{
$query = "INSERT INTO pagetoaddressbookmapping (page, addressbookid) VALUES (?, ?)";
$res = $this->sqlite->query($query, $id, $row['id']);
return ($res !== false);
}
return false;
}
public function addContactEntryToAddressbookForPage($id, $user, $params)
{
require_once(DOKU_PLUGIN.'davcard/vendor/autoload.php');
$vcard = new \Sabre\VObject\Component\VCard();
$formattedname = $params['firstname'].' '.$params['lastname']; // FIXME: Make this configurable?
$structuredname = array($params['lastname'], $params['firstname'], '', '', '');
$vcard->FN = $formattedname;
if($params['cellphone'] != '')
{
$vcard->add('TEL', $params['cellphone'], array('type' => 'cell'));
}
if($params['phone'] != '')
{
$vcard->add('TEL', $params['phone'], array('type' => 'home'));
}
$vcard->N = $structuredname;
$vcard->add('ADR', array('', '', $params['street'], $params['city'], '', $params['zipcode'], $params['country']), array('type' => 'home'));
$contactdata = $vcard->serialize();
if(strpos($id, 'webdav://') === 0)
{
$wdc =& plugin_load('helper', 'webdavclient');
if(is_null($wdc))
return false;
$connectionId = str_replace('webdav://', '', $id);
return $wdc->addAddressbookEntry($connectionId, $contactdata);
}
else
{
$addressbookid = $this->getAddressbookIdForPage($id);
$uri = uniqid('dokuwiki-').'.vcf';
$now = new \DateTime();
$query = "INSERT INTO addressbookobjects (contactdata, uri, addressbookid, lastmodified, etag, size, formattedname, structuredname) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
$res = $this->sqlite->query($query,
$contactdata,
$uri,
$addressbookid,
$now->getTimestamp(),
md5($contactdata),
strlen($contactdata),
$formattedname,
implode(';', $structuredname)
);
// If successfully, update the sync token database
if($res !== false)
{
$this->updateSyncTokenLog($addressbookid, $uri, 'added');
return true;
}
}
}
private function parseVcard($card, $uri)
{
require_once(DOKU_PLUGIN.'davcard/vendor/autoload.php');
$vObject = \Sabre\VObject\Reader::read($card);
$formattedname = '';
$structuredname = '';
$tel = array();
$addr = array();
$mail = array();
$photo = array();
+ $birthday = '';
+ $note = '';
+ $title = '';
+ $url = '';
if(isset($vObject->FN))
$formattedname = (string)$vObject->FN;
if(isset($vObject->N))
$structuredname = join(';', $vObject->N->getParts());
if(isset($vObject->TEL))
{
foreach($vObject->TEL as $number)
{
if(isset($number['TYPE']))
$tel[(string)$number['TYPE']] = (string)$number;
else
$tel[] = (string)$number;
}
}
if(isset($vObject->ADR))
{
foreach($vObject->ADR as $adr)
{
if(isset($adr['TYPE']))
$addr[(string)$adr['TYPE']] = $adr->getParts();
else
$addr[] = $adr->getParts();
}
}
if(isset($vObject->EMAIL))
{
foreach($vObject->EMAIL as $email)
{
if(isset($email['TYPE']))
$mail[(string)$email['TYPE']] = (string)$email;
else
$mail[] = (string)$email;
}
}
if(isset($vObject->PHOTO))
{
if(isset($vObject->PHOTO['TYPE']))
{
$photo[(string)$vObject->PHOTO['TYPE']] = (string)$vObject->PHOTO;
}
else
$photo[] = (string)$vObject->PHOTO;
}
+ if(isset($vObject->BDAY))
+ {
+ $birthday = (string)$vObject->BDAY;
+ $birthday = str_replace('-', '', $birthday);
+ }
+
+ if(isset($vObject->NOTE))
+ {
+ $note = (string)$vObject->NOTE;
+ }
+
+ if(isset($vObject->TITLE))
+ {
+ $title = (string)$vObject->TITLE;
+ }
+
+ if(isset($vObject->URL))
+ {
+ $url = (string)$vObject->URL;
+ }
+
return array(
'formattedname' => $formattedname,
'structuredname' => $structuredname,
'tel' => $tel,
'mail' => $mail,
'addr' => $addr,
'uri' => $uri,
- 'photo' => $photo
+ 'photo' => $photo,
+ 'birthday' => $birthday,
+ 'note' => $note,
+ 'title' => $title,
+ 'url' => $url,
);
}
public function getAddressbookSettings($addressbookid)
{
$query = "SELECT id, principaluri, displayname, uri, description, synctoken FROM addressbooks WHERE id= ? ";
$res = $this->sqlite->query($query, $addressbookid);
$row = $this->sqlite->res2row($res);
return $row;
}
public function getSyncTokenForAddressbook($addressbookid)
{
$row = $this->getAddressbookSettings($addressbookid);
if(isset($row['synctoken']))
return $row['synctoken'];
return false;
}
/**
* Helper function to convert the operation name to
* an operation code as stored in the database
*
* @param string $operationName The operation name
*
* @return mixed The operation code or false
*/
public function operationNameToOperation($operationName)
{
switch($operationName)
{
case 'added':
return 1;
break;
case 'modified':
return 2;
break;
case 'deleted':
return 3;
break;
}
return false;
}
private function updateSyncTokenLog($addressbookid, $uri, $operation)
{
$currentToken = $this->getSyncTokenForAddressbook($addressbookid);
$operationCode = $this->operationNameToOperation($operation);
if(($operationCode === false) || ($currentToken === false))
return false;
$values = array($uri,
$currentToken,
$addressbookid,
$operationCode
);
$query = "INSERT INTO addressbookchanges (uri, synctoken, addressbookid, operation) VALUES(?, ?, ?, ?)";
$res = $this->sqlite->query($query, $uri, $currentToken, $addressbookid, $operationCode);
if($res === false)
return false;
$currentToken++;
$query = "UPDATE addressbooks SET synctoken = ? WHERE id = ?";
$res = $this->sqlite->query($query, $currentToken, $addressbookid);
return ($res !== false);
}
}
diff --git a/style.css b/style.css
--- a/style.css
+++ b/style.css
@@ -1,82 +1,104 @@
div.dokuwiki a.plugin_davcard_url:link,
div.dokuwiki a.plugin_davcard_url:active,
div.dokuwiki a.plugin_davcard_url:hover,
div.dokuwiki a.plugin_davcard_url:visited {
position: relative;
padding-left: 18px;
z-index: 10;
}
div.dokuwiki a.plugin_davcard_url:link span.plugin_davcard_popup,
div.dokuwiki a.plugin_davcard_url:active span.plugin_davcard_popup,
div.dokuwiki a.plugin_davcard_url:visited span.plugin_davcard_popup {
display: none;
}
div.dokuwiki a.plugin_davcard_url:hover {
text-decoration: none !important;
z-index: 15;
}
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup {
display: block;
position: absolute;
top: 1.2em;
left: 18px;
width: 20em;
height: 64px;
min-height: 64px;
height: auto;
background-color: __background__;
border: 1px solid __border__;
padding: 0.5em;
font-size: 90%;
}
div.dokuwiki a.plugin_davcard_url span.plugin_davcard_nopopup {
display:none;
}
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.adr,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.tel,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.email_outer,
{
display:block;
position: relative;
margin-left: 45px;
}
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.adr span.type,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.tel span.type,
div.dokuwiki a.plugin_davcard_url:hover span.plugin_davcard_popup span.email_type,
{
font-weight: bold;
margin-left: -45px;
position: absolute;
}
div.dokuwiki .plugin_davcard_popup_overlay {
position: absolute;
padding: 0.5em;
margin-top: 1em;
}
div.dokuwiki .plugin_davcard_popup_overlay ul {
margin: 0;
list-style-type: none;
}
div.dokuwiki .plugin_davcard_popup_overlay ul li {
margin-left: 2em;
}
div.dokuwiki .plugin_davcard_popup_overlay ul li.dataov_name {
margin-left: 0;
margin-bottom: 0.3em;
}
div.dokuwiki .plugin_davcard_popup_overlay ul li.dataov_name div {
font-weight: bold;
}
+div.dokuwiki .plugin_davcard_popup_overlay img {
+ max-width: 100px;
+ height: auto;
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_container {
+
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_image {
+ float: left;
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_content {
+ float: right;
+}
+
+div.dokuwiki .plugin_davcard_popup_overlay .plugin_davcard_popup_container::after {
+ content:"";
+ display:block;
+ clear:both;
+}
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Dec 24, 7:43 PM (1 d, 12 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
529879
Default Alt Text
(26 KB)
Attached To
rDAVCARD DokuWiki davcard PlugIn
Event Timeline
Log In to Comment