aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/AccessList.php148
-rw-r--r--include/Contact.php6
-rw-r--r--include/DReport.php55
-rw-r--r--include/ItemObject.php8
-rw-r--r--include/RedDAV/RedBasicAuth.php212
-rw-r--r--include/RedDAV/RedBrowser.php372
-rw-r--r--include/RedDAV/RedDirectory.php536
-rw-r--r--include/RedDAV/RedFile.php322
-rw-r--r--include/account.php22
-rw-r--r--include/acl_selectors.php26
-rw-r--r--include/api.php10
-rw-r--r--include/attach.php96
-rw-r--r--include/bbcode.php6
-rw-r--r--include/cli_startup.php3
-rw-r--r--include/comanche.php4
-rw-r--r--include/config.php83
-rw-r--r--include/contact_selectors.php2
-rw-r--r--include/conversation.php42
-rw-r--r--include/crypto.php17
-rw-r--r--include/datetime.php53
-rwxr-xr-xinclude/dba/dba_driver.php9
-rwxr-xr-xinclude/dba/dba_mysqli.php8
-rw-r--r--include/deliver.php3
-rw-r--r--include/enotify.php9
-rw-r--r--include/event.php13
-rw-r--r--include/features.php113
-rw-r--r--include/follow.php7
-rw-r--r--include/group.php12
-rw-r--r--include/identity.php290
-rw-r--r--include/import.php9
-rwxr-xr-xinclude/items.php455
-rw-r--r--include/language.php15
-rw-r--r--include/menu.php4
-rw-r--r--include/message.php9
-rw-r--r--include/nav.php19
-rw-r--r--include/network.php89
-rw-r--r--include/notifier.php63
-rwxr-xr-xinclude/oembed.php72
-rw-r--r--include/permissions.php14
-rw-r--r--include/photo/photo_driver.php3
-rw-r--r--include/photo/photo_gd.php17
-rw-r--r--include/photo/photo_imagick.php18
-rw-r--r--include/photos.php12
-rwxr-xr-xinclude/plugin.php75
-rw-r--r--include/poller.php2
-rw-r--r--include/profile_selectors.php12
-rw-r--r--include/queue_fn.php28
-rw-r--r--include/ratenotif.php1
-rw-r--r--include/reddav.php22
-rw-r--r--include/security.php43
-rw-r--r--include/session.php23
-rw-r--r--include/taxonomy.php7
-rw-r--r--include/text.php124
-rw-r--r--include/widgets.php193
-rw-r--r--include/zot.php116
55 files changed, 1764 insertions, 2168 deletions
diff --git a/include/AccessList.php b/include/AccessList.php
deleted file mode 100644
index 43f1de111..000000000
--- a/include/AccessList.php
+++ /dev/null
@@ -1,148 +0,0 @@
-<?php
-
-
-class AccessList {
-
- private $allow_cid;
- private $allow_gid;
- private $deny_cid;
- private $deny_gid;
-
- /* indicates if we are using the default constructor values or values that have been set explicitly. */
-
- private $explicit;
-
- function __construct($channel) {
-
- if($channel) {
- $this->allow_cid = $channel['channel_allow_cid'];
- $this->allow_gid = $channel['channel_allow_gid'];
- $this->deny_cid = $channel['channel_deny_cid'];
- $this->deny_gid = $channel['channel_deny_gid'];
- }
- else {
- $this->allow_cid = '';
- $this->allow_gid = '';
- $this->deny_cid = '';
- $this->deny_gid = '';
- }
-
- $this->explicit = false;
- }
-
- function get_explicit() {
- return $this->explicit;
- }
-
- /**
- * Set AccessList from strings such as those in already
- * existing stored data items
- */
-
- function set($arr,$explicit = true) {
- $this->allow_cid = $arr['allow_cid'];
- $this->allow_gid = $arr['allow_gid'];
- $this->deny_cid = $arr['deny_cid'];
- $this->deny_gid = $arr['deny_gid'];
-
- $this->explicit = $explicit;
- }
-
- /**
- * return an array consisting of the current
- * access list components where the elements
- * are directly storable.
- */
-
- function get() {
- return array(
- 'allow_cid' => $this->allow_cid,
- 'allow_gid' => $this->allow_gid,
- 'deny_cid' => $this->deny_cid,
- 'deny_gid' => $this->deny_gid,
- );
- }
-
- /**
- * Set AccessList from arrays, such as those provided by
- * acl_selector(). For convenience, a string (or non-array) input is
- * assumed to be a comma-separated list and auto-converted into an array.
- */
-
- function set_from_array($arr,$explicit = true) {
- $this->allow_cid = perms2str((is_array($arr['contact_allow']))
- ? $arr['contact_allow'] : explode(',',$arr['contact_allow']));
- $this->allow_gid = perms2str((is_array($arr['group_allow']))
- ? $arr['group_allow'] : explode(',',$arr['group_allow']));
- $this->deny_cid = perms2str((is_array($arr['contact_deny']))
- ? $arr['contact_deny'] : explode(',',$arr['contact_deny']));
- $this->deny_gid = perms2str((is_array($arr['group_deny']))
- ? $arr['group_deny'] : explode(',',$arr['group_deny']));
-
- $this->explicit = $explicit;
- }
-
- function is_private() {
- return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false);
- }
-
-}
-
-/**
- * @brief Used to wrap ACL elements in angle brackets for storage.
- *
- * @param[in,out] array &$item
- */
-function sanitise_acl(&$item) {
- if (strlen($item))
- $item = '<' . notags(trim($item)) . '>';
- else
- unset($item);
-}
-
-/**
- * @brief Convert an ACL array to a storable string.
- *
- * @param array $p
- * @return array
- */
-function perms2str($p) {
- $ret = '';
-
- if (is_array($p))
- $tmp = $p;
- else
- $tmp = explode(',', $p);
-
- if (is_array($tmp)) {
- array_walk($tmp, 'sanitise_acl');
- $ret = implode('', $tmp);
- }
-
- return $ret;
-}
-
-
-/**
- * @brief Turn user/group ACLs stored as angle bracketed text into arrays.
- *
- * turn string array of angle-bracketed elements into string array
- * e.g. "<123xyz><246qyo><sxo33e>" => array(123xyz,246qyo,sxo33e);
- *
- * @param string $s
- * @return array
- */
-function expand_acl($s) {
- $ret = array();
-
- if(strlen($s)) {
- $t = str_replace('<','',$s);
- $a = explode('>',$t);
- foreach($a as $aa) {
- if($aa)
- $ret[] = $aa;
- }
- }
-
- return $ret;
-}
diff --git a/include/Contact.php b/include/Contact.php
index 3bd5f9936..611371db6 100644
--- a/include/Contact.php
+++ b/include/Contact.php
@@ -331,6 +331,7 @@ function channel_remove($channel_id, $local = true, $unset_session=true) {
dbesc(datetime_convert()),
intval($channel_id)
);
+
// if this was the default channel, set another one as default
if($a->account['account_default_channel'] == $channel_id) {
$r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 limit 1",
@@ -344,12 +345,11 @@ function channel_remove($channel_id, $local = true, $unset_session=true) {
}
else {
$rr = q("update account set account_default_channel = 0 where account_id = %d",
- intval($r[0]['channel_id']),
- intval($a->account['account_id']));
+ intval($a->account['account_id'])
+ );
}
}
-
logger('deleting hublocs',LOGGER_DEBUG);
$r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s' and hubloc_url = '%s' ",
diff --git a/include/DReport.php b/include/DReport.php
deleted file mode 100644
index ef86c8cbc..000000000
--- a/include/DReport.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-
-class DReport {
-
- private $location;
- private $sender;
- private $recipient;
- private $message_id;
- private $status;
- private $date;
-
- function __construct($location,$sender,$recipient,$message_id,$status = 'deliver') {
- $this->location = $location;
- $this->sender = $sender;
- $this->recipient = $recipient;
- $this->message_id = $message_id;
- $this->status = $status;
- $this->date = datetime_convert();
- }
-
- function update($status) {
- $this->status = $status;
- $this->date = datetime_convert();
- }
-
- function addto_recipient($name) {
- $this->recipient = $this->recipient . ' ' . $name;
- }
-
- function addto_update($status) {
- $this->status = $this->status . ' ' . $status;
- }
-
-
- function set($arr) {
- $this->location = $arr['location'];
- $this->sender = $arr['sender'];
- $this->recipient = $arr['recipient'];
- $this->message_id = $arr['message_id'];
- $this->status = $arr['status'];
- $this->date = $arr['date'];
- }
-
- function get() {
- return array(
- 'location' => $this->location,
- 'sender' => $this->sender,
- 'recipient' => $this->recipient,
- 'message_id' => $this->message_id,
- 'status' => $this->status,
- 'date' => $this->date
- );
- }
-}
diff --git a/include/ItemObject.php b/include/ItemObject.php
index 8be99d91e..2be7e3ac9 100644
--- a/include/ItemObject.php
+++ b/include/ItemObject.php
@@ -264,7 +264,7 @@ class Item extends BaseObject {
if($keep_reports === 0)
$keep_reports = 30;
- if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0)
+ if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0)
$dreport = t('Delivery Report');
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
@@ -681,6 +681,11 @@ class Item extends BaseObject {
$qc = ((local_channel()) ? get_pconfig(local_channel(),'system','qcomment') : null);
$qcomment = (($qc) ? explode("\n",$qc) : null);
+ $arr = array('comment_buttons' => '','id' => $this->get_id());
+ call_hooks('comment_buttons',$arr);
+ $comment_buttons = $arr['comment_buttons'];
+
+
$comment_box = replace_macros($template,array(
'$return_path' => '',
'$threaded' => $this->is_threaded(),
@@ -689,6 +694,7 @@ class Item extends BaseObject {
'$id' => $this->get_id(),
'$parent' => $this->get_id(),
'$qcomment' => $qcomment,
+ '$comment_buttons' => $comment_buttons,
'$profile_uid' => $conv->get_profile_owner(),
'$mylink' => $observer['xchan_url'],
'$mytitle' => t('This is you'),
diff --git a/include/RedDAV/RedBasicAuth.php b/include/RedDAV/RedBasicAuth.php
deleted file mode 100644
index 19dd9a5f0..000000000
--- a/include/RedDAV/RedBasicAuth.php
+++ /dev/null
@@ -1,212 +0,0 @@
-<?php
-
-namespace RedMatrix\RedDAV;
-
-use Sabre\DAV;
-
-/**
- * @brief Authentication backend class for RedDAV.
- *
- * This class also contains some data which is not necessary for authentication
- * like timezone settings.
- *
- * @extends Sabre\DAV\Auth\Backend\AbstractBasic
- *
- * @link http://github.com/friendica/red
- * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
- */
-class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic {
-
- /**
- * @brief This variable holds the currently logged-in channel_address.
- *
- * It is used for building path in filestorage/.
- *
- * @var string|null
- */
- protected $channel_name = null;
- /**
- * channel_id of the current channel of the logged-in account.
- *
- * @var int
- */
- public $channel_id = 0;
- /**
- * channel_hash of the current channel of the logged-in account.
- *
- * @var string
- */
- public $channel_hash = '';
- /**
- * Set in mod/cloud.php to observer_hash.
- *
- * @var string
- */
- public $observer = '';
- /**
- *
- * @see RedBrowser::set_writeable()
- * @var \Sabre\DAV\Browser\Plugin
- */
- public $browser;
- /**
- * channel_id of the current visited path. Set in RedDirectory::getDir().
- *
- * @var int
- */
- public $owner_id = 0;
- /**
- * channel_name of the current visited path. Set in RedDirectory::getDir().
- *
- * Used for creating the path in cloud/
- *
- * @var string
- */
- public $owner_nick = '';
- /**
- * Timezone from the visiting channel's channel_timezone.
- *
- * Used in @ref RedBrowser
- *
- * @var string
- */
- protected $timezone = '';
-
-
- /**
- * @brief Validates a username and password.
- *
- * Guest access is granted with the password "+++".
- *
- * @see \Sabre\DAV\Auth\Backend\AbstractBasic::validateUserPass
- * @param string $username
- * @param string $password
- * @return bool
- */
- protected function validateUserPass($username, $password) {
- if (trim($password) === '+++') {
- logger('guest: ' . $username);
- return true;
- }
-
- require_once('include/auth.php');
- $record = account_verify_password($username, $password);
- if ($record && $record['account_default_channel']) {
- $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1",
- intval($record['account_id']),
- intval($record['account_default_channel'])
- );
- if ($r) {
- return $this->setAuthenticated($r[0]);
- }
- }
- $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1",
- dbesc($username)
- );
- if ($r) {
- $x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1",
- intval($r[0]['channel_account_id'])
- );
- if ($x) {
- // @fixme this foreach should not be needed?
- foreach ($x as $record) {
- if (($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED)
- && (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) {
- logger('password verified for ' . $username);
- return $this->setAuthenticated($r[0]);
- }
- }
- }
- }
-
- $error = 'password failed for ' . $username;
- logger($error);
- log_failed_login($error);
-
- return false;
- }
-
- /**
- * @brief Sets variables and session parameters after successfull authentication.
- *
- * @param array $r
- * Array with the values for the authenticated channel.
- * @return bool
- */
- protected function setAuthenticated($r) {
- $this->channel_name = $r['channel_address'];
- $this->channel_id = $r['channel_id'];
- $this->channel_hash = $this->observer = $r['channel_hash'];
- $_SESSION['uid'] = $r['channel_id'];
- $_SESSION['account_id'] = $r['channel_account_id'];
- $_SESSION['authenticated'] = true;
- return true;
- }
-
- /**
- * Sets the channel_name from the currently logged-in channel.
- *
- * @param string $name
- * The channel's name
- */
- public function setCurrentUser($name) {
- $this->channel_name = $name;
- }
- /**
- * Returns information about the currently logged-in channel.
- *
- * If nobody is currently logged in, this method should return null.
- *
- * @see \Sabre\DAV\Auth\Backend\AbstractBasic::getCurrentUser
- * @return string|null
- */
- public function getCurrentUser() {
- return $this->channel_name;
- }
-
- /**
- * @brief Sets the timezone from the channel in RedBasicAuth.
- *
- * Set in mod/cloud.php if the channel has a timezone set.
- *
- * @param string $timezone
- * The channel's timezone.
- * @return void
- */
- public function setTimezone($timezone) {
- $this->timezone = $timezone;
- }
- /**
- * @brief Returns the timezone.
- *
- * @return string
- * Return the channel's timezone.
- */
- public function getTimezone() {
- return $this->timezone;
- }
-
- /**
- * @brief Set browser plugin for SabreDAV.
- *
- * @see RedBrowser::set_writeable()
- * @param \Sabre\DAV\Browser\Plugin $browser
- */
- public function setBrowserPlugin($browser) {
- $this->browser = $browser;
- }
-
- /**
- * @brief Prints out all RedBasicAuth variables to logger().
- *
- * @return void
- */
- public function log() {
- logger('channel_name ' . $this->channel_name, LOGGER_DATA);
- logger('channel_id ' . $this->channel_id, LOGGER_DATA);
- logger('channel_hash ' . $this->channel_hash, LOGGER_DATA);
- logger('observer ' . $this->observer, LOGGER_DATA);
- logger('owner_id ' . $this->owner_id, LOGGER_DATA);
- logger('owner_nick ' . $this->owner_nick, LOGGER_DATA);
- }
-} \ No newline at end of file
diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php
deleted file mode 100644
index 1aa5f435e..000000000
--- a/include/RedDAV/RedBrowser.php
+++ /dev/null
@@ -1,372 +0,0 @@
-<?php
-
-namespace RedMatrix\RedDAV;
-
-use Sabre\DAV;
-
-/**
- * @brief Provides a DAV frontend for the webbrowser.
- *
- * RedBrowser is a SabreDAV server-plugin to provide a view to the DAV storage
- * for the webbrowser.
- *
- * @extends \Sabre\DAV\Browser\Plugin
- *
- * @link http://github.com/friendica/red
- * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
- */
-class RedBrowser extends DAV\Browser\Plugin {
-
- /**
- * @see set_writeable()
- * @see \Sabre\DAV\Auth\Backend\BackendInterface
- * @var RedBasicAuth
- */
- private $auth;
-
- /**
- * @brief Constructor for RedBrowser class.
- *
- * $enablePost will be activated through set_writeable() in a later stage.
- * At the moment the write_storage permission is only valid for the whole
- * folder. No file specific permissions yet.
- * @todo disable enablePost by default and only activate if permissions
- * grant edit rights.
- *
- * Disable assets with $enableAssets = false. Should get some thumbnail views
- * anyway.
- *
- * @param RedBasicAuth &$auth
- */
- public function __construct(&$auth) {
- $this->auth = $auth;
- parent::__construct(true, false);
- }
-
- /**
- * The DAV browser is instantiated after the auth module and directory classes
- * but before we know the current directory and who the owner and observer
- * are. So we add a pointer to the browser into the auth module and vice versa.
- * Then when we've figured out what directory is actually being accessed, we
- * call the following function to decide whether or not to show web elements
- * which include writeable objects.
- *
- * @fixme It only disable/enable the visible parts. Not the POST handler
- * which handels the actual requests when uploading files or creating folders.
- *
- * @todo Maybe this whole way of doing this can be solved with some
- * $server->subscribeEvent().
- */
- public function set_writeable() {
- if (! $this->auth->owner_id) {
- $this->enablePost = false;
- }
-
- if (! perm_is_allowed($this->auth->owner_id, get_observer_hash(), 'write_storage')) {
- $this->enablePost = false;
- } else {
- $this->enablePost = true;
- }
- }
-
- /**
- * @brief Creates the directory listing for the given path.
- *
- * @param string $path which should be displayed
- */
- public function generateDirectoryIndex($path) {
- // (owner_id = channel_id) is visitor owner of this directory?
- $is_owner = ((local_channel() && $this->auth->owner_id == local_channel()) ? true : false);
-
- if ($this->auth->getTimezone())
- date_default_timezone_set($this->auth->getTimezone());
-
- require_once('include/conversation.php');
- require_once('include/text.php');
- if ($this->auth->owner_nick) {
- $html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick);
- }
-
- $files = $this->server->getPropertiesForPath($path, array(
- '{DAV:}displayname',
- '{DAV:}resourcetype',
- '{DAV:}getcontenttype',
- '{DAV:}getcontentlength',
- '{DAV:}getlastmodified',
- ), 1);
-
-
- $parent = $this->server->tree->getNodeForPath($path);
-
- $parentpath = array();
- // only show parent if not leaving /cloud/; TODO how to improve this?
- if ($path && $path != "cloud") {
- list($parentUri) = DAV\URLUtil::splitPath($path);
- $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
-
- $parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : '';
- $parentpath['path'] = $fullPath;
- }
-
- $f = array();
- foreach ($files as $file) {
- $ft = array();
- $type = null;
-
- // This is the current directory, we can skip it
- if (rtrim($file['href'],'/') == $path) continue;
-
- list(, $name) = DAV\URLUtil::splitPath($file['href']);
-
- if (isset($file[200]['{DAV:}resourcetype'])) {
- $type = $file[200]['{DAV:}resourcetype']->getValue();
-
- // resourcetype can have multiple values
- if (!is_array($type)) $type = array($type);
-
- foreach ($type as $k=>$v) {
- // Some name mapping is preferred
- switch ($v) {
- case '{DAV:}collection' :
- $type[$k] = t('Collection');
- break;
- case '{DAV:}principal' :
- $type[$k] = t('Principal');
- break;
- case '{urn:ietf:params:xml:ns:carddav}addressbook' :
- $type[$k] = t('Addressbook');
- break;
- case '{urn:ietf:params:xml:ns:caldav}calendar' :
- $type[$k] = t('Calendar');
- break;
- case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' :
- $type[$k] = t('Schedule Inbox');
- break;
- case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' :
- $type[$k] = t('Schedule Outbox');
- break;
- case '{http://calendarserver.org/ns/}calendar-proxy-read' :
- $type[$k] = 'Proxy-Read';
- break;
- case '{http://calendarserver.org/ns/}calendar-proxy-write' :
- $type[$k] = 'Proxy-Write';
- break;
- }
- }
- $type = implode(', ', $type);
- }
-
- // If no resourcetype was found, we attempt to use
- // the contenttype property
- if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
- $type = $file[200]['{DAV:}getcontenttype'];
- }
- if (!$type) $type = t('Unknown');
-
- $size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : '';
- $lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : '');
-
- $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
-
-
- $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
-
- $displayName = $this->escapeHTML($displayName);
- $type = $this->escapeHTML($type);
-
- $icon = '';
-
- if ($this->enableAssets) {
- $node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name);
- foreach (array_reverse($this->iconMap) as $class=>$iconName) {
- if ($node instanceof $class) {
- $icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>';
- break;
- }
- }
- }
-
- $parentHash = '';
- $owner = $this->auth->owner_id;
- $splitPath = explode('/', $fullPath);
- if (count($splitPath) > 3) {
- for ($i = 3; $i < count($splitPath); $i++) {
- $attachName = urldecode($splitPath[$i]);
- $attachHash = $this->findAttachHash($owner, $parentHash, $attachName);
- $parentHash = $attachHash;
- }
- }
-
- $attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>";
-
- // put the array for this file together
- $ft['attachId'] = $this->findAttachIdByHash($attachHash);
- $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser();
- $ft['icon'] = $icon;
- $ft['attachIcon'] = (($size) ? $attachIcon : '');
- // @todo Should this be an item value, not a global one?
- $ft['is_owner'] = $is_owner;
- $ft['fullPath'] = $fullPath;
- $ft['displayName'] = $displayName;
- $ft['type'] = $type;
- $ft['size'] = $size;
- $ft['sizeFormatted'] = userReadableSize($size);
- $ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : '');
- $ft['iconFromType'] = getIconFromType($type);
-
- $f[] = $ft;
- }
-
- $output = '';
- if ($this->enablePost) {
- $this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output));
- }
-
- $html .= replace_macros(get_markup_template('cloud.tpl'), array(
- '$header' => t('Files') . ": " . $this->escapeHTML($path) . "/",
- '$total' => t('Total'),
- '$actionspanel' => $output,
- '$shared' => t('Shared'),
- '$create' => t('Create'),
- '$upload' => t('Upload'),
- '$is_owner' => $is_owner,
- '$parentpath' => $parentpath,
- '$entries' => $f,
- '$name' => t('Name'),
- '$type' => t('Type'),
- '$size' => t('Size'),
- '$lastmod' => t('Last Modified'),
- '$parent' => t('parent'),
- '$edit' => t('Edit'),
- '$delete' => t('Delete'),
- '$nick' => $this->auth->getCurrentUser()
- ));
-
- $a = get_app();
- $a->page['content'] = $html;
- load_pdl($a);
-
- $theme_info_file = "view/theme/" . current_theme() . "/php/theme.php";
- if (file_exists($theme_info_file)){
- require_once($theme_info_file);
- if (function_exists(str_replace('-', '_', current_theme()) . '_init')) {
- $func = str_replace('-', '_', current_theme()) . '_init';
- $func($a);
- }
- }
- construct_page($a);
- }
-
- /**
- * @brief Creates a form to add new folders and upload files.
- *
- * @param \Sabre\DAV\INode $node
- * @param string &$output
- */
- public function htmlActionsPanel(DAV\INode $node, &$output) {
- if (! $node instanceof DAV\ICollection)
- return;
-
- // We also know fairly certain that if an object is a non-extended
- // SimpleCollection, we won't need to show the panel either.
- if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
- return;
-
- // Storage and quota for the account (all channels of the owner of this directory)!
- $limit = service_class_fetch($owner, 'attach_upload_limit');
- $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d",
- intval($this->auth->channel_account_id)
- );
- $used = $r[0]['total'];
- if ($used) {
- $quotaDesc = t('You are using %1$s of your available file storage.');
- $quotaDesc = sprintf($quotaDesc,
- userReadableSize($used));
- }
- if ($limit && $used) {
- $quotaDesc = t('You are using %1$s of %2$s available file storage. (%3$s&#37;)');
- $quotaDesc = sprintf($quotaDesc,
- userReadableSize($used),
- userReadableSize($limit),
- round($used / $limit, 1) * 100);
- }
-
- // prepare quota for template
- $quota = array();
- $quota['used'] = $used;
- $quota['limit'] = $limit;
- $quota['desc'] = $quotaDesc;
- $quota['warning'] = ((($limit) && ((round($used / $limit, 1) * 100) >= 90)) ? t('WARNING:') : ''); // 10485760 bytes = 100MB
-
- $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array(
- '$folder_header' => t('Create new folder'),
- '$folder_submit' => t('Create'),
- '$upload_header' => t('Upload file'),
- '$upload_submit' => t('Upload'),
- '$quota' => $quota
- ));
- }
-
- /**
- * This method takes a path/name of an asset and turns it into url
- * suiteable for http access.
- *
- * @param string $assetName
- * @return string
- */
- protected function getAssetUrl($assetName) {
- return z_root() . '/cloud/?sabreAction=asset&assetName=' . urlencode($assetName);
- }
-
- /**
- * @brief Return the hash of an attachment.
- *
- * Given the owner, the parent folder and and attach name get the attachment
- * hash.
- *
- * @param int $owner
- * The owner_id
- * @param string $hash
- * The parent's folder hash
- * @param string $attachName
- * The name of the attachment
- * @return string
- */
-
- protected function findAttachHash($owner, $parentHash, $attachName) {
- $r = q("SELECT hash FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited DESC LIMIT 1",
- intval($owner),
- dbesc($parentHash),
- dbesc($attachName)
- );
- $hash = "";
- if ($r) {
- foreach ($r as $rr) {
- $hash = $rr['hash'];
- }
- }
- return $hash;
- }
-
- /**
- * @brief Returns an attachment's id for a given hash.
- *
- * This id is used to access the attachment in filestorage/
- *
- * @param string $attachHash
- * The hash of an attachment
- * @return string
- */
- protected function findAttachIdByHash($attachHash) {
- $r = q("SELECT id FROM attach WHERE hash = '%s' ORDER BY edited DESC LIMIT 1",
- dbesc($attachHash)
- );
- $id = "";
- if ($r) {
- foreach ($r as $rr) {
- $id = $rr['id'];
- }
- }
- return $id;
- }
-}
diff --git a/include/RedDAV/RedDirectory.php b/include/RedDAV/RedDirectory.php
deleted file mode 100644
index 8d8af5bd3..000000000
--- a/include/RedDAV/RedDirectory.php
+++ /dev/null
@@ -1,536 +0,0 @@
-<?php
-
-namespace RedMatrix\RedDAV;
-
-use Sabre\DAV;
-
-/**
- * @brief RedDirectory class.
- *
- * A class that represents a directory.
- *
- * @extends \Sabre\DAV\Node
- * @implements \Sabre\DAV\ICollection
- * @implements \Sabre\DAV\IQuota
- *
- * @link http://github.com/friendica/red
- * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
- */
-class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
-
- /**
- * @brief The path inside /cloud
- *
- * @var string
- */
- private $red_path;
- private $folder_hash;
- /**
- * @brief The full path as seen in the browser.
- * /cloud + $red_path
- * @todo I think this is not used anywhere, we always strip '/cloud' and only use it in debug
- * @var string
- */
- private $ext_path;
- private $root_dir = '';
- private $auth;
- /**
- * @brief The real path on the filesystem.
- * The actual path in store/ with the hashed names.
- *
- * @var string
- */
- private $os_path = '';
-
- /**
- * @brief Sets up the directory node, expects a full path.
- *
- * @param string $ext_path a full path
- * @param RedBasicAuth &$auth_plugin
- */
- public function __construct($ext_path, &$auth_plugin) {
-// $ext_path = urldecode($ext_path);
- logger('directory ' . $ext_path, LOGGER_DATA);
- $this->ext_path = $ext_path;
- // remove "/cloud" from the beginning of the path
- $modulename = get_app()->module;
- $this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path);
- if (! $this->red_path) {
- $this->red_path = '/';
- }
- $this->auth = $auth_plugin;
- $this->folder_hash = '';
- $this->getDir();
-
- if ($this->auth->browser) {
- $this->auth->browser->set_writeable();
- }
- }
-
- private function log() {
- logger('ext_path ' . $this->ext_path, LOGGER_DATA);
- logger('os_path ' . $this->os_path, LOGGER_DATA);
- logger('red_path ' . $this->red_path, LOGGER_DATA);
- }
-
- /**
- * @brief Returns an array with all the child nodes.
- *
- * @throw \Sabre\DAV\Exception\Forbidden
- * @return array \Sabre\DAV\INode[]
- */
- public function getChildren() {
- logger('children for ' . $this->ext_path, LOGGER_DATA);
- $this->log();
-
- if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- $contents = RedCollectionData($this->red_path, $this->auth);
- return $contents;
- }
-
- /**
- * @brief Returns a child by name.
- *
- *
- * @throw \Sabre\DAV\Exception\Forbidden
- * @throw \Sabre\DAV\Exception\NotFound
- * @param string $name
- */
- public function getChild($name) {
- logger($name, LOGGER_DATA);
-
- if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- $modulename = get_app()->module;
- if ($this->red_path === '/' && $name === $modulename) {
- return new RedDirectory('/' . $modulename, $this->auth);
- }
-
- $x = RedFileData($this->ext_path . '/' . $name, $this->auth);
- if ($x) {
- return $x;
- }
-
- throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found.');
- }
-
- /**
- * @brief Returns the name of the directory.
- *
- * @return string
- */
- public function getName() {
- //logger(basename($this->red_path), LOGGER_DATA);
- return (basename($this->red_path));
- }
-
- /**
- * @brief Renames the directory.
- *
- * @todo handle duplicate directory name
- *
- * @throw \Sabre\DAV\Exception\Forbidden
- * @param string $name The new name of the directory.
- * @return void
- */
- public function setName($name) {
- logger('old name ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA);
-
- if ((! $name) || (! $this->auth->owner_id)) {
- logger('permission denied ' . $name);
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) {
- logger('permission denied '. $name);
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- list($parent_path, ) = DAV\URLUtil::splitPath($this->red_path);
- $new_path = $parent_path . '/' . $name;
-
- $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d",
- dbesc($name),
- dbesc($this->folder_hash),
- intval($this->auth->owner_id)
- );
-
- $this->red_path = $new_path;
- }
-
- /**
- * @brief Creates a new file in the directory.
- *
- * Data will either be supplied as a stream resource, or in certain cases
- * as a string. Keep in mind that you may have to support either.
- *
- * After successful creation of the file, you may choose to return the ETag
- * of the new file here.
- *
- * @throw \Sabre\DAV\Exception\Forbidden
- * @param string $name Name of the file
- * @param resource|string $data Initial payload
- * @return null|string ETag
- */
- public function createFile($name, $data = null) {
- logger($name, LOGGER_DEBUG);
-
- if (! $this->auth->owner_id) {
- logger('permission denied ' . $name);
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) {
- logger('permission denied ' . $name);
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- $mimetype = z_mime_content_type($name);
-
- $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
- intval($this->auth->owner_id)
- );
-
- if (! $c) {
- logger('no channel');
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- $filesize = 0;
- $hash = random_string();
-
- $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash;
-
- $direct = null;
-
- if($this->folder_hash) {
- $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1",
- dbesc($this->folder_hash),
- intval($c[0]['channel_id'])
- );
- if($r)
- $direct = $r[0];
- }
-
- if(($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) {
- $allow_cid = $direct['allow_cid'];
- $allow_gid = $direct['allow_gid'];
- $deny_cid = $direct['deny_cid'];
- $deny_gid = $direct['deny_gid'];
- }
- else {
- $allow_cid = $c[0]['channel_allow_cid'];
- $allow_gid = $c[0]['channel_allow_gid'];
- $deny_cid = $c[0]['channel_deny_cid'];
- $deny_gid = $c[0]['channel_deny_gid'];
- }
-
- $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
- intval($c[0]['channel_account_id']),
- intval($c[0]['channel_id']),
- dbesc($hash),
- dbesc($this->auth->observer),
- dbesc($name),
- dbesc($this->folder_hash),
- intval(1),
- dbesc($mimetype),
- intval($filesize),
- intval(0),
- intval($is_photo),
- dbesc($f),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc($allow_cid),
- dbesc($allow_gid),
- dbesc($deny_cid),
- dbesc($deny_gid)
- );
-
-
-
- // returns the number of bytes that were written to the file, or FALSE on failure
- $size = file_put_contents($f, $data);
- // delete attach entry if file_put_contents() failed
- if ($size === false) {
- logger('file_put_contents() failed to ' . $f);
- attach_delete($c[0]['channel_id'], $hash);
- return;
- }
-
- // returns now
- $edited = datetime_convert();
-
-
-
- $is_photo = 0;
- $x = @getimagesize($f);
- logger('getimagesize: ' . print_r($x,true), LOGGER_DATA);
- if(($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) {
- $is_photo = 1;
- }
-
-
- // updates entry with filesize and timestamp
- $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
- dbesc($size),
- intval($is_photo),
- dbesc($edited),
- dbesc($hash),
- intval($c[0]['channel_id'])
- );
-
- // update the folder's lastmodified timestamp
- $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
- dbesc($edited),
- dbesc($this->folder_hash),
- intval($c[0]['channel_id'])
- );
-
- $maxfilesize = get_config('system', 'maxfilesize');
- if (($maxfilesize) && ($size > $maxfilesize)) {
- attach_delete($c[0]['channel_id'], $hash);
- return;
- }
-
- // check against service class quota
- $limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit');
- if ($limit !== false) {
- $x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ",
- intval($c[0]['channel_account_id'])
- );
- if (($x) && ($x[0]['total'] + $size > $limit)) {
- logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit);
- attach_delete($c[0]['channel_id'], $hash);
- return;
- }
- }
-
- if($is_photo) {
- $album = '';
- if($this->folder_hash) {
- $f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d",
- dbesc($this->folder_hash),
- intval($c[0]['channel_id'])
- );
- if($f1)
- $album = $f1[0]['filename'];
- }
-
- require_once('include/photos.php');
- $args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct);
- $p = photo_upload($c[0],get_app()->get_observer(),$args);
- }
-
- }
-
- /**
- * @brief Creates a new subdirectory.
- *
- * @param string $name the directory to create
- * @return void
- */
- public function createDirectory($name) {
- logger($name, LOGGER_DEBUG);
-
- if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- $r = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
- intval($this->auth->owner_id)
- );
-
- if ($r) {
- $result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash));
- if (! $result['success']) {
- logger('error ' . print_r($result, true), LOGGER_DEBUG);
- }
- }
- }
-
- /**
- * @brief delete directory
- */
-
- public function delete() {
- logger('delete file ' . basename($this->red_path), LOGGER_DEBUG);
-
- if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- if ($this->auth->owner_id !== $this->auth->channel_id) {
- if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
- }
-
- attach_delete($this->auth->owner_id, $this->folder_hash);
- }
-
-
- /**
- * @brief Checks if a child exists.
- *
- * @param string $name
- * The name to check if it exists.
- * @return boolean
- */
- public function childExists($name) {
- // On /cloud we show a list of available channels.
- // @todo what happens if no channels are available?
- $modulename = get_app()->module;
- if ($this->red_path === '/' && $name === $modulename) {
- //logger('We are at ' $modulename . ' show a channel list', LOGGER_DEBUG);
- return true;
- }
-
- $x = RedFileData($this->ext_path . '/' . $name, $this->auth, true);
- //logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA);
- if ($x)
- return true;
-
- return false;
- }
-
- /**
- * @todo add description of what this function does.
- *
- * @throw \Sabre\DAV\Exception\NotFound
- * @return void
- */
- function getDir() {
-
- logger('GetDir: ' . $this->ext_path, LOGGER_DEBUG);
- $this->auth->log();
- $modulename = get_app()->module;
-
- $file = $this->ext_path;
-
- $x = strpos($file, '/' . $modulename);
- if ($x === 0) {
- $file = substr($file, strlen($modulename) + 1);
- }
-
- if ((! $file) || ($file === '/')) {
- return;
- }
-
- $file = trim($file, '/');
- $path_arr = explode('/', $file);
-
- if (! $path_arr)
- return;
-
- logger('paths: ' . print_r($path_arr, true), LOGGER_DATA);
-
- $channel_name = $path_arr[0];
-
- $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND channel_removed = 0 LIMIT 1",
- dbesc($channel_name)
- );
-
- if (! $r) {
- throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.');
- }
-
- $channel_id = $r[0]['channel_id'];
- $this->auth->owner_id = $channel_id;
- $this->auth->owner_nick = $channel_name;
-
- $path = '/' . $channel_name;
- $folder = '';
- $os_path = '';
-
- for ($x = 1; $x < count($path_arr); $x++) {
- $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0",
- dbesc($folder),
- dbesc($path_arr[$x]),
- intval($channel_id)
- );
- if ($r && intval($r[0]['is_dir'])) {
- $folder = $r[0]['hash'];
- if (strlen($os_path))
- $os_path .= '/';
- $os_path .= $folder;
-
- $path = $path . '/' . $r[0]['filename'];
- }
- }
- $this->folder_hash = $folder;
- $this->os_path = $os_path;
- }
-
- /**
- * @brief Returns the last modification time for the directory, as a UNIX
- * timestamp.
- *
- * It looks for the last edited file in the folder. If it is an empty folder
- * it returns the lastmodified time of the folder itself, to prevent zero
- * timestamps.
- *
- * @return int last modification time in UNIX timestamp
- */
- public function getLastModified() {
- $r = q("SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1",
- dbesc($this->folder_hash),
- intval($this->auth->owner_id)
- );
- if (! $r) {
- $r = q("SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
- dbesc($this->folder_hash),
- intval($this->auth->owner_id)
- );
- if (! $r)
- return '';
- }
- return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U');
- }
-
- /**
- * @brief Return quota usage.
- *
- * @fixme Should guests relly see the used/free values from filesystem of the
- * complete store directory?
- *
- * @return array with used and free values in bytes.
- */
- public function getQuotaInfo() {
- // values from the filesystem of the complete <i>store/</i> directory
- $limit = disk_total_space('store');
- $free = disk_free_space('store');
-
- if ($this->auth->owner_id) {
- $c = q("select * from channel where channel_id = %d and channel_removed = 0 limit 1",
- intval($this->auth->owner_id)
- );
-
- $ulimit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit');
- $limit = (($ulimit) ? $ulimit : $limit);
-
- $x = q("select sum(filesize) as total from attach where aid = %d",
- intval($c[0]['channel_account_id'])
- );
- $free = (($x) ? $limit - $x[0]['total'] : 0);
- }
-
- return array(
- $limit - $free,
- $free
- );
- }
-} \ No newline at end of file
diff --git a/include/RedDAV/RedFile.php b/include/RedDAV/RedFile.php
deleted file mode 100644
index 3283a6e88..000000000
--- a/include/RedDAV/RedFile.php
+++ /dev/null
@@ -1,322 +0,0 @@
-<?php
-
-namespace RedMatrix\RedDAV;
-
-use Sabre\DAV;
-
-/**
- * @brief This class represents a file in DAV.
- *
- * It provides all functions to work with files in Red's cloud through DAV protocol.
- *
- * @extends \Sabre\DAV\Node
- * @implements \Sabre\DAV\IFile
- *
- * @link http://github.com/friendica/red
- * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
- */
-class RedFile extends DAV\Node implements DAV\IFile {
-
- /**
- * The file from attach table.
- *
- * @var array
- * data
- * flags
- * filename (string)
- * filetype (string)
- */
- private $data;
- /**
- * @see \Sabre\DAV\Auth\Backend\BackendInterface
- * @var \RedMatrix\RedDAV\RedBasicAuth
- */
- private $auth;
- /**
- * @var string
- */
- private $name;
-
- /**
- * Sets up the node, expects a full path name.
- *
- * @param string $name
- * @param array $data from attach table
- * @param &$auth
- */
- public function __construct($name, $data, &$auth) {
- $this->name = $name;
- $this->data = $data;
- $this->auth = $auth;
-
- logger(print_r($this->data, true), LOGGER_DATA);
- }
-
- /**
- * @brief Returns the name of the file.
- *
- * @return string
- */
- public function getName() {
- //logger(basename($this->name), LOGGER_DATA);
- return basename($this->name);
- }
-
- /**
- * @brief Renames the file.
- *
- * @throw Sabre\DAV\Exception\Forbidden
- * @param string $name The new name of the file.
- * @return void
- */
- public function setName($newName) {
- logger('old name ' . basename($this->name) . ' -> ' . $newName, LOGGER_DATA);
-
- if ((! $newName) || (! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
- logger('permission denied '. $newName);
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- $newName = str_replace('/', '%2F', $newName);
-
- $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND id = %d",
- dbesc($newName),
- dbesc($this->data['hash']),
- intval($this->data['id'])
- );
- }
-
- /**
- * @brief Updates the data of the file.
- *
- * @param resource $data
- * @return void
- */
- public function put($data) {
- logger('put file: ' . basename($this->name), LOGGER_DEBUG);
- $size = 0;
-
- // @todo only 3 values are needed
- $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
- intval($this->auth->owner_id)
- );
-
- $is_photo = false;
- $album = '';
-
- $r = q("SELECT flags, folder, os_storage, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
- dbesc($this->data['hash']),
- intval($c[0]['channel_id'])
- );
- if ($r) {
- if (intval($r[0]['os_storage'])) {
- $d = q("select folder, data from attach where hash = '%s' and uid = %d limit 1",
- dbesc($this->data['hash']),
- intval($c[0]['channel_id'])
- );
- if($d) {
- if($d[0]['folder']) {
- $f1 = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1",
- dbesc($d[0]['folder']),
- intval($c[0]['channel_id'])
- );
- if($f1) {
- $album = $f1[0]['filename'];
- $direct = $f1[0];
- }
- }
- $fname = dbunescbin($d[0]['data']);
- if(strpos($fname,'store') === false)
- $f = 'store/' . $this->auth->owner_nick . '/' . $fname ;
- else
- $f = $fname;
-
- // @todo check return value and set $size directly
- @file_put_contents($f, $data);
- $size = @filesize($f);
- logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG);
- }
- $gis = @getimagesize($f);
- logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA);
- if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
- $is_photo = 1;
- }
- }
- else {
- // this shouldn't happen any more
- $r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d",
- dbescbin(stream_get_contents($data)),
- dbesc($this->data['hash']),
- intval($this->data['uid'])
- );
- $r = q("SELECT length(data) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
- dbesc($this->data['hash']),
- intval($this->data['uid'])
- );
- if ($r) {
- $size = $r[0]['fsize'];
- }
- }
- }
-
- // returns now()
- $edited = datetime_convert();
-
- $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
- dbesc($size),
- intval($is_photo),
- dbesc($edited),
- dbesc($this->data['hash']),
- intval($c[0]['channel_id'])
- );
-
- if($is_photo) {
- require_once('include/photos.php');
- $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct );
- $p = photo_upload($c[0],get_app()->get_observer(),$args);
- }
-
- // update the folder's lastmodified timestamp
- $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
- dbesc($edited),
- dbesc($r[0]['folder']),
- intval($c[0]['channel_id'])
- );
-
- // @todo do we really want to remove the whole file if an update fails
- // because of maxfilesize or quota?
- // There is an Exception "InsufficientStorage" or "PaymentRequired" for
- // our service class from SabreDAV we could use.
-
- $maxfilesize = get_config('system', 'maxfilesize');
- if (($maxfilesize) && ($size > $maxfilesize)) {
- attach_delete($c[0]['channel_id'], $this->data['hash']);
- return;
- }
-
- $limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit');
- if ($limit !== false) {
- $x = q("select sum(filesize) as total from attach where aid = %d ",
- intval($c[0]['channel_account_id'])
- );
- if (($x) && ($x[0]['total'] + $size > $limit)) {
- logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit);
- attach_delete($c[0]['channel_id'], $this->data['hash']);
- return;
- }
- }
- }
-
- /**
- * @brief Returns the raw data.
- *
- * @return string
- */
- public function get() {
- logger('get file ' . basename($this->name), LOGGER_DEBUG);
- logger('os_path: ' . $this->os_path, LOGGER_DATA);
-
- $r = q("SELECT data, flags, os_storage, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
- dbesc($this->data['hash']),
- intval($this->data['uid'])
- );
- if ($r) {
- // @todo this should be a global definition
- $unsafe_types = array('text/html', 'text/css', 'application/javascript');
-
- if (in_array($r[0]['filetype'], $unsafe_types)) {
- header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"');
- header('Content-type: text/plain');
- }
-
- if (intval($r[0]['os_storage'])) {
- $x = dbunescbin($r[0]['data']);
- if(strpos($x,'store') === false)
- $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x;
- else
- $f = $x;
- return fopen($f, 'rb');
- }
- return dbunescbin($r[0]['data']);
- }
- }
-
- /**
- * @brief Returns the ETag for a file.
- *
- * An ETag is a unique identifier representing the current version of the file.
- * If the file changes, the ETag MUST change.
- * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
- *
- * Return null if the ETag can not effectively be determined.
- *
- * @return null|string
- */
- public function getETag() {
- $ret = null;
- if ($this->data['hash']) {
- $ret = '"' . $this->data['hash'] . '"';
- }
- return $ret;
- }
-
- /**
- * @brief Returns the mime-type for a file.
- *
- * If null is returned, we'll assume application/octet-stream
- *
- * @return mixed
- */
- public function getContentType() {
- // @todo this should be a global definition.
- $unsafe_types = array('text/html', 'text/css', 'application/javascript');
- if (in_array($this->data['filetype'], $unsafe_types)) {
- return 'text/plain';
- }
- return $this->data['filetype'];
- }
-
- /**
- * @brief Returns the size of the node, in bytes.
- *
- * @return int
- * filesize in bytes
- */
- public function getSize() {
- return $this->data['filesize'];
- }
-
- /**
- * @brief Returns the last modification time for the file, as a unix
- * timestamp.
- *
- * @return int last modification time in UNIX timestamp
- */
- public function getLastModified() {
- return datetime_convert('UTC', 'UTC', $this->data['edited'], 'U');
- }
-
- /**
- * @brief Delete the file.
- *
- * This method checks the permissions and then calls attach_delete() function
- * to actually remove the file.
- *
- * @throw \Sabre\DAV\Exception\Forbidden
- */
- public function delete() {
- logger('delete file ' . basename($this->name), LOGGER_DEBUG);
-
- if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
-
- if ($this->auth->owner_id !== $this->auth->channel_id) {
- if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
- }
-
- attach_delete($this->auth->owner_id, $this->data['hash']);
- }
-}
diff --git a/include/account.php b/include/account.php
index e448bdcc6..4c828003e 100644
--- a/include/account.php
+++ b/include/account.php
@@ -11,6 +11,7 @@ require_once('include/text.php');
require_once('include/language.php');
require_once('include/datetime.php');
require_once('include/crypto.php');
+require_once('include/identity.php');
function check_account_email($email) {
@@ -329,7 +330,7 @@ function send_reg_approval_email($arr) {
return($delivered ? true : false);
}
-function send_verification_email($email,$password) {
+function send_register_success_email($email,$password) {
$email_msg = replace_macros(get_intltext_template('register_open_eml.tpl'), array(
'$sitename' => get_config('system','sitename'),
@@ -353,7 +354,7 @@ function send_verification_email($email,$password) {
* @param string $hash
* @return array|boolean
*/
-function user_allow($hash) {
+function account_allow($hash) {
$ret = array('success' => false);
@@ -406,6 +407,9 @@ function user_allow($hash) {
pop_lang();
+ if(get_config('system','auto_channel_create') || UNO)
+ auto_channel_create($register[0]['uid']);
+
if ($res) {
info( t('Account approved.') . EOL );
return true;
@@ -414,7 +418,7 @@ function user_allow($hash) {
/**
- * @brief Denies a user registration.
+ * @brief Denies an account registration.
*
* This does not have to go through user_remove() and save the nickname
* permanently against re-registration, as the person was not yet
@@ -423,7 +427,8 @@ function user_allow($hash) {
* @param string $hash
* @return boolean
*/
-function user_deny($hash) {
+
+function account_deny($hash) {
$register = q("SELECT * FROM register WHERE hash = '%s' LIMIT 1",
dbesc($hash)
@@ -452,11 +457,14 @@ function user_deny($hash) {
}
+// called from regver to activate an account from the email verification link
-function user_approve($hash) {
+function account_approve($hash) {
$ret = array('success' => false);
+ // Note: when the password in the register table is 'verify', the uid actually contains the account_id
+
$register = q("SELECT * FROM `register` WHERE `hash` = '%s' and password = 'verify' LIMIT 1",
dbesc($hash)
);
@@ -491,6 +499,10 @@ function user_approve($hash) {
intval($register[0]['uid'])
);
+
+ if(get_config('system','auto_channel_create') || UNO)
+ auto_channel_create($register[0]['uid']);
+
info( t('Account verified. Please login.') . EOL );
return true;
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 4d44ec12e..3c8f34321 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -210,10 +210,13 @@ function fixacl(&$item) {
$item = str_replace(array('<','>'),array('',''),$item);
}
-function populate_acl($defaults = null,$show_jotnets = true) {
+function populate_acl($defaults = null,$show_jotnets = true, $showall = '') {
$allow_cid = $allow_gid = $deny_cid = $deny_gid = false;
+ if(! $showall)
+ $showall = t('Visible to your default audience');
+
if(is_array($defaults)) {
$allow_cid = ((strlen($defaults['allow_cid']))
? explode('><', $defaults['allow_cid']) : array() );
@@ -231,22 +234,21 @@ function populate_acl($defaults = null,$show_jotnets = true) {
$jotnets = '';
if($show_jotnets) {
-logger('jot_networks');
call_hooks('jot_networks', $jotnets);
}
$tpl = get_markup_template("acl_selector.tpl");
$o = replace_macros($tpl, array(
- '$showall'=> t("Visible to your default audience"),
- '$show' => t("Show"),
- '$hide' => t("Don't show"),
- '$allowcid' => json_encode($allow_cid),
- '$allowgid' => json_encode($allow_gid),
- '$denycid' => json_encode($deny_cid),
- '$denygid' => json_encode($deny_gid),
- '$jnetModalTitle' => t('Other networks and post services'),
- '$jotnets' => $jotnets,
- '$aclModalTitle' => t('Permissions'),
+ '$showall' => $showall,
+ '$show' => t("Show"),
+ '$hide' => t("Don't show"),
+ '$allowcid' => json_encode($allow_cid),
+ '$allowgid' => json_encode($allow_gid),
+ '$denycid' => json_encode($deny_cid),
+ '$denygid' => json_encode($deny_gid),
+ '$jnetModalTitle' => t('Other networks and post services'),
+ '$jotnets' => $jotnets,
+ '$aclModalTitle' => t('Permissions'),
'$aclModalDismiss' => t('Close')
));
diff --git a/include/api.php b/include/api.php
index 5053977c5..e78e6cc37 100644
--- a/include/api.php
+++ b/include/api.php
@@ -2106,10 +2106,10 @@ require_once('include/api_auth.php');
'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl,
'shorturllength' => '30',
'hubzilla' => array(
- 'PLATFORM_NAME' => PLATFORM_NAME,
- 'RED_VERSION' => RED_VERSION,
+ 'PLATFORM_NAME' => Zotlabs\Project\System::get_platform_name(),
+ 'RED_VERSION' => Zotlabs\Project\System::get_project_version(),
'ZOT_REVISION' => ZOT_REVISION,
- 'DB_UPDATE_VERSION' => DB_UPDATE_VERSION
+ 'DB_UPDATE_VERSION' => Zotlabs\Project\System::get_update_version()
)
));
@@ -2142,12 +2142,12 @@ require_once('include/api_auth.php');
if($type === 'xml') {
header("Content-type: application/xml");
- echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<version>' . RED_VERSION . '</version>' . "\r\n";
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<version>' . Zotlabs\Project\System::get_project_version() . '</version>' . "\r\n";
killme();
}
elseif($type === 'json') {
header("Content-type: application/json");
- echo '"' . RED_VERSION . '"';
+ echo '"' . Zotlabs\Project\System::get_project_version() . '"';
killme();
}
}
diff --git a/include/attach.php b/include/attach.php
index 8595d5d86..2777b5813 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -13,6 +13,7 @@
require_once('include/permissions.php');
require_once('include/security.php');
+require_once('include/group.php');
/**
* @brief Guess the mimetype from file ending.
@@ -1242,7 +1243,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
$channel_address = (($c) ? $c[0]['channel_address'] : 'notfound');
$photo_sql = (($is_photo) ? " and is_photo = 1 " : '');
- $r = q("SELECT hash, flags, is_dir, is_photo, folder FROM attach WHERE hash = '%s' AND uid = %d $photo_sql limit 1",
+ $r = q("SELECT hash, os_storage, flags, is_dir, is_photo, folder FROM attach WHERE hash = '%s' AND uid = %d $photo_sql limit 1",
dbesc($resource),
intval($channel_id)
);
@@ -1313,7 +1314,9 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
intval($channel_id)
);
- file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', $notify=0);
+ file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', $notify=1);
+
+ return;
}
/**
@@ -1468,7 +1471,7 @@ function pipe_streams($in, $out) {
* @param string $deny_cid
* @param string $deny_gid
* @param string $verb
- * @param boolean $no_activity
+ * @param boolean $notify
*/
function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $verb, $notify) {
@@ -1514,13 +1517,21 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
$mid = item_message_id();
- $arr = array();
+ $objtype = ACTIVITY_OBJ_FILE;
+ $arr = array();
+ $arr['aid'] = get_account_id();
+ $arr['uid'] = $channel_id;
$arr['item_wall'] = 1;
$arr['item_origin'] = 1;
$arr['item_unseen'] = 1;
-
- $objtype = ACTIVITY_OBJ_FILE;
+ $arr['author_xchan'] = $poster['xchan_hash'];
+ $arr['owner_xchan'] = $poster['xchan_hash'];
+ $arr['title'] = '';
+ $arr['item_hidden'] = 1;
+ $arr['obj_type'] = $objtype;
+ $arr['resource_id'] = $object['hash'];
+ $arr['resource_type'] = 'attach';
$private = (($arr_allow_cid[0] || $arr_allow_gid[0] || $arr_deny_cid[0] || $arr_deny_gid[0]) ? 1 : 0);
@@ -1548,36 +1559,27 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
}
+ //send update activity and create a new one
if($update && $verb == 'post' ) {
- //send update activity and create a new one
-
//updates should be sent to everybody with recursive perms and all eventual former allowed members ($object['allow_cid'] etc.).
$u_arr_allow_cid = array_unique(array_merge($arr_allow_cid, expand_acl($object['allow_cid'])));
$u_arr_allow_gid = array_unique(array_merge($arr_allow_gid, expand_acl($object['allow_gid'])));
$u_arr_deny_cid = array_unique(array_merge($arr_deny_cid, expand_acl($object['deny_cid'])));
$u_arr_deny_gid = array_unique(array_merge($arr_deny_gid, expand_acl($object['deny_gid'])));
+ $private = (($u_arr_allow_cid[0] || $u_arr_allow_gid[0] || $u_arr_deny_cid[0] || $u_arr_deny_gid[0]) ? 1 : 0);
+
$u_mid = item_message_id();
- $arr['aid'] = get_account_id();
- $arr['uid'] = $channel_id;
$arr['mid'] = $u_mid;
$arr['parent_mid'] = $u_mid;
- $arr['author_xchan'] = $poster['xchan_hash'];
- $arr['owner_xchan'] = $poster['xchan_hash'];
- $arr['title'] = '';
- //updates should be visible to everybody -> perms may have changed
- $arr['allow_cid'] = '';
- $arr['allow_gid'] = '';
- $arr['deny_cid'] = '';
- $arr['deny_gid'] = '';
- $arr['item_hidden'] = 1;
- $arr['item_private'] = 0;
+ $arr['allow_cid'] = perms2str($u_arr_allow_cid);
+ $arr['allow_gid'] = perms2str($u_arr_allow_gid);
+ $arr['deny_cid'] = perms2str($u_arr_deny_cid);
+ $arr['deny_gid'] = perms2str($u_arr_deny_gid);
+ $arr['item_private'] = $private;
$arr['verb'] = ACTIVITY_UPDATE;
- $arr['obj_type'] = $objtype;
$arr['object'] = $u_jsonobject;
- $arr['resource_id'] = $object['hash'];
- $arr['resource_type'] = 'attach';
$arr['body'] = '';
$post = item_store($arr);
@@ -1593,32 +1595,25 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
//notice( t('File activity updated') . EOL);
}
+ //don't create new activity if notify was not enabled
if(! $notify) {
return;
}
- $arr = array();
+ //don't create new activity if we have an update request but there is no item to update
+ //this can e.g. happen when deleting images
+ if(! $y && $verb == 'update') {
+ return;
+ }
- $arr['aid'] = get_account_id();
- $arr['uid'] = $channel_id;
$arr['mid'] = $mid;
$arr['parent_mid'] = $mid;
- $arr['item_wall'] = 1;
- $arr['item_origin'] = 1;
- $arr['item_unseen'] = 1;
- $arr['author_xchan'] = $poster['xchan_hash'];
- $arr['owner_xchan'] = $poster['xchan_hash'];
- $arr['title'] = '';
$arr['allow_cid'] = perms2str($arr_allow_cid);
$arr['allow_gid'] = perms2str($arr_allow_gid);
$arr['deny_cid'] = perms2str($arr_deny_cid);
$arr['deny_gid'] = perms2str($arr_deny_gid);
- $arr['item_hidden'] = 1;
$arr['item_private'] = $private;
$arr['verb'] = (($update) ? ACTIVITY_UPDATE : ACTIVITY_POST);
- $arr['obj_type'] = $objtype;
- $arr['resource_id'] = $object['hash'];
- $arr['resource_type'] = 'attach';
$arr['object'] = (($update) ? $u_jsonobject : $jsonobject);
$arr['body'] = '';
@@ -1705,7 +1700,7 @@ function recursive_activity_recipients($arr_allow_cid, $arr_allow_gid, $arr_deny
//turn allow_gid into allow_cid's
foreach($arr_allow_gid as $gid) {
- $in_group = in_group($gid);
+ $in_group = group_get_members($gid);
$arr_allow_cid = array_unique(array_merge($arr_allow_cid, $in_group));
}
@@ -1727,7 +1722,7 @@ function recursive_activity_recipients($arr_allow_cid, $arr_allow_gid, $arr_deny
* */
if($parent_arr['allow_gid']) {
foreach($parent_arr['allow_gid'][$count] as $gid) {
- $in_group = in_group($gid);
+ $in_group = group_get_members($gid);
$parent_arr['allow_cid'][$count] = array_unique(array_merge($parent_arr['allow_cid'][$count], $in_group));
}
}
@@ -1808,31 +1803,6 @@ function recursive_activity_recipients($arr_allow_cid, $arr_allow_gid, $arr_deny
return $ret;
}
-/**
- * @brief Returns members of a group.
- *
- * @param int $group_id id of the group to look up
- */
-function in_group($group_id) {
- $group_members = array();
-
- /** @TODO make these two queries one with a join. */
- $x = q("SELECT id FROM groups WHERE hash = '%s'",
- dbesc($group_id)
- );
-
- $r = q("SELECT xchan FROM group_member WHERE gid = %d",
- intval($x[0]['id'])
- );
-
- foreach($r as $ig) {
- $group_members[] = $ig['xchan'];
- }
-
- return $group_members;
-}
-
-
function filepath_macro($s) {
return str_replace(
diff --git a/include/bbcode.php b/include/bbcode.php
index a8372d728..477436475 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -684,7 +684,11 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
}
// Check for centered text
if (strpos($Text,'[/center]') !== false) {
- $Text = preg_replace("(\[center\](.*?)\[\/center\])ism", "<div style=\"text-align:center;\">$1</div>", $Text);
+ $Text = preg_replace("(\[center\](.*?)\[\/center\])ism", "<div style=\"text-align:center;\">$1</div>", $Text);
+ }
+ // Check for footer
+ if (strpos($Text,'[/footer]') !== false) {
+ $Text = preg_replace("(\[footer\](.*?)\[\/footer\])ism", "<div class=\"wall-item-footer\">$1</div>", $Text);
}
// Check for list text
$Text = str_replace("[*]", "<li>", $Text);
diff --git a/include/cli_startup.php b/include/cli_startup.php
index 027d62953..70ab1a24a 100644
--- a/include/cli_startup.php
+++ b/include/cli_startup.php
@@ -15,6 +15,9 @@ function cli_startup() {
if(is_null($db)) {
@include(".htconfig.php");
+ if(! defined('UNO'))
+ define('UNO', 0);
+
$a->timezone = ((x($default_timezone)) ? $default_timezone : 'UTC');
date_default_timezone_set($a->timezone);
diff --git a/include/comanche.php b/include/comanche.php
index 1537226ca..ddf331321 100644
--- a/include/comanche.php
+++ b/include/comanche.php
@@ -275,6 +275,7 @@ function comanche_widget($name, $text) {
$vars = array();
$matches = array();
+
$cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $text, $matches, PREG_SET_ORDER);
if ($cnt) {
foreach ($matches as $mtch) {
@@ -287,8 +288,7 @@ function comanche_widget($name, $text) {
if(! function_exists($func)) {
if(file_exists('widget/' . trim($name) . '.php'))
require_once('widget/' . trim($name) . '.php');
- elseif(folder_exists('widget/'. trim($name))
- && (file_exists('widget/' . trim($name) . '/' . trim($name) . '.php')))
+ elseif(file_exists('widget/' . trim($name) . '/' . trim($name) . '.php'))
require_once('widget/' . trim($name) . '/' . trim($name) . '.php');
}
else {
diff --git a/include/config.php b/include/config.php
index c94d25eb8..51d4e99ac 100644
--- a/include/config.php
+++ b/include/config.php
@@ -531,3 +531,86 @@ function del_xconfig($xchan, $family, $key) {
);
return $ret;
}
+
+
+// account configuration storage is built on top of the under-utilised xconfig
+
+function load_aconfig($account_id) {
+ load_xconfig('a_' . $account_id);
+}
+
+function get_aconfig($account_id, $family, $key) {
+ return get_xconfig('a_' . $account_id, $family, $key);
+}
+
+function set_aconfig($account_id, $family, $key, $value) {
+ return set_xconfig('a_' . $account_id, $family, $key, $value);
+}
+
+function del_aconfig($account_id, $family, $key) {
+ return del_xconfig('a_' . $account_id, $family, $key);
+}
+
+
+function load_abconfig($chash,$xhash) {
+ $r = q("select * from abconfig where chan = '%s' and xchan = '%s'",
+ dbesc($chash),
+ dbesc($xhash)
+ );
+ return $r;
+}
+
+function get_abconfig($chash,$xhash,$family,$key) {
+ $r = q("select * from abconfig where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' limit 1",
+ dbesc($chash),
+ dbesc($xhash),
+ dbesc($family),
+ dbesc($key)
+ );
+ if($r) {
+ return ((preg_match('|^a:[0-9]+:{.*}$|s', $r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
+ }
+ return false;
+}
+
+
+function set_abconfig($chash,$xhash,$family,$key,$value) {
+
+ $dbvalue = ((is_array($value)) ? serialize($value) : $value);
+ $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
+
+ if(get_abconfig($chash,$xhash,$family,$key) === false) {
+ $r = q("insert into abconfig ( chan, xchan, cat, k, v ) values ( '%s', '%s', '%s', '%s', '%s' ) ",
+ dbesc($chash),
+ dbesc($xhash),
+ dbesc($family),
+ dbesc($key),
+ dbesc($dbvalue)
+ );
+ }
+ else {
+ $r = q("update abconfig set v = '%s' where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' ",
+ dbesc($dbvalue),
+ dbesc($chash),
+ dbesc($xhash),
+ dbesc($family),
+ dbesc($key)
+ );
+ }
+ if($r)
+ return $value;
+ return false;
+}
+
+
+function del_abconfig($chash,$xhash,$family,$key) {
+
+ $r = q("delete from abconfig where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' ",
+ dbesc($chash),
+ dbesc($xhash),
+ dbesc($family),
+ dbesc($key)
+ );
+
+ return $r;
+}
diff --git a/include/contact_selectors.php b/include/contact_selectors.php
index 8671f1bd1..d44bee784 100644
--- a/include/contact_selectors.php
+++ b/include/contact_selectors.php
@@ -79,7 +79,7 @@ function network_to_name($s) {
NETWORK_MAIL => t('Email'),
NETWORK_DIASPORA => t('Diaspora'),
NETWORK_FACEBOOK => t('Facebook'),
- NETWORK_ZOT => t('Zot!'),
+ NETWORK_ZOT => t('Zot'),
NETWORK_LINKEDIN => t('LinkedIn'),
NETWORK_XMPP => t('XMPP/IM'),
NETWORK_MYSPACE => t('MySpace'),
diff --git a/include/conversation.php b/include/conversation.php
index 747bb5d0a..39119b2bb 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -942,25 +942,35 @@ function item_photo_menu($item){
$clean_url = normalise_link($item['author-link']);
}
- $menu = Array(
+ $poco_rating = get_config('system','poco_rating_enable');
+ // if unset default to enabled
+ if($poco_rating === false)
+ $poco_rating = true;
+
+ $ratings_url = (($poco_rating) ? z_root() . '/ratings/' . urlencode($item['author_xchan']) : '');
+
+ $post_menu = Array(
t("View Source") => $vsrc_link,
t("Follow Thread") => $sub_link,
t("Unfollow Thread") => $unsub_link,
- t("View Status") => $status_link,
+ );
+
+ $author_menu = array(
t("View Profile") => $profile_link,
- t("View Photos") => $photos_link,
t("Activity/Posts") => $posts_link,
t("Connect") => $follow_url,
t("Edit Connection") => $contact_url,
- t("Send PM") => $pm_url,
+ t("Message") => $pm_url,
+ t('Ratings') => $ratings_url,
t("Poke") => $poke_link
);
- $args = array('item' => $item, 'menu' => $menu);
+
+ $args = array('item' => $item, 'post_menu' => $post_menu, 'author_menu' => $author_menu);
call_hooks('item_photo_menu', $args);
- $menu = $args['menu'];
+ $menu = array_merge($args['post_menu'],$args['author_menu']);
$o = "";
foreach($menu as $k=>$v){
@@ -1585,8 +1595,17 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
if (is_null($nickname))
$nickname = $channel['channel_address'];
+
$uid = (($a->profile['profile_uid']) ? $a->profile['profile_uid'] : local_channel());
+ if($uid == local_channel()) {
+ $cal_link = '';
+ }
+ else {
+ $cal_link = '/cal/' . $nickname;
+ }
+
+
if (get_pconfig($uid, 'system', 'noprofiletabs'))
return;
@@ -1634,6 +1653,17 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
);
}
+ if($p['view_stream'] && $cal_link) {
+ $tabs[] = array(
+ 'label' => t('Events'),
+ 'url' => $a->get_baseurl() . $cal_link,
+ 'sel' => ((argv(0) == 'cal' || argv(0) == 'events') ? 'active' : ''),
+ 'title' => t('Events'),
+ 'id' => 'event-tab',
+ );
+ }
+
+
if ($p['chat']) {
require_once('include/chat.php');
$has_chats = chatroom_list_count($uid);
diff --git a/include/crypto.php b/include/crypto.php
index 494a2a5b9..94a6b4a58 100644
--- a/include/crypto.php
+++ b/include/crypto.php
@@ -20,7 +20,22 @@ function rsa_verify($data,$sig,$key,$alg = 'sha256') {
if(intval(OPENSSL_ALGO_SHA256) && $alg === 'sha256')
$alg = OPENSSL_ALGO_SHA256;
- $verify = openssl_verify($data,$sig,$key,$alg);
+ $verify = @openssl_verify($data,$sig,$key,$alg);
+
+ if(! $verify) {
+ logger('openssl_verify: ' . openssl_error_string(),LOGGER_NORMAL,LOG_ERR);
+ logger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR);
+ // provide a backtrace so that we can debug key issues
+ if(version_compare(PHP_VERSION, '5.4.0') >= 0) {
+ $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ if($stack) {
+ foreach($stack as $s) {
+ logger('stack: ' . basename($s['file']) . ':' . $s['line'] . ':' . $s['function'] . '()',LOGGER_DEBUG,LOG_ERR);
+ }
+ }
+ }
+ }
+
return $verify;
}
diff --git a/include/datetime.php b/include/datetime.php
index 1d10e7ad7..57b2b6d37 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -129,7 +129,7 @@ function dob($dob) {
else
$value = (($year) ? datetime_convert('UTC','UTC',$dob,'Y-m-d') : datetime_convert('UTC','UTC',$dob,'m-d'));
- $o = '<input type="text" name="dob" value="' . $value . '" placeholder="' . t('YYYY-MM-DD or MM-DD') . '" />';
+ $o = '<input class="form-control" type="text" name="dob" value="' . $value . '" placeholder="' . t('YYYY-MM-DD or MM-DD') . '" />';
// if ($dob && $dob != '0000-00-00')
// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob');
@@ -269,15 +269,16 @@ function relative_date($posted_date, $format = null) {
return t('less than a second ago');
}
- $a = array( 12 * 30 * 24 * 60 * 60 => array( t('year'), t('years')),
- 30 * 24 * 60 * 60 => array( t('month'), t('months')),
- 7 * 24 * 60 * 60 => array( t('week'), t('weeks')),
- 24 * 60 * 60 => array( t('day'), t('days')),
- 60 * 60 => array( t('hour'), t('hours')),
- 60 => array( t('minute'), t('minutes')),
- 1 => array( t('second'), t('seconds'))
+ $a = array( 12 * 30 * 24 * 60 * 60 => 'y',
+ 30 * 24 * 60 * 60 => 'm',
+ 7 * 24 * 60 * 60 => 'w',
+ 24 * 60 * 60 => 'd',
+ 60 * 60 => 'h',
+ 60 => 'i',
+ 1 => 's'
);
+
foreach ($a as $secs => $str) {
$d = $etime / $secs;
if ($d >= 1) {
@@ -285,11 +286,43 @@ function relative_date($posted_date, $format = null) {
if (! $format)
$format = t('%1$d %2$s ago', 'e.g. 22 hours ago, 1 minute ago');
- return sprintf($format, $r, (($r == 1) ? $str[0] : $str[1]));
+ return sprintf($format, $r, plural_dates($str,$r));
}
}
}
+function plural_dates($k,$n) {
+
+ switch($k) {
+ case 'y':
+ return tt('year','years',$n,'relative_date');
+ break;
+ case 'm':
+ return tt('month','months',$n,'relative_date');
+ break;
+ case 'w':
+ return tt('week','weeks',$n,'relative_date');
+ break;
+ case 'd':
+ return tt('day','days',$n,'relative_date');
+ break;
+ case 'h':
+ return tt('hour','hours',$n,'relative_date');
+ break;
+ case 'i':
+ return tt('minute','minutes',$n,'relative_date');
+ break;
+ case 's':
+ return tt('second','seconds',$n,'relative_date');
+ break;
+ default:
+ return;
+ }
+}
+
+
+
+
/**
* @brief Returns timezone correct age in years.
*
@@ -516,7 +549,7 @@ function update_birthdays() {
$ev['event_xchan'] = $rr['xchan_hash'];
$ev['start'] = datetime_convert('UTC', 'UTC', $rr['abook_dob']);
$ev['finish'] = datetime_convert('UTC', 'UTC', $rr['abook_dob'] . ' + 1 day ');
- $ev['adjust'] = 1;
+ $ev['adjust'] = intval(feature_enabled($rr['abook_channel'],'smart_birthdays'));
$ev['summary'] = sprintf( t('%1$s\'s birthday'), $rr['xchan_name']);
$ev['description'] = sprintf( t('Happy Birthday %1$s'),
'[zrl=' . $rr['xchan_url'] . ']' . $rr['xchan_name'] . '[/zrl]') ;
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index 1fb3d5c00..3c5b0b67e 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -303,9 +303,9 @@ function q($sql) {
if($stmt === false) {
if(version_compare(PHP_VERSION, '5.4.0') >= 0)
logger('dba: vsprintf error: ' .
- print_r(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1), true));
+ print_r(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1), true),LOGGER_NORMAL,LOG_CRIT);
else
- logger('dba: vsprintf error: ' . print_r(debug_backtrace(), true));
+ logger('dba: vsprintf error: ' . print_r(debug_backtrace(), true),LOGGER_NORMAL,LOG_CRIT);
}
return $db->q($stmt);
}
@@ -314,7 +314,7 @@ function q($sql) {
* This will happen occasionally trying to store the
* session data after abnormal program termination
*/
- logger('dba: no database: ' . print_r($args,true));
+ logger('dba: no database: ' . print_r($args,true),LOGGER_NORMAL,LOG_CRIT);
return false;
}
@@ -385,6 +385,7 @@ function db_getfunc($f) {
if(isset($lookup[$f]) && isset($lookup[$f][ACTIVE_DBTYPE]))
return $lookup[$f][ACTIVE_DBTYPE];
- logger('Unable to abstract DB function "'. $f . '" for dbtype ' . ACTIVE_DBTYPE, LOGGER_DEBUG);
+ logger('Unable to abstract DB function "'. $f . '" for dbtype ' . ACTIVE_DBTYPE, LOGGER_DEBUG, LOG_ERR);
return $f;
}
+
diff --git a/include/dba/dba_mysqli.php b/include/dba/dba_mysqli.php
index 74a999974..6986d4586 100755
--- a/include/dba/dba_mysqli.php
+++ b/include/dba/dba_mysqli.php
@@ -32,7 +32,7 @@ class dba_mysqli extends dba_driver {
if($this->error) {
- logger('dba_mysqli: ERROR: ' . printable($sql) . "\n" . $this->error);
+ logger('dba_mysqli: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR);
if(file_exists('dbfail.out')) {
file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . "\n" . $this->error . "\n", FILE_APPEND);
}
@@ -40,13 +40,13 @@ class dba_mysqli extends dba_driver {
if(($result === true) || ($result === false)) {
if($this->debug) {
- logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'));
+ logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'), LOGGER_NORMAL,(($result) ? LOG_INFO : LOG_ERR));
}
return $result;
}
if($this->debug) {
- logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returned ' . $result->num_rows . ' results.');
+ logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returned ' . $result->num_rows . ' results.', LOGGER_NORMAL, LOG_INFO);
}
$r = array();
@@ -55,7 +55,7 @@ class dba_mysqli extends dba_driver {
$r[] = $x;
$result->free_result();
if($this->debug) {
- logger('dba_mysqli: ' . printable(print_r($r,true)));
+ logger('dba_mysqli: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO);
}
}
return $r;
diff --git a/include/deliver.php b/include/deliver.php
index 7ff0fa125..40df543d5 100644
--- a/include/deliver.php
+++ b/include/deliver.php
@@ -31,6 +31,7 @@ function deliver_run($argv, $argc) {
if(($r[0]['outq_posturl'] === z_root() . '/post') && ($r[0]['outq_msg'])) {
logger('deliver: local delivery', LOGGER_DEBUG);
+
// local delivery
// we should probably batch these and save a few delivery processes
@@ -72,7 +73,7 @@ function deliver_run($argv, $argc) {
}
}
- // otherwise it's a remote delivery - call queue_deliver();
+ // otherwise it's a remote delivery - call queue_deliver() with the $immediate flag
queue_deliver($r[0],true);
diff --git a/include/enotify.php b/include/enotify.php
index c9b6e0463..e182377c0 100644
--- a/include/enotify.php
+++ b/include/enotify.php
@@ -273,14 +273,14 @@ function notification($params) {
$preamble = sprintf( t('%1$s, you\'ve received an new connection request from \'%2$s\' at %3$s'), $recip['channel_name'], $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s, you\'ve received [zrl=%2$s]a new connection request[/zrl] from %3$s.'),
$recip['channel_name'],
- $itemlink,
+ $siteurl . '/connections/ifpending',
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]');
$body = sprintf( t('You may visit their profile at %s'),$sender['xchan_url']);
$sitelink = t('Please visit %s to approve or reject the connection request.');
- $tsitelink = sprintf( $sitelink, $siteurl );
- $hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
- $itemlink = $params['link'];
+ $tsitelink = sprintf( $sitelink, $siteurl . '/connections/ifpending');
+ $hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/connections/ifpending">' . $sitename . '</a>');
+ $itemlink = $params['link'];
}
if ($params['type'] == NOTIFY_SUGGEST) {
@@ -529,6 +529,7 @@ function notification($params) {
$tpl = get_markup_template('email_notify_html.tpl');
$email_html_body = replace_macros($tpl,array(
'$banner' => $datarray['banner'],
+ '$notify_icon' => Zotlabs\Project\System::get_notify_icon(),
'$product' => $datarray['product'],
'$preamble' => $datarray['preamble'],
'$sitename' => $datarray['sitename'],
diff --git a/include/event.php b/include/event.php
index 539bfe484..2969f4f61 100644
--- a/include/event.php
+++ b/include/event.php
@@ -67,7 +67,7 @@ function ical_wrapper($ev) {
$o .= "BEGIN:VCALENDAR";
$o .= "\r\nVERSION:2.0";
$o .= "\r\nMETHOD:PUBLISH";
- $o .= "\r\nPRODID:-//" . get_config('system','sitename') . "//" . PLATFORM_NAME . "//" . strtoupper(get_app()->language). "\r\n";
+ $o .= "\r\nPRODID:-//" . get_config('system','sitename') . "//" . Zotlabs\Project\System::get_platform_name() . "//" . strtoupper(get_app()->language). "\r\n";
if(array_key_exists('start', $ev))
$o .= format_event_ical($ev);
else {
@@ -440,6 +440,17 @@ function event_addtocal($item_id, $uid) {
$ev['event_hash'] = $item['resource_id'];
}
+ if($ev->private)
+ $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
+ else {
+ $acl = new Zotlabs\Access\AccessList($channel);
+ $x = $acl->get();
+ $ev['allow_cid'] = $x['allow_cid'];
+ $ev['allow_gid'] = $x['allow_gid'];
+ $ev['deny_cid'] = $x['deny_cid'];
+ $ev['deny_gid'] = $x['deny_gid'];
+ }
+
$event = event_store_event($ev);
if($event) {
$r = q("update item set resource_id = '%s', resource_type = 'event' where id = %d and uid = %d",
diff --git a/include/features.php b/include/features.php
index 4e962b00e..ff6b71d4c 100644
--- a/include/features.php
+++ b/include/features.php
@@ -5,12 +5,19 @@
*/
+
+
+
function feature_enabled($uid,$feature) {
- $x = get_pconfig($uid,'feature',$feature);
+
+ $x = get_config('feature_lock',$feature);
if($x === false) {
- $x = get_config('feature',$feature);
- if($x === false)
- $x = get_feature_default($feature);
+ $x = get_pconfig($uid,'feature',$feature);
+ if($x === false) {
+ $x = get_config('feature',$feature);
+ if($x === false)
+ $x = get_feature_default($feature);
+ }
}
$arr = array('uid' => $uid, 'feature' => $feature, 'enabled' => $x);
call_hooks('feature_enabled',$arr);
@@ -18,7 +25,7 @@ function feature_enabled($uid,$feature) {
}
function get_feature_default($feature) {
- $f = get_features();
+ $f = get_features(false);
foreach($f as $cat) {
foreach($cat as $feat) {
if(is_array($feat) && $feat[0] === $feature)
@@ -29,66 +36,92 @@ function get_feature_default($feature) {
}
-function get_features() {
+function get_features($filtered = true) {
+
+ if(UNO && $filtered)
+ return array();
$arr = array(
// General
'general' => array(
t('General Features'),
-// This is per post, and different from fixed expiration 'expire' which isn't working yet
- array('content_expire', t('Content Expiration'), t('Remove posts/comments and/or private messages at a future time'), false),
- array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles'), false),
- array('advanced_profiles', t('Advanced Profiles'), t('Additional profile sections and selections'),false),
- array('profile_export', t('Profile Import/Export'), t('Save and load profile details across sites/channels'),false),
- array('webpages', t('Web Pages'), t('Provide managed web pages on your channel'),false),
- array('private_notes', t('Private Notes'), t('Enables a tool to store notes and reminders'),false),
- array('nav_channel_select', t('Navigation Channel Select'), t('Change channels directly from within the navigation dropdown menu'),false),
- array('photo_location', t('Photo Location'), t('If location data is available on uploaded photos, link this to a map.'),false),
-
- array('expert', t('Expert Mode'), t('Enable Expert Mode to provide advanced configuration options'),false),
- array('premium_channel', t('Premium Channel'), t('Allows you to set restrictions and terms on those that connect with your channel'),false),
+ // This is per post, and different from fixed expiration 'expire' which isn't working yet
+ array('content_expire', t('Content Expiration'), t('Remove posts/comments and/or private messages at a future time'), false, get_config('feature_lock','content_expire')),
+ array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles'), false, get_config('feature_lock','multi_profiles')),
+ array('advanced_profiles', t('Advanced Profiles'), t('Additional profile sections and selections'),false,get_config('feature_lock','advanced_profiles')),
+ array('profile_export', t('Profile Import/Export'), t('Save and load profile details across sites/channels'),false,get_config('feature_lock','profile_export')),
+ array('webpages', t('Web Pages'), t('Provide managed web pages on your channel'),false,get_config('feature_lock','webpages')),
+ array('hide_rating', t('Hide Rating'), t('Hide the rating buttons on your channel and profile pages. Note: People can still rate you somewhere else.'),false,get_config('feature_lock','hide_rating')),
+ array('private_notes', t('Private Notes'), t('Enables a tool to store notes and reminders (note: not encrypted)'),false,get_config('feature_lock','private_notes')),
+ array('nav_channel_select', t('Navigation Channel Select'), t('Change channels directly from within the navigation dropdown menu'),false,get_config('feature_lock','nav_channel_select')),
+ array('photo_location', t('Photo Location'), t('If location data is available on uploaded photos, link this to a map.'),false,get_config('feature_lock','photo_location')),
+
+ array('smart_birthdays', t('Smart Birthdays'), t('Make birthday events timezone aware in case your friends are scattered across the planet.'),true,get_config('feature_lock','smart_birthdays')),
+ array('expert', t('Expert Mode'), t('Enable Expert Mode to provide advanced configuration options'),false,get_config('feature_lock','expert')),
+ array('premium_channel', t('Premium Channel'), t('Allows you to set restrictions and terms on those that connect with your channel'),false,get_config('feature_lock','premium_channel')),
),
// Post composition
'composition' => array(
t('Post Composition Features'),
-// array('richtext', t('Richtext Editor'), t('Enable richtext editor'),false),
- array('markdown', t('Use Markdown'), t('Allow use of "Markdown" to format posts'),false),
- array('large_photos', t('Large Photos'), t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),false),
- array('channel_sources', t('Channel Sources'), t('Automatically import channel content from other channels or feeds'),false),
- array('content_encrypt', t('Even More Encryption'), t('Allow optional encryption of content end-to-end with a shared secret key'),false),
- array('consensus_tools', t('Enable Voting Tools'), t('Provide a class of post which others can vote on'),false),
- array('delayed_posting', t('Delayed Posting'), t('Allow posts to be published at a later date'),false),
- array('suppress_duplicates', t('Suppress Duplicate Posts/Comments'), t('Prevent posts with identical content to be published with less than two minutes in between submissions.'),true),
+// array('richtext', t('Richtext Editor'), t('Enable richtext editor'),falseget_config('feature_lock','richtext')),
+// array('markdown', t('Use Markdown'), t('Allow use of "Markdown" to format posts'),false,get_config('feature_lock','markdown')),
+ array('large_photos', t('Large Photos'), t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),false,get_config('feature_lock','large_photos')),
+ array('channel_sources', t('Channel Sources'), t('Automatically import channel content from other channels or feeds'),false,get_config('feature_lock','channel_sources')),
+ array('content_encrypt', t('Even More Encryption'), t('Allow optional encryption of content end-to-end with a shared secret key'),false,get_config('feature_lock','content_encrypt')),
+ array('consensus_tools', t('Enable Voting Tools'), t('Provide a class of post which others can vote on'),false,get_config('feature_lock','consensus_tools')),
+ array('delayed_posting', t('Delayed Posting'), t('Allow posts to be published at a later date'),false,get_config('feature_lock','delayed_posting')),
+ array('suppress_duplicates', t('Suppress Duplicate Posts/Comments'), t('Prevent posts with identical content to be published with less than two minutes in between submissions.'),true,get_config('feature_lock','suppress_duplicates')),
),
// Network Tools
'net_module' => array(
t('Network and Stream Filtering'),
- array('archives', t('Search by Date'), t('Ability to select posts by date ranges'),false),
- array('groups', t('Collections Filter'), t('Enable widget to display Network posts only from selected collections'),false),
- array('savedsearch', t('Saved Searches'), t('Save search terms for re-use'),false),
- array('personal_tab', t('Network Personal Tab'), t('Enable tab to display only Network posts that you\'ve interacted on'),false),
- array('new_tab', t('Network New Tab'), t('Enable tab to display all new Network activity'),false),
- array('affinity', t('Affinity Tool'), t('Filter stream activity by depth of relationships'),false),
- array('connfilter', t('Connection Filtering'), t('Filter incoming posts from connections based on keywords/content')),
- array('suggest', t('Suggest Channels'), t('Show channel suggestions'),false),
+ array('archives', t('Search by Date'), t('Ability to select posts by date ranges'),false,get_config('feature_lock','archives')),
+ array('groups', t('Privacy Groups'), t('Enable management and selection of privacy groups'),true,get_config('feature_lock','groups')),
+ array('savedsearch', t('Saved Searches'), t('Save search terms for re-use'),false,get_config('feature_lock','savedsearch')),
+ array('personal_tab', t('Network Personal Tab'), t('Enable tab to display only Network posts that you\'ve interacted on'),false,get_config('feature_lock','personal_tab')),
+ array('new_tab', t('Network New Tab'), t('Enable tab to display all new Network activity'),false,get_config('feature_lock','new_tab')),
+ array('affinity', t('Affinity Tool'), t('Filter stream activity by depth of relationships'),false,get_config('feature_lock','affinity')),
+ array('connfilter', t('Connection Filtering'), t('Filter incoming posts from connections based on keywords/content'),false,get_config('feature_lock','connfilter')),
+ array('suggest', t('Suggest Channels'), t('Show channel suggestions'),false,get_config('feature_lock','suggest')),
),
// Item tools
'tools' => array(
t('Post/Comment Tools'),
- array('commtag', t('Tagging'), t('Ability to tag existing posts'),false),
- array('categories', t('Post Categories'), t('Add categories to your posts'),false),
- array('filing', t('Saved Folders'), t('Ability to file posts under folders'),false),
- array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments'),false),
- array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator'),false),
- array('tagadelic', t('Tag Cloud'), t('Provide a personal tag cloud on your channel page'),false),
+ array('commtag', t('Community Tagging'), t('Ability to tag existing posts'),false,get_config('feature_lock','commtag')),
+ array('categories', t('Post Categories'), t('Add categories to your posts'),false,get_config('feature_lock','categories')),
+ array('filing', t('Saved Folders'), t('Ability to file posts under folders'),false,get_config('feature_lock','filing')),
+ array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments'),false,get_config('feature_lock','dislike')),
+ array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator'),false,get_config('feature_lock','star_posts')),
+ array('tagadelic', t('Tag Cloud'), t('Provide a personal tag cloud on your channel page'),false,get_config('feature_lock','tagedelic')),
),
);
+ // removed any locked features and remove the entire category if this makes it empty
+
+ if($filtered) {
+ foreach($arr as $k => $x) {
+ $has_items = false;
+ for($y = 0; $y < count($arr[$k]); $y ++) {
+ if(is_array($arr[$k][$y])) {
+ if($arr[$k][$y][4] === false) {
+ $has_items = true;
+ }
+ else {
+ unset($arr[$k][$y]);
+ }
+ }
+ }
+ if(! $has_items) {
+ unset($arr[$k]);
+ }
+ }
+ }
+
call_hooks('get_features',$arr);
return $arr;
}
diff --git a/include/follow.php b/include/follow.php
index 97be82da7..5e1146657 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -122,6 +122,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
else
$permissions = $j['permissions'];
+
foreach($permissions as $k => $v) {
if($v) {
$their_perms = $their_perms | intval($global_perms[$k][1]);
@@ -167,6 +168,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
}
}
+
if(! $xchan_hash) {
$result['message'] = t('Channel discovery failed.');
logger('follow: ' . $result['message']);
@@ -202,6 +204,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
$default_group = $r[0]['channel_default_group'];
}
+
if($is_http) {
@@ -226,6 +229,8 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
dbesc($xchan_hash),
intval($uid)
);
+
+
if($r) {
$abook_instance = $r[0]['abook_instance'];
@@ -242,7 +247,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
);
}
else {
-
$closeness = get_pconfig($uid,'system','new_abook_closeness');
if($closeness === false)
$closeness = 80;
@@ -270,6 +274,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
dbesc($xchan_hash),
intval($uid)
);
+
if($r) {
$result['abook'] = $r[0];
proc_run('php', 'include/notifier.php', 'permission_create', $result['abook']['abook_id']);
diff --git a/include/group.php b/include/group.php
index 0875b10f9..22f221059 100644
--- a/include/group.php
+++ b/include/group.php
@@ -200,7 +200,7 @@ function group_get_members($gid) {
if(intval($gid)) {
$r = q("SELECT * FROM `group_member`
LEFT JOIN abook ON abook_xchan = `group_member`.`xchan` left join xchan on xchan_hash = abook_xchan
- WHERE `gid` = %d AND abook_channel = %d and `group_member`.`uid` = %d and xchan_deleted = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
+ WHERE `gid` = %d AND abook_channel = %d and `group_member`.`uid` = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
intval($gid),
intval(local_channel()),
intval(local_channel())
@@ -229,7 +229,7 @@ function mini_group_select($uid,$group = '') {
logger('mini_group_select: ' . print_r($grps,true), LOGGER_DATA);
$o = replace_macros(get_markup_template('group_selection.tpl'), array(
- '$label' => t('Add new connections to this collection (privacy group)'),
+ '$label' => t('Add new connections to this privacy group'),
'$groups' => $grps
));
return $o;
@@ -292,10 +292,10 @@ function group_side($every="connections",$each="group",$edit = false, $group_id
$tpl = get_markup_template("group_side.tpl");
$o = replace_macros($tpl, array(
- '$title' => t('Collections'),
- '$edittext' => t('Edit collection'),
- '$createtext' => t('Add new collection'),
- '$ungrouped' => (($every === 'contacts') ? t('Channels not in any collection') : ''),
+ '$title' => t('Privacy Groups'),
+ '$edittext' => t('Edit group'),
+ '$createtext' => t('Add privacy group'),
+ '$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''),
'$groups' => $groups,
'$add' => t('add'),
));
diff --git a/include/identity.php b/include/identity.php
index 98ba26bd8..382b096fe 100644
--- a/include/identity.php
+++ b/include/identity.php
@@ -178,7 +178,7 @@ function create_identity($arr) {
$ret = array('success' => false);
if(! $arr['account_id']) {
- $ret['message'] = t('No account identifier');
+ $ret['message'] = t('No account identifier');
return $ret;
}
$ret = identity_check_service_class($arr['account_id']);
@@ -352,7 +352,7 @@ function create_identity($arr) {
);
if($role_permissions) {
- $myperms = ((array_key_exists('perms_auto',$role_permissions) && $role_permissions['perms_auto']) ? intval($role_permissions['perms_accept']) : 0);
+ $myperms = ((array_key_exists('perms_accept',$role_permissions)) ? intval($role_permissions['perms_accept']) : 0);
}
else
$myperms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK
@@ -482,7 +482,9 @@ function identity_basic_export($channel_id, $items = false) {
$ret = array();
- $ret['compatibility'] = array('project' => PLATFORM_NAME, 'version' => RED_VERSION, 'database' => DB_UPDATE_VERSION);
+ // use constants here as otherwise we will have no idea if we can import from a site
+ // with a non-standard platform and version.
+ $ret['compatibility'] = array('project' => PLATFORM_NAME, 'version' => RED_VERSION, 'database' => DB_UPDATE_VERSION, 'server_role' => Zotlabs\Project\System::get_server_role());
$r = q("select * from channel where channel_id = %d limit 1",
intval($channel_id)
@@ -503,8 +505,12 @@ function identity_basic_export($channel_id, $items = false) {
if($r) {
$ret['abook'] = $r;
- foreach($r as $rr)
- $xchans[] = $rr['abook_xchan'];
+ for($x = 0; $x < count($ret['abook']); $x ++) {
+ $xchans[] = $ret['abook'][$x]['abook_chan'];
+ $abconfig = load_abconfig($ret['channel']['channel_hash'],$ret['abook'][$x]['abook_xchan']);
+ if($abconfig)
+ $ret['abook'][$x]['abconfig'] = $abconfig;
+ }
stringify_array_elms($xchans);
}
@@ -898,6 +904,55 @@ function profile_load(&$a, $nickname, $profile = '') {
}
+function profile_edit_menu($uid) {
+
+ $a = get_app();
+ $ret = array();
+
+ $is_owner = (($uid == local_channel()) ? true : false);
+
+ // show edit profile to profile owner
+ if($is_owner) {
+ $ret['menu'] = array(
+ 'chg_photo' => t('Change profile photo'),
+ 'entries' => array(),
+ );
+
+ $multi_profiles = feature_enabled(local_channel(), 'multi_profiles');
+ if($multi_profiles) {
+ $ret['multi'] = 1;
+ $ret['edit'] = array($a->get_baseurl(). '/profiles', t('Edit Profiles'), '', t('Edit'));
+ $ret['menu']['cr_new'] = t('Create New Profile');
+ }
+ else {
+ $ret['edit'] = array($a->get_baseurl() . '/profiles/' . $uid, t('Edit Profile'), '', t('Edit'));
+ }
+
+ $r = q("SELECT * FROM profile WHERE uid = %d",
+ local_channel()
+ );
+
+ if($r) {
+ foreach($r as $rr) {
+ if(!($multi_profiles || $rr['is_default']))
+ continue;
+ $ret['menu']['entries'][] = array(
+ 'photo' => $rr['thumb'],
+ 'id' => $rr['id'],
+ 'alt' => t('Profile Image'),
+ 'profile_name' => $rr['profile_name'],
+ 'isdefault' => $rr['is_default'],
+ 'visible_to_everybody' => t('Visible to everybody'),
+ 'edit_visibility' => t('Edit visibility'),
+ );
+ }
+ }
+ }
+
+ return $ret;
+
+}
+
/**
* @brief Formats a profile for display in the sidebar.
*
@@ -911,7 +966,7 @@ function profile_load(&$a, $nickname, $profile = '') {
* @return HTML string suitable for sidebar inclusion
* Exceptions: Returns empty string if passed $profile is wrong type or not populated
*/
-function profile_sidebar($profile, $block = 0, $show_connect = true) {
+function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = false) {
$a = get_app();
@@ -922,17 +977,18 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) {
$pdesc = true;
$reddress = true;
+ if(! perm_is_allowed($profile['uid'],((is_array($observer)) ? $observer['xchan_hash'] : ''),'view_profile')) {
+ $block = true;
+ }
+
if((! is_array($profile)) && (! count($profile)))
return $o;
head_set_icon($profile['thumb']);
- $is_owner = (($profile['uid'] == local_channel()) ? true : false);
-
if(is_sys_channel($profile['uid']))
$show_connect = false;
-
$profile['picdate'] = urlencode($profile['picdate']);
call_hooks('profile_sidebar_enter', $profile);
@@ -954,42 +1010,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) {
$connect_url = z_root() . '/connect/' . $profile['channel_address'];
}
- // show edit profile to yourself
- if($is_owner) {
- $profile['menu'] = array(
- 'chg_photo' => t('Change profile photo'),
- 'entries' => array(),
- );
-
- $multi_profiles = feature_enabled(local_channel(), 'multi_profiles');
- if($multi_profiles) {
- $profile['edit'] = array($a->get_baseurl(). '/profiles', t('Profiles'),"", t('Manage/edit profiles'));
- $profile['menu']['cr_new'] = t('Create New Profile');
- }
- else
- $profile['edit'] = array($a->get_baseurl() . '/profiles/' . $profile['id'], t('Edit Profile'),'',t('Edit Profile'));
-
- $r = q("SELECT * FROM `profile` WHERE `uid` = %d",
- local_channel());
-
- if($r) {
- foreach($r as $rr) {
- if(!($multi_profiles || $rr['is_default']))
- continue;
- $profile['menu']['entries'][] = array(
- 'photo' => $rr['thumb'],
- 'id' => $rr['id'],
- 'alt' => t('Profile Image'),
- 'profile_name' => $rr['profile_name'],
- 'isdefault' => $rr['is_default'],
- 'visible_to_everybody' => t('visible to everybody'),
- 'edit_visibility' => t('Edit visibility'),
- );
- }
- }
- }
-
-
if((x($profile,'address') == 1)
|| (x($profile,'locality') == 1)
|| (x($profile,'region') == 1)
@@ -1006,9 +1026,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) {
// logger('online: ' . $profile['online']);
- if(! perm_is_allowed($profile['uid'],((is_array($observer)) ? $observer['xchan_hash'] : ''),'view_profile')) {
- $block = true;
- }
if(($profile['hidewall'] && (! local_channel()) && (! remote_channel())) || $block ) {
$location = $reddress = $pdesc = $gender = $marital = $homepage = False;
@@ -1046,12 +1063,18 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) {
$channel_menu .= comanche_block($menublock);
}
- $tpl = get_markup_template('profile_vcard.tpl');
+ if($zcard)
+ $tpl = get_markup_template('profile_vcard_short.tpl');
+ else
+ $tpl = get_markup_template('profile_vcard.tpl');
require_once('include/widgets.php');
- $z = widget_rating(array('target' => $profile['channel_hash']));
+
+ if(! feature_enabled($profile['uid'],'hide_rating'))
+ $z = widget_rating(array('target' => $profile['channel_hash']));
$o .= replace_macros($tpl, array(
+ '$zcard' => $zcard,
'$profile' => $profile,
'$connect' => $connect,
'$connect_url' => $connect_url,
@@ -1065,6 +1088,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) {
'$reddress' => $reddress,
'$rating' => $z,
'$contact_block' => $contact_block,
+ '$editmenu' => profile_edit_menu($profile['uid'])
));
$arr = array('profile' => &$profile, 'entry' => &$o);
@@ -1227,11 +1251,25 @@ function advanced_profile(&$a) {
if(! perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'view_profile'))
return '';
- $o = '';
+ if($a->profile['name']) {
+
+ $profile_fields_basic = get_profile_fields_basic();
+ $profile_fields_advanced = get_profile_fields_advanced();
+
+ $advanced = ((feature_enabled($a->profile['profile_uid'],'advanced_profiles')) ? true : false);
+ if($advanced)
+ $fields = $profile_fields_advanced;
+ else
+ $fields = $profile_fields_basic;
+
+ $clean_fields = array();
+ if($fields) {
+ foreach($fields as $k => $v) {
+ $clean_fields[] = trim($k);
+ }
+ }
- $o .= '<h2>' . t('Profile') . '</h2>';
- if($a->profile['name']) {
$tpl = get_markup_template('profile_advanced.tpl');
@@ -1258,7 +1296,7 @@ function advanced_profile(&$a) {
$profile['like_button_label'] = tt('Like','Likes',$profile['like_count'],'noun');
if($likers) {
foreach($likers as $l)
- $profile['likers'][] = array('name' => $l['xchan_name'],'url' => zid($l['xchan_url']));
+ $profile['likers'][] = array('name' => $l['xchan_name'],'photo' => zid($l['xchan_photo_s']), 'url' => zid($l['xchan_url']));
}
if(($a->profile['dob']) && ($a->profile['dob'] != '0000-00-00')) {
@@ -1350,6 +1388,8 @@ function advanced_profile(&$a) {
'$canlike' => (($profile['canlike'])? true : false),
'$likethis' => t('Like this thing'),
'$profile' => $profile,
+ '$fields' => $clean_fields,
+ '$editmenu' => profile_edit_menu($a->profile['profile_uid']),
'$things' => $things
));
}
@@ -1695,3 +1735,145 @@ function profiles_build_sync($channel_id) {
build_sync_packet($channel_id,array('profile' => $r));
}
}
+
+
+function auto_channel_create($account_id) {
+
+ if(! $account_id)
+ return false;
+
+ $arr = array();
+ $arr['account_id'] = $account_id;
+ $arr['name'] = get_aconfig($account_id,'register','channel_name');
+ $arr['nickname'] = legal_webbie(get_aconfig($account_id,'register','channel_address'));
+ $arr['permissions_role'] = get_aconfig($account_id,'register','permissions_role');
+
+ del_aconfig($account_id,'register','channel_name');
+ del_aconfig($account_id,'register','channel_address');
+ del_aconfig($account_id,'register','permissions_role');
+
+ if((! $arr['name']) || (! $arr['nickname'])) {
+ $x = q("select * from account where account_id = %d limit 1",
+ intval($account_id)
+ );
+ if($x) {
+ if(! $arr['name'])
+ $arr['name'] = substr($x[0]['account_email'],0,strpos($x[0]['account_email'],'@'));
+ if(! $arr['nickname'])
+ $arr['nickname'] = legal_webbie(substr($x[0]['account_email'],0,strpos($x[0]['account_email'],'@')));
+ }
+ }
+ if(! $arr['permissions_role'])
+ $arr['permissions_role'] = 'social';
+
+ if(validate_channelname($arr['name']))
+ return false;
+ if($arr['nickname'] === 'sys')
+ $arr['nickname'] = $arr['nickname'] . mt_rand(1000,9999);
+
+ $arr['nickname'] = check_webbie(array($arr['nickname'], $arr['nickname'] . mt_rand(1000,9999)));
+
+ return create_identity($arr);
+
+}
+
+function get_cover_photo($channel_id,$format = 'bbcode', $res = PHOTO_RES_COVER_1200) {
+
+ $r = q("select height, width, resource_id, type from photo where uid = %d and scale = %d and photo_usage = %d",
+ intval($channel_id),
+ intval($res),
+ intval(PHOTO_COVER)
+ );
+ if(! $r)
+ return false;
+
+ $output = false;
+
+ $url = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $res ;
+
+ switch($format) {
+ case 'bbcode':
+ $output = '[zrl=' . $r[0]['width'] . 'x' . $r[0]['height'] . ']' . $url . '[/zrl]';
+ break;
+ case 'html':
+ $output = '<img class="zrl" width="' . $r[0]['width'] . '" height="' . $r[0]['height'] . '" src="' . $url . '" alt="' . t('cover photo') . '" />';
+ break;
+ case 'array':
+ default:
+ $output = array(
+ 'width' => $r[0]['width'],
+ 'height' => $r[0]['type'],
+ 'type' => $r[0]['type'],
+ 'url' => $url
+ );
+ break;
+ }
+
+ return $output;
+
+}
+
+function get_zcard($channel,$observer_hash = '',$args = array()) {
+
+ logger('get_zcard');
+
+ $maxwidth = (($args['width']) ? intval($args['width']) : 0);
+ $maxheight = (($args['height']) ? intval($args['height']) : 0);
+
+
+ if(($maxwidth > 1200) || ($maxwidth < 1))
+ $maxwidth = 1200;
+
+ if($maxwidth <= 425) {
+ $width = 425;
+ $size = 'hz_small';
+ $cover_size = PHOTO_RES_COVER_425;
+ $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
+ }
+ elseif($maxwidth <= 900) {
+ $width = 900;
+ $size = 'hz_medium';
+ $cover_size = PHOTO_RES_COVER_850;
+ $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
+ }
+ elseif($maxwidth <= 1200) {
+ $width = 1200;
+ $size = 'hz_large';
+ $cover_size = PHOTO_RES_COVER_1200;
+ $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
+ }
+
+// $scale = (float) $maxwidth / $width;
+// $translate = intval(($scale / 1.0) * 100);
+
+
+ $channel['channel_addr'] = $channel['channel_address'] . '@' . get_app()->get_hostname();
+ $zcard = array('chan' => $channel);
+
+ $r = q("select height, width, resource_id, scale, type from photo where uid = %d and scale = %d and photo_usage = %d",
+ intval($channel['channel_id']),
+ intval($cover_size),
+ intval(PHOTO_COVER)
+ );
+
+ if($r) {
+ $cover = $r[0];
+ $cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['scale'];
+ }
+ else {
+ $cover = $pphoto;
+ }
+
+ $o .= replace_macros(get_markup_template('zcard.tpl'),array(
+ '$maxwidth' => $maxwidth,
+ '$scale' => $scale,
+ '$translate' => $translate,
+ '$size' => $size,
+ '$cover' => $cover,
+ '$pphoto' => $pphoto,
+ '$zcard' => $zcard
+ ));
+
+ return $o;
+
+}
diff --git a/include/import.php b/include/import.php
index ffaea6c1a..b7ec1c565 100644
--- a/include/import.php
+++ b/include/import.php
@@ -2,7 +2,7 @@
require_once('include/menu.php');
-function import_channel($channel, $account_id) {
+function import_channel($channel, $account_id, $seize) {
if(! array_key_exists('channel_system',$channel)) {
$channel['channel_system'] = (($channel['channel_pageflags'] & 0x1000) ? 1 : 0);
@@ -496,6 +496,8 @@ function import_items($channel,$items) {
}
}
+ $deliver = false; // Don't deliver any messages or notifications when importing
+
foreach($items as $i) {
$item = get_item_elements($i,$allow_code);
if(! $item)
@@ -509,16 +511,15 @@ function import_items($channel,$items) {
if($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
- item_store_update($item);
+ item_store_update($item,$allow_code,$deliver);
continue;
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- $item_result = item_store($item);
+ $item_result = item_store($item,$allow_code,$deliver);
}
-
}
}
}
diff --git a/include/items.php b/include/items.php
index 44f9633a9..bb4d1108e 100755
--- a/include/items.php
+++ b/include/items.php
@@ -159,7 +159,7 @@ function filter_insecure($channel_id, $arr) {
$ret = array();
- if((! intval(get_pconfig($channel_id, 'system', 'filter_insecure_collections'))) || (! $arr))
+ if((! intval(get_pconfig($channel_id, 'system', 'filter_insecure_privacy_groups'))) || (! $arr))
return $arr;
$str = '';
@@ -552,6 +552,12 @@ function get_public_feed($channel, $params) {
$params['top'] = ((x($params,'top')) ? intval($params['top']) : 0);
$params['cat'] = ((x($params,'cat')) ? $params['cat'] : '');
+
+ // put a sane lower limit on feed requests if not specified
+
+ if($params['begin'] === NULL_DATE)
+ $params['begin'] = datetime_convert('UTC','UTC','now - 1 month');
+
switch($params['type']) {
case 'json':
header("Content-type: application/atom+json");
@@ -587,8 +593,8 @@ function get_feed_for($channel, $observer_hash, $params) {
}
$items = items_fetch(array(
'wall' => '1',
- 'datequery' => $params['begin'],
- 'datequery2' => $params['end'],
+ 'datequery' => $params['end'],
+ 'datequery2' => $params['begin'],
'start' => $params['start'], // FIXME
'records' => $params['records'], // FIXME
'direction' => $params['direction'], // FIXME
@@ -604,8 +610,8 @@ function get_feed_for($channel, $observer_hash, $params) {
$atom = '';
$atom .= replace_macros($feed_template, array(
- '$version' => xmlify(RED_VERSION),
- '$red' => xmlify(PLATFORM_NAME),
+ '$version' => xmlify(Zotlabs\Project\System::get_project_version()),
+ '$red' => xmlify(Zotlabs\Project\System::get_platform_name()),
'$feed_id' => xmlify($channel['xchan_url']),
'$feed_title' => xmlify($channel['channel_name']),
'$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) ,
@@ -623,6 +629,7 @@ function get_feed_for($channel, $observer_hash, $params) {
'$community' => '',
));
+
call_hooks('atom_feed', $atom);
if($items) {
@@ -842,7 +849,7 @@ function get_item_elements($x,$allow_code = false) {
if($allow_code)
$arr['body'] = $x['body'];
else
- $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'],ENT_COMPAT,'UTF-8',false) : '');
+ $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'],ENT_COMPAT,'UTF-8',false) : '');
$key = get_config('system','pubkey');
@@ -910,6 +917,7 @@ function get_item_elements($x,$allow_code = false) {
$arr['attach'] = activity_sanitise($x['attach']);
$arr['term'] = decode_tags($x['tags']);
+ $arr['iconfig'] = decode_item_meta($x['meta']);
$arr['item_private'] = ((array_key_exists('flags',$x) && is_array($x['flags']) && in_array('private',$x['flags'])) ? 1 : 0);
@@ -1317,6 +1325,9 @@ function encode_item($item,$mirror = false) {
if($item['term'])
$x['tags'] = encode_item_terms($item['term'],$mirror);
+ if($item['iconfig'])
+ $x['meta'] = encode_item_meta($item['iconfig'],$mirror);
+
if($item['diaspora_meta']) {
$z = json_decode($item['diaspora_meta'],true);
if($z) {
@@ -1427,6 +1438,30 @@ function encode_item_terms($terms,$mirror = false) {
return $ret;
}
+function encode_item_meta($meta,$mirror = false) {
+ $ret = array();
+
+ if($meta) {
+ foreach($meta as $m) {
+ if($m['sharing'] || $mirror)
+ $ret[] = array('family' => $m['cat'], 'key' => $m['k'], 'value' => $m['v'], 'sharing' => intval($m['sharing']));
+ }
+ }
+
+ return $ret;
+}
+
+function decode_item_meta($meta) {
+ $ret = array();
+
+ if(is_array($meta) && $meta) {
+ foreach($meta as $m) {
+ $ret[] = array('cat' => escape_tags($m['family']),'k' => escape_tags($m['key']),'v' => $m['value'],'sharing' => $m['sharing']);
+ }
+ }
+ return $ret;
+}
+
/**
* @brief
*
@@ -2160,7 +2195,7 @@ function encode_rel_links($links) {
* * \e boolean \b success
* * \e int \b item_id
*/
-function item_store($arr, $allow_exec = false) {
+function item_store($arr, $allow_exec = false, $deliver = true) {
$d = array('item' => $arr, 'allow_exec' => $allow_exec);
call_hooks('item_store', $d );
@@ -2439,6 +2474,13 @@ function item_store($arr, $allow_exec = false) {
unset($arr['term']);
}
+ $meta = null;
+ if(array_key_exists('iconfig',$arr)) {
+ $meta = $arr['iconfig'];
+ unset($arr['iconfig']);
+ }
+
+
if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid) || strlen($public_policy))
$private = 1;
else
@@ -2516,6 +2558,15 @@ function item_store($arr, $allow_exec = false) {
$arr['term'] = $terms;
}
+ if($meta) {
+ foreach($meta as $m) {
+ set_iconfig($current_post,$m['cat'],$m['k'],$m['v'],$m['sharing']);
+ }
+ $arr['iconfig'] = $meta;
+ }
+
+
+
call_hooks('post_remote_end',$arr);
// update the commented timestamp on the parent
@@ -2537,7 +2588,7 @@ function item_store($arr, $allow_exec = false) {
// so that we have an item in the DB that's marked deleted and won't store a fresh post
// that isn't aware that we were already told to delete it.
- if(! intval($arr['item_deleted'])) {
+ if(($deliver) && (! intval($arr['item_deleted']))) {
send_status_notifications($current_post,$arr);
tag_deliver($arr['uid'],$current_post);
}
@@ -2550,7 +2601,7 @@ function item_store($arr, $allow_exec = false) {
-function item_store_update($arr,$allow_exec = false) {
+function item_store_update($arr,$allow_exec = false, $deliver = true) {
$d = array('item' => $arr, 'allow_exec' => $allow_exec);
call_hooks('item_store_update', $d );
@@ -2737,6 +2788,13 @@ function item_store_update($arr,$allow_exec = false) {
unset($arr['term']);
}
+ $meta = null;
+ if(array_key_exists('iconfig',$arr)) {
+ $meta = $arr['iconfig'];
+ unset($arr['iconfig']);
+ }
+
+
dbesc_array($arr);
logger('item_store_update: ' . print_r($arr,true), LOGGER_DATA);
@@ -2778,11 +2836,24 @@ function item_store_update($arr,$allow_exec = false) {
$arr['term'] = $terms;
}
+ $r = q("delete from iconfig where iid = %d",
+ intval($orig_post_id)
+ );
+
+ if($meta) {
+ foreach($meta as $m) {
+ set_iconfig($orig_post_id,$m['cat'],$m['k'],$m['v'],$m['sharing']);
+ }
+ $arr['iconfig'] = $meta;
+ }
+
call_hooks('post_remote_update_end',$arr);
- send_status_notifications($orig_post_id,$arr);
+ if($deliver) {
+ send_status_notifications($orig_post_id,$arr);
+ tag_deliver($uid,$orig_post_id);
+ }
- tag_deliver($uid,$orig_post_id);
$ret['success'] = true;
$ret['item_id'] = $orig_post_id;
@@ -2816,13 +2887,13 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id,
$signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
- /** @FIXME $uprvkey is undefined, do we still need this if-statement? */
- if( $uprvkey !== false )
+
+ if( $channel && $channel['channel_prvkey'] )
$authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256'));
else
$authorsig = '';
- $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => base64_encode($authorsig));
+ $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => $authorsig);
$y = json_encode($x);
@@ -2831,6 +2902,7 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id,
intval($post_id)
);
+
if(! $r)
logger('store_diaspora_comment_sig: DB write failed');
@@ -3436,6 +3508,7 @@ function check_item_source($uid, $item) {
if(! $r[0]['src_patt'])
return true;
+
require_once('include/html2plain.php');
$text = prepare_text($item['body'],$item['mimetype']);
$text = html2plain($text);
@@ -3651,10 +3724,6 @@ function mail_store($arr) {
/**
* @brief Process atom feed and update anything/everything we might need to update.
*
- * $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or
- * might not) try and subscribe to it.
- * $datedir sorts in reverse order
- *
* @param array $xml
* The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
* @param $importer
@@ -3685,6 +3754,16 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
return;
}
+ $sys_expire = intval(get_config('system','default_expire_days'));
+ $chn_expire = intval($importer['channel_expire_days']);
+
+ $expire_days = $sys_expire;
+
+ if(($chn_expire != 0) && ($chn_expire < $sys_expire))
+ $expire_days = $chn_expire;
+
+ // logger('expire_days: ' . $expire_days);
+
$feed = new SimplePie();
$feed->set_raw_data($xml);
$feed->init();
@@ -3788,6 +3867,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
intval($importer['channel_id'])
);
+
// Update content if 'updated' changes
if($r) {
@@ -3846,6 +3926,17 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$datarray['owner_xchan'] = $contact['xchan_hash'];
+ if(array_key_exists('created',$datarray) && $datarray['created'] != NULL_DATE && $expire_days) {
+ $t1 = $datarray['created'];
+ $t2 = datetime_convert('UTC','UTC','now - ' . $expire_days . 'days');
+ if($t1 < $t2) {
+ logger('feed content older than expiration. Ignoring.', LOGGER_DEBUG, LOG_INFO);
+ continue;
+ }
+ }
+
+
+
$r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
dbesc($item_id),
intval($importer['channel_id'])
@@ -3892,6 +3983,72 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
}
}
+
+/**
+ * @brief Process atom feed and return the first post and structure
+ *
+ * @param array $xml
+ * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
+ * @param $importer
+ * The contact_record (joined to user_record) of the local user who owns this
+ * relationship. It is this person's stuff that is going to be updated.
+ */
+
+function process_salmon_feed($xml, $importer) {
+
+ $ret = array();
+
+ require_once('library/simplepie/simplepie.inc');
+
+ if(! strlen($xml)) {
+ logger('process_feed: empty input');
+ return;
+ }
+
+ $feed = new SimplePie();
+ $feed->set_raw_data($xml);
+ $feed->init();
+
+ if($feed->error())
+ logger('Error parsing XML: ' . $feed->error());
+
+ $permalink = $feed->get_permalink();
+
+ if($feed->get_item_quantity()) {
+
+ // this should be exactly one
+
+ logger('feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
+
+ $items = $feed->get_items();
+
+ foreach($items as $item) {
+
+ $item_id = base64url_encode($item->get_id());
+
+ logger('processing ' . $item_id, LOGGER_DEBUG);
+
+ $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
+ if(isset($rawthread[0]['attribs']['']['ref'])) {
+ $is_reply = true;
+ $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
+ }
+
+ if($is_reply)
+ $ret['is_reply'] = true;
+
+ $ret['author'] = array();
+
+ $datarray = get_atom_elements($feed,$item,$ret['author']);
+
+ $ret['item'] = $datarray;
+ }
+ }
+
+ return $ret;
+}
+
+
function update_feed_item($uid,$datarray) {
logger('update_feed_item: not implemented! ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA);
}
@@ -3975,12 +4132,25 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
$o .= '<thr:in-reply-to ref="' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
}
+ if(activity_match($item['obj_type'],ACTIVITY_OBJ_EVENT) && activity_match($item['verb'],ACTIVITY_POST)) {
+ $obj = ((is_array($item['obj'])) ? $item['object'] : json_decode($item['object'],true));
+
+ $o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
+ $o .= '<summary>' . xmlify(bbcode($obj['title'])) . '</summary>' . "\r\n";
+ $o .= '<dtstart xmlns="urn:ietf:params:xml:ns:xcal">' . datetime_convert('UTC','UTC', $obj['start'],'Ymd\\THis' . (($obj['adjust']) ? '\\Z' : '')) . '</dtstart>' . "\r\n";
+ $o .= '<dtend xmlns="urn:ietf:params:xml:ns:xcal">' . datetime_convert('UTC','UTC', $obj['finish'],'Ymd\\THis' . (($obj['adjust']) ? '\\Z' : '')) . '</dtend>' . "\r\n";
+ $o .= '<location>' . bbcode($obj['location']) . '</location>' . "\r\n";
+ $o .= '<content type="' . $type . '" >' . xmlify(bbcode($obj['description'])) . '</content>' . "\r\n";
+ }
+ else {
+ $o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
+ $o .= '<content type="' . $type . '" >' . xmlify(prepare_text($body,$item['mimetype'])) . '</content>' . "\r\n";
+ }
+
$o .= '<id>' . xmlify($item['mid']) . '</id>' . "\r\n";
- $o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
$o .= '<published>' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '</published>' . "\r\n";
$o .= '<updated>' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '</updated>' . "\r\n";
- $o .= '<content type="' . $type . '" >' . xmlify(prepare_text($body,$item['mimetype'])) . '</content>' . "\r\n";
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
if($item['location']) {
@@ -4643,6 +4813,10 @@ function fetch_post_tags($items,$link = false) {
dbesc($tag_finder_str),
intval(TERM_OBJ_POST)
);
+ $imeta = q("select * from iconfig where iid in ( %s )",
+ dbesc($tag_finder_str)
+ );
+
}
for($x = 0; $x < count($items); $x ++) {
@@ -4666,6 +4840,26 @@ function fetch_post_tags($items,$link = false) {
}
}
}
+ if($imeta) {
+ foreach($imeta as $i) {
+ if(array_key_exists('item_id',$items[$x])) {
+ if($i['iid'] == $items[$x]['item_id']) {
+ if(! is_array($items[$x]['iconfig']))
+ $items[$x]['iconfig'] = array();
+ $i['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$i['v'])) ? unserialize($i['v']) : $i['v']);
+ $items[$x]['iconfig'][] = $i;
+ }
+ }
+ else {
+ if($i['iid'] == $items[$x]['id']) {
+ if(! is_array($items[$x]['iconfig']))
+ $items[$x]['iconfig'] = array();
+ $i['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$i['v'])) ? unserialize($i['v']) : $i['v']);
+ $items[$x]['iconfig'][] = $i;
+ }
+ }
+ }
+ }
}
return $items;
@@ -4835,7 +5029,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
intval($uid)
);
if(! $r) {
- $result['message'] = t('Collection not found.');
+ $result['message'] = t('Privacy group not found.');
return $result;
}
@@ -4851,14 +5045,14 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
} else {
$contact_str = ' 0 ';
- $result['message'] = t('Collection is empty.');
+ $result['message'] = t('Privacy group is empty.');
return $result;
}
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) ";
$x = group_rec_byhash($uid,$r[0]['hash']);
- $result['headline'] = sprintf( t('Collection: %s'),$x['name']);
+ $result['headline'] = sprintf( t('Privacy group: %s'),$x['name']);
}
elseif($arr['cid'] && $uid) {
@@ -4876,15 +5070,15 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
if ($arr['datequery']) {
- $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery']))));
+ $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert('UTC','UTC',$arr['datequery']))));
}
if ($arr['datequery2']) {
- $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery2']))));
+ $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert('UTC','UTC',$arr['datequery2']))));
}
if(! array_key_exists('nouveau',$arr)) {
$sql_extra2 = " AND item.parent = item.id ";
- $sql_extra3 = '';
+// $sql_extra3 = '';
}
if($arr['search']) {
@@ -5274,3 +5468,212 @@ function asencode_person($p) {
return $ret;
}
+
+
+function send_profile_photo_activity($channel,$photo,$profile) {
+
+ // for now only create activities for the default profile
+
+ if(! intval($profile['is_default']))
+ return;
+
+ $arr = array();
+ $arr['item_thread_top'] = 1;
+ $arr['item_origin'] = 1;
+ $arr['item_wall'] = 1;
+ $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
+ $arr['verb'] = ACTIVITY_UPDATE;
+
+ $arr['object'] = json_encode(array(
+ 'type' => $arr['obj_type'],
+ 'id' => z_root() . '/photo/profile/l/' . $channel['channel_id'],
+ 'link' => array('rel' => 'photo', 'type' => $photo['type'], 'href' => z_root() . '/photo/profile/l/' . $channel['channel_id'])
+ ));
+
+ if(stripos($profile['gender'],t('female')) !== false)
+ $t = t('%1$s updated her %2$s');
+ elseif(stripos($profile['gender'],t('male')) !== false)
+ $t = t('%1$s updated his %2$s');
+ else
+ $t = t('%1$s updated their %2$s');
+
+ $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('profile photo') . '[/zrl]';
+
+ $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg=150x150]' . z_root() . '/photo/' . $photo['resource_id'] . '-4[/zmg][/zrl]';
+
+ $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
+
+ $acl = new Zotlabs\Access\AccessList($channel);
+ $x = $acl->get();
+ $arr['allow_cid'] = $x['allow_cid'];
+
+ $arr['allow_gid'] = $x['allow_gid'];
+ $arr['deny_cid'] = $x['deny_cid'];
+ $arr['deny_gid'] = $x['deny_gid'];
+
+ $arr['uid'] = $channel['channel_id'];
+ $arr['aid'] = $channel['channel_account_id'];
+
+ $arr['owner_xchan'] = $channel['channel_hash'];
+ $arr['author_xchan'] = $channel['channel_hash'];
+
+ post_activity_item($arr);
+
+
+}
+
+
+
+
+
+function get_iconfig(&$item, $family, $key) {
+
+ $is_item = false;
+ if(is_array($item)) {
+ $is_item = true;
+ if((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig'])))
+ $item['iconfig'] = array();
+
+ if(array_key_exists('item_id',$item))
+ $iid = $item['item_id'];
+ else
+ $iid = $item['id'];
+ }
+ elseif(intval($item))
+ $iid = $item;
+
+ if(! $iid)
+ return false;
+
+ if(is_array($item) && array_key_exists('iconfig',$item) && is_array($item['iconfig'])) {
+ foreach($item['iconfig'] as $c) {
+ if($c['iid'] == $iid && $c['cat'] == $family && $c['k'] == $key)
+ return $c['v'];
+ }
+ }
+
+ $r = q("select * from iconfig where iid = %d and cat = '%s' and k = '%s' limit 1",
+ intval($iid),
+ dbesc($family),
+ dbesc($key)
+ );
+ if($r) {
+ $r[0]['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
+ if($is_item)
+ $item['iconfig'][] = $r[0];
+ return $r[0]['v'];
+ }
+ return false;
+
+}
+
+/**
+ * set_iconfig(&$item, $family, $key, $value, $sharing = false);
+ *
+ * $item - item array or item id. If passed an array the iconfig meta information is
+ * added to the item structure (which will need to be saved with item_store eventually).
+ * If passed an id, the DB is updated, but may not be federated and/or cloned.
+ * $family - namespace of meta variable
+ * $key - key of meta variable
+ * $value - value of meta variable
+ * $sharing - boolean (default false); if true the meta information is propagated with the item
+ * to other sites/channels, mostly useful when $item is an array and has not yet been stored/delivered.
+ * If the meta information is added after delivery and you wish it to be shared, it may be necessary to
+ * alter the item edited timestamp and invoke the delivery process on the updated item. The edited
+ * timestamp needs to be altered in order to trigger an item_store_update() at the receiving end.
+ */
+
+
+function set_iconfig(&$item, $family, $key, $value, $sharing = false) {
+
+ $dbvalue = ((is_array($value)) ? serialize($value) : $value);
+ $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
+
+ $is_item = false;
+ $idx = null;
+
+ if(is_array($item)) {
+ $is_item = true;
+ if((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig'])))
+ $item['iconfig'] = array();
+ elseif($item['iconfig']) {
+ for($x = 0; $x < count($item['iconfig']); $x ++) {
+ if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
+ $idx = $x;
+ }
+ }
+ }
+ $entry = array('cat' => $family, 'k' => $key, 'v' => $value, 'sharing' => $sharing);
+
+ if(is_null($idx))
+ $item['iconfig'][] = $entry;
+ else
+ $item['iconfig'][$idx] = $entry;
+ return $value;
+ }
+
+ if(intval($item))
+ $iid = intval($item);
+
+ if(! $iid)
+ return false;
+
+ if(get_iconfig($item, $family, $key) === false) {
+ $r = q("insert into iconfig( iid, cat, k, v, sharing ) values ( %d, '%s', '%s', '%s', %d ) ",
+ intval($iid),
+ dbesc($family),
+ dbesc($key),
+ dbesc($dbvalue),
+ intval($sharing)
+ );
+ }
+ else {
+ $r = q("update iconfig set v = '%s', sharing = %d where iid = %d and cat = '%s' and k = '%s' ",
+ dbesc($dbvalue),
+ intval($sharing),
+ intval($iid),
+ dbesc($family),
+ dbesc($key)
+ );
+ }
+
+ if(! $r)
+ return false;
+
+ return $value;
+}
+
+
+
+function del_iconfig(&$item, $family, $key) {
+
+
+ $is_item = false;
+ $idx = null;
+
+ if(is_array($item)) {
+ $is_item = true;
+ if(is_array($item['iconfig'])) {
+ for($x = 0; $x < count($item['iconfig']); $x ++) {
+ if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
+ unset($item['iconfig'][$x]);
+ }
+ }
+ }
+ return true;
+ }
+
+ if(intval($item))
+ $iid = intval($item);
+
+ if(! $iid)
+ return false;
+
+ return q("delete from iconfig where iid = %d and cat = '%s' and k = '%s' ",
+ intval($iid),
+ dbesc($family),
+ dbesc($key)
+ );
+
+}
+
diff --git a/include/language.php b/include/language.php
index 59979aa85..121816ae6 100644
--- a/include/language.php
+++ b/include/language.php
@@ -65,15 +65,22 @@ function get_best_language() {
if(isset($langs) && count($langs)) {
foreach ($langs as $lang => $v) {
$lang = strtolower($lang);
- if(file_exists("view/$lang") && is_dir("view/$lang")) {
+ if(is_dir("view/$lang")) {
$preferred = $lang;
break;
}
}
}
- if(isset($preferred))
- return $preferred;
+ if(! isset($preferred))
+ $preferred = 'unset';
+
+ $arr = array('langs' => $langs, 'preferred' => $preferred);
+
+ call_hooks('get_best_language',$arr);
+
+ if($arr['preferred'] !== 'unset')
+ return $arr['preferred'];
$a = get_app();
return ((isset($a->config['system']['language'])) ? $a->config['system']['language'] : 'en');
@@ -182,7 +189,7 @@ function t($s, $ctx = '') {
function translate_projectname($s) {
- return str_replace(array('$projectname','$Projectname'),array(PLATFORM_NAME,ucfirst(PLATFORM_NAME)),$s);
+ return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Project\System::get_platform_name(),ucfirst(Zotlabs\Project\System::get_platform_name())),$s);
}
diff --git a/include/menu.php b/include/menu.php
index 075372515..d90cefddb 100644
--- a/include/menu.php
+++ b/include/menu.php
@@ -299,7 +299,7 @@ function menu_add_item($menu_id, $uid, $arr) {
$channel = get_app()->get_channel();
}
- $acl = new AccessList($channel);
+ $acl = new Zotlabs\Access\AccessList($channel);
$acl->set_from_array($arr);
$p = $acl->get();
@@ -340,7 +340,7 @@ function menu_edit_item($menu_id, $uid, $arr) {
$channel = get_app()->get_channel();
}
- $acl = new AccessList($channel);
+ $acl = new Zotlabs\Access\AccessList($channel);
$acl->set_from_array($arr);
$p = $acl->get();
diff --git a/include/message.php b/include/message.php
index 940fcc275..f24bb6e4b 100644
--- a/include/message.php
+++ b/include/message.php
@@ -11,6 +11,7 @@ require_once('include/attach.php');
function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='',$expires = ''){
$ret = array('success' => false);
+ $is_reply = false;
$a = get_app();
$observer_hash = get_observer_hash();
@@ -51,6 +52,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
$conv_guid = '';
if(strlen($replyto)) {
+ $is_reply = true;
$r = q("select conv_guid from mail where channel_id = %d and ( mid = '%s' or parent_mid = '%s' ) limit 1",
intval(local_channel()),
dbesc($replyto),
@@ -187,8 +189,8 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
- $r = q("INSERT INTO mail ( account_id, conv_guid, mail_obscured, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires )
- VALUES ( %d, '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
+ $r = q("INSERT INTO mail ( account_id, conv_guid, mail_obscured, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires, mail_isreply )
+ VALUES ( %d, '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d )",
intval($channel['channel_account_id']),
dbesc($conv_guid),
intval(1),
@@ -201,7 +203,8 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
dbesc($mid),
dbesc($replyto),
dbesc(datetime_convert()),
- dbescdate($expires)
+ dbescdate($expires),
+ intval($is_reply)
);
// verify the save
diff --git a/include/nav.php b/include/nav.php
index 1630c4731..5f630745c 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -76,7 +76,7 @@ EOT;
if(local_channel()) {
- if($chans && count($chans) > 1 && feature_enabled(local_channel(),'nav_channel_select'))
+ if($chans && count($chans) > 1 && feature_enabled(local_channel(),'nav_channel_select') && (! UNO))
$nav['channels'] = $chans;
$nav['logout'] = Array('logout',t('Logout'), "", t('End this session'),'logout_nav_btn');
@@ -84,7 +84,7 @@ EOT;
// user menu
$nav['usermenu'][] = Array('channel/' . $channel['channel_address'], t('Home'), "", t('Your posts and conversations'),'channel_nav_btn');
$nav['usermenu'][] = Array('profile/' . $channel['channel_address'], t('View Profile'), "", t('Your profile page'),'profile_nav_btn');
- if(feature_enabled(local_channel(),'multi_profiles'))
+ if(feature_enabled(local_channel(),'multi_profiles') && (! UNO))
$nav['usermenu'][] = Array('profiles', t('Edit Profiles'),"", t('Manage/Edit profiles'),'profiles_nav_btn');
else
$nav['usermenu'][] = Array('profiles/' . $prof[0]['id'], t('Edit Profile'),"", t('Edit your profile'),'profiles_nav_btn');
@@ -94,16 +94,17 @@ EOT;
require_once('include/chat.php');
$has_chats = chatroom_list_count(local_channel());
- $nav['usermenu'][] = Array('chat/' . $channel['channel_address'] . (($has_chats) ? '' : '/new'), t('Chat'),"",t('Your chatrooms'),'chat_nav_btn');
+ if(! UNO)
+ $nav['usermenu'][] = Array('chat/' . $channel['channel_address'] . (($has_chats) ? '' : '/new'), t('Chat'),"",t('Your chatrooms'),'chat_nav_btn');
require_once('include/menu.php');
$has_bookmarks = menu_list_count(local_channel(),'',MENU_BOOKMARK) + menu_list_count(local_channel(),'',MENU_SYSTEM|MENU_BOOKMARK);
- if($has_bookmarks) {
+ if(($has_bookmarks) && (! UNO)) {
$nav['usermenu'][] = Array('bookmarks', t('Bookmarks'), "", t('Your bookmarks'),'bookmarks_nav_btn');
}
- if(feature_enabled($channel['channel_id'],'webpages'))
+ if(feature_enabled($channel['channel_id'],'webpages') && (! UNO))
$nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages'),'webpages_nav_btn');
}
else {
@@ -154,7 +155,8 @@ EOT;
$nav['help'] = array($help_url, t('Help'), "", t('Help and documentation'),'help_nav_btn');
- $nav['apps'] = array('apps', t('Apps'), "", t('Applications, utilities, links, games'),'apps_nav_btn');
+ if(! UNO)
+ $nav['apps'] = array('apps', t('Apps'), "", t('Applications, utilities, links, games'),'apps_nav_btn');
$nav['search'] = array('search', t('Search'), "", t('Search site @name, #tag, ?docs, content'));
@@ -196,8 +198,9 @@ EOT;
$nav['all_events'] = array('events', t('Events'), "", t('Event Calendar'),'events_nav_btn');
$nav['all_events']['all']=array('events', t('See all events'), "", "");
$nav['all_events']['mark'] = array('', t('Mark all events seen'), '','');
-
- $nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage Your Channels'),'manage_nav_btn');
+
+ if(! UNO)
+ $nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage Your Channels'),'manage_nav_btn');
$nav['settings'] = array('settings', t('Settings'),"", t('Account/Channel Settings'),'settings_nav_btn');
diff --git a/include/network.php b/include/network.php
index 859a60650..93fd836f8 100644
--- a/include/network.php
+++ b/include/network.php
@@ -40,7 +40,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
$ch = @curl_init($url);
if(($redirects > 8) || (! $ch))
- return false;
+ return $ret;
@curl_setopt($ch, CURLOPT_HEADER, true);
@curl_setopt($ch, CURLINFO_HEADER_OUT, true);
@@ -171,7 +171,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
$ch = curl_init($url);
if(($redirects > 8) || (! $ch))
- return ret;
+ return $ret;
@curl_setopt($ch, CURLOPT_HEADER, true);
@curl_setopt($ch, CURLINFO_HEADER_OUT, true);
@@ -294,8 +294,8 @@ function z_post_url_json($url, $params, $redirects = 0, $opts = array()) {
}
-function json_return_and_die($x) {
- header("content-type: application/json");
+function json_return_and_die($x, $content_type = 'application/json') {
+ header("Content-type: $content_type");
echo json_encode($x);
killme();
}
@@ -1144,6 +1144,10 @@ function discover_by_webbie($webbie) {
dbesc($addr)
);
+ // fix relative urls
+ if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0))
+ $vcard['photo'] = $diaspora_base . '/' . $vcard['photo'];
+
/**
*
* Diaspora communications are notoriously unreliable and receiving profile update messages (indeed any messages)
@@ -1615,18 +1619,19 @@ function format_and_send_email($sender,$xchan,$item) {
// load the template for private message notifications
$tpl = get_markup_template('email_notify_html.tpl');
$email_html_body = replace_macros($tpl,array(
- '$banner' => $banner,
- '$product' => $product,
- '$preamble' => '',
- '$sitename' => $sitename,
- '$siteurl' => $siteurl,
+ '$banner' => $banner,
+ '$notify_icon' => Zotlabs\Project\System::get_notify_icon(),
+ '$product' => $product,
+ '$preamble' => '',
+ '$sitename' => $sitename,
+ '$siteurl' => $siteurl,
'$source_name' => $sender['xchan_name'],
'$source_link' => $sender['xchan_url'],
'$source_photo' => $sender['xchan_photo_m'],
- '$username' => $xchan['xchan_name'],
+ '$username' => $xchan['xchan_name'],
'$hsitelink' => $datarray['hsitelink'],
'$hitemlink' => $datarray['hitemlink'],
- '$thanks' => $thanks,
+ '$thanks' => $thanks,
'$site_admin' => $site_admin,
'$title' => $title,
'$htmlversion' => $htmlversion,
@@ -1635,20 +1640,20 @@ function format_and_send_email($sender,$xchan,$item) {
// load the template for private message notifications
$tpl = get_markup_template('email_notify_text.tpl');
$email_text_body = replace_macros($tpl, array(
- '$banner' => $banner,
- '$product' => $product,
- '$preamble' => '',
- '$sitename' => $sitename,
- '$siteurl' => $siteurl,
+ '$banner' => $banner,
+ '$product' => $product,
+ '$preamble' => '',
+ '$sitename' => $sitename,
+ '$siteurl' => $siteurl,
'$source_name' => $sender['xchan_name'],
'$source_link' => $sender['xchan_url'],
'$source_photo' => $sender['xchan_photo_m'],
- '$username' => $xchan['xchan_name'],
- '$hsitelink' => $datarray['hsitelink'],
- '$hitemlink' => $datarray['hitemlink'],
- '$thanks' => $thanks,
+ '$username' => $xchan['xchan_name'],
+ '$hsitelink' => $datarray['hsitelink'],
+ '$hitemlink' => $datarray['hitemlink'],
+ '$thanks' => $thanks,
'$site_admin' => $site_admin,
- '$title' => $title,
+ '$title' => $title,
'$textversion' => $textversion
));
@@ -1662,13 +1667,13 @@ function format_and_send_email($sender,$xchan,$item) {
// use the EmailNotification library to send the message
enotify::send(array(
- 'fromName' => $product,
- 'fromEmail' => $sender_email,
- 'replyTo' => $sender_email,
- 'toEmail' => str_replace('mailto:','',$xchan['xchan_addr']),
- 'messageSubject' => (($title) ? $title : t('No Subject')),
- 'htmlVersion' => $email_html_body,
- 'textVersion' => $email_text_body,
+ 'fromName' => $product,
+ 'fromEmail' => $sender_email,
+ 'replyTo' => $sender_email,
+ 'toEmail' => str_replace('mailto:','',$xchan['xchan_addr']),
+ 'messageSubject' => (($title) ? $title : t('No Subject')),
+ 'htmlVersion' => $email_html_body,
+ 'textVersion' => $email_text_body,
'additionalMailHeader' => '',
));
@@ -1717,7 +1722,7 @@ function get_site_info() {
global $a;
$register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN');
- $directory_mode = Array('DIRECTORY_MODE_NORMAL', 'DIRECTORY_MODE_SECONDARY','DIRECTORY_MODE_PRIMARY', 256 => 'DIRECTORY_MODE_STANDALONE');
+ $directory_mode = Array('DIRECTORY_MODE_NORMAL', 'DIRECTORY_MODE_PRIMARY', 'DIRECTORY_MODE_SECONDARY', 256 => 'DIRECTORY_MODE_STANDALONE');
$sql_extra = '';
@@ -1763,16 +1768,13 @@ function get_site_info() {
$site_info = get_config('system','info');
$site_name = get_config('system','sitename');
if(! get_config('system','hidden_version_siteinfo')) {
- $version = RED_VERSION;
- $tag = get_std_version();
+ $version = Zotlabs\Project\System::get_project_version();
+ $tag = Zotlabs\Project\System::get_std_version();
if(@is_dir('.git') && function_exists('shell_exec')) {
$commit = trim( @shell_exec('git log -1 --format="%h"'));
-// if(! get_config('system','hidden_tag_siteinfo'))
-// $tag = trim( @shell_exec('git describe --tags --abbrev=0'));
-// else
-// $tag = '';
}
+
if(! isset($commit) || strlen($commit) > 16)
$commit = '';
}
@@ -1788,10 +1790,22 @@ function get_site_info() {
$hide_in_statistics = intval(get_config('system','hide_in_statistics'));
$site_expire = intval(get_config('system', 'default_expire_days'));
+ load_config('feature_lock');
+ $locked_features = array();
+ if(is_array($a->config['feature_lock']) && count($a->config['feature_lock'])) {
+ foreach($a->config['feature_lock'] as $k => $v) {
+ if($k === 'config_loaded')
+ continue;
+ $locked_features[$k] = intval($v);
+ }
+ }
+
+
$data = Array(
'version' => $version,
'version_tag' => $tag,
+ 'server_role' => Zotlabs\Project\System::get_server_role(),
'commit' => $commit,
'url' => z_root(),
'plugins' => $visible_plugins,
@@ -1799,12 +1813,13 @@ function get_site_info() {
'invitation_only' => intval(get_config('system','invitation_only')),
'directory_mode' => $directory_mode[get_config('system','directory_mode')],
'language' => get_config('system','language'),
- 'rss_connections' => get_config('system','feed_contacts'),
+ 'rss_connections' => intval(get_config('system','feed_contacts')),
'expiration' => $site_expire,
'default_service_restrictions' => $service_class,
+ 'locked_features' => $locked_features,
'admin' => $admin,
'site_name' => (($site_name) ? $site_name : ''),
- 'platform' => PLATFORM_NAME,
+ 'platform' => Zotlabs\Project\System::get_platform_name(),
'dbdriver' => $db->getdriver(),
'lastpoll' => get_config('system','lastpoll'),
'info' => (($site_info) ? $site_info : ''),
diff --git a/include/notifier.php b/include/notifier.php
index 50981df9d..628847d54 100644
--- a/include/notifier.php
+++ b/include/notifier.php
@@ -68,7 +68,6 @@ require_once('include/html2plain.php');
require_once('include/cli_startup.php');
require_once('include/zot.php');
require_once('include/queue_fn.php');
-require_once('include/session.php');
require_once('include/datetime.php');
require_once('include/items.php');
require_once('include/bbcode.php');
@@ -188,6 +187,7 @@ function notifier_run($argv, $argc){
$recipients[] = $r[0]['abook_xchan'];
$private = false;
$packet_type = 'refresh';
+ $packet_recips = array(array('guid' => $r[0]['xchan_guid'],'guid_sig' => $r[0]['xchan_guid_sig'],'hash' => $r[0]['xchan_hash']));
}
}
}
@@ -297,7 +297,7 @@ function notifier_run($argv, $argc){
$channel = $s[0];
if($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) {
- logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}");
+ logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING);
return;
}
@@ -316,7 +316,7 @@ function notifier_run($argv, $argc){
return;
if(strpos($r[0]['postopts'],'nodeliver') !== false) {
- logger('notifier: target item is undeliverable', LOGGER_DEBUG);
+ logger('notifier: target item is undeliverable', LOGGER_DEBUG, LOG_NOTICE);
return;
}
@@ -352,8 +352,8 @@ function notifier_run($argv, $argc){
// $cmd === 'relay' indicates the owner is sending it to the original recipients
// don't allow the item in the relay command to relay to owner under any circumstances, it will loop
- logger('notifier: relay_to_owner: ' . (($relay_to_owner) ? 'true' : 'false'), LOGGER_DATA);
- logger('notifier: top_level_post: ' . (($top_level_post) ? 'true' : 'false'), LOGGER_DATA);
+ logger('notifier: relay_to_owner: ' . (($relay_to_owner) ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
+ logger('notifier: top_level_post: ' . (($top_level_post) ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
// tag_deliver'd post which needs to be sent back to the original author
@@ -395,7 +395,7 @@ function notifier_run($argv, $argc){
// TODO verify this is needed - copied logic from same place in old code
if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
- logger('notifier: ignoring delete notification for non-wall item');
+ logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE);
return;
}
}
@@ -410,18 +410,19 @@ function notifier_run($argv, $argc){
$x = $encoded_item;
$x['title'] = 'private';
$x['body'] = 'private';
- logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA);
+ logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
stringify_array_elms($recipients);
if(! $recipients)
return;
-// logger('notifier: recipients: ' . print_r($recipients,true));
+// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
$env_recips = (($private) ? array() : null);
$details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',',$recipients) . ")");
+
$recip_list = array();
if($details) {
@@ -436,15 +437,42 @@ function notifier_run($argv, $argc){
if(! $delivery_options)
format_and_send_email($channel,$d,$target_item);
}
+ }
+ }
-
- }
+ $narr = array(
+ 'channel' => $channel,
+ 'env_recips' => $env_recips,
+ 'packet_recips' => $packet_recips,
+ 'recipients' => $recipients,
+ 'item' => $item,
+ 'target_item' => $target_item,
+ 'top_level_post' => $top_level_post,
+ 'private' => $private,
+ 'followup' => $followup,
+ 'relay_to_owner' => $relay_to_owner,
+ 'uplink' => $uplink,
+ 'cmd' => $cmd,
+ 'mail' => $mail,
+ 'location' => $location,
+ 'request' => $request,
+ 'normal_mode' => $normal_mode,
+ 'packet_type' => $packet_type,
+ 'walltowall' => $walltowall,
+ 'queued' => array()
+ );
+
+ call_hooks('notifier_process', $narr);
+ if($narr['queued']) {
+ foreach($narr['queued'] as $pq)
+ $deliveries[] = $pq;
}
+
if(($private) && (! $env_recips)) {
// shouldn't happen
- logger('notifier: private message with no envelope recipients.' . print_r($argv,true));
+ logger('notifier: private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE);
}
logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG);
@@ -459,7 +487,7 @@ function notifier_run($argv, $argc){
if(! $r) {
- logger('notifier: no hubs');
+ logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
return;
}
@@ -482,7 +510,7 @@ function notifier_run($argv, $argc){
foreach($hubs as $hub) {
if(in_array($hub['hubloc_url'],$dead_hubs)) {
- logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG);
+ logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG, LOG_INFO);
continue;
}
@@ -502,8 +530,8 @@ function notifier_run($argv, $argc){
}
}
- logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG);
-
+ logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG);
+
foreach($dhubs as $hub) {
@@ -512,6 +540,7 @@ function notifier_run($argv, $argc){
$narr = array(
'channel' => $channel,
'env_recips' => $env_recips,
+ 'packet_recips' => $packet_recips,
'recipients' => $recipients,
'item' => $item,
'target_item' => $target_item,
@@ -547,7 +576,7 @@ function notifier_run($argv, $argc){
$packet = null;
if($packet_type === 'refresh' || $packet_type === 'purge') {
- $packet = zot_build_packet($channel,$packet_type);
+ $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
}
elseif($packet_type === 'request') {
$packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hash,
@@ -576,7 +605,7 @@ function notifier_run($argv, $argc){
));
// only create delivery reports for normal undeleted items
- if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted'])) {
+ if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ",
dbesc($target_item['mid']),
dbesc($hub['hubloc_host']),
diff --git a/include/oembed.php b/include/oembed.php
index e50d34c7d..fb7a30e65 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -3,6 +3,34 @@ function oembed_replacecb($matches){
$embedurl=$matches[1];
+
+ // site white/black list
+
+ if(($x = get_config('system','embed_deny'))) {
+ $l = explode("\n",$x);
+ if($l) {
+ foreach($l as $ll) {
+ if(trim($ll) && strpos($embedurl,trim($ll)) !== false)
+ return '<a href="' . $embedurl . '">' . $embedurl . '</a>';
+ }
+ }
+ }
+ if(($x = get_config('system','embed_allow'))) {
+ $found = false;
+ $l = explode("\n",$x);
+ if($l) {
+ foreach($l as $ll) {
+ if(trim($ll) && strpos($embedurl,trim($ll)) !== false) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ if(! $found) {
+ return '<a href="' . $embedurl . '">' . $embedurl . '</a>';
+ }
+ }
+
// implements a personal embed white/black list for logged in members
if(local_channel()) {
if(($x = get_pconfig(local_channel(),'system','embed_deny'))) {
@@ -53,6 +81,10 @@ function oembed_fetch_url($embedurl){
$a = get_app();
+ $embedurl = str_replace('&amp;','&', $embedurl);
+
+// logger('fetch: ' . $embedurl);
+
$txt = Cache::get($a->videowidth . $embedurl);
if(strstr($txt,'youtu') && strstr(z_root(),'https:')) {
@@ -78,7 +110,6 @@ function oembed_fetch_url($embedurl){
else {
// try oembed autodiscovery
$redirects = 0;
-
$result = z_fetch_url($embedurl, false, $redirects, array('timeout' => 15, 'accept_content' => "text/*", 'novalidate' => true ));
if($result['success'])
$html_text = $result['body'];
@@ -88,8 +119,8 @@ function oembed_fetch_url($embedurl){
if ($dom){
$xpath = new DOMXPath($dom);
$attr = "oembed";
-
$xattr = oe_build_xpath("class","oembed");
+
$entries = $xpath->query("//link[@type='application/json+oembed']");
foreach($entries as $e){
$href = $e->getAttributeNode("href")->nodeValue;
@@ -121,20 +152,29 @@ function oembed_fetch_url($embedurl){
if ($txt[0]!="{") $txt='{"type":"error"}';
//save in cache
- Cache::set($a->videowidth . $embedurl,$txt);
+
+ if(! get_config('system','oembed_cache_disable'))
+ Cache::set($a->videowidth . $embedurl,$txt);
}
$j = json_decode($txt);
$j->embedurl = $embedurl;
+
+// logger('fetch return: ' . print_r($j,true));
+
return $j;
+
+
}
function oembed_format_object($j){
$a = get_app();
$embedurl = $j->embedurl;
+// logger('format: ' . print_r($j,true));
+
$jhtml = oembed_iframe($j->embedurl,(isset($j->width) ? $j->width : null), (isset($j->height) ? $j->height : null));
$ret="<span class='oembed ".$j->type."'>";
@@ -173,6 +213,14 @@ function oembed_format_object($j){
$ret.="<br>";
}; break;
case "link": {
+ if($j->thumbnail_url) {
+ if(is_matrix_url($embedurl)) {
+ $embedurl = zid($embedurl);
+ $j->thumbnail_url = zid($j->thumbnail_url);
+ }
+ $ret = '<a href="' . $embedurl . '" ><img src="' . $j->thumbnail_url . '" alt="thumbnail" /></a><br /><br />';
+ }
+
//$ret = "<a href='".$embedurl."'>".$j->title."</a>";
}; break;
case "rich": {
@@ -184,23 +232,29 @@ function oembed_format_object($j){
// add link to source if not present in "rich" type
if ( $j->type!='rich' || !strpos($j->html,$embedurl) ){
$embedlink = (isset($j->title))?$j->title:$embedurl;
- $ret .= '<span class="bookmark-identifier">#^</span>' . "<a href='$embedurl' rel='oembed'>$embedlink</a>";
- $ret .= "<br>";
+ $ret .= '<br />' . "<a href='$embedurl' rel='oembed'>$embedlink</a>";
+ $ret .= "<br />";
if (isset($j->author_name)) $ret.=" by ".$j->author_name;
if (isset($j->provider_name)) $ret.=" on ".$j->provider_name;
} else {
// add <a> for html2bbcode conversion
- $ret .= "<a href='$embedurl' rel='oembed'/>";
+ $ret .= "<br /><a href='$embedurl' rel='oembed'>$embedurl</a>";
}
$ret.="<br style='clear:left'></span>";
return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret));
}
function oembed_iframe($src,$width,$height) {
- if(! $width || strstr($width,'%'))
+ $scroll = ' scrolling="no" ';
+ if(! $width || strstr($width,'%')) {
$width = '640';
- if(! $height || strstr($height,'%'))
+ $scroll = ' scrolling="auto" ';
+ }
+ if(! $height || strstr($height,'%')) {
$height = '300';
+ $scroll = ' scrolling="auto" ';
+ }
+
// try and leave some room for the description line.
$height = intval($height) + 80;
$width = intval($width) + 40;
@@ -209,7 +263,7 @@ function oembed_iframe($src,$width,$height) {
// Make sure any children are sandboxed within their own iframe.
- return '<iframe height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >'
+ return '<iframe ' . $scroll . 'height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >'
. t('Embedded content') . '</iframe>';
}
diff --git a/include/permissions.php b/include/permissions.php
index a8e761f87..e4cd9ddda 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -626,7 +626,7 @@ function get_role_perms($role) {
$ret['channel_w_mail'] = PERMS_SPECIFIC;
$ret['channel_w_chat'] = PERMS_SPECIFIC;
$ret['channel_a_delegate'] = PERMS_SPECIFIC;
- $ret['channel_r_storage'] = PERMS_PUBLIC;
+ $ret['channel_r_storage'] = PERMS_SPECIFIC;
$ret['channel_w_storage'] = PERMS_SPECIFIC;
$ret['channel_r_pages'] = PERMS_PUBLIC;
$ret['channel_w_pages'] = PERMS_SPECIFIC;
@@ -641,10 +641,10 @@ function get_role_perms($role) {
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK
- |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT
+ |PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT
|PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL;
$ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK
- |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT
+ |PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT
|PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL;
$ret['channel_r_stream'] = PERMS_PUBLIC;
$ret['channel_r_profile'] = PERMS_PUBLIC;
@@ -864,10 +864,10 @@ function get_role_perms($role) {
*/
function get_roles() {
$roles = array(
- t('Social Networking') => array('social' => t('Mostly Public'), 'social_restricted' => t('Restricted'), 'social_private' => t('Private')),
- t('Community Forum') => array('forum' => t('Mostly Public'), 'forum_restricted' => t('Restricted'), 'forum_private' => t('Private')),
- t('Feed Republish') => array('feed' => t('Mostly Public'), 'feed_restricted' => t('Restricted')),
- t('Special Purpose') => array('soapbox' => t('Celebrity/Soapbox'), 'repository' => t('Group Repository')),
+ t('Social Networking') => array('social' => t('Social - Mostly Public'), 'social_restricted' => t('Social - Restricted'), 'social_private' => t('Social - Private')),
+ t('Community Forum') => array('forum' => t('Forum - Mostly Public'), 'forum_restricted' => t('Forum - Restricted'), 'forum_private' => t('Forum - Private')),
+ t('Feed Republish') => array('feed' => t('Feed - Mostly Public'), 'feed_restricted' => t('Feed - Restricted')),
+ t('Special Purpose') => array('soapbox' => t('Special - Celebrity/Soapbox'), 'repository' => t('Special - Group Repository')),
t('Other') => array('custom' => t('Custom/Expert Mode'))
);
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 0de3b9c97..dce92d8da 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -69,6 +69,8 @@ abstract class photo_driver {
abstract function cropImage($max,$x,$y,$w,$h);
+ abstract function cropImageRect($maxx,$maxy,$x,$y,$w,$h);
+
abstract function imageString();
@@ -229,6 +231,7 @@ abstract class photo_driver {
$this->doScaleImage($dest_width,$dest_height);
}
+
public function scaleImageSquare($dim) {
if(!$this->is_valid())
return FALSE;
diff --git a/include/photo/photo_gd.php b/include/photo/photo_gd.php
index 2ac7287e4..24bdc204f 100644
--- a/include/photo/photo_gd.php
+++ b/include/photo/photo_gd.php
@@ -108,6 +108,23 @@ class photo_gd extends photo_driver {
$this->setDimensions();
}
+ public function cropImageRect($maxx,$maxy,$x,$y,$w,$h) {
+ if(!$this->is_valid())
+ return FALSE;
+
+ $dest = imagecreatetruecolor( $maxx, $maxy );
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ if ($this->type=='image/png') imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
+ imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $maxx, $maxy, $w, $h);
+ if($this->image)
+ imagedestroy($this->image);
+ $this->image = $dest;
+ $this->setDimensions();
+ }
+
+
+
public function imageString() {
if(!$this->is_valid())
return FALSE;
diff --git a/include/photo/photo_imagick.php b/include/photo/photo_imagick.php
index 3f84fd06c..32bb61342 100644
--- a/include/photo/photo_imagick.php
+++ b/include/photo/photo_imagick.php
@@ -163,6 +163,24 @@ class photo_imagick extends photo_driver {
$this->doScaleImage($max,$max);
}
+ public function cropImageRect($maxx,$maxy,$x,$y,$w,$h) {
+ if(!$this->is_valid())
+ return FALSE;
+
+ $this->image->setFirstIterator();
+ do {
+ $this->image->cropImage($w, $h, $x, $y);
+ /**
+ * We need to remove the canvas,
+ * or the image is not resized to the crop:
+ * http://php.net/manual/en/imagick.cropimage.php#97232
+ */
+ $this->image->setImagePage(0, 0, 0, 0);
+ } while ($this->image->nextImage());
+
+ $this->doScaleImage($maxx,$maxy);
+ }
+
public function imageString() {
if(!$this->is_valid())
return FALSE;
diff --git a/include/photos.php b/include/photos.php
index 93511d2c0..5dd5f3c62 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -48,7 +48,7 @@ function photo_upload($channel, $observer, $args) {
// all other settings. 'allow_cid' being passed from an external source takes priority over channel settings.
// ...messy... needs re-factoring once the photos/files integration stabilises
- $acl = new AccessList($channel);
+ $acl = new Zotlabs\Access\AccessList($channel);
if(array_key_exists('directory',$args) && $args['directory'])
$acl->set($args['directory']);
if(array_key_exists('allow_cid',$args))
@@ -296,11 +296,11 @@ function photo_upload($channel, $observer, $args) {
$photo_link = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' . t('a new photo') . '[/zrl]';
- $album_link = '[zrl=' . z_root() . '/photos/album/' . bin2hex($album) . ']' . $album . '[/zrl]';
+ $album_link = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/album/' . bin2hex($album) . ']' . $album . '[/zrl]';
$activity_format = sprintf(t('%1$s posted %2$s to %3$s','photo_upload'), $author_link, $photo_link, $album_link);
- $summary = $activity_format . "\n\n" . (($args['body']) ? $args['body'] . "\n\n" : '');
+ $summary = (($args['body']) ? $args['body'] : '') . '[footer]' . $activity_format . '[/footer]';
$obj_body = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']'
. $tag . z_root() . "/photo/{$photo_hash}-{$scale}." . $ph->getExt() . '[/zmg]'
@@ -391,8 +391,8 @@ function photo_upload($channel, $observer, $args) {
$arr['deny_cid'] = $ac['deny_cid'];
$arr['deny_gid'] = $ac['deny_gid'];
$arr['verb'] = ACTIVITY_POST;
- $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
- $arr['object'] = json_encode($object);
+ $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
+ $arr['object'] = json_encode($object);
$arr['tgt_type'] = ACTIVITY_OBJ_ALBUM;
$arr['target'] = json_encode($target);
$arr['item_wall'] = 1;
@@ -400,7 +400,7 @@ function photo_upload($channel, $observer, $args) {
$arr['item_thread_top'] = 1;
$arr['item_private'] = intval($acl->is_private());
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
- $arr['body'] = $summary;
+ $arr['body'] = $summary;
// this one is tricky because the item and the photo have the same permissions, those of the photo.
diff --git a/include/plugin.php b/include/plugin.php
index 4a35a0170..bd844442f 100755
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -291,7 +291,7 @@ function call_hooks($name, &$data = null) {
$func = $hook[1];
$func($a, $data);
} else {
- // remove orphan hooks
+
q("DELETE FROM hook WHERE hook = '%s' AND file = '%s' AND function = '%s'",
dbesc($name),
dbesc($hook[0]),
@@ -313,7 +313,6 @@ function call_hooks($name, &$data = null) {
* * Version: 1.2.3
* * Author: John <profile url>
* * Author: Jane <email>
- * * Compat: Red [(version)], Friendica [(version)]
* *
*\endcode
* @param string $plugin the name of the plugin
@@ -325,8 +324,9 @@ function get_plugin_info($plugin){
'name' => $plugin,
'description' => '',
'author' => array(),
+ 'maintainer' => array(),
'version' => '',
- 'compat' => ''
+ 'requires' => ''
);
if (!is_file("addon/$plugin/$plugin.php"))
@@ -342,17 +342,16 @@ function get_plugin_info($plugin){
if ($l != ""){
list($k, $v) = array_map("trim", explode(":", $l, 2));
$k = strtolower($k);
- if ($k == 'author'){
+ if ($k == 'author' || $k == 'maintainer'){
$r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
if ($r) {
- $info['author'][] = array('name' => $m[1], 'link' => $m[2]);
+ $info[$k][] = array('name' => $m[1], 'link' => $m[2]);
} else {
- $info['author'][] = array('name' => $v);
- }
- } else {
- if (array_key_exists($k, $info)){
- $info[$k] = $v;
+ $info[$k][] = array('name' => $v);
}
+ }
+ else {
+ $info[$k] = $v;
}
}
}
@@ -361,6 +360,51 @@ function get_plugin_info($plugin){
return $info;
}
+function check_plugin_versions($info) {
+
+ if(! is_array($info))
+ return true;
+
+ if(array_key_exists('minversion',$info)) {
+ if(! version_compare(STD_VERSION,trim($info['minversion']), '>=')) {
+ logger('minversion limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING);
+ return false;
+ }
+ }
+ if(array_key_exists('maxversion',$info)) {
+ if(version_compare(STD_VERSION,trim($info['maxversion']), '>')) {
+ logger('maxversion limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING);
+ return false;
+ }
+ }
+ if(array_key_exists('minphpversion',$info)) {
+ if(! version_compare(PHP_VERSION,trim($info['minphpversion']), '>=')) {
+ logger('minphpversion limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING);
+ return false;
+ }
+ }
+
+ if(array_key_exists('requires',$info)) {
+ $arr = explode(',',$info['requires']);
+ $found = true;
+ if($arr) {
+ foreach($arr as $test) {
+ $test = trim($test);
+ if(! $test)
+ continue;
+ if(! in_array($test,get_app()->plugins))
+ $found = false;
+ }
+ }
+ if(! $found)
+ return false;
+ }
+
+ return true;
+}
+
+
+
/**
* @brief Parse theme comment in search of theme infos.
@@ -626,17 +670,6 @@ function get_markup_template($s, $root = '') {
return $template;
}
-// return the standardised version. Since we can't easily compare
-// before the STD_VERSION definition was applied, we have to treat
-// all prior release versions the same. You can dig through them
-// with other means (such as RED_VERSION) if necessary.
-
-function get_std_version() {
- if(defined('STD_VERSION'))
- return STD_VERSION;
- return '0.0.0';
-}
-
function folder_exists($folder)
{
diff --git a/include/poller.php b/include/poller.php
index 031fb4533..808b54ee5 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -205,7 +205,7 @@ function poller_run($argv, $argc){
$keep_reports = intval(get_config('system','expire_delivery_reports'));
if($keep_reports === 0)
- $keep_reports = 30;
+ $keep_reports = 10;
q("delete from dreport where dreport_time < %s - INTERVAL %s",
db_utcnow(),
diff --git a/include/profile_selectors.php b/include/profile_selectors.php
index a80677cb3..9f993f803 100644
--- a/include/profile_selectors.php
+++ b/include/profile_selectors.php
@@ -7,7 +7,7 @@ function gender_selector($current="",$suffix="") {
call_hooks('gender_selector', $select);
- $o .= "<select name=\"gender$suffix\" id=\"gender-select$suffix\" size=\"1\" >";
+ $o .= "<select class=\"form-control\" name=\"gender$suffix\" id=\"gender-select$suffix\" size=\"1\" >";
foreach($select as $selection) {
if($selection !== 'NOTRANSLATION') {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
@@ -24,7 +24,7 @@ function gender_selector_min($current="",$suffix="") {
call_hooks('gender_selector_min', $select);
- $o .= "<select name=\"gender$suffix\" id=\"gender-select$suffix\" size=\"1\" >";
+ $o .= "<select class=\"form-control\" name=\"gender$suffix\" id=\"gender-select$suffix\" size=\"1\" >";
foreach($select as $selection) {
if($selection !== 'NOTRANSLATION') {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
@@ -44,7 +44,7 @@ function sexpref_selector($current="",$suffix="") {
call_hooks('sexpref_selector', $select);
- $o .= "<select name=\"sexual$suffix\" id=\"sexual-select$suffix\" size=\"1\" >";
+ $o .= "<select class=\"form-control\" name=\"sexual$suffix\" id=\"sexual-select$suffix\" size=\"1\" >";
foreach($select as $selection) {
if($selection !== 'NOTRANSLATION') {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
@@ -62,7 +62,7 @@ function sexpref_selector_min($current="",$suffix="") {
call_hooks('sexpref_selector_min', $select);
- $o .= "<select name=\"sexual$suffix\" id=\"sexual-select$suffix\" size=\"1\" >";
+ $o .= "<select class=\"form-control\" name=\"sexual$suffix\" id=\"sexual-select$suffix\" size=\"1\" >";
foreach($select as $selection) {
if($selection !== 'NOTRANSLATION') {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
@@ -81,7 +81,7 @@ function marital_selector($current="",$suffix="") {
call_hooks('marital_selector', $select);
- $o .= "<select name=\"marital\" id=\"marital-select\" size=\"1\" >";
+ $o .= "<select class=\"form-control\" name=\"marital\" id=\"marital-select\" size=\"1\" >";
foreach($select as $selection) {
if($selection !== 'NOTRANSLATION') {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
@@ -98,7 +98,7 @@ function marital_selector_min($current="",$suffix="") {
call_hooks('marital_selector_min', $select);
- $o .= "<select name=\"marital\" id=\"marital-select\" size=\"1\" >";
+ $o .= "<select class=\"form-control\" name=\"marital\" id=\"marital-select\" size=\"1\" >";
foreach($select as $selection) {
if($selection !== 'NOTRANSLATION') {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
diff --git a/include/queue_fn.php b/include/queue_fn.php
index 1e53d7488..676620e2f 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -88,6 +88,7 @@ function queue_deliver($outq, $immediate = false) {
}
}
else {
+
// zot sites should all have a site record, unless they've been dead for as long as
// your site has existed. Since we don't know for sure what these sites are,
// call them unknown
@@ -100,6 +101,11 @@ function queue_deliver($outq, $immediate = false) {
}
}
+ $arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
+ call_hooks('queue_deliver',$arr);
+ if($arr['handled'])
+ return;
+
// "post" queue driver - used for diaspora and friendica-over-diaspora communications.
if($outq['outq_driver'] === 'post') {
@@ -118,11 +124,31 @@ function queue_deliver($outq, $immediate = false) {
dbesc($outq['outq_hash'])
);
remove_queue_item($outq['outq_hash']);
+
+ // server is responding - see if anything else is going to this destination and is piled up
+ // and try to send some more. We're relying on the fact that do_delivery() results in an
+ // immediate delivery otherwise we could get into a queue loop.
+
+ if(! $immediate) {
+ $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
+ dbesc($outq['outq_posturl'])
+ );
+
+ $piled_up = array();
+ if($x) {
+ foreach($x as $xx) {
+ $piled_up[] = $xx['outq_hash'];
+ }
+ }
+ if($piled_up) {
+ do_delivery($piled_up);
+ }
+ }
}
else {
logger('deliver: queue post returned ' . $result['return_code']
. ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
- update_queue_item($argv[$x]);
+ update_queue_item($outq['outq_posturl']);
}
return;
}
diff --git a/include/ratenotif.php b/include/ratenotif.php
index e94f30247..2c636c710 100644
--- a/include/ratenotif.php
+++ b/include/ratenotif.php
@@ -11,7 +11,6 @@ function ratenotif_run($argv, $argc){
$a = get_app();
- require_once("session.php");
require_once("datetime.php");
require_once('include/items.php');
require_once('include/Contact.php');
diff --git a/include/reddav.php b/include/reddav.php
index c592597a9..a0bd1b1fc 100644
--- a/include/reddav.php
+++ b/include/reddav.php
@@ -19,13 +19,13 @@
*/
use Sabre\DAV;
-use RedMatrix\RedDAV;
+use Zotlabs\Storage;
require_once('vendor/autoload.php');
require_once('include/attach.php');
-require_once('include/RedDAV/RedFile.php');
-require_once('include/RedDAV/RedDirectory.php');
-require_once('include/RedDAV/RedBasicAuth.php');
+//require_once('Zotlabs/Storage/File.php');
+//require_once('Zotlabs/Storage/Directory.php');
+//require_once('Zotlabs/Storage/BasicAuth.php');
/**
* @brief Returns an array with viewable channels.
@@ -51,7 +51,7 @@ function RedChannelList(&$auth) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
- $ret[] = new RedDAV\RedDirectory('/cloud/' . $rr['channel_address'], $auth);
+ $ret[] = new Zotlabs\Storage\Directory('/cloud/' . $rr['channel_address'], $auth);
}
}
}
@@ -167,9 +167,9 @@ function RedCollectionData($file, &$auth) {
foreach ($r as $rr) {
//logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
if (intval($rr['is_dir'])) {
- $ret[] = new RedDAV\RedDirectory($path . '/' . $rr['filename'], $auth);
+ $ret[] = new Zotlabs\Storage\Directory($path . '/' . $rr['filename'], $auth);
} else {
- $ret[] = new RedDAV\RedFile($path . '/' . $rr['filename'], $rr, $auth);
+ $ret[] = new Zotlabs\Storage\File($path . '/' . $rr['filename'], $rr, $auth);
}
}
@@ -204,7 +204,7 @@ function RedFileData($file, &$auth, $test = false) {
if ((! $file) || ($file === '/')) {
- return new RedDAV\RedDirectory('/', $auth);
+ return new Zotlabs\Storage\Directory('/', $auth);
}
$file = trim($file, '/');
@@ -274,7 +274,7 @@ function RedFileData($file, &$auth, $test = false) {
if ($test)
return true;
// final component was a directory.
- return new RedDAV\RedDirectory($file, $auth);
+ return new Zotlabs\Storage\Directory($file, $auth);
}
if ($errors) {
@@ -293,9 +293,9 @@ function RedFileData($file, &$auth, $test = false) {
return true;
if (intval($r[0]['is_dir'])) {
- return new RedDAV\RedDirectory($path . '/' . $r[0]['filename'], $auth);
+ return new Zotlabs\Storage\Directory($path . '/' . $r[0]['filename'], $auth);
} else {
- return new RedDAV\RedFile($path . '/' . $r[0]['filename'], $r[0], $auth);
+ return new Zotlabs\Storage\File($path . '/' . $r[0]['filename'], $r[0], $auth);
}
}
return false;
diff --git a/include/security.php b/include/security.php
index d4ebe0024..215cc92cb 100644
--- a/include/security.php
+++ b/include/security.php
@@ -18,20 +18,13 @@ function authenticate_success($user_record, $login_initial = false, $interactive
$_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
+ $lastlog_updated = false;
+
if(x($user_record, 'account_id')) {
$a->account = $user_record;
$_SESSION['account_id'] = $user_record['account_id'];
$_SESSION['authenticated'] = 1;
- if($login_initial || $update_lastlog) {
- q("update account set account_lastlog = '%s' where account_id = %d",
- dbesc(datetime_convert()),
- intval($_SESSION['account_id'])
- );
- $a->account['account_lastlog'] = datetime_convert();
- call_hooks('logged_in', $a->account);
-
- }
$uid_to_load = (((x($_SESSION,'uid')) && (intval($_SESSION['uid'])))
? intval($_SESSION['uid'])
@@ -42,9 +35,19 @@ function authenticate_success($user_record, $login_initial = false, $interactive
change_channel($uid_to_load);
}
+ if($login_initial || $update_lastlog) {
+ q("update account set account_lastlog = '%s' where account_id = %d",
+ dbesc(datetime_convert()),
+ intval($_SESSION['account_id'])
+ );
+ $a->account['account_lastlog'] = datetime_convert();
+ $lastlog_updated = true;
+ call_hooks('logged_in', $a->account);
+ }
+
}
- if($login_initial) {
+ if(($login_initial) && (! $lastlog_updated)) {
call_hooks('logged_in', $user_record);
@@ -145,7 +148,7 @@ function change_channel($change_channel) {
* @return string additional SQL where statement
*/
-function permissions_sql($owner_id, $remote_observer = null) {
+function permissions_sql($owner_id, $remote_observer = null, $table = '') {
$local_channel = local_channel();
@@ -155,10 +158,14 @@ function permissions_sql($owner_id, $remote_observer = null) {
* default permissions - anonymous user
*/
- $sql = " AND allow_cid = ''
- AND allow_gid = ''
- AND deny_cid = ''
- AND deny_gid = ''
+ if($table)
+ $table .= '.';
+
+
+ $sql = " AND {$table}allow_cid = ''
+ AND {$table}allow_gid = ''
+ AND {$table}deny_cid = ''
+ AND {$table}deny_gid = ''
";
/**
@@ -178,7 +185,7 @@ function permissions_sql($owner_id, $remote_observer = null) {
*/
else {
- $observer = (($remote_observer) ? $remote_observer : get_observer_hash());
+ $observer = ((! is_null($remote_observer)) ? $remote_observer : get_observer_hash());
if($observer) {
$groups = init_groups_visitor($observer);
@@ -190,8 +197,8 @@ function permissions_sql($owner_id, $remote_observer = null) {
}
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
- " AND ( NOT (deny_cid like '%s' OR deny_gid $regexop '%s')
- AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '') )
+ " AND ( NOT ({$table}deny_cid like '%s' OR {$table}deny_gid $regexop '%s')
+ AND ( {$table}allow_cid like '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') )
)
",
dbesc(protect_sprintf( '%<' . $observer . '>%')),
diff --git a/include/session.php b/include/session.php
index 92004bc18..43bba528b 100644
--- a/include/session.php
+++ b/include/session.php
@@ -1,4 +1,5 @@
<?php
+
/**
* @file include/session.php
*
@@ -14,8 +15,8 @@ $session_expire = 180000;
function new_cookie($time) {
$old_sid = session_id();
-// ??? This shouldn't have any effect if called after session_start()
-// We probably need to set the session expiration and change the PHPSESSID cookie.
+ // ??? This shouldn't have any effect if called after session_start()
+ // We probably need to set the session expiration and change the PHPSESSID cookie.
session_set_cookie_params($time);
session_regenerate_id(false);
@@ -108,8 +109,9 @@ ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_httponly', 1);
/*
- * PHP function which sets our user-level session storage functions.
+ * Set our session storage functions.
*/
+
session_set_save_handler(
'ref_session_open',
'ref_session_close',
@@ -117,4 +119,17 @@ session_set_save_handler(
'ref_session_write',
'ref_session_destroy',
'ref_session_gc'
-); \ No newline at end of file
+);
+
+
+ // Force cookies to be secure (https only) if this site is SSL enabled. Must be done before session_start().
+
+ if(intval(get_app()->config['system']['ssl_cookie_protection'])) {
+ $arr = session_get_cookie_params();
+ session_set_cookie_params(
+ ((isset($arr['lifetime'])) ? $arr['lifetime'] : 0),
+ ((isset($arr['path'])) ? $arr['path'] : '/'),
+ ((isset($arr['domain'])) ? $arr['domain'] : get_app()->get_hostname()),
+ ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
+ ((isset($arr['httponly'])) ? $arr['httponly'] : true));
+ } \ No newline at end of file
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 0bf89a7c1..5ef106938 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -398,16 +398,17 @@ function get_things($profile_hash,$uid) {
$things[$k] = null;
foreach($r as $rr) {
- $l = q("select xchan_name, xchan_url from likes left join xchan on likee = xchan_hash where
+ $l = q("select xchan_name, xchan_photo_s, xchan_url from likes left join xchan on likee = xchan_hash where
target_type = '%s' and target_id = '%s' and channel_id = %d",
dbesc(ACTIVITY_OBJ_THING),
dbesc($rr['obj_obj']),
intval($uid)
);
- for($x = 0; $x < count($l); $x ++)
+ for($x = 0; $x < count($l); $x ++) {
$l[$x]['xchan_url'] = zid($l[$x]['xchan_url']);
-
+ $l[$x]['xchan_photo_s'] = zid($l[$x]['xchan_photo_s']);
+ }
if(! $things[$rr['obj_verb']])
$things[$rr['obj_verb']] = array();
diff --git a/include/text.php b/include/text.php
index dd52b16b6..621f4cf93 100644
--- a/include/text.php
+++ b/include/text.php
@@ -536,9 +536,10 @@ function attribute_contains($attr, $s) {
*
* @param string $msg Message to log
* @param int $level A log level.
+ * @param int $priority - compatible with syslog
*/
-function logger($msg, $level = 0) {
+function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
// turn off logger in install mode
global $a;
global $db;
@@ -559,8 +560,8 @@ function logger($msg, $level = 0) {
$where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': ';
}
- $s = datetime_convert() . ':' . session_id() . ' ' . $where . $msg . PHP_EOL;
- $pluginfo = array('filename' => $logfile, 'loglevel' => $level, 'message' => $s,'logged' => false);
+ $s = datetime_convert() . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL;
+ $pluginfo = array('filename' => $logfile, 'loglevel' => $level, 'message' => $s,'priority' => $priority, 'logged' => false);
call_hooks('logger',$pluginfo);
@@ -568,6 +569,23 @@ function logger($msg, $level = 0) {
@file_put_contents($pluginfo['filename'], $pluginfo['message'], FILE_APPEND);
}
+function log_priority_str($priority) {
+ $parr = array(
+ LOG_EMERG => 'LOG_EMERG',
+ LOG_ALERT => 'LOG_ALERT',
+ LOG_CRIT => 'LOG_CRIT',
+ LOG_ERR => 'LOG_ERR',
+ LOG_WARNING => 'LOG_WARNING',
+ LOG_NOTICE => 'LOG_NOTICE',
+ LOG_INFO => 'LOG_INFO',
+ LOG_DEBUG => 'LOG_DEBUG'
+ );
+
+ if($parr[$priority])
+ return $parr[$priority];
+ return 'LOG_UNDEFINED';
+}
+
/**
* @brief This is a special logging facility for developers.
*
@@ -794,7 +812,7 @@ function contact_block() {
);
if(count($r)) {
- $contacts = sprintf( tt('%d Connection','%d Connections', $total),$total);
+ $contacts = t('Connections');
$micropro = Array();
foreach($r as $rr) {
$rr['archived'] = (intval($rr['abook_archived']) ? true : false);
@@ -807,7 +825,7 @@ function contact_block() {
$o = replace_macros($tpl, array(
'$contacts' => $contacts,
'$nickname' => $a->profile['channel_address'],
- '$viewconnections' => t('View Connections'),
+ '$viewconnections' => (($total > $shown) ? sprintf(t('View all %s connections'),$total) : ''),
'$micropro' => $micropro,
));
@@ -950,16 +968,24 @@ function get_poke_verbs() {
// index is present tense verb
// value is array containing past tense verb, translation of present, translation of past
- $arr = array(
- 'poke' => array( 'poked', t('poke'), t('poked')),
- 'ping' => array( 'pinged', t('ping'), t('pinged')),
- 'prod' => array( 'prodded', t('prod'), t('prodded')),
- 'slap' => array( 'slapped', t('slap'), t('slapped')),
- 'finger' => array( 'fingered', t('finger'), t('fingered')),
- 'rebuff' => array( 'rebuffed', t('rebuff'), t('rebuffed')),
- );
+ if(get_config('system','poke_basic')) {
+ $arr = array(
+ 'poke' => array( 'poked', t('poke'), t('poked')),
+ );
+ }
+ else {
+ $arr = array(
+ 'poke' => array( 'poked', t('poke'), t('poked')),
+ 'ping' => array( 'pinged', t('ping'), t('pinged')),
+ 'prod' => array( 'prodded', t('prod'), t('prodded')),
+ 'slap' => array( 'slapped', t('slap'), t('slapped')),
+ 'finger' => array( 'fingered', t('finger'), t('fingered')),
+ 'rebuff' => array( 'rebuffed', t('rebuff'), t('rebuffed')),
+ );
+
+ call_hooks('poke_verbs', $arr);
+ }
- call_hooks('poke_verbs', $arr);
return $arr;
}
@@ -972,7 +998,7 @@ function get_mood_verbs() {
'tired' => t('tired'),
'perky' => t('perky'),
'angry' => t('angry'),
- 'stupefied' => t('stupified'),
+ 'stupefied' => t('stupefied'),
'puzzled' => t('puzzled'),
'interested' => t('interested'),
'bitter' => t('bitter'),
@@ -1418,7 +1444,7 @@ function prepare_body(&$item,$attach = false) {
call_hooks('prepare_body_init', $item);
-
+ $s = '';
$photo = '';
$is_photo = ((($item['verb'] === ACTIVITY_POST) && ($item['obj_type'] === ACTIVITY_OBJ_PHOTO)) ? true : false);
@@ -1428,7 +1454,7 @@ function prepare_body(&$item,$attach = false) {
// if original photo width is <= 640px prepend it to item body
if($object['link'][0]['width'] && $object['link'][0]['width'] <= 640) {
- $s = '<div class="inline-photo-item-wrapper"><a href="' . zid(rawurldecode($object['id'])) . '" target="_blank"><img class="inline-photo-item" style="max-width:' . $object['link'][0]['width'] . 'px; width:100%; height:auto;" src="' . zid(rawurldecode($object['link'][0]['href'])) . '"></a></div>' . $s;
+ $s .= '<div class="inline-photo-item-wrapper"><a href="' . zid(rawurldecode($object['id'])) . '" target="_blank"><img class="inline-photo-item" style="max-width:' . $object['link'][0]['width'] . 'px; width:100%; height:auto;" src="' . zid(rawurldecode($object['link'][0]['href'])) . '"></a></div>' . $s;
}
// if original photo width is > 640px make it a cover photo
@@ -1438,7 +1464,7 @@ function prepare_body(&$item,$attach = false) {
}
}
- $s = prepare_text($item['body'],$item['mimetype'], false);
+ $s .= prepare_text($item['body'],$item['mimetype'], false);
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event($item['object']) : false);
@@ -2698,5 +2724,67 @@ function item_url_replace($channel,&$item,$old,$new) {
$item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey']));
$item['item_verified'] = 1;
}
+
+ // @fixme item['plink'] and item['llink']
+
+}
+
+
+/**
+ * @brief Used to wrap ACL elements in angle brackets for storage.
+ *
+ * @param[in,out] array &$item
+ */
+function sanitise_acl(&$item) {
+ if (strlen($item))
+ $item = '<' . notags(trim($item)) . '>';
+ else
+ unset($item);
+}
+
+/**
+ * @brief Convert an ACL array to a storable string.
+ *
+ * @param array $p
+ * @return array
+ */
+function perms2str($p) {
+ $ret = '';
+
+ if (is_array($p))
+ $tmp = $p;
+ else
+ $tmp = explode(',', $p);
+
+ if (is_array($tmp)) {
+ array_walk($tmp, 'sanitise_acl');
+ $ret = implode('', $tmp);
+ }
+
+ return $ret;
+}
+
+
+/**
+ * @brief Turn user/group ACLs stored as angle bracketed text into arrays.
+ *
+ * turn string array of angle-bracketed elements into string array
+ * e.g. "<123xyz><246qyo><sxo33e>" => array(123xyz,246qyo,sxo33e);
+ *
+ * @param string $s
+ * @return array
+ */
+function expand_acl($s) {
+ $ret = array();
+
+ if(strlen($s)) {
+ $t = str_replace('<','',$s);
+ $a = explode('>',$t);
+ foreach($a as $aa) {
+ if($aa)
+ $ret[] = $aa;
+ }
+ }
+ return $ret;
}
diff --git a/include/widgets.php b/include/widgets.php
index 4b14d6c94..0d31133e7 100644
--- a/include/widgets.php
+++ b/include/widgets.php
@@ -8,7 +8,7 @@
require_once('include/dir_fns.php');
require_once('include/contact_widgets.php');
require_once('include/attach.php');
-
+require_once('include/Contact.php');
function widget_profile($args) {
$a = get_app();
@@ -16,6 +16,16 @@ function widget_profile($args) {
return profile_sidebar($a->profile, $block, true);
}
+function widget_zcard($args) {
+ $a = get_app();
+ $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
+ $channel = channelx_by_n($a->profile_uid);
+ return get_zcard($channel,get_observer_hash(),array('width' => 875));
+}
+
+
+
+
// FIXME The problem with the next widget is that we don't have a search function for webpages that we can send the links to.
// Then we should also provide an option to search webpages and conversations.
@@ -170,8 +180,8 @@ function widget_follow($args) {
}
return replace_macros(get_markup_template('follow.tpl'),array(
'$connect' => t('Add New Connection'),
- '$desc' => t('Enter the channel address'),
- '$hint' => t('Example: bob@example.com, http://example.com/barbara'),
+ '$desc' => t('Enter channel address'),
+ '$hint' => t('Examples: bob@example.com, https://example.com/barbara'),
'$follow' => t('Connect'),
'$abook_usage_message' => $abook_usage_message
));
@@ -369,6 +379,17 @@ function widget_fullprofile($arr) {
return profile_sidebar($a->profile, $block);
}
+function widget_shortprofile($arr) {
+ $a = get_app();
+ if(! $a->profile['profile_uid'])
+ return;
+
+ $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
+
+ return profile_sidebar($a->profile, $block, true, true);
+}
+
+
function widget_categories($arr) {
$a = get_app();
@@ -493,37 +514,42 @@ function widget_settings_menu($arr) {
'selected' => ((argv(1) === 'channel') ? 'active' : ''),
),
- array(
- 'label' => t('Additional features'),
- 'url' => $a->get_baseurl(true).'/settings/features',
- 'selected' => ((argv(1) === 'features') ? 'active' : ''),
- ),
+ );
- array(
- 'label' => t('Feature/Addon settings'),
- 'url' => $a->get_baseurl(true).'/settings/featured',
- 'selected' => ((argv(1) === 'featured') ? 'active' : ''),
- ),
+ if(get_features()) {
+ $tabs[] = array(
+ 'label' => t('Additional features'),
+ 'url' => $a->get_baseurl(true).'/settings/features',
+ 'selected' => ((argv(1) === 'features') ? 'active' : ''),
+ );
+ }
- array(
- 'label' => t('Display settings'),
- 'url' => $a->get_baseurl(true).'/settings/display',
- 'selected' => ((argv(1) === 'display') ? 'active' : ''),
- ),
+ $tabs[] = array(
+ 'label' => t('Feature/Addon settings'),
+ 'url' => $a->get_baseurl(true).'/settings/featured',
+ 'selected' => ((argv(1) === 'featured') ? 'active' : ''),
+ );
- array(
- 'label' => t('Connected apps'),
- 'url' => $a->get_baseurl(true) . '/settings/oauth',
- 'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
- ),
+ $tabs[] = array(
+ 'label' => t('Display settings'),
+ 'url' => $a->get_baseurl(true).'/settings/display',
+ 'selected' => ((argv(1) === 'display') ? 'active' : ''),
+ );
- array(
+ $tabs[] = array(
+ 'label' => t('Connected apps'),
+ 'url' => $a->get_baseurl(true) . '/settings/oauth',
+ 'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
+ );
+
+ // IF can go away when UNO export and import is fully functional
+ if(! UNO) {
+ $tabs[] = array(
'label' => t('Export channel'),
'url' => $a->get_baseurl(true) . '/uexport',
'selected' => ''
- ),
-
- );
+ );
+ }
if($role === false || $role === 'custom') {
$tabs[] = array(
@@ -804,21 +830,39 @@ function widget_suggestedchats($arr) {
}
function widget_item($arr) {
- // FIXME there is no $a here
- $uid = $a->profile['profile_uid'];
- if((! $uid) || (! $arr['mid']))
+
+ $channel_id = 0;
+ if(array_key_exists('channel_id',$arr) && intval($arr['channel_id']))
+ $channel_id = intval($arr['channel_id']);
+ if(! $channel_id)
+ $channel_id = get_app()->profile_uid;
+ if(! $channel_id)
return '';
- if(! perm_is_allowed($uid, get_observer_hash(), 'view_pages'))
+
+ if((! $arr['mid']) && (! $arr['title']))
return '';
- require_once('include/security.php');
- $sql_extra = item_permissions_sql($uid);
+ if(! perm_is_allowed($channel_id, get_observer_hash(), 'view_pages'))
+ return '';
- $r = q("select * from item where mid = '%s' and uid = %d and item_type = " . intval(ITEM_TYPE_WEBPAGE) . " $sql_extra limit 1",
- dbesc($arr['mid']),
- intval($uid)
- );
+ require_once('include/security.php');
+ $sql_extra = item_permissions_sql($channel_id);
+
+ if($arr['title']) {
+ $r = q("select item.* from item left join item_id on item.id = item_id.iid
+ where item.uid = %d and sid = '%s' and service = 'WEBPAGE' and item_type = %d $sql_options $revision limit 1",
+ intval($channel_id),
+ dbesc($arr['title']),
+ intval(ITEM_TYPE_WEBPAGE)
+ );
+ }
+ else {
+ $r = q("select * from item where mid = '%s' and uid = %d and item_type = " . intval(ITEM_TYPE_WEBPAGE) . " $sql_extra limit 1",
+ dbesc($arr['mid']),
+ intval($channel_id)
+ );
+ }
if(! $r)
return '';
@@ -912,8 +956,8 @@ function widget_photo($arr) {
// ensure they can't sneak in an eval(js) function
- if(strpos($style,'(') !== false)
- return '';
+ if(strpbrk($style,'(\'"<>') !== false)
+ $style = '';
if(array_key_exists('zrl', $arr) && isset($arr['zrl']))
$zrl = (($arr['zrl']) ? true : false);
@@ -933,6 +977,59 @@ function widget_photo($arr) {
}
+function widget_cover_photo($arr) {
+
+ require_once('include/identity.php');
+ $o = '';
+
+ $a = get_app();
+
+ $channel_id = 0;
+ if(array_key_exists('channel_id', $arr) && intval($arr['channel_id']))
+ $channel_id = intval($arr['channel_id']);
+ if(! $channel_id)
+ $channel_id = $a->profile_uid;
+ if(! $channel_id)
+ return '';
+
+ $channel = channelx_by_n($channel_id);
+
+ if(array_key_exists('style', $arr) && isset($arr['style']))
+ $style = $arr['style'];
+ else
+ $style = 'width:100%; height: auto;';
+
+ // ensure they can't sneak in an eval(js) function
+
+ if(strpbrk($style,'(\'"<>') !== false)
+ $style = '';
+
+ if(array_key_exists('title', $arr) && isset($arr['title']))
+ $title = $arr['title'];
+ else
+ $title = $channel['channel_name'];
+
+ if(array_key_exists('subtitle', $arr) && isset($arr['subtitle']))
+ $subtitle = $arr['subtitle'];
+ else
+ $subtitle = $channel['xchan_addr'];
+
+ $c = get_cover_photo($channel_id,'html');
+
+ if($c) {
+ $photo_html = (($style) ? str_replace('alt=',' style="' . $style . '" alt=',$c) : $c);
+
+ $o = replace_macros(get_markup_template('cover_photo_widget.tpl'),array(
+ '$photo_html' => $photo_html,
+ '$title' => $title,
+ '$subtitle' => $subtitle,
+ '$hovertitle' => t('Click to show more'),
+ ));
+ }
+ return $o;
+}
+
+
function widget_photo_rand($arr) {
require_once('include/photos.php');
@@ -1075,16 +1172,18 @@ function widget_rating($arr) {
}
+
+ $o = '<div class="widget">';
+ $o .= '<h3>' . t('Rating Tools') . '</h3>';
+
if((($remote) || (local_channel())) && (! $self)) {
- $o = '<div class="widget rateme">';
if($remote)
- $o .= '<a class="rateme" href="' . $url . '"><i class="icon-pencil"></i> ' . t('Rate Me') . '</a>';
+ $o .= '<a class="btn btn-block btn-primary btn-sm" href="' . $url . '"><i class="icon-pencil"></i> ' . t('Rate Me') . '</a>';
else
- $o .= '<div class="rateme fakelink" onclick="doRatings(\'' . $hash . '\'); return false;"><i class="icon-pencil"></i> ' . t('Rate Me') . '</div>';
- $o .= '</div>';
+ $o .= '<div class="btn btn-block btn-primary btn-sm" onclick="doRatings(\'' . $hash . '\'); return false;"><i class="icon-pencil"></i> ' . t('Rate Me') . '</div>';
}
- $o .= '<div class="widget rateme"><a class="rateme" href="ratings/' . $hash . '"><i class="icon-eye-open"></i> ' . t('View Ratings') . '</a>';
+ $o .= '<a class="btn btn-block btn-default btn-sm" href="ratings/' . $hash . '"><i class="icon-eye-open"></i> ' . t('View Ratings') . '</a>';
$o .= '</div>';
return $o;
@@ -1119,7 +1218,7 @@ function widget_forums($arr) {
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
- $r1 = q("select * from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and abook_channel = %d order by xchan_name $limit ",
+ $r1 = q("select * from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ",
intval(PERMS_W_TAGWALL),
intval(PERMS_W_STREAM),
intval(local_channel())
@@ -1214,10 +1313,12 @@ function widget_admin($arr) {
'site' => array(z_root() . '/admin/site/', t('Site'), 'site'),
'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users'),
'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'),
+ 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'),
+ 'features' => array(z_root() . '/admin/features/', t('Features'), 'features'),
'plugins' => array(z_root() . '/admin/plugins/', t('Plugins'), 'plugins'),
'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'),
'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'),
- 'profs' => array(z_root() . '/admin/profs', t('Profile Config'), 'profs'),
+ 'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'),
'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync')
);
diff --git a/include/zot.php b/include/zot.php
index 922637bc1..a60a50d8f 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -11,7 +11,6 @@
require_once('include/crypto.php');
require_once('include/items.php');
require_once('include/hubloc.php');
-require_once('include/DReport.php');
require_once('include/queue_fn.php');
@@ -142,7 +141,7 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot
$data[$k] = $v;
}
- logger('zot_build_packet: ' . print_r($data,true), LOGGER_DATA);
+ logger('zot_build_packet: ' . print_r($data,true), LOGGER_DATA, LOG_DEBUG);
// Hush-hush ultra top-secret mode
@@ -194,7 +193,7 @@ function zot_finger($webbie, $channel = null, $autofallback = true) {
logger('zot_finger: no address :' . $webbie);
return array('success' => false);
}
- logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA);
+ logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG);
// potential issue here; the xchan_addr points to the primary hub.
// The webbie we were called with may not, so it might not be found
@@ -211,7 +210,7 @@ function zot_finger($webbie, $channel = null, $autofallback = true) {
if ($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') {
logger('zot_finger: alternate network: ' . $webbie);
- logger('url: '.$url.', net: '.var_export($r[0]['hubloc_network'],true), LOGGER_DATA);
+ logger('url: '.$url.', net: '.var_export($r[0]['hubloc_network'],true), LOGGER_DATA, LOG_DEBUG);
return array('success' => false);
}
} else {
@@ -288,9 +287,9 @@ function zot_refresh($them, $channel = null, $force = false) {
return true;
}
- logger('zot_refresh: them: ' . print_r($them,true), LOGGER_DATA);
+ logger('zot_refresh: them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG);
if ($channel)
- logger('zot_refresh: channel: ' . print_r($channel,true), LOGGER_DATA);
+ logger('zot_refresh: channel: ' . print_r($channel,true), LOGGER_DATA, LOG_DEBUG);
$url = null;
@@ -353,7 +352,7 @@ function zot_refresh($them, $channel = null, $force = false) {
$result = z_post_url($url . $rhs,$postvars);
- logger('zot_refresh: zot-info: ' . print_r($result,true), LOGGER_DATA);
+ logger('zot_refresh: zot-info: ' . print_r($result,true), LOGGER_DATA, LOG_DEBUG);
if ($result['success']) {
@@ -381,7 +380,7 @@ function zot_refresh($them, $channel = null, $force = false) {
$channel['channel_prvkey']);
if($permissions)
$permissions = json_decode($permissions,true);
- logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA);
+ logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA, LOG_DEBUG);
}
else
$permissions = $j['permissions'];
@@ -523,6 +522,11 @@ function zot_refresh($them, $channel = null, $force = false) {
unset($new_connection[0]['abook_id']);
unset($new_connection[0]['abook_account']);
unset($new_connection[0]['abook_channel']);
+
+ $abconfig = load_abconfig($channel['channel_hash'],$new_connection['abook_xchan']);
+ if($abconfig)
+ $new_connection['abconfig'] = $abconfig;
+
build_sync_packet($channel['channel_id'], array('abook' => $new_connection));
}
}
@@ -614,7 +618,7 @@ function zot_register_hub($arr) {
$x = z_fetch_url($url);
- logger('zot_register_hub: ' . print_r($x,true), LOGGER_DATA);
+ logger('zot_register_hub: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
if($x['success']) {
$record = json_decode($x['body'],true);
@@ -754,8 +758,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
dbesc($xchan_hash)
);
- logger('import_xchan: update: existing: ' . print_r($r[0],true), LOGGER_DATA);
- logger('import_xchan: update: new: ' . print_r($arr,true), LOGGER_DATA);
+ logger('import_xchan: update: existing: ' . print_r($r[0],true), LOGGER_DATA, LOG_DEBUG);
+ logger('import_xchan: update: new: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
$what .= 'xchan ';
$changed = true;
}
@@ -955,7 +959,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$ret['hash'] = $xchan_hash;
}
- logger('import_xchan: result: ' . print_r($ret,true), LOGGER_DATA);
+ logger('import_xchan: result: ' . print_r($ret,true), LOGGER_DATA, LOG_DEBUG);
return $ret;
}
@@ -980,7 +984,7 @@ function zot_process_response($hub, $arr, $outq) {
if (! $x) {
logger('zot_process_response: No json from ' . $hub);
- logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA);
+ logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA, LOG_DEBUG);
}
if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) {
@@ -1015,7 +1019,7 @@ function zot_process_response($hub, $arr, $outq) {
// async messages remain in the queue until processed.
if(intval($outq['outq_async']))
- queue_set_delivered($outq['outq_hash'],$outq['outq_channel']);
+ remove_queue_item($outq['outq_hash'],$outq['outq_channel']);
logger('zot_process_response: ' . print_r($x,true), LOGGER_DEBUG);
}
@@ -1037,7 +1041,7 @@ function zot_process_response($hub, $arr, $outq) {
*/
function zot_fetch($arr) {
- logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA);
+ logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
$url = $arr['sender']['url'] . $arr['callback'];
@@ -1134,7 +1138,7 @@ function zot_import($arr, $sender_url) {
$i['notify'] = json_decode(crypto_unencapsulate($i['notify'],get_config('system','prvkey')),true);
}
- logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA);
+ logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA, LOG_DEBUG);
$hub = zot_gethub($i['notify']['sender']);
if((! $hub) || ($hub['hubloc_url'] != $sender_url)) {
@@ -1151,7 +1155,7 @@ function zot_import($arr, $sender_url) {
if(array_key_exists('message',$i) && array_key_exists('type',$i['message']) && $i['message']['type'] === 'rating') {
// rating messages are processed only by directory servers
- logger('Rating received: ' . print_r($arr,true), LOGGER_DATA);
+ logger('Rating received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
$result = process_rating_delivery($i['notify']['sender'],$i['message']);
continue;
}
@@ -1261,8 +1265,8 @@ function zot_import($arr, $sender_url) {
continue;
}
- logger('Activity received: ' . print_r($arr,true), LOGGER_DATA);
- logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA);
+ logger('Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
$relay = ((array_key_exists('flags',$i['message']) && in_array('relay',$i['message']['flags'])) ? true : false);
$result = process_delivery($i['notify']['sender'],$arr,$deliveries,$relay,false,$message_request);
@@ -1270,16 +1274,16 @@ function zot_import($arr, $sender_url) {
elseif($i['message']['type'] === 'mail') {
$arr = get_mail_elements($i['message']);
- logger('Mail received: ' . print_r($arr,true), LOGGER_DATA);
- logger('Mail recipients: ' . print_r($deliveries,true), LOGGER_DATA);
+ logger('Mail received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Mail recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
$result = process_mail_delivery($i['notify']['sender'],$arr,$deliveries);
}
elseif($i['message']['type'] === 'profile') {
$arr = get_profile_elements($i['message']);
- logger('Profile received: ' . print_r($arr,true), LOGGER_DATA);
- logger('Profile recipients: ' . print_r($deliveries,true), LOGGER_DATA);
+ logger('Profile received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Profile recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
$result = process_profile_delivery($i['notify']['sender'],$arr,$deliveries);
}
@@ -1288,16 +1292,16 @@ function zot_import($arr, $sender_url) {
$arr = $i['message'];
- logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA);
- logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA);
+ logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
$result = process_channel_sync_delivery($i['notify']['sender'],$arr,$deliveries);
}
elseif($i['message']['type'] === 'location') {
$arr = $i['message'];
- logger('Location message received: ' . print_r($arr,true), LOGGER_DATA);
- logger('Location message recipients: ' . print_r($deliveries,true), LOGGER_DATA);
+ logger('Location message received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Location message recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
$result = process_location_delivery($i['notify']['sender'],$arr,$deliveries);
}
@@ -1483,7 +1487,7 @@ function public_recips($msg) {
}
}
- logger('public_recips: ' . print_r($r,true), LOGGER_DATA);
+ logger('public_recips: ' . print_r($r,true), LOGGER_DATA, LOG_DEBUG);
return $r;
}
@@ -1501,7 +1505,7 @@ function public_recips($msg) {
*/
function allowed_public_recips($msg) {
- logger('allowed_public_recips: ' . print_r($msg,true),LOGGER_DATA);
+ logger('allowed_public_recips: ' . print_r($msg,true),LOGGER_DATA, LOG_DEBUG);
if(array_key_exists('public_scope',$msg['message']))
$scope = $msg['message']['public_scope'];
@@ -1589,7 +1593,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
foreach($deliveries as $d) {
$local_public = $public;
- $DR = new DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
+ $DR = new Zotlabs\Zot\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
@@ -2068,7 +2072,7 @@ function process_mail_delivery($sender, $arr, $deliveries) {
foreach($deliveries as $d) {
- $DR = new DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
+ $DR = new Zotlabs\Zot\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
@@ -2868,12 +2872,15 @@ function import_site($arr, $pubkey) {
*/
function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
+ if(UNO)
+ return;
+
$a = get_app();
logger('build_sync_packet');
if($packet)
- logger('packet: ' . print_r($packet, true),LOGGER_DATA);
+ logger('packet: ' . print_r($packet, true),LOGGER_DATA, LOG_DEBUG);
if(! $uid)
$uid = local_channel();
@@ -2967,7 +2974,9 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
$interval = ((get_config('system','delivery_interval') !== false)
? intval(get_config('system','delivery_interval')) : 2 );
- logger('build_sync_packet: packet: ' . print_r($info,true), LOGGER_DATA);
+ logger('build_sync_packet: packet: ' . print_r($info,true), LOGGER_DATA, LOG_DEBUG);
+
+ $total = count($synchubs);
foreach($synchubs as $hub) {
$hash = random_string();
@@ -2982,7 +2991,9 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
));
proc_run('php', 'include/deliver.php', $hash);
- if($interval)
+ $total = $total - 1;
+
+ if($interval && $total)
@time_sleep_until(microtime(true) + (float) $interval);
}
}
@@ -2997,6 +3008,9 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
*/
function process_channel_sync_delivery($sender, $arr, $deliveries) {
+ if(UNO)
+ return;
+
require_once('include/import.php');
/** @FIXME this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic. */
@@ -3115,6 +3129,11 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
foreach($arr['abook'] as $abook) {
+ $abconfig = null;
+
+ if(array_key_exists('abconfig',$abook) && is_array($abook['abconfig']) && count($abook['abconfig']))
+ $abconfig = $abook['abconfig'];
+
if(! array_key_exists('abook_blocked',$abook)) {
// convert from redmatrix
$abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001) ? 1 : 0);
@@ -3186,8 +3205,9 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
logger('process_channel_sync_delivery: total_feeds service class limit exceeded');
continue;
}
- q("insert into abook ( abook_xchan, abook_channel ) values ('%s', %d ) ",
+ q("insert into abook ( abook_xchan, abook_account, abook_channel ) values ('%s', %d, %d ) ",
dbesc($clean['abook_xchan']),
+ intval($channel['channel_account_id']),
intval($channel['channel_id'])
);
$total_friends ++;
@@ -3204,8 +3224,13 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
}
}
-
-
+ if($abconfig) {
+ // @fixme does not handle sync of del_abconfig
+ foreach($abconfig as $abc) {
+ if($abc['chan'] === $channel['channel_hash'])
+ set_abconfig($abc['chan'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
+ }
+ }
}
}
@@ -3403,14 +3428,12 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
// we should probably do this for all items, but usually we only send one.
- require_once('include/DReport.php');
-
if(array_key_exists('item',$arr) && is_array($arr['item'][0])) {
- $DR = new DReport(z_root(),$d['hash'],$d['hash'],$arr['item'][0]['message_id'],'channel sync processed');
+ $DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],$arr['item'][0]['message_id'],'channel sync processed');
$DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
}
else
- $DR = new DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
+ $DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
$result[] = $DR->get();
@@ -3828,7 +3851,7 @@ function zotinfo($arr) {
$ret['site']['channels'] = channel_total();
- $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']';
+ $ret['site']['version'] = Zotlabs\Project\System::get_platform_name() . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']';
$ret['site']['admin'] = get_config('system','admin_email');
@@ -3848,7 +3871,7 @@ function zotinfo($arr) {
$ret['site']['sellpage'] = get_config('system','sellpage');
$ret['site']['location'] = get_config('system','site_location');
$ret['site']['realm'] = get_directory_realm();
- $ret['site']['project'] = PLATFORM_NAME;
+ $ret['site']['project'] = Zotlabs\Project\System::get_platform_name();
}
@@ -3864,7 +3887,7 @@ function zotinfo($arr) {
function check_zotinfo($channel,$locations,&$ret) {
-// logger('locations: ' . print_r($locations,true),LOGGER_DATA);
+// logger('locations: ' . print_r($locations,true),LOGGER_DATA, LOG_DEBUG);
// This function will likely expand as we find more things to detect and fix.
// 1. Because magic-auth is reliant on it, ensure that the system channel has a valid hubloc
@@ -3924,6 +3947,9 @@ function check_zotinfo($channel,$locations,&$ret) {
function delivery_report_is_storable($dr) {
+ if(get_config('system','disable_dreport'))
+ return false;
+
call_hooks('dreport_is_storable',$dr);
// let plugins accept or reject - if neither, continue on
@@ -4085,7 +4111,7 @@ function zot_reply_pickup($data) {
$sitekey = $hubsite['hubloc_sitekey'];
- logger('mod_zot: Checking sitekey: ' . $sitekey, LOGGER_DATA);
+ logger('mod_zot: Checking sitekey: ' . $sitekey, LOGGER_DATA, LOG_DEBUG);
if(rsa_verify($data['callback'],base64url_decode($data['callback_sig']),$sitekey)) {
$forgery = false;