aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMario <mario@mariovavti.com>2020-03-02 09:50:11 +0000
committerMario <mario@mariovavti.com>2020-03-02 09:50:11 +0000
commitba566fd64bbb57fb52779a3f29f30e730cab7744 (patch)
tree85ff6e77a4a0bbbdde7638055270f5a3a2b33f55 /include
parent19bb9e018152ce528846fb955b58d76f1bb6bdec (diff)
parent85c07d57fe0f468eb8cc84584f3636b590aa929f (diff)
downloadvolse-hubzilla-ba566fd64bbb57fb52779a3f29f30e730cab7744.tar.gz
volse-hubzilla-ba566fd64bbb57fb52779a3f29f30e730cab7744.tar.bz2
volse-hubzilla-ba566fd64bbb57fb52779a3f29f30e730cab7744.zip
Merge branch 'dev' into z6connect
Diffstat (limited to 'include')
-rw-r--r--include/bbcode.php142
-rw-r--r--include/cdav.php186
-rw-r--r--include/channel.php42
-rw-r--r--include/conversation.php38
-rw-r--r--include/features.php16
-rw-r--r--include/import.php138
-rwxr-xr-xinclude/items.php6
-rw-r--r--include/language.php7
-rw-r--r--include/nav.php2
-rw-r--r--include/text.php105
-rw-r--r--include/zid.php1
-rw-r--r--include/zot.php6
12 files changed, 642 insertions, 47 deletions
diff --git a/include/bbcode.php b/include/bbcode.php
index 301ffbd24..b2e3f1d3b 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -655,6 +655,109 @@ function bb_observer($Text) {
return $Text;
}
+function bb_imgoptions($match) {
+
+ // $Text = preg_replace_callback("/\[([zi])mg([ \=])(.*?)\](.*?)\[\/[zi]mg\]/ism",'bb_imgoptions',$Text);
+ // alt text cannot contain ']'
+
+ // [img|zmg=wwwxhhh float=left|right alt=alt text]url[/img|zmg]
+
+ $local_match = null;
+ $width = 0;
+ $float = false;
+ $alt = false;
+
+ $style = EMPTY_STR;
+
+ $attributes = $match[3];
+
+ $x = preg_match("/alt='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $alt = $matches[1];
+ }
+
+ $x = preg_match("/alt=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $alt = $matches[1];
+ }
+
+ $x = preg_match("/width='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $width = $matches[1];
+ }
+
+ $x = preg_match("/width=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $width = $matches[1];
+ }
+
+ $x = preg_match("/height='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $height = $matches[1];
+ }
+
+ $x = preg_match("/height=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $height = $matches[1];
+ }
+
+ $x = preg_match("/style='(.*?)'/ism", $attributes, $matches);
+ if ($x) {
+ $style = $matches[1];
+ }
+
+ $x = preg_match("/style=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($x) {
+ $style = $matches[1];
+ }
+
+ // legacy img options
+
+ if ($match[2] === '=') {
+ // pull out (optional) legacy size declarations first
+ if (preg_match("/([0-9]*)x([0-9]*)/ism",$match[3],$local_match)) {
+ $width = intval($local_match[1]);
+ }
+ $match[3] = substr($match[3],strpos($match[3],' '));
+ }
+
+ // then (optional) legacy float specifiers
+ if ($n = strpos($match[3],'float=left') !== false) {
+ $float = 'left';
+ $match[3] = substr($match[3],$n + 10);
+ }
+ if ($n = strpos($match[3],'float=right') !== false) {
+ $float = 'right';
+ $match[3] = substr($match[3],$n + 11);
+ }
+
+ // finally alt text which extends to the close of the tag
+ if ((! $alt) && ($n = strpos($match[3],'alt=') !== false)) {
+ $alt = substr($match[3],$n + 4);
+ }
+
+ // now assemble the resulting img tag from these components
+
+ $output = '<img ' . (($match[1] === 'z') ? 'class="zrl" ' : '') . ' ';
+
+ if ($width) {
+ $style .= 'width: 100%; max-width: ' . $width . 'px; ';
+ }
+ else {
+ $style .= 'max-width: 100%; ';
+ }
+ if ($float) {
+ $style .= 'float: ' . $float . '; ';
+ }
+
+ $output .= (($style) ? 'style="' . $style . '" ' : '') . 'alt="' . htmlentities(($alt) ? $alt : t('Image/photo'),ENT_COMPAT,'UTF-8') . '" ';
+
+ $output .= 'src="' . $match[4] . '" >';
+
+ return $output;
+
+}
+
function bb_code_protect($s) {
return 'b64.^9e%.' . base64_encode($s) . '.b64.$9e%';
}
@@ -1237,45 +1340,20 @@ function bbcode($Text, $options = []) {
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
- }
-
- // [img float={left, right}]pathtoimage[/img]
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img float=left\](.*?)\[\/img\]/ism", '<img src="$1" style="max-width: 100%; float: left;" alt="' . t('Image/photo') . '" />', $Text);
- }
+ // [img=pathtoimage]image description[/img]
if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img float=right\](.*?)\[\/img\]/ism", '<img src="$1" style="max-width: 100%; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg float=left\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" style="max-width: 100%; float: left;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[img=http(.*?)\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="http$1" alt="$2" title="$2"/>', $Text);
}
+ // [zmg]pathtoimage[/zmg]
if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg float=right\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" style="max-width: 100%; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
-
- // [img=widthxheight]pathtoimage[/img]
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
+ // [zmg=pathtoimage]image description[/zmg]
if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
+ $Text = preg_replace("/\[zmg=http(.*?)\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="http$1" alt="$2" title="$2"/>', $Text);
}
- // [img=widthxheight float={left, right}]pathtoimage[/img]
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/img]') !== false) {
- $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
- }
- if (strpos($Text,'[/zmg]') !== false) {
- $Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
- }
+ $Text = preg_replace_callback("/\[([zi])mg([ \=])(.*?)\](.*?)\[\/[zi]mg\]/ism",'bb_imgoptions',$Text);
// style (sanitized)
if (strpos($Text,'[/style]') !== false) {
diff --git a/include/cdav.php b/include/cdav.php
new file mode 100644
index 000000000..ef248a9fe
--- /dev/null
+++ b/include/cdav.php
@@ -0,0 +1,186 @@
+<?php
+
+/**
+ * @brief Process CardDAV card
+ *
+ * @param array $f fields
+ * @param obj $vcard SabreDAV object
+ * @param bool $edit update card
+ *
+ */
+
+function process_cdav_card($f, &$vcard, $edit = false) {
+
+ if($f['org'])
+ $vcard->ORG = $f['org'];
+ else
+ if($edit)
+ unset($vcard->ORG);
+
+
+ if($f['title'])
+ $vcard->TITLE = $f['title'];
+ else
+ if($edit)
+ unset($vcard->TITLE);
+
+ if($edit)
+ unset($vcard->TEL);
+ if($f['tel']) {
+ $i = 0;
+ foreach($f['tel'] as $item) {
+ if($item) {
+ $vcard->add('TEL', $item, ['type' => $f['tel_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->EMAIL);
+ if($f['email']) {
+ $i = 0;
+ foreach($f['email'] as $item) {
+ if($item) {
+ $vcard->add('EMAIL', $item, ['type' => $f['email_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->IMPP);
+ if($f['impp']) {
+ $i = 0;
+ foreach($f['impp'] as $item) {
+ if($item) {
+ $vcard->add('IMPP', $item, ['type' => $f['impp_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->URL);
+ if($f['url']) {
+ $i = 0;
+ foreach($f['url'] as $item) {
+ if($item) {
+ $vcard->add('URL', $item, ['type' => $f['url_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($edit)
+ unset($vcard->ADR);
+ if($f['adr']) {
+ $i = 0;
+ foreach($f['adr'] as $item) {
+ if($item) {
+ $vcard->add('ADR', $item, ['type' => $f['adr_type'][$i]]);
+ }
+ $i++;
+ }
+ }
+
+ if($f['note']) {
+ $vcard->NOTE = $f['note'];
+ }
+ else
+ if($edit)
+ unset($vcard->NOTE);
+}
+
+
+/**
+ * @brief Import CardDAV or CalDAV card
+ *
+ * @param mixed $id card id
+ * @param str $ext card extension
+ * @param str $table name
+ * @param str $column name
+ * @param obj $objects
+ * @param str $profile
+ * @param obj $backend
+ * @param array $ids
+ * @param bool $notice
+ *
+ */
+
+function import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, &$ids, $notice = false) {
+
+ $i = 0;
+ $newid = (count($ids) ? false : true);
+
+ while ($object = $objects->getNext()) {
+
+ if($_REQUEST['a_upload'])
+ $object = $object->convert(\Sabre\VObject\Document::VCARD40);
+
+ $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR);
+
+ //level 3 Means that the document is invalid,
+ //level 2 means a warning. A warning means it's valid but it could cause interopability issues,
+ //level 1 means that there was a problem earlier, but the problem was automatically repaired.
+
+ if($ret[0]['level'] < 3) {
+
+ if($newid) {
+ do {
+ $duplicate = false;
+ $objectUri = random_string(40) . '.' . $ext;
+
+ $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1",
+ dbesc($id),
+ dbesc($objectUri)
+ );
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+ $ids[$i] = $objectUri;
+ }
+ else
+ $objectUri = $ids[$i];
+
+ $i++;
+
+ if($ext == 'ics')
+ $backend->createCalendarObject($id, $objectUri, $object->serialize());
+
+ if($ext == 'vcf')
+ $backend->createCard($id, $objectUri, $object->serialize());
+ }
+ else {
+ if($notice && $ext == 'ics') {
+ notice(
+ '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL .
+ '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL .
+ '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL .
+ '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
+ );
+ }
+
+ if($notice && $exp == 'vcf') {
+ notice(
+ '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL .
+ '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL .
+ '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
+ );
+ }
+ }
+ }
+}
+
+
+function get_cdav_id($principaluri, $uri, $table) {
+
+ $r = q("SELECT * FROM $table WHERE principaluri = '%s' AND uri = '%s' LIMIT 1",
+ dbesc($principaluri),
+ dbesc($uri)
+ );
+ if(! $r)
+ return false;
+
+ return $r[0];
+}
diff --git a/include/channel.php b/include/channel.php
index 61603fb42..4aad64f3d 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -923,11 +923,38 @@ function identity_basic_export($channel_id, $sections = null, $zap_compat = fals
$ret['abook'] = $r;
for($x = 0; $x < count($ret['abook']); $x ++) {
+
$xchans[] = $ret['abook'][$x]['abook_xchan'];
+ $my_perms = [];
+ $their_perms = [];
+ $newconfig = [];
$abconfig = load_abconfig($channel_id,$ret['abook'][$x]['abook_xchan']);
- if($abconfig)
- $ret['abook'][$x]['abconfig'] = $abconfig;
+ if($abconfig) {
+ foreach ($abconfig as $abc) {
+
+ if ($abc['cat'] === 'my_perms' && intval($abc['v'])) {
+ $my_perms[] = $abc['k'];
+ continue;
+ }
+ if ($abc['cat'] === 'their_perms' && intval($abc['v'])) {
+ $their_perms[] = $abc['k'];
+ continue;
+ }
+ if ($zap_compat && preg_match('|^a:[0-9]+:{.*}$|s', $abc['v'])) {
+ $abc['v'] = serialise(unserialize($abc['v']));
+ }
+ $newconfig[] = $abc;
+ }
+
+ $ret['abook'][$x]['abconfig'] = $newconfig;
+ if ($zap_compat) {
+ $ret['abook'][$x]['abconfig'][] = [ 'chan' => $channel_id, 'xchan' => $ret['abook'][$x]['abook_chan'], 'cat' => 'system', 'k' => 'my_perms', 'v' => implode(',',$my_perms) ];
+ $ret['abook'][$x]['abconfig'][] = [ 'chan' => $channel_id, 'xchan' => $ret['abook'][$x]['abook_chan'], 'cat' => 'system', 'k' => 'their_perms', 'v' => implode(',',$their_perms) ];
+ }
+ }
+
translate_abook_perms_outbound($ret['abook'][$x]);
+
}
// pick up the zot6 xchan and hublocs also
@@ -967,8 +994,17 @@ function identity_basic_export($channel_id, $sections = null, $zap_compat = fals
$r = q("select * from pconfig where uid = %d",
intval($channel_id)
);
- if($r)
+
+ if($r) {
+ if ($zap_compat) {
+ for($x = 0; $x < count($r); $x ++) {
+ if (preg_match('|^a:[0-9]+:{.*}$|s', $r[$x]['v'])) {
+ $r[$x]['v'] = serialise(unserialize($r[$x]['v']));
+ }
+ }
+ }
$ret['config'] = $r;
+ }
// All other term types will be included in items, if requested.
diff --git a/include/conversation.php b/include/conversation.php
index 07d43e660..62d4b405f 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -413,12 +413,18 @@ function visible_activity($item) {
if(intval($item['item_notshown']))
return false;
+ if ($item['obj_type'] === 'Answer') {
+ return false;
+ }
+
foreach($hidden_activities as $act) {
if((activity_match($item['verb'], $act)) && ($item['mid'] != $item['parent_mid'])) {
return false;
}
}
+
+
if(is_edit_activity($item))
return false;
@@ -619,11 +625,17 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$items = $cb['items'];
- $conv_responses = array(
- 'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
- 'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')),
- 'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
- );
+ $conv_responses = [
+ 'like' => ['title' => t('Likes','title')],
+ 'dislike' => ['title' => t('Dislikes','title')],
+ 'agree' => ['title' => t('Agree','title')],
+ 'disagree' => ['title' => t('Disagree','title')],
+ 'abstain' => ['title' => t('Abstain','title')],
+ 'attendyes' => ['title' => t('Attending','title')],
+ 'attendno' => ['title' => t('Not attending','title')],
+ 'attendmaybe' => ['title' => t('Might attend','title')],
+ 'answer' => []
+ ];
// array with html for each thread (parent+comments)
@@ -1130,7 +1142,7 @@ function builtin_activity_puller($item, &$conv_responses) {
// if this item is a post or comment there's nothing for us to do here, just return.
- if(activity_match($item['verb'],ACTIVITY_POST))
+ if(activity_match($item['verb'],ACTIVITY_POST) && $item['obj_type'] !== 'Answer')
return;
foreach($conv_responses as $mode => $v) {
@@ -1162,6 +1174,9 @@ function builtin_activity_puller($item, &$conv_responses) {
case 'attendmaybe':
$verb = ACTIVITY_ATTENDMAYBE;
break;
+ case 'answer':
+ $verb = ACTIVITY_POST;
+ break;
default:
return;
break;
@@ -1177,9 +1192,11 @@ function builtin_activity_puller($item, &$conv_responses) {
if(! $item['thr_parent'])
$item['thr_parent'] = $item['parent_mid'];
-
$conv_responses[$mode]['mids'][$item['thr_parent']][] = 'b64.' . base64url_encode($item['mid']);
+ if($item['obj_type'] === 'Answer')
+ continue;
+
if(! ((isset($conv_responses[$mode][$item['thr_parent'] . '-l']))
&& (is_array($conv_responses[$mode][$item['thr_parent'] . '-l']))))
$conv_responses[$mode][$item['thr_parent'] . '-l'] = array();
@@ -1276,7 +1293,7 @@ function hz_status_editor($a, $x, $popup = false) {
$feature_voting = feature_enabled($x['profile_uid'], 'consensus_tools');
if(x($x, 'hide_voting'))
$feature_voting = false;
-
+
$feature_nocomment = feature_enabled($x['profile_uid'], 'disable_comments');
if(x($x, 'disable_comments'))
$feature_nocomment = false;
@@ -1424,6 +1441,11 @@ function hz_status_editor($a, $x, $popup = false) {
'$embedPhotosModalOK' => t('OK'),
'$setloc' => $setloc,
'$voting' => t('Toggle voting'),
+ '$poll' => t('Toggle poll'),
+ '$poll_option_label' => t('Option'),
+ '$poll_add_option_label' => t('Add option'),
+ '$poll_expire_unit_label' => [t('Minutes'), t('Hours'), t('Days')],
+ '$multiple_answers' => ['poll_multiple_answers', t("Allow multiple answers"), '', '', [t('No'), t('Yes')]],
'$feature_voting' => $feature_voting,
'$consensus' => ((array_key_exists('item',$x)) ? $x['item']['item_consensus'] : 0),
'$nocommenttitle' => t('Disable comments'),
diff --git a/include/features.php b/include/features.php
index 87df0c50d..c6cfcf822 100644
--- a/include/features.php
+++ b/include/features.php
@@ -299,6 +299,22 @@ function get_features($filtered = true, $level = (-1)) {
t('Network'),
[
+ 'events_tab',
+ t('Events Filter'),
+ t('Ability to display only events'),
+ false,
+ get_config('feature_lock','events_tab')
+ ],
+
+ [
+ 'polls_tab',
+ t('Polls Filter'),
+ t('Ability to display only polls'),
+ false,
+ get_config('feature_lock','polls_tab')
+ ],
+
+ [
'savedsearch',
t('Saved Searches'),
t('Save search terms for re-use'),
diff --git a/include/import.php b/include/import.php
index 6a3895b9f..bfe71963f 100644
--- a/include/import.php
+++ b/include/import.php
@@ -1503,6 +1503,144 @@ function sync_files($channel, $files) {
}
}
+
+/**
+ * @brief Synchronize addressbooks.
+ *
+ * @param array $channel
+ * @param array $data
+ */
+function sync_addressbook($channel, $data) {
+
+ if(! \Zotlabs\Lib\Apps::system_app_installed($channel['channel_id'], 'CardDAV'))
+ return;
+
+ logger("debug: " . print_r($data,true), LOGGER_DEBUG);
+
+ require_once('include/cdav.php');
+
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ if($data['action'] !== 'create') {
+ $id = get_cdav_id($principalUri, $data['uri'], 'addressbooks');
+ if(! $id)
+ return;
+ }
+
+ $pdo = \DBA::$dba->db;
+
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri);
+
+ switch($data['action']) {
+
+ case 'create':
+ $carddavBackend->createAddressBook($principalUri, $data['uri'], $data['properties']);
+ break;
+
+ case 'drop':
+ $carddavBackend->deleteAddressBook($id);
+ break;
+
+ case 'edit':
+ $patch = new \Sabre\DAV\PropPatch($data['mutations']);
+ $carddavBackend->updateAddressBook($id, $patch);
+ $patch->commit();
+ break;
+
+ case 'delete_card':
+ $carddavBackend->deleteCard($id, $data['carduri']);
+ break;
+
+ case 'update_card':
+ $vcard = \Sabre\VObject\Reader::read($data['card']);
+ $object = $vcard->convert(\Sabre\VObject\Document::VCARD40);
+ $cardData = $vcard->serialize();
+ $carddavBackend->updateCard($id, $data['carduri'], $cardData);
+ break;
+
+ case 'import':
+ $objects = new \Sabre\VObject\Splitter\VCard($data['card']);
+ $profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
+ import_cdav_card($id, 'vcf', 'cards', 'addressbookid', $objects, $profile, $carddavBackend, $data['ids']);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * @brief Synchronize calendars.
+ *
+ * @param array $channel
+ * @param array $data
+ */
+function sync_calendar($channel, $data) {
+
+ if(! \Zotlabs\Lib\Apps::system_app_installed($channel['channel_id'], 'Calendar'))
+ return;
+
+ logger("debug: " . print_r($data,true), LOGGER_DEBUG);
+
+ require_once('include/cdav.php');
+
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ if($data['action'] !== 'create') {
+ $x = get_cdav_id($principalUri, $data['uri'], 'calendarinstances');
+ if(! $x)
+ return;
+ $id = [ $x['id'], $x['calendarid'] ];
+ }
+
+ $pdo = \DBA::$dba->db;
+
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+ $calendars = $caldavBackend->getCalendarsForUser($principalUri);
+
+ switch($data['action']) {
+
+ case 'create':
+ $id = $caldavBackend->createCalendar($principalUri, $data['uri'], $data['properties']);
+ set_pconfig($channel['channel_id'], 'cdav_calendar', $id[0], 1);
+ break;
+
+ case 'drop':
+ $caldavBackend->deleteCalendar($id);
+ break;
+
+ case 'edit':
+ $patch = new \Sabre\DAV\PropPatch($data['mutations']);
+ $caldavBackend->updateCalendar($id, $patch);
+ $patch->commit();
+ break;
+
+ case 'delete_card':
+ $caldavBackend->deleteCalendarObject($id, $data['carduri']);
+ break;
+
+ case 'update_card':
+ $caldavBackend->updateCalendarObject($id, $data['carduri'], $data['card']);
+ break;
+
+ case 'switch':
+ set_pconfig($channel['channel_id'], 'cdav_calendar', $id[0], $data['switch']);
+ break;
+
+ case 'import':
+ $objects = new \Sabre\VObject\Splitter\ICalendar($data['card']);
+ $profile = \Sabre\VObject\Node::PROFILE_CALDAV;
+ import_cdav_card($id, 'ics', 'calendarobjects', 'calendarid', $objects, $profile, $caldavBackend, $data['ids']);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
/**
* @brief Rename a key in an array.
*
diff --git a/include/items.php b/include/items.php
index 9f90b2f3b..9768fdf23 100755
--- a/include/items.php
+++ b/include/items.php
@@ -9,6 +9,7 @@ use Zotlabs\Lib\MarkdownSoap;
use Zotlabs\Lib\MessageFilter;
use Zotlabs\Lib\ThreadListener;
use Zotlabs\Lib\IConfig;
+use Zotlabs\Lib\Activity;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\AccessList;
use Zotlabs\Daemon\Master;
@@ -1947,6 +1948,11 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if(intval($r[0]['item_uplink']) && (! $r[0]['item_private']))
$arr['item_private'] = 0;
+
+ if(in_array($arr['obj_type'], ['Note','Answer']) && $r[0]['obj_type'] === 'Question' && intval($r[0]['item_wall'])) {
+ Activity::update_poll($r[0],$arr);
+ }
+
}
else {
logger('item_store: item parent was not found - ignoring item');
diff --git a/include/language.php b/include/language.php
index e9d62e434..622b9614d 100644
--- a/include/language.php
+++ b/include/language.php
@@ -217,9 +217,10 @@ function t($s, $ctx = '') {
*/
function translate_projectname($s) {
-
- return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Lib\System::get_platform_name(),ucfirst(Zotlabs\Lib\System::get_platform_name())),$s);
-
+ if(strpos($s,'rojectname') !== false) {
+ return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Lib\System::get_platform_name(),ucfirst(Zotlabs\Lib\System::get_platform_name())),$s);
+ }
+ return $s;
}
diff --git a/include/nav.php b/include/nav.php
index 672cc2689..bd4d000f7 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -59,6 +59,8 @@ function nav($template = 'default') {
if($banner === false)
$banner = get_config('system','sitename');
+
+ call_hooks('get_banner',$banner);
App::$page['header'] .= replace_macros(get_markup_template('hdr.tpl'), array(
//we could additionally use this to display important system notifications e.g. for updates
diff --git a/include/text.php b/include/text.php
index 87ed9f658..1475ff334 100644
--- a/include/text.php
+++ b/include/text.php
@@ -1731,6 +1731,11 @@ function prepare_body(&$item,$attach = false,$opts = false) {
}
}
+ $poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],[ ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE ])) ? format_poll($item, $s, $opts) : false);
+ if ($poll) {
+ $s = $poll;
+ }
+
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);
$prep_arr = [
@@ -1814,6 +1819,89 @@ function prepare_binary($item) {
}
+function format_poll($item,$s,$opts) {
+
+ if (! is_array($item['obj'])) {
+ $act = json_decode($item['obj'],true);
+ }
+ else {
+ $act = $item['obj'];
+ }
+
+ if (! is_array($act)) {
+ return EMPTY_STR;
+ }
+
+ $commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR),$item);
+
+ //logger('format_poll: ' . print_r($item,true));
+ $activated = ((local_channel() && local_channel() == $item['uid']) ? true : false);
+ $output = $s . EOL. EOL;
+
+ if ($act['type'] === 'Question') {
+ if ($activated and $commentable) {
+ $output .= '<form id="question-form-' . $item['id'] . '" >';
+ }
+ if (array_key_exists('anyOf',$act) && is_array($act['anyOf'])) {
+ foreach ($act['anyOf'] as $poll) {
+ if (array_key_exists('name',$poll) && $poll['name']) {
+ $text = html2plain(purify_html($poll['name']),256);
+ if (array_path_exists('replies/totalItems',$poll)) {
+ $total = $poll['replies']['totalItems'];
+ }
+ else {
+ $total = 0;
+ }
+ if ($activated && $commentable) {
+ $output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+ }
+ else {
+ $output .= '[ ] ' . $text . ' (' . $total . ')' . EOL;
+ }
+ }
+ }
+ }
+ if (array_key_exists('oneOf',$act) && is_array($act['oneOf'])) {
+ foreach ($act['oneOf'] as $poll) {
+ if (array_key_exists('name',$poll) && $poll['name']) {
+ $text = html2plain(purify_html($poll['name']),256);
+ if (array_path_exists('replies/totalItems',$poll)) {
+ $total = $poll['replies']['totalItems'];
+ }
+ else {
+ $total = 0;
+ }
+ if ($activated && $commentable) {
+ $output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
+ }
+ else {
+ $output .= '( ) ' . $text . ' (' . $total . ')' . EOL;
+ }
+ }
+ }
+ }
+ if ($item['comments_closed'] > NULL_DATE) {
+ $t = datetime_convert('UTC',date_default_timezone_get(), $item['comments_closed'], 'Y-m-d h:i');
+ $closed = ((datetime_convert() > $item['comments_closed']) ? true : false);
+ if ($closed) {
+ $message = t('Poll has ended.');
+ }
+ else {
+ $message = sprintf(t('Poll ends: %s'),$t);
+ }
+ $output .= EOL . '<div>' . $message . '</div>';
+ }
+ if ($activated and $commentable) {
+ $output .= EOL . '<input type="button" class="btn btn-std btn-success" name="vote" value="vote" onclick="submitPoll(' . $item['id'] . '); return false;">'. '</form>';
+ }
+
+ }
+ return $output;
+}
+
+
+
+
/**
* @brief Given a text string, convert from content_type to HTML.
*
@@ -3644,7 +3732,7 @@ function array_path_exists($str,$arr) {
if($search) {
foreach($search as $s) {
- if(array_key_exists($s,$ptr)) {
+ if($ptr && array_key_exists($s,$ptr)) {
$ptr = $ptr[$s];
}
else {
@@ -3694,3 +3782,18 @@ function svg2bb($s) {
}
return EMPTY_STR;
}
+
+
+
+function serialise($x) {
+ return ((is_array($x)) ? 'json:' . json_encode($x) : $x);
+}
+
+function unserialise($x) {
+ if (is_array($x)) {
+ return $x;
+ }
+ $y = ((substr($x,0,5) === 'json:') ? json_decode(substr($x,5),true) : '');
+ return ((is_array($y)) ? $y : $x);
+}
+
diff --git a/include/zid.php b/include/zid.php
index 3b3dd8554..325af5580 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -1,6 +1,7 @@
<?php
use Zotlabs\Lib\Verify;
+use Zotlabs\Zot\Finger;
function is_matrix_url($url) {
diff --git a/include/zot.php b/include/zot.php
index d08146287..5d5ac8424 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -3611,6 +3611,12 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('app',$arr) && $arr['app'])
sync_apps($channel,$arr['app']);
+ if(array_key_exists('addressbook',$arr) && $arr['addressbook'])
+ sync_addressbook($channel,$arr['addressbook']);
+
+ if(array_key_exists('calendar',$arr) && $arr['calendar'])
+ sync_calendar($channel,$arr['calendar']);
+
if(array_key_exists('chatroom',$arr) && $arr['chatroom'])
sync_chatrooms($channel,$arr['chatroom']);