diff options
author | Paolo Tacconi <p.tacconi@giunti.it> | 2016-04-15 09:22:27 +0200 |
---|---|---|
committer | Paolo Tacconi <p.tacconi@giunti.it> | 2016-04-15 09:22:27 +0200 |
commit | c38c79d71c8ef70ef649f83e322f1984b75ee2dd (patch) | |
tree | 958fcd22f04546f40b6ac68bb58cfe1a1b1fb7f6 /include | |
parent | 1806da0851dd5cf5978b19d12783ae3101a11257 (diff) | |
parent | 45a854762b451dafb882bc56efce054b64420627 (diff) | |
download | volse-hubzilla-c38c79d71c8ef70ef649f83e322f1984b75ee2dd.tar.gz volse-hubzilla-c38c79d71c8ef70ef649f83e322f1984b75ee2dd.tar.bz2 volse-hubzilla-c38c79d71c8ef70ef649f83e322f1984b75ee2dd.zip |
Merge branch 'redmatrix-master'
Diffstat (limited to 'include')
70 files changed, 3604 insertions, 3373 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/BaseObject.php b/include/BaseObject.php index 4bfac5fa0..a88978a83 100644 --- a/include/BaseObject.php +++ b/include/BaseObject.php @@ -1,4 +1,5 @@ <?php /** @file */ + if(class_exists('BaseObject')) return; diff --git a/include/Contact.php b/include/Contact.php index 3bd5f9936..e011c60c8 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -75,12 +75,12 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') { $a = get_app(); if(! $xchan) { - if($a->poi) { - $xchan = $a->poi; + if(App::$poi) { + $xchan = App::$poi; } - elseif(is_array($a->profile) && $a->profile['channel_hash']) { + elseif(is_array(App::$profile) && App::$profile['channel_hash']) { $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($a->profile['channel_hash']) + dbesc(App::$profile['channel_hash']) ); if($r) $xchan = $r[0]; @@ -102,7 +102,7 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') { } if(array_key_exists('channel_id',$xchan)) - $a->profile_uid = $xchan['channel_id']; + App::$profile_uid = $xchan['channel_id']; $url = (($observer) ? z_root() . '/magic?f=&dest=' . $xchan['xchan_url'] . '&addr=' . $xchan['xchan_addr'] @@ -111,7 +111,7 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') { return replace_macros(get_markup_template('xchan_vcard.tpl'),array( '$name' => $xchan['xchan_name'], - '$photo' => ((is_array($a->profile) && array_key_exists('photo',$a->profile)) ? $a->profile['photo'] : $xchan['xchan_photo_l']), + '$photo' => ((is_array(App::$profile) && array_key_exists('photo',App::$profile)) ? App::$profile['photo'] : $xchan['xchan_photo_l']), '$follow' => $xchan['xchan_addr'], '$link' => zid($xchan['xchan_url']), '$connect' => $connect, @@ -235,7 +235,7 @@ function account_remove($account_id,$local = true,$unset_session=true) { unset($_SESSION['authenticated']); unset($_SESSION['uid']); notice( sprintf(t("User '%s' deleted"),$account_email) . EOL); - goaway(get_app()->get_baseurl()); + goaway(z_root()); } return $r; @@ -263,7 +263,7 @@ function rrmdir($path) return false; } -function channel_remove($channel_id, $local = true, $unset_session=true) { +function channel_remove($channel_id, $local = true, $unset_session=false) { if(! $channel_id) return; @@ -331,25 +331,25 @@ 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) { + if(App::$account['account_default_channel'] == $channel_id) { $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 limit 1", - intval($a->account['account_id']), + intval(App::$account['account_id']), intval(PAGE_REMOVED)); if ($r) { $rr = q("update account set account_default_channel = %d where account_id = %d", intval($r[0]['channel_id']), - intval($a->account['account_id'])); + intval(App::$account['account_id'])); logger("Default channel deleted, changing default to channel_id " . $r[0]['channel_id']); } 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(App::$account['account_id']) + ); } } - logger('deleting hublocs',LOGGER_DEBUG); $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s' and hubloc_url = '%s' ", @@ -389,9 +389,8 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { proc_run('php','include/directory.php',$channel_id); if($channel_id == local_channel() && $unset_session) { - unset($_SESSION['authenticated']); - unset($_SESSION['uid']); - goaway($a->get_baseurl()); + \Zotlabs\Web\Session::nuke(); + goaway(z_root()); } } diff --git a/include/ConversationObject.php b/include/ConversationObject.php index 7e0d67c10..82f381b0c 100644 --- a/include/ConversationObject.php +++ b/include/ConversationObject.php @@ -15,6 +15,7 @@ require_once('include/items.php'); */ class Conversation extends BaseObject { + private $threads = array(); private $mode = null; private $observer = null; @@ -47,33 +48,26 @@ class Conversation extends BaseObject { $a = $this->get_app(); - $this->observer = $a->get_observer(); + $this->observer = App::get_observer(); $ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : ''); switch($mode) { case 'network': -// if(array_key_exists('firehose',$a->data) && intval($a->data['firehose'])) { -// $this->profile_owner = intval($a->data['firehose']); -// $this->writable = false; -// } -// else { - $this->profile_owner = local_channel(); - $this->writable = true; -// } + $this->profile_owner = local_channel(); + $this->writable = true; break; case 'channel': - $this->profile_owner = $a->profile['profile_uid']; + $this->profile_owner = App::$profile['profile_uid']; $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'); break; case 'display': // in this mode we set profile_owner after initialisation (from conversation()) and then // pull some trickery which allows us to re-invoke this function afterward // it's an ugly hack so FIXME -// $this->profile_owner = $a->profile['uid']; $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'); break; case 'page': - $this->profile_owner = $a->profile['uid']; + $this->profile_owner = App::$profile['uid']; $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'); break; default: @@ -142,11 +136,11 @@ class Conversation extends BaseObject { public function add_thread($item) { $item_id = $item->get_id(); if(!$item_id) { - logger('[ERROR] Conversation::add_thread : Item has no ID!!', LOGGER_DEBUG); + logger('Item has no ID!!', LOGGER_DEBUG, LOG_ERR); return false; } if($this->get_thread($item->get_id())) { - logger('[WARN] Conversation::add_thread : Thread already exists ('. $item->get_id() .').', LOGGER_DEBUG); + logger('Thread already exists ('. $item->get_id() .').', LOGGER_DEBUG, LOG_WARNING); return false; } @@ -177,11 +171,6 @@ class Conversation extends BaseObject { } } require_once('include/identity.php'); -// $sys = get_sys_channel(); - -// if($sys && $item->get_data_value('uid') == $sys['channel_id']) { -// $item->set_commentable(false); -// } $item->set_conversation($this); $this->threads[] = $item; @@ -209,7 +198,7 @@ class Conversation extends BaseObject { $item_data = $item->get_template_data($conv_responses); } if(!$item_data) { - logger('[ERROR] Conversation::get_template_data : Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG); + logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR); return false; } $result[] = $item_data; 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/Import/import_diaspora.php b/include/Import/import_diaspora.php index a0f473b50..a94e73395 100644 --- a/include/Import/import_diaspora.php +++ b/include/Import/import_diaspora.php @@ -8,7 +8,7 @@ require_once('include/photo/photo_driver.php'); function import_diaspora($data) { $a = get_app(); - $account = $a->get_account(); + $account = App::get_account(); if(! $account) return false; diff --git a/include/ItemObject.php b/include/ItemObject.php index 8be99d91e..9d5acd95f 100644 --- a/include/ItemObject.php +++ b/include/ItemObject.php @@ -97,7 +97,7 @@ class Item extends BaseObject { $mode = $conv->get_mode(); if(local_channel() && $observer['xchan_hash'] === $item['author_xchan']) - $edpost = array($a->get_baseurl($ssl_state)."/editpost/".$item['id'], t("Edit")); + $edpost = array(z_root()."/editpost/".$item['id'], t("Edit")); else $edpost = false; @@ -241,7 +241,7 @@ class Item extends BaseObject { $has_bookmarks = false; if(is_array($item['term'])) { foreach($item['term'] as $t) { - if($t['type'] == TERM_BOOKMARK) + if(!UNO && $t['type'] == TERM_BOOKMARK) $has_bookmarks = true; } } @@ -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,14 +681,20 @@ 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(), - '$jsreload' => (($conv->get_mode() === 'display') ? $_SESSION['return_url'] : ''), + '$jsreload' => '', //(($conv->get_mode() === 'display') ? $_SESSION['return_url'] : ''), '$type' => (($conv->get_mode() === 'channel') ? 'wall-comment' : 'net-comment'), '$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'), @@ -708,7 +714,7 @@ class Item extends BaseObject { '$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false), '$encrypt' => t('Encrypt text'), '$cipher' => $conv->get_cipher(), - '$sourceapp' => get_app()->sourcename + '$sourceapp' => App::$sourcename )); 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%)'); - $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..c64197b49 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) { @@ -247,7 +248,7 @@ function verify_email_address($arr) { $res = mail($arr['email'], email_header_encode(sprintf( t('Registration confirmation for %s'), get_config('system','sitename'))), $email_msg, - 'From: ' . 'Administrator' . '@' . get_app()->get_hostname() . "\n" + 'From: ' . 'Administrator' . '@' . App::get_hostname() . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -313,7 +314,7 @@ function send_reg_approval_email($arr) { $res = mail($admin['email'], sprintf( t('Registration request at %s'), get_config('system','sitename')), $email_msg, - 'From: ' . t('Administrator') . '@' . get_app()->get_hostname() . "\n" + 'From: ' . t('Administrator') . '@' . App::get_hostname() . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -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'), @@ -340,7 +341,7 @@ function send_verification_email($email,$password) { $res = mail($email, sprintf( t('Registration details for %s'), get_config('system','sitename')), $email_msg, - 'From: ' . t('Administrator') . '@' . get_app()->get_hostname() . "\n" + 'From: ' . t('Administrator') . '@' . App::get_hostname() . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -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; @@ -643,7 +655,7 @@ function account_service_class_allows($aid, $property, $usage = false) { function service_class_fetch($uid, $property) { $a = get_app(); if($uid == local_channel()) { - $service_class = $a->account['account_service_class']; + $service_class = App::$account['account_service_class']; } else { $r = q("select account_service_class as service_class diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 4d44ec12e..92f9436a2 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -23,7 +23,7 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) { // e.g. 'network_pre_group_deny', 'profile_pre_group_allow' - call_hooks($a->module . '_pre_' . $selname, $arr); + call_hooks(App::$module . '_pre_' . $selname, $arr); if($r) { foreach($r as $rr) { @@ -39,7 +39,7 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) { } $o .= "</select>\r\n"; - call_hooks($a->module . '_post_' . $selname, $o); + call_hooks(App::$module . '_post_' . $selname, $o); return $o; @@ -127,7 +127,7 @@ function contact_selector($selname, $selclass, $preselected = false, $options) { // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' - call_hooks($a->module . '_pre_' . $selname, $arr); + call_hooks(App::$module . '_pre_' . $selname, $arr); if(count($r)) { foreach($r as $rr) { @@ -145,7 +145,7 @@ function contact_selector($selname, $selclass, $preselected = false, $options) { $o .= "</select>\r\n"; - call_hooks($a->module . '_post_' . $selname, $o); + call_hooks(App::$module . '_post_' . $selname, $o); return $o; }*/ @@ -182,7 +182,7 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' - call_hooks($a->module . '_pre_' . $selname, $arr); + call_hooks(App::$module . '_pre_' . $selname, $arr); if($r) { foreach($r as $rr) { @@ -200,7 +200,7 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p $o .= "</select>\r\n"; - call_hooks($a->module . '_post_' . $selname, $o); + call_hooks(App::$module . '_post_' . $selname, $o); return $o; } @@ -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/activities.php b/include/activities.php index df43f1f6f..9ba191391 100644 --- a/include/activities.php +++ b/include/activities.php @@ -11,7 +11,7 @@ function profile_activity($changed, $value) { require_once('include/items.php'); - $self = $a->get_channel(); + $self = App::get_channel(); if(! count($self)) return; diff --git a/include/api.php b/include/api.php index 5053977c5..fd644947c 100644 --- a/include/api.php +++ b/include/api.php @@ -34,7 +34,7 @@ require_once('include/api_auth.php'); function api_user() { $aid = get_account_id(); - $channel = get_app()->get_channel(); + $channel = App::get_channel(); if(($aid) && (x($_REQUEST,'channel'))) { @@ -79,7 +79,7 @@ require_once('include/api_auth.php'); $type="json"; foreach ($API as $p=>$info){ - if (strpos($a->query_string, $p)===0){ + if (strpos(App::$query_string, $p)===0){ $called_api= explode("/",$p); //unset($_SERVER['PHP_AUTH_USER']); if ($info['auth'] === true && api_user() === false) { @@ -88,18 +88,18 @@ require_once('include/api_auth.php'); load_contact_links(api_user()); - $channel = $a->get_channel(); + $channel = App::get_channel(); - logger('API call for ' . $channel['channel_name'] . ': ' . $a->query_string); + logger('API call for ' . $channel['channel_name'] . ': ' . App::$query_string); logger('API parameters: ' . print_r($_REQUEST,true)); $type="json"; - if (strpos($a->query_string, ".xml")>0) $type="xml"; - if (strpos($a->query_string, ".json")>0) $type="json"; - if (strpos($a->query_string, ".rss")>0) $type="rss"; - if (strpos($a->query_string, ".atom")>0) $type="atom"; - if (strpos($a->query_string, ".as")>0) $type="as"; + if (strpos(App::$query_string, ".xml")>0) $type="xml"; + if (strpos(App::$query_string, ".json")>0) $type="json"; + if (strpos(App::$query_string, ".rss")>0) $type="rss"; + if (strpos(App::$query_string, ".atom")>0) $type="atom"; + if (strpos(App::$query_string, ".as")>0) $type="as"; $r = call_user_func($info['func'], $a, $type); if ($r===false) return; @@ -141,7 +141,7 @@ require_once('include/api_auth.php'); } } header("HTTP/1.1 404 Not Found"); - logger('API call not implemented: '.$a->query_string." - ".print_r($_REQUEST,true)); + logger('API call not implemented: '.App::$query_string." - ".print_r($_REQUEST,true)); $r = '<status><error>not implemented</error></status>'; switch($type){ case "xml": @@ -171,12 +171,12 @@ require_once('include/api_auth.php'); $arr['$user'] = $user_info; $arr['$rss'] = array( 'alternate' => $user_info['url'], - 'self' => $a->get_baseurl(). "/". $a->query_string, - 'base' => $a->get_baseurl(), + 'self' => z_root(). "/". App::$query_string, + 'base' => z_root(), 'updated' => api_date(null), 'atom_updated' => datetime_convert('UTC','UTC','now',ATOM_TIME), 'language' => $user_info['language'], - 'logo' => $a->get_baseurl()."/images/rm-64.png", + 'logo' => z_root()."/images/rm-64.png", ); return $arr; @@ -213,7 +213,7 @@ require_once('include/api_auth.php'); $extra_query .= " AND abook_channel = ".intval(api_user()); } - if (is_null($user) && argc() > (count($called_api)-1) && (strstr($a->cmd,'/users'))){ + if (is_null($user) && argc() > (count($called_api)-1) && (strstr(App::$cmd,'/users'))){ $argid = count($called_api); list($xx, $null) = explode(".",argv($argid)); if(is_numeric($xx)){ @@ -318,7 +318,7 @@ require_once('include/api_auth.php'); 'location' => ($usr) ? $usr[0]['channel_location'] : '', 'profile_image_url' => $uinfo[0]['xchan_photo_l'], 'url' => $uinfo[0]['xchan_url'], - 'contact_url' => $a->get_baseurl() . "/connections/".$uinfo[0]['abook_id'], + 'contact_url' => z_root() . "/connections/".$uinfo[0]['abook_id'], 'protected' => false, 'friends_count' => intval($countfriends), 'created_at' => api_date($uinfo[0]['abook_created']), @@ -326,7 +326,7 @@ require_once('include/api_auth.php'); 'time_zone' => 'UTC', //$uinfo[0]['timezone'], 'geo_enabled' => false, 'statuses_count' => intval($countitms), //#XXX: fix me - 'lang' => get_app()->language, + 'lang' => App::$language, 'description' => (($profile) ? $profile[0]['pdesc'] : ''), 'followers_count' => intval($countfollowers), 'favourites_count' => intval($starred), @@ -486,7 +486,7 @@ require_once('include/api_auth.php'); function api_account_logout(&$a, $type){ require_once('include/auth.php'); - nuke_session(); + \Zotlabs\Web\Session::nuke(); return api_apply_template("user", $type, array('$user' => null)); } @@ -635,13 +635,13 @@ require_once('include/api_auth.php'); function api_albums(&$a,$type) { - json_return_and_die(photos_albums_list($a->get_channel(),$a->get_observer())); + json_return_and_die(photos_albums_list(App::get_channel(),App::get_observer())); } api_register_func('api/red/albums','api_albums', true); function api_photos(&$a,$type) { $album = $_REQUEST['album']; - json_return_and_die(photos_list_photos($a->get_channel(),$a->get_observer(),$album)); + json_return_and_die(photos_list_photos(App::get_channel(),App::get_observer(),$album)); } api_register_func('api/red/photos','api_photos', true); @@ -768,7 +768,7 @@ require_once('include/api_auth.php'); } $txt = html2bbcode($txt); - $a->argv[1] = $user_info['screen_name']; + App::$argv[1] = $user_info['screen_name']; $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo $_FILES['userfile'] = $_FILES['media']; @@ -872,7 +872,7 @@ require_once('include/api_auth.php'); // upload each image if we have any $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo require_once('mod/wall_attach.php'); - $a->data['api_info'] = $user_info; + App::$data['api_info'] = $user_info; $media = wall_attach_post($a); if(strlen($media)>0) @@ -885,7 +885,7 @@ require_once('include/api_auth.php'); // upload each image if we have any $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo require_once('mod/wall_attach.php'); - $a->data['api_info'] = $user_info; + App::$data['api_info'] = $user_info; $media = wall_attach_post($a); if(strlen($media)>0) @@ -960,7 +960,7 @@ require_once('include/api_auth.php'); $arr['records'] = 999999; $arr['item_type'] = '*'; - $i = items_fetch($arr,$a->get_channel(),get_observer_hash()); + $i = items_fetch($arr,App::get_channel(),get_observer_hash()); if(! $i) json_return_and_die(array()); @@ -1230,7 +1230,7 @@ require_once('include/api_auth.php'); $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; if (api_user() != $user_info['uid']) { - $observer = get_app()->get_observer(); + $observer = App::get_observer(); require_once('include/permissions.php'); if(! perm_is_allowed($user_info['uid'],(($observer) ? $observer['xchan_hash'] : ''),'view_stream')) return ''; @@ -1272,8 +1272,8 @@ require_once('include/api_auth.php'); break; case "as": $as = api_format_as($a, $ret, $user_info); - $as['title'] = $a->config['sitename']." Home Timeline"; - $as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all"; + $as['title'] = App::$config['sitename']." Home Timeline"; + $as['link']['url'] = z_root()."/".$user_info["screen_name"]."/all"; return($as); break; } @@ -1333,8 +1333,8 @@ require_once('include/api_auth.php'); break; case "as": $as = api_format_as($a, $ret, $user_info); - $as['title'] = $a->config['sitename']. " " . t('Public Timeline'); - $as['link']['url'] = $a->get_baseurl()."/"; + $as['title'] = App::$config['sitename']. " " . t('Public Timeline'); + $as['link']['url'] = z_root()."/"; return($as); break; } @@ -1409,7 +1409,7 @@ require_once('include/api_auth.php'); //$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false); - $observer = get_app()->get_observer(); + $observer = App::get_observer(); $item_normal = item_normal(); @@ -1526,7 +1526,7 @@ require_once('include/api_auth.php'); //$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false); - $myurl = $a->get_baseurl() . '/channel/'. $a->user['nickname']; + $myurl = z_root() . '/channel/'. App::$user['nickname']; $myurl = substr($myurl,strpos($myurl,'://')+3); $myurl = str_replace(array('www.','.'),array('','\\.'),$myurl); $diasp_url = str_replace('/channel/','/u/',$myurl); @@ -1561,8 +1561,8 @@ require_once('include/api_auth.php'); break; case "as": $as = api_format_as($a, $ret, $user_info); - $as["title"] = $a->config['sitename']." Mentions"; - $as['link']['url'] = $a->get_baseurl()."/"; + $as["title"] = App::$config['sitename']." Mentions"; + $as['link']['url'] = z_root()."/"; return($as); break; } @@ -1633,7 +1633,7 @@ require_once('include/api_auth.php'); $arr['cid'] = $user_info['id']; - $r = items_fetch($arr,get_app()->get_channel(),get_observer_hash()); + $r = items_fetch($arr,App::get_channel(),get_observer_hash()); $ret = api_format_items($r,$user_info); @@ -1752,7 +1752,7 @@ require_once('include/api_auth.php'); $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; if (api_user() != $user_info['uid']) { - $observer = get_app()->get_observer(); + $observer = App::get_observer(); require_once('include/permissions.php'); if(! perm_is_allowed($user_info['uid'],(($observer) ? $observer['xchan_hash'] : ''),'view_stream')) return ''; @@ -1783,8 +1783,8 @@ require_once('include/api_auth.php'); break; case "as": $as = api_format_as($a, $ret, $user_info); - $as['title'] = $a->config['sitename']." Home Timeline"; - $as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all"; + $as['title'] = App::$config['sitename']." Home Timeline"; + $as['link']['url'] = z_root()."/".$user_info["screen_name"]."/all"; return($as); break; } @@ -1801,7 +1801,7 @@ require_once('include/api_auth.php'); function api_format_as($a, $ret, $user_info) { $as = array(); - $as['title'] = $a->config['sitename']." Public Timeline"; + $as['title'] = App::$config['sitename']." Public Timeline"; $items = array(); foreach ($ret as $item) { $singleitem["actor"]["displayName"] = $item["user"]["name"]; @@ -1857,7 +1857,7 @@ require_once('include/api_auth.php'); $items[] = $singleitem; } $as['items'] = $items; - $as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all"; + $as['link']['url'] = z_root()."/".$user_info["screen_name"]."/all"; $as['link']['rel'] = "alternate"; $as['link']['type'] = "text/html"; return($as); @@ -1978,8 +1978,8 @@ require_once('include/api_auth.php'); 'entities' => '', 'objecttype' => (($item['obj_type']) ? $item['obj_type'] : ACTIVITY_OBJ_NOTE), 'verb' => (($item['verb']) ? $item['verb'] : ACTIVITY_POST), - 'self' => $a->get_baseurl()."/api/statuses/show/".$item['id'].".".$type, - 'edit' => $a->get_baseurl()."/api/statuses/show/".$item['id'].".".$type, + 'self' => z_root()."/api/statuses/show/".$item['id'].".".$type, + 'edit' => z_root()."/api/statuses/show/".$item['id'].".".$type, ); $status = array_merge($status, $status2); @@ -2088,8 +2088,8 @@ require_once('include/api_auth.php'); load_config('system'); $name = get_config('system','sitename'); - $server = $a->get_hostname(); - $logo = $a->get_baseurl() . '/images/rm-64.png'; + $server = App::get_hostname(); + $logo = z_root() . '/images/rm-64.png'; $email = get_config('system','admin_email'); $closed = ((get_config('system','register_policy') == REGISTER_CLOSED) ? 'true' : 'false'); $private = ((get_config('system','block_public')) ? 'true' : 'false'); @@ -2097,7 +2097,7 @@ require_once('include/api_auth.php'); if(get_config('system','api_import_size')) $texlimit = string(get_config('system','api_import_size')); $ssl = ((get_config('system','have_ssl')) ? 'true' : 'false'); - $sslserver = (($ssl === 'true') ? str_replace('http:','https:',$a->get_baseurl()) : ''); + $sslserver = (($ssl === 'true') ? str_replace('http:','https:',z_root()) : ''); $config = array( 'site' => array('name' => $name,'server' => $server, 'theme' => 'default', 'path' => '', @@ -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(); } } @@ -2270,9 +2270,9 @@ require_once('include/api_auth.php'); if ($page<0) $page=0; $start = $page*$count; - $channel = $a->get_channel(); + $channel = App::get_channel(); - $profile_url = $a->get_baseurl() . '/channel/' . $channel['channel_address']; + $profile_url = z_root() . '/channel/' . $channel['channel_address']; if ($box=="sentbox") { $sql_extra = "`from_xchan`='".dbesc( $channel['channel_hash'] )."'"; } diff --git a/include/api_auth.php b/include/api_auth.php index 26a9df8d4..dc8492b20 100644 --- a/include/api_auth.php +++ b/include/api_auth.php @@ -20,9 +20,9 @@ function api_login(&$a){ if (!is_null($token)){ $oauth->loginUser($token->uid); - $a->set_oauth_key($consumer->key); + App::set_oauth_key($consumer->key); - call_hooks('logged_in', $a->user); + call_hooks('logged_in', App::$user); return; } killme(); diff --git a/include/apps.php b/include/apps.php index 0a62dc5a8..fac58b850 100644 --- a/include/apps.php +++ b/include/apps.php @@ -48,12 +48,12 @@ function parse_app_description($f) { $ret = array(); $baseurl = z_root(); - $channel = get_app()->get_channel(); + $channel = App::get_channel(); $address = (($channel) ? $channel['channel_address'] : ''); //future expansion - $observer = get_app()->get_observer(); + $observer = App::get_observer(); $lines = @file($f); @@ -217,7 +217,7 @@ function app_render($papp,$mode = 'view') { return ''; break; case 'observer': - $observer = get_app()->get_observer(); + $observer = App::get_observer(); if(! $observer) return ''; break; @@ -239,7 +239,7 @@ function app_render($papp,$mode = 'view') { $hosturl = z_root() . '/'; } elseif(remote_channel()) { - $observer = get_app()->get_observer(); + $observer = App::get_observer(); if($observer && $observer['xchan_network'] === 'zot') { // some folks might have xchan_url redirected offsite, use the connurl $x = parse_url($observer['xchan_connurl']); @@ -354,7 +354,7 @@ function app_store($arr) { } - $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : random_string(). '.' . get_app()->get_hostname()); + $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : random_string(). '.' . App::get_hostname()); $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : ''); $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash()); $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown')); diff --git a/include/attach.php b/include/attach.php index 8595d5d86..ae4681994 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. @@ -845,7 +846,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { // Caution: This re-uses $sql_options set further above - $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_options limit 1", + $r = q("select * from attach where uid = %d and hash = '%s' $sql_options limit 1", intval($channel_id), dbesc($hash) ); @@ -863,6 +864,12 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { // This would've been called already with a success result in photos_upload() if it was a photo. call_hooks('photo_upload_end',$ret); } + + $sync = attach_export_data($channel,$hash); + + if($sync) + build_sync_packet($channel['channel_id'],array('file' => array($sync))); + return $ret; } @@ -1242,7 +1249,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 +1320,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,13 +1477,13 @@ 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) { require_once('include/items.php'); - $poster = get_app()->get_observer(); + $poster = App::get_observer(); //if we got no object something went wrong if(!$object) @@ -1514,13 +1523,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 +1565,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 +1601,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'] = ''; @@ -1701,11 +1702,11 @@ function recursive_activity_recipients($arr_allow_cid, $arr_allow_gid, $arr_deny $ret = array(); $parent_arr = array(); $count_values = array(); - $poster = get_app()->get_observer(); + $poster = App::get_observer(); //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 +1728,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 +1809,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( @@ -1844,3 +1820,89 @@ function filepath_macro($s) { } +function attach_export_data($channel, $resource_id, $deleted = false) { + + $ret = array(); + + $paths = array(); + + $hash_ptr = $resource_id; + + $ret['fetch_url'] = z_root() . '/getfile'; + $ret['original_channel'] = $channel['channel_address']; + + + if($deleted) { + $ret['attach'] = array(array('hash' => $resource_id, 'deleted' => 1)); + return $ret; + } + + do { + $r = q("select * from attach where hash = '%s' and uid = %d limit 1", + dbesc($hash_ptr), + intval($channel['channel_id']) + ); + if(! $r) + break; + + if($hash_ptr === $resource_id) { + $attach_ptr = $r[0]; + } + + $hash_ptr = $r[0]['folder']; + $paths[] = $r[0]; + } while($hash_ptr); + + + + + $paths = array_reverse($paths); + + $ret['attach'] = $paths; + + + if($attach_ptr['is_photo']) { + $r = q("select * from photo where resource_id = '%s' and uid = %d order by scale asc", + dbesc($resource_id), + intval($channel['channel_id']) + ); + if($r) { + for($x = 0; $x < count($r); $x ++) { + $r[$x]['data'] = base64_encode($r[$x]['data']); + } + $ret['photo'] = $r; + } + + $r = q("select * from item where resource_id = '%s' and resource_type = 'photo' and uid = %d ", + dbesc($resource_id), + intval($channel['channel_id']) + ); + if($r) { + $ret['item'] = array(); + $items = q("select item.*, item.id as item_id from item where item.parent = %d ", + intval($r[0]['id']) + ); + if($items) { + xchan_query($items); + $items = fetch_post_tags($items,true); + foreach($items as $rr) + $ret['item'][] = encode_item($rr,true); + } + } + } + + return $ret; + +} + + +/* strip off 'store/nickname/' from the provided path */ + +function get_attach_binname($s) { + $p = $s; + if(strpos($s,'store/') === 0) { + $p = substr($s,6); + $p = substr($p,strpos($p,'/')+1); + } + return $p; +}
\ No newline at end of file diff --git a/include/auth.php b/include/auth.php index 4f0c4c928..9643da8eb 100644 --- a/include/auth.php +++ b/include/auth.php @@ -12,33 +12,6 @@ require_once('include/api_auth.php'); require_once('include/security.php'); -/** - * @brief Resets the current session. - * - * @return void - */ -function nuke_session() { - new_cookie(0); // 0 means delete on browser exit - - unset($_SESSION['authenticated']); - unset($_SESSION['account_id']); - unset($_SESSION['uid']); - unset($_SESSION['visitor_id']); - unset($_SESSION['administrator']); - unset($_SESSION['cid']); - unset($_SESSION['theme']); - unset($_SESSION['mobile_theme']); - unset($_SESSION['show_mobile']); - unset($_SESSION['page_flags']); - unset($_SESSION['delegate']); - unset($_SESSION['delegate_channel']); - unset($_SESSION['my_url']); - unset($_SESSION['my_address']); - unset($_SESSION['addr']); - unset($_SESSION['return_url']); - unset($_SESSION['remote_service_class']); - unset($_SESSION['remote_hub']); -} /** * @brief Verify login credentials. @@ -124,11 +97,11 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) && // process a logout request - if(((x($_POST, 'auth-params')) && ($_POST['auth-params'] === 'logout')) || ($a->module === 'logout')) { + if(((x($_POST, 'auth-params')) && ($_POST['auth-params'] === 'logout')) || (App::$module === 'logout')) { // process logout request $args = array('channel_id' => local_channel()); call_hooks('logging_out', $args); - nuke_session(); + \Zotlabs\Web\Session::nuke(); info( t('Logged out.') . EOL); goaway(z_root()); } @@ -144,7 +117,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) && intval(ACCOUNT_ROLE_ADMIN) ); if($x) { - new_cookie(60 * 60 * 24); // one day + \Zotlabs\Web\Session::new_cookie(60 * 60 * 24); // one day $_SESSION['last_login_date'] = datetime_convert(); unset($_SESSION['visitor_id']); // no longer a visitor authenticate_success($x[0], true, true); @@ -155,75 +128,41 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) && dbesc($_SESSION['visitor_id']) ); if($r) { - get_app()->set_observer($r[0]); + App::set_observer($r[0]); } else { unset($_SESSION['visitor_id']); unset($_SESSION['authenticated']); } - $a->set_groups(init_groups_visitor($_SESSION['visitor_id'])); + App::set_groups(init_groups_visitor($_SESSION['visitor_id'])); } // already logged in user returning if(x($_SESSION, 'uid') || x($_SESSION, 'account_id')) { - // first check if we're enforcing that sessions can't change IP address - // @todo what to do with IPv6 addresses - if($_SESSION['addr'] && $_SESSION['addr'] != $_SERVER['REMOTE_ADDR']) { - logger('SECURITY: Session IP address changed: ' . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); - - $partial1 = substr($_SESSION['addr'], 0, strrpos($_SESSION['addr'], '.')); - $partial2 = substr($_SERVER['REMOTE_ADDR'], 0, strrpos($_SERVER['REMOTE_ADDR'], '.')); - - $paranoia = intval(get_pconfig($_SESSION['uid'], 'system', 'paranoia')); - if(! $paranoia) - $paranoia = intval(get_config('system', 'paranoia')); - - switch($paranoia) { - case 0: - // no IP checking - break; - case 2: - // check 2 octets - $partial1 = substr($partial1, 0, strrpos($partial1, '.')); - $partial2 = substr($partial2, 0, strrpos($partial2, '.')); - if($partial1 == $partial2) - break; - case 1: - // check 3 octets - if($partial1 == $partial2) - break; - case 3: - default: - // check any difference at all - logger('Session address changed. Paranoid setting in effect, blocking session. ' - . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); - nuke_session(); - goaway(z_root()); - break; - } - } + Zotlabs\Web\Session::return_check(); $r = q("select * from account where account_id = %d limit 1", intval($_SESSION['account_id']) ); if(($r) && (($r[0]['account_flags'] == ACCOUNT_OK) || ($r[0]['account_flags'] == ACCOUNT_UNVERIFIED))) { - get_app()->account = $r[0]; + App::$account = $r[0]; $login_refresh = false; if(! x($_SESSION,'last_login_date')) { $_SESSION['last_login_date'] = datetime_convert('UTC','UTC'); } if(strcmp(datetime_convert('UTC','UTC','now - 12 hours'), $_SESSION['last_login_date']) > 0 ) { $_SESSION['last_login_date'] = datetime_convert(); + Zotlabs\Web\Session::extend_cookie(); $login_refresh = true; } authenticate_success($r[0], false, false, false, $login_refresh); } else { $_SESSION['account_id'] = 0; - nuke_session(); + \Zotlabs\Web\Session::nuke(); goaway(z_root()); } } // end logged in user returning @@ -231,7 +170,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) && else { if(isset($_SESSION)) { - nuke_session(); + \Zotlabs\Web\Session::nuke(); } // handle a fresh login request @@ -264,16 +203,16 @@ else { $record = $addon_auth['user_record']; } else { - $record = get_app()->account = account_verify_password($_POST['username'], $_POST['password']); + $record = App::$account = account_verify_password($_POST['username'], $_POST['password']); - if(get_app()->account) { - $_SESSION['account_id'] = get_app()->account['account_id']; + if(App::$account) { + $_SESSION['account_id'] = App::$account['account_id']; } else { notice( t('Failed authentication') . EOL); } - logger('authenticate: ' . print_r(get_app()->account, true), LOGGER_DEBUG); + logger('authenticate: ' . print_r(App::$account, true), LOGGER_ALL); } if((! $record) || (! count($record))) { @@ -301,11 +240,13 @@ else { // (i.e. expire when the browser is closed), even when there's a time expiration // on the cookie - if($_POST['remember']) { - new_cookie(31449600); // one year + if($_POST['remember_me']) { + $_SESSION['remember_me'] = 1; + \Zotlabs\Web\Session::new_cookie(31449600); // one year } else { - new_cookie(0); // 0 means delete on browser exit + $_SESSION['remember_me'] = 0; + \Zotlabs\Web\Session::new_cookie(0); // 0 means delete on browser exit } // if we haven't failed up this point, log them in. diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 81b95b30b..1ed57bfd4 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -473,7 +473,7 @@ function format_event_diaspora($ev) { $ev['start'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $ev['start'] , $bd_format))) - . '](' . $a->get_baseurl() . '/localtime/?f=&time=' . urlencode(datetime_convert('UTC','UTC',$ev['start'])) . ")\n"; + . '](' . z_root() . '/localtime/?f=&time=' . urlencode(datetime_convert('UTC','UTC',$ev['start'])) . ")\n"; if(! $ev['nofinish']) $o .= t('Finishes:') . ' ' . '[' @@ -481,7 +481,7 @@ function format_event_diaspora($ev) { $ev['finish'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $ev['finish'] , $bd_format ))) - . '](' . $a->get_baseurl() . '/localtime/?f=&time=' . urlencode(datetime_convert('UTC','UTC',$ev['finish'])) . ")\n"; + . '](' . z_root() . '/localtime/?f=&time=' . urlencode(datetime_convert('UTC','UTC',$ev['finish'])) . ")\n"; if(strlen($ev['location'])) $o .= t('Location:') . bb2diaspora($ev['location']) diff --git a/include/bbcode.php b/include/bbcode.php index a8372d728..78a2759c1 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -37,7 +37,7 @@ function tryzrlvideo($match) { if($zrl) $link = zid($link); - return '<video controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . get_app()->videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>'; + return '<video controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>'; } // [noparse][i]italic[/i][/noparse] turns into @@ -243,9 +243,7 @@ function bb_ShareAttributes($match) { if ($matches[1] != "") $message_id = $matches[1]; - - /** @FIXME - this should really be a wall-item-ago so it will get updated on the client */ - $reldate = (($posted) ? relative_date($posted) : ''); + $reldate = '<span class="autotime" title="' . datetime_convert('UTC', date_default_timezone_get(), $posted, 'c') . '" >' . datetime_convert('UTC', date_default_timezone_get(), $posted, 'r') . '</span>'; $headline = '<div class="shared_container"> <div class="shared_header">'; @@ -280,9 +278,9 @@ function bb_location($match) { function bb_iframe($match) { $a = get_app(); - $sandbox = ((strpos($match[1], $a->get_hostname())) ? ' sandbox="allow-scripts" ' : ''); + $sandbox = ((strpos($match[1], App::get_hostname())) ? ' sandbox="allow-scripts" ' : ''); - return '<iframe ' . $sandbox . ' src="' . $match[1] . '" width="' . $a->videowidth . '" height="' . $a->videoheight . '"><a href="' . $match[1] . '">' . $match[1] . '</a></iframe>'; + return '<iframe ' . $sandbox . ' src="' . $match[1] . '" width="' . App::$videowidth . '" height="' . App::$videoheight . '"><a href="' . $match[1] . '">' . $match[1] . '</a></iframe>'; } function bb_ShareAttributesSimple($match) { @@ -315,9 +313,9 @@ function bb_ShareAttributesSimple($match) { function rpost_callback($match) { if ($match[2]) { - return str_replace($match[0], get_rpost_path(get_app()->get_observer()) . '&title=' . urlencode($match[2]) . '&body=' . urlencode($match[3]), $match[0]); + return str_replace($match[0], get_rpost_path(App::get_observer()) . '&title=' . urlencode($match[2]) . '&body=' . urlencode($match[3]), $match[0]); } else { - return str_replace($match[0], get_rpost_path(get_app()->get_observer()) . '&body=' . urlencode($match[3]), $match[0]); + return str_replace($match[0], get_rpost_path(App::get_observer()) . '&body=' . urlencode($match[3]), $match[0]); } } @@ -401,7 +399,7 @@ function bb_observer($Text) { $a = get_app(); - $observer = $a->get_observer(); + $observer = App::get_observer(); if ((strpos($Text,'[/observer]') !== false) || (strpos($Text,'[/rpost]') !== false)) { if ($observer) { @@ -415,7 +413,7 @@ function bb_observer($Text) { } } - $channel = $a->get_channel(); + $channel = App::get_channel(); if (strpos($Text,'[/channel]') !== false) { if ($channel) { @@ -477,7 +475,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) if($cache) $observer = false; else - $observer = $a->get_observer(); + $observer = App::get_observer(); if ((strpos($Text,'[/observer]') !== false) || (strpos($Text,'[/rpost]') !== false)) { if ($observer) { @@ -494,7 +492,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) if($cache) $channel = false; else - $channel = $a->get_channel(); + $channel = App::get_channel(); if (strpos($Text,'[/channel]') !== false) { if ($channel) { @@ -593,6 +591,11 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) $Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" >$1</a>', $Text); $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" >$2</a>', $Text); } + + // Remove bookmarks from UNO + if (UNO) + $Text = str_replace('<span class="bookmark-identifier">#^</span>', '', $Text); + // Perform MAIL Search if (strpos($Text,'[/mail]') !== false) { $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1" target="_blank" >$1</a>', $Text); @@ -684,7 +687,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); @@ -841,7 +848,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) // crypt if (strpos($Text,'[/crypt]') !== false) { $x = random_string(); - $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br /><div id="' . $x . '"><img src="' .$a->get_baseurl() . '/images/lock_icon.gif" onclick="red_decrypt(\'rot13\',\'\',\'$1\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br /></div>', $Text); + $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br /><div id="' . $x . '"><img src="' .z_root() . '/images/lock_icon.gif" onclick="red_decrypt(\'rot13\',\'\',\'$1\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br /></div>', $Text); $Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text); } @@ -921,7 +928,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) // $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); // if ($tryoembed) -// $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="http://www.youtube.com/embed/$1" frameborder="0"></iframe>', $Text); +// $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="' . App::$videowidth . '" height="' . App::$videoheight . '" src="http://www.youtube.com/embed/$1" frameborder="0"></iframe>', $Text); // else // $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", "http://www.youtube.com/watch?v=$1", $Text); // } @@ -935,7 +942,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) // $Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $Text); // if ($tryoembed) -// $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="http://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text); +// $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="' . App::$videowidth . '" height="' . App::$videoheight . '" src="http://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text); // else // $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", "http://vimeo.com/$1", $Text); // } diff --git a/include/chat.php b/include/chat.php index 81c5c5d62..604402045 100644 --- a/include/chat.php +++ b/include/chat.php @@ -202,7 +202,7 @@ function chatroom_list($uid) { require_once('include/security.php'); $sql_extra = permissions_sql($uid); - $r = q("select cr_name, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name", + $r = q("select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name", intval($uid) ); diff --git a/include/cli_startup.php b/include/cli_startup.php index 027d62953..a99164d4c 100644 --- a/include/cli_startup.php +++ b/include/cli_startup.php @@ -9,25 +9,32 @@ function cli_startup() { global $a, $db, $default_timezone; if(is_null($a)) { - $a = new App; + $a = new miniApp; } + + App::init(); if(is_null($db)) { @include(".htconfig.php"); - $a->timezone = ((x($default_timezone)) ? $default_timezone : 'UTC'); - date_default_timezone_set($a->timezone); + $a->convert(); + + if(! defined('UNO')) + define('UNO', 0); + + App::$timezone = ((x($default_timezone)) ? $default_timezone : 'UTC'); + date_default_timezone_set(App::$timezone); require_once('include/dba/dba_driver.php'); $db = dba_factory($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type); unset($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type); }; - require_once('include/session.php'); + \Zotlabs\Web\Session::init(); load_config('system'); - $a->set_baseurl(get_config('system','baseurl')); + App::set_baseurl(get_config('system','baseurl')); load_hooks(); diff --git a/include/comanche.php b/include/comanche.php index 1537226ca..4d55aee19 100644 --- a/include/comanche.php +++ b/include/comanche.php @@ -56,34 +56,34 @@ function comanche_parser(&$a, $s, $pass = 0) { if($pass == 0) { $cnt = preg_match("/\[layout\](.*?)\[\/layout\]/ism", $s, $matches); if($cnt) - $a->page['template'] = trim($matches[1]); + App::$page['template'] = trim($matches[1]); $cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches); if($cnt) { - $a->page['template'] = trim($matches[2]); - $a->page['template_style'] = trim($matches[2]) . '_' . $matches[1]; + App::$page['template'] = trim($matches[2]); + App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1]; } $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches); if($cnt) { - $a->page['template'] = trim($matches[1]); + App::$page['template'] = trim($matches[1]); } $cnt = preg_match("/\[theme=(.*?)\](.*?)\[\/theme\]/ism", $s, $matches); if($cnt) { - $a->layout['schema'] = trim($matches[1]); - $a->layout['theme'] = trim($matches[2]); + App::$layout['schema'] = trim($matches[1]); + App::$layout['theme'] = trim($matches[2]); } $cnt = preg_match("/\[theme\](.*?)\[\/theme\]/ism", $s, $matches); if($cnt) - $a->layout['theme'] = trim($matches[1]); + App::$layout['theme'] = trim($matches[1]); $cnt = preg_match_all("/\[webpage\](.*?)\[\/webpage\]/ism", $s, $matches, PREG_SET_ORDER); if($cnt) { // only the last webpage definition is used if there is more than one foreach($matches as $mtch) { - $a->layout['webpage'] = comanche_webpage($a,$mtch[1]); + App::$layout['webpage'] = comanche_webpage($a,$mtch[1]); } } @@ -92,7 +92,7 @@ function comanche_parser(&$a, $s, $pass = 0) { $cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $s, $matches, PREG_SET_ORDER); if($cnt) { foreach($matches as $mtch) { - $a->layout['region_' . $mtch[1]] = comanche_region($a,$mtch[2]); + App::$layout['region_' . $mtch[1]] = comanche_region($a,$mtch[2]); } } @@ -122,8 +122,8 @@ function comanche_menu($s, $class = '') { function comanche_replace_region($match) { $a = get_app(); - if (array_key_exists($match[1], $a->page)) { - return $a->page[$match[1]]; + if (array_key_exists($match[1], App::$page)) { + return App::$page[$match[1]]; } } @@ -136,7 +136,7 @@ function comanche_replace_region($match) { * @return channel_id */ function comanche_get_channel_id() { - $channel_id = ((is_array(get_app()->profile)) ? get_app()->profile['profile_uid'] : 0); + $channel_id = ((is_array(App::$profile)) ? App::$profile['profile_uid'] : 0); if ((! $channel_id) && (local_channel())) $channel_id = local_channel(); @@ -190,7 +190,7 @@ function comanche_block($s, $class = '') { } if(trim($r[0]['body']) === '$content') { - $o .= get_app()->page['content']; + $o .= App::$page['content']; } else { $o .= prepare_text($r[0]['body'], $r[0]['mimetype']); @@ -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 { @@ -378,6 +378,6 @@ function comanche_region(&$a, $s) { function register_page_template($arr) { - get_app()->page_layouts[$arr['template']] = array($arr['variant']); + App::$page_layouts[$arr['template']] = array($arr['variant']); return; } diff --git a/include/config.php b/include/config.php index c94d25eb8..712b4ca11 100644 --- a/include/config.php +++ b/include/config.php @@ -22,7 +22,7 @@ * an identifier. This is for example for people who do not have a local account. * The storage is of size MEDIUMTEXT. * @code{.php} - * $observer = $a->get_observer_hash(); + * $observer = App::get_observer_hash(); * if ($observer) { * $var = get_xconfig($observer, 'category', 'key'); * }@endcode @@ -38,7 +38,7 @@ * @brief Loads the hub's configuration from database to a cached storage. * * Retrieve a category ($family) of config variables from database to a cached - * storage in the global $a->config[$family]. + * storage in the global App::$config[$family]. * * @param string $family * The category of the configuration value @@ -46,19 +46,19 @@ function load_config($family) { global $a; - if(! array_key_exists($family, $a->config)) - $a->config[$family] = array(); + if(! array_key_exists($family, App::$config)) + App::$config[$family] = array(); - if(! array_key_exists('config_loaded', $a->config[$family])) { + if(! array_key_exists('config_loaded', App::$config[$family])) { $r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family)); if($r !== false) { if($r) { foreach($r as $rr) { $k = $rr['k']; - $a->config[$family][$k] = $rr['v']; + App::$config[$family][$k] = $rr['v']; } } - $a->config[$family]['config_loaded'] = true; + App::$config[$family]['config_loaded'] = true; } } } @@ -68,7 +68,7 @@ function load_config($family) { * and a key. * * Get a particular config variable from the given category ($family) and the - * $key from a cached storage in $a->config[$family]. If a key is found in the + * $key from a cached storage in App::$config[$family]. If a key is found in the * DB but does not exist in local config cache, pull it into the cache so we * do not have to hit the DB again for this item. * @@ -83,16 +83,16 @@ function load_config($family) { function get_config($family, $key) { global $a; - if((! array_key_exists($family, $a->config)) || (! array_key_exists('config_loaded', $a->config[$family]))) + if((! array_key_exists($family, App::$config)) || (! array_key_exists('config_loaded', App::$config[$family]))) load_config($family); - if(array_key_exists('config_loaded', $a->config[$family])) { - if(! array_key_exists($key, $a->config[$family])) { + if(array_key_exists('config_loaded', App::$config[$family])) { + if(! array_key_exists($key, App::$config[$family])) { return false; } - return ((! is_array($a->config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', $a->config[$family][$key])) - ? unserialize($a->config[$family][$key]) - : $a->config[$family][$key] + return ((! is_array(App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$family][$key])) + ? unserialize(App::$config[$family][$key]) + : App::$config[$family][$key] ); } return false; @@ -148,7 +148,7 @@ function set_config($family, $key, $value) { dbesc($dbvalue) ); if($ret) { - $a->config[$family][$key] = $value; + App::$config[$family][$key] = $value; $ret = $value; } return $ret; @@ -161,7 +161,7 @@ function set_config($family, $key, $value) { ); if($ret) { - $a->config[$family][$key] = $value; + App::$config[$family][$key] = $value; $ret = $value; } return $ret; @@ -170,7 +170,7 @@ function set_config($family, $key, $value) { /** * @brief Deletes the given key from the hub's configuration database. * - * Removes the configured value from the stored cache in $a->config[$family] + * Removes the configured value from the stored cache in App::$config[$family] * and removes it from the database. * * @param string $family @@ -183,8 +183,8 @@ function del_config($family, $key) { global $a; $ret = false; - if(array_key_exists($family, $a->config) && array_key_exists($key, $a->config[$family])) - unset($a->config[$family][$key]); + if(array_key_exists($family, App::$config) && array_key_exists($key, App::$config[$family])) + unset(App::$config[$family][$key]); $ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'", dbesc($family), dbesc($key) @@ -197,7 +197,7 @@ function del_config($family, $key) { * @brief Loads all configuration values of a channel into a cached storage. * * All configuration values of the given channel are stored in global cache - * which is available under the global variable $a->config[$uid]. + * which is available under the global variable App::$config[$uid]. * * @param string $uid * The channel_id @@ -209,8 +209,8 @@ function load_pconfig($uid) { if($uid === false) return false; - if(! array_key_exists($uid, $a->config)) - $a->config[$uid] = array(); + if(! array_key_exists($uid, App::$config)) + App::$config[$uid] = array(); $r = q("SELECT * FROM pconfig WHERE uid = %d", intval($uid) @@ -220,11 +220,11 @@ function load_pconfig($uid) { foreach($r as $rr) { $k = $rr['k']; $c = $rr['cat']; - if(! array_key_exists($c, $a->config[$uid])) { - $a->config[$uid][$c] = array(); - $a->config[$uid][$c]['config_loaded'] = true; + if(! array_key_exists($c, App::$config[$uid])) { + App::$config[$uid][$c] = array(); + App::$config[$uid][$c]['config_loaded'] = true; } - $a->config[$uid][$c][$k] = $rr['v']; + App::$config[$uid][$c][$k] = $rr['v']; } } } @@ -234,7 +234,7 @@ function load_pconfig($uid) { * ($family) and a key. * * Get a particular channel's config value from the given category ($family) - * and the $key from a cached storage in $a->config[$uid]. + * and the $key from a cached storage in App::$config[$uid]. * * Returns false if not set. * @@ -254,15 +254,15 @@ function get_pconfig($uid, $family, $key, $instore = false) { if($uid === false) return false; - if(! array_key_exists($uid, $a->config)) + if(! array_key_exists($uid, App::$config)) load_pconfig($uid); - if((! array_key_exists($family, $a->config[$uid])) || (! array_key_exists($key, $a->config[$uid][$family]))) + if((! array_key_exists($family, App::$config[$uid])) || (! array_key_exists($key, App::$config[$uid][$family]))) return false; - return ((! is_array($a->config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', $a->config[$uid][$family][$key])) - ? unserialize($a->config[$uid][$family][$key]) - : $a->config[$uid][$family][$key] + return ((! is_array(App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$uid][$family][$key])) + ? unserialize(App::$config[$uid][$family][$key]) + : App::$config[$uid][$family][$key] ); } @@ -287,27 +287,38 @@ function get_pconfig($uid, $family, $key, $instore = false) { function set_pconfig($uid, $family, $key, $value) { global $a; + // this catches subtle errors where this function has been called + // with local_channel() when not logged in (which returns false) + // and throws an error in array_key_exists below. + // we provide a function backtrace in the logs so that we can find + // and fix the calling function. + + if($uid === false) { + btlogger('UID is FALSE!', LOGGER_NORMAL, LOG_ERR); + return; + } + // manage array value $dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); if(get_pconfig($uid, $family, $key) === false) { - if(! array_key_exists($uid, $a->config)) - $a->config[$uid] = array(); - if(! array_key_exists($family, $a->config[$uid])) - $a->config[$uid][$family] = array(); + if(! array_key_exists($uid, App::$config)) + App::$config[$uid] = array(); + if(! array_key_exists($family, App::$config[$uid])) + App::$config[$uid][$family] = array(); // keep a separate copy for all variables which were // set in the life of this page. We need this to // synchronise channel clones. - if(! array_key_exists('transient', $a->config[$uid])) - $a->config[$uid]['transient'] = array(); - if(! array_key_exists($family, $a->config[$uid]['transient'])) - $a->config[$uid]['transient'][$family] = array(); + if(! array_key_exists('transient', App::$config[$uid])) + App::$config[$uid]['transient'] = array(); + if(! array_key_exists($family, App::$config[$uid]['transient'])) + App::$config[$uid]['transient'][$family] = array(); - $a->config[$uid][$family][$key] = $value; - $a->config[$uid]['transient'][$family][$key] = $value; + App::$config[$uid][$family][$key] = $value; + App::$config[$uid]['transient'][$family][$key] = $value; $ret = q("INSERT INTO pconfig ( uid, cat, k, v ) VALUES ( %d, '%s', '%s', '%s' ) ", intval($uid), @@ -332,13 +343,13 @@ function set_pconfig($uid, $family, $key, $value) { // set in the life of this page. We need this to // synchronise channel clones. - if(! array_key_exists('transient', $a->config[$uid])) - $a->config[$uid]['transient'] = array(); - if(! array_key_exists($family, $a->config[$uid]['transient'])) - $a->config[$uid]['transient'][$family] = array(); + if(! array_key_exists('transient', App::$config[$uid])) + App::$config[$uid]['transient'] = array(); + if(! array_key_exists($family, App::$config[$uid]['transient'])) + App::$config[$uid]['transient'][$family] = array(); - $a->config[$uid][$family][$key] = $value; - $a->config[$uid]['transient'][$family][$key] = $value; + App::$config[$uid][$family][$key] = $value; + App::$config[$uid]['transient'][$family][$key] = $value; if($ret) return $value; @@ -349,7 +360,7 @@ function set_pconfig($uid, $family, $key, $value) { /** * @brief Deletes the given key from the channel's configuration. * - * Removes the configured value from the stored cache in $a->config[$uid] + * Removes the configured value from the stored cache in App::$config[$uid] * and removes it from the database. * * @param string $uid @@ -364,8 +375,8 @@ function del_pconfig($uid, $family, $key) { global $a; $ret = false; - if (x($a->config[$uid][$family], $key)) - unset($a->config[$uid][$family][$key]); + if (x(App::$config[$uid][$family], $key)) + unset(App::$config[$uid][$family][$key]); $ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'", intval($uid), dbesc($family), @@ -380,7 +391,7 @@ function del_pconfig($uid, $family, $key) { * @brief Loads a full xchan's configuration into a cached storage. * * All configuration values of the given observer hash are stored in global - * cache which is available under the global variable $a->config[$xchan]. + * cache which is available under the global variable App::$config[$xchan]. * * @param string $xchan * The observer's hash @@ -392,8 +403,8 @@ function load_xconfig($xchan) { if(! $xchan) return false; - if(! array_key_exists($xchan, $a->config)) - $a->config[$xchan] = array(); + if(! array_key_exists($xchan, App::$config)) + App::$config[$xchan] = array(); $r = q("SELECT * FROM xconfig WHERE xchan = '%s'", dbesc($xchan) @@ -403,11 +414,11 @@ function load_xconfig($xchan) { foreach($r as $rr) { $k = $rr['k']; $c = $rr['cat']; - if(! array_key_exists($c, $a->config[$xchan])) { - $a->config[$xchan][$c] = array(); - $a->config[$xchan][$c]['config_loaded'] = true; + if(! array_key_exists($c, App::$config[$xchan])) { + App::$config[$xchan][$c] = array(); + App::$config[$xchan][$c]['config_loaded'] = true; } - $a->config[$xchan][$c][$k] = $rr['v']; + App::$config[$xchan][$c][$k] = $rr['v']; } } } @@ -417,7 +428,7 @@ function load_xconfig($xchan) { * name ($family) and a key. * * Get a particular observer's config value from the given category ($family) - * and the $key from a cached storage in $a->config[$xchan]. + * and the $key from a cached storage in App::$config[$xchan]. * * Returns false if not set. * @@ -435,15 +446,15 @@ function get_xconfig($xchan, $family, $key) { if(! $xchan) return false; - if(! array_key_exists($xchan, $a->config)) + if(! array_key_exists($xchan, App::$config)) load_xconfig($xchan); - if((! array_key_exists($family, $a->config[$xchan])) || (! array_key_exists($key, $a->config[$xchan][$family]))) + if((! array_key_exists($family, App::$config[$xchan])) || (! array_key_exists($key, App::$config[$xchan][$family]))) return false; - return ((! is_array($a->config[$xchan][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', $a->config[$xchan][$family][$key])) - ? unserialize($a->config[$xchan][$family][$key]) - : $a->config[$xchan][$family][$key] + return ((! is_array(App::$config[$xchan][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$xchan][$family][$key])) + ? unserialize(App::$config[$xchan][$family][$key]) + : App::$config[$xchan][$family][$key] ); } @@ -473,12 +484,12 @@ function set_xconfig($xchan, $family, $key, $value) { $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); if(get_xconfig($xchan, $family, $key) === false) { - if(! array_key_exists($xchan, $a->config)) - $a->config[$xchan] = array(); - if(! array_key_exists($family, $a->config[$xchan])) - $a->config[$xchan][$family] = array(); + if(! array_key_exists($xchan, App::$config)) + App::$config[$xchan] = array(); + if(! array_key_exists($family, App::$config[$xchan])) + App::$config[$xchan][$family] = array(); - $a->config[$xchan][$family][$key] = $value; + App::$config[$xchan][$family][$key] = $value; $ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' ) ", dbesc($xchan), dbesc($family), @@ -497,7 +508,7 @@ function set_xconfig($xchan, $family, $key, $value) { dbesc($key) ); - $a->config[$xchan][$family][$key] = $value; + App::$config[$xchan][$family][$key] = $value; if($ret) return $value; @@ -507,7 +518,7 @@ function set_xconfig($xchan, $family, $key, $value) { /** * @brief Deletes the given key from the observer's config. * - * Removes the configured value from the stored cache in $a->config[$xchan] + * Removes the configured value from the stored cache in App::$config[$xchan] * and removes it from the database. * * @param string $xchan @@ -522,8 +533,8 @@ function del_xconfig($xchan, $family, $key) { global $a; $ret = false; - if(x($a->config[$xchan][$family], $key)) - unset($a->config[$xchan][$family][$key]); + if(x(App::$config[$xchan][$family], $key)) + unset(App::$config[$xchan][$family][$key]); $ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'", dbesc($xchan), dbesc($family), @@ -531,3 +542,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..0de4ece00 100644 --- a/include/contact_selectors.php +++ b/include/contact_selectors.php @@ -73,16 +73,18 @@ function contact_poll_interval($current, $disabled = false) { function network_to_name($s) { $nets = array( - NETWORK_DFRN => t('Friendica'), - NETWORK_OSTATUS => t('OStatus'), - NETWORK_FEED => t('RSS/Atom'), - NETWORK_MAIL => t('Email'), - NETWORK_DIASPORA => t('Diaspora'), - NETWORK_FACEBOOK => t('Facebook'), - NETWORK_ZOT => t('Zot!'), - NETWORK_LINKEDIN => t('LinkedIn'), - NETWORK_XMPP => t('XMPP/IM'), - NETWORK_MYSPACE => t('MySpace'), + NETWORK_DFRN => t('Friendica'), + NETWORK_FRND => t('Friendica'), + NETWORK_OSTATUS => t('OStatus'), + NETWORK_GNUSOCIAL => t('GNU-Social'), + NETWORK_FEED => t('RSS/Atom'), + NETWORK_MAIL => t('Email'), + NETWORK_DIASPORA => t('Diaspora'), + NETWORK_FACEBOOK => t('Facebook'), + NETWORK_ZOT => t('Zot'), + NETWORK_LINKEDIN => t('LinkedIn'), + NETWORK_XMPP => t('XMPP/IM'), + NETWORK_MYSPACE => t('MySpace'), ); call_hooks('network_to_name', $nets); diff --git a/include/contact_widgets.php b/include/contact_widgets.php index a60b8b1c3..ba1241fcb 100644 --- a/include/contact_widgets.php +++ b/include/contact_widgets.php @@ -10,7 +10,7 @@ function findpeople_widget() { if(get_config('system','invitation_only')) { $x = get_pconfig(local_channel(),'system','invites_remaining'); if($x || is_site_admin()) { - $a->page['aside'] .= '<div class="side-link" id="side-invite-remain">' + App::$page['aside'] .= '<div class="side-link" id="side-invite-remain">' . sprintf( tt('%d invitation available','%d invitations available',$x), $x) . '</div>' . $inv; } @@ -68,7 +68,7 @@ function categories_widget($baseurl,$selected = '') { $a = get_app(); - if(! feature_enabled($a->profile['profile_uid'],'categories')) + if(! feature_enabled(App::$profile['profile_uid'],'categories')) return ''; $item_normal = item_normal(); @@ -83,9 +83,9 @@ function categories_widget($baseurl,$selected = '') { and item.item_wall = 1 $item_normal order by term.term asc", - intval($a->profile['profile_uid']), + intval(App::$profile['profile_uid']), intval(TERM_CATEGORY), - dbesc($a->profile['channel_hash']) + dbesc(App::$profile['channel_hash']) ); if($r && count($r)) { foreach($r as $rr) @@ -126,7 +126,7 @@ function common_friends_visitor_widget($profile_uid) { return replace_macros(get_markup_template('remote_friends_common.tpl'), array( '$desc' => sprintf( tt("%d connection in common", "%d connections in common", $t), $t), - '$base' => $a->get_baseurl(), + '$base' => z_root(), '$uid' => $profile_uid, '$cid' => $observer, '$linkmore' => (($t > 5) ? 'true' : ''), diff --git a/include/conversation.php b/include/conversation.php index 747bb5d0a..7d80b08fc 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -54,7 +54,7 @@ function item_redir_and_replace_images($body, $images, $cid) { $origbody = $body; $newbody = ''; - $observer = get_app()->get_observer(); + $observer = App::get_observer(); $obhash = (($observer) ? $observer['xchan_hash'] : ''); $obaddr = (($observer) ? $observer['xchan_addr'] : ''); @@ -489,7 +489,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $live_update_div = '<div id="live-network"></div>' . "\r\n" . "<script> var profile_uid = " . $_SESSION['uid'] - . "; var netargs = '" . substr($a->cmd,8) + . "; var netargs = '" . substr(App::$cmd,8) . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'search')) ? '&search=' . $_GET['search'] : '') @@ -504,12 +504,12 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ . ((x($_GET,'cmax')) ? '&cmax=' . $_GET['cmax'] : '') . ((x($_GET,'file')) ? '&file=' . $_GET['file'] : '') . ((x($_GET,'uri')) ? '&uri=' . $_GET['uri'] : '') - . "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; + . "'; var profile_page = " . App::$pager['page'] . "; </script>\r\n"; } } elseif ($mode === 'channel') { - $profile_owner = $a->profile['profile_uid']; + $profile_owner = App::$profile['profile_uid']; $page_writeable = ($profile_owner == local_channel()); if (!$update) { @@ -519,8 +519,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ // because browser prefetching might change it on us. We have to deliver it with the page. $live_update_div = '<div id="live-channel"></div>' . "\r\n" - . "<script> var profile_uid = " . $a->profile['profile_uid'] - . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; + . "<script> var profile_uid = " . App::$profile['profile_uid'] + . "; var netargs = '?f='; var profile_page = " . App::$pager['page'] . "; </script>\r\n"; } } } @@ -532,7 +532,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ } elseif ($mode === 'page') { - $profile_owner = $a->profile['uid']; + $profile_owner = App::$profile['uid']; $page_writeable = ($profile_owner == local_channel()); $live_update_div = '<div id="live-page"></div>' . "\r\n"; } @@ -542,11 +542,11 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ } elseif ($mode === 'photos') { - $profile_onwer = $a->profile['profile_uid']; + $profile_onwer = App::$profile['profile_uid']; $page_writeable = ($profile_owner == local_channel()); $live_update_div = '<div id="live-photos"></div>' . "\r\n"; // for photos we've already formatted the top-level item (the photo) - $content_html = $a->data['photo_html']; + $content_html = App::$data['photo_html']; } $page_dropping = ((local_channel() && local_channel() == $profile_owner) ? true : false); @@ -555,13 +555,13 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $page_dropping = false; - $channel = $a->get_channel(); - $observer = $a->get_observer(); + $channel = App::get_channel(); + $observer = App::get_observer(); if($update) $return_url = $_SESSION['return_url']; else - $return_url = $_SESSION['return_url'] = $a->query_string; + $return_url = $_SESSION['return_url'] = App::$query_string; load_contact_links(local_channel()); @@ -623,7 +623,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $nickname = $item['nickname']; } else - $nickname = $a->user['nickname']; + $nickname = App::$user['nickname']; $profile_name = ((strlen($item['author-name'])) ? $item['author-name'] : $item['name']); if($item['author-link'] && (! $item['author-name'])) @@ -844,12 +844,12 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $o .= replace_macros($page_template, array( - '$baseurl' => $a->get_baseurl($ssl_state), + '$baseurl' => z_root(), '$photo_item' => $content_html, '$live_update' => $live_update_div, '$remove' => t('remove'), '$mode' => $mode, - '$user' => $a->user, + '$user' => App::$user, '$threads' => $threads, '$wait' => t('Loading...'), '$dropping' => ($page_dropping?t('Delete Selected Items'):False), @@ -869,13 +869,13 @@ function best_link_url($item) { $clean_url = normalise_link($item['author-link']); if((local_channel()) && (local_channel() == $item['uid'])) { - if(isset($a->contacts) && x($a->contacts,$clean_url)) { - if($a->contacts[$clean_url]['network'] === NETWORK_DFRN) { - $best_url = $a->get_baseurl($ssl_state) . '/redir/' . $a->contacts[$clean_url]['id']; + if(isset(App::$contacts) && x(App::$contacts,$clean_url)) { + if(App::$contacts[$clean_url]['network'] === NETWORK_DFRN) { + $best_url = z_root() . '/redir/' . App::$contacts[$clean_url]['id']; $sparkle = true; } else - $best_url = $a->contacts[$clean_url]['url']; + $best_url = App::$contacts[$clean_url]['url']; } } if(! $best_url) { @@ -907,9 +907,9 @@ function item_photo_menu($item){ if($local_channel) { $ssl_state = true; - if(! count($a->contacts)) + if(! count(App::$contacts)) load_contact_links($local_channel); - $channel = $a->get_channel(); + $channel = App::get_channel(); $channel_hash = (($channel) ? $channel['channel_hash'] : ''); } @@ -925,42 +925,52 @@ function item_photo_menu($item){ $profile_link = chanlink_hash($item['author_xchan']); if($item['uid'] > 0) - $pm_url = $a->get_baseurl($ssl_state) . '/mail/new/?f=&hash=' . $item['author_xchan']; + $pm_url = z_root() . '/mail/new/?f=&hash=' . $item['author_xchan']; - if($a->contacts && array_key_exists($item['author_xchan'],$a->contacts)) - $contact = $a->contacts[$item['author_xchan']]; + if(App::$contacts && array_key_exists($item['author_xchan'],App::$contacts)) + $contact = App::$contacts[$item['author_xchan']]; else if($local_channel && $item['author']['xchan_addr']) $follow_url = z_root() . '/follow/?f=&url=' . $item['author']['xchan_addr']; if($contact) { - $poke_link = $a->get_baseurl($ssl_state) . '/poke/?f=&c=' . $contact['abook_id']; + $poke_link = z_root() . '/poke/?f=&c=' . $contact['abook_id']; if (! intval($contact['abook_self'])) - $contact_url = $a->get_baseurl($ssl_state) . '/connedit/' . $contact['abook_id']; - $posts_link = $a->get_baseurl($ssl_state) . '/network/?cid=' . $contact['abook_id']; + $contact_url = z_root() . '/connedit/' . $contact['abook_id']; + $posts_link = z_root() . '/network/?cid=' . $contact['abook_id']; $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){ @@ -1100,6 +1110,11 @@ function status_editor($a, $x, $popup = false) { $o = ''; + require_once('include/Contact.php'); + $c = channelx_by_n($x['profile_uid']); + if($c && $c['channel_moved']) + return $o; + $geotag = (($x['allow_location']) ? replace_macros(get_markup_template('jot_geotag.tpl'), array()) : ''); $plaintext = true; @@ -1144,9 +1159,9 @@ function status_editor($a, $x, $popup = false) { $tpl = get_markup_template('jot-header.tpl'); - $a->page['htmlhead'] .= replace_macros($tpl, array( + App::$page['htmlhead'] .= replace_macros($tpl, array( '$newpost' => 'true', - '$baseurl' => $a->get_baseurl(true), + '$baseurl' => z_root(), '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), '$pretext' => ((x($x,'pretext')) ? $x['pretext'] : ''), '$geotag' => $geotag, @@ -1158,7 +1173,9 @@ function status_editor($a, $x, $popup = false) { '$term' => t('Tag term:'), '$fileas' => t('Save to Folder:'), '$whereareu' => t('Where are you right now?'), - '$expireswhen' => t('Expires YYYY-MM-DD HH:MM') + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM'), + '$editor_autocomplete'=> ((x($x,'editor_autocomplete')) ? $x['editor_autocomplete'] : ''), + '$bbco_autocomplete'=> ((x($x,'bbco_autocomplete')) ? $x['bbco_autocomplete'] : ''), )); $tpl = get_markup_template('jot.tpl'); @@ -1187,8 +1204,8 @@ function status_editor($a, $x, $popup = false) { call_hooks('jot_networks', $jotnets); $o .= replace_macros($tpl, array( - '$return_path' => ((x($x, 'return_path')) ? $x['return_path'] : $a->query_string), - '$action' => $a->get_baseurl(true) . '/item', + '$return_path' => ((x($x, 'return_path')) ? $x['return_path'] : App::$query_string), + '$action' => z_root() . '/item', '$share' => (x($x,'button') ? $x['button'] : t('Share')), '$webpage' => $webpage, '$placeholdpagetitle' => ((x($x,'ptlabel')) ? $x['ptlabel'] : t('Page link name')), @@ -1231,7 +1248,7 @@ function status_editor($a, $x, $popup = false) { '$content' => ((x($x,'body')) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8') : ''), '$attachment' => ((x($x, 'attachment')) ? $x['attachment'] : ''), '$post_id' => '', - '$baseurl' => $a->get_baseurl(true), + '$baseurl' => z_root(), '$defloc' => $x['default_location'], '$visitor' => $x['visitor'], '$public' => t('Public post'), @@ -1259,6 +1276,7 @@ function status_editor($a, $x, $popup = false) { '$expiryModalOK' => t('OK'), '$expiryModalCANCEL' => t('Cancel'), '$expanded' => ((x($x, 'expanded')) ? $x['expanded'] : false), + '$bbcode' => ((x($x, 'bbcode')) ? $x['bbcode'] : false) )); if ($popup === true) { @@ -1409,12 +1427,12 @@ function prepare_page($item) { $a = get_app(); $naked = 1; // $naked = ((get_pconfig($item['uid'],'system','nakedpage')) ? 1 : 0); - $observer = $a->get_observer(); + $observer = App::get_observer(); //240 chars is the longest we can have before we start hitting problems with suhosin sites $preview = substr(urlencode($item['body']), 0, 240); - $link = z_root() . '/' . $a->cmd; - if(array_key_exists('webpage',$a->layout) && array_key_exists('authored',$a->layout['webpage'])) { - if($a->layout['webpage']['authored'] === 'none') + $link = z_root() . '/' . App::$cmd; + if(array_key_exists('webpage',App::$layout) && array_key_exists('authored',App::$layout['webpage'])) { + if(App::$layout['webpage']['authored'] === 'none') $naked = 1; // ... other possible options } @@ -1493,7 +1511,7 @@ function network_tabs() { if ($no_active=='active') $all_active='active'; - $cmd = $a->cmd; + $cmd = App::$cmd; // tabs $tabs = array(); @@ -1577,15 +1595,25 @@ function network_tabs() { function profile_tabs($a, $is_owner = false, $nickname = null){ // Don't provide any profile tabs if we're running as the sys channel - if ($a->is_sys) + + if (App::$is_sys) return; - $channel = $a->get_channel(); + $channel = App::get_channel(); if (is_null($nickname)) $nickname = $channel['channel_address']; - $uid = (($a->profile['profile_uid']) ? $a->profile['profile_uid'] : local_channel()); + + $uid = ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : local_channel()); + + if($uid == local_channel()) { + $cal_link = ''; + } + else { + $cal_link = '/cal/' . $nickname; + } + if (get_pconfig($uid, 'system', 'noprofiletabs')) return; @@ -1593,8 +1621,8 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ if (x($_GET, 'tab')) $tab = notags(trim($_GET['tab'])); - $url = $a->get_baseurl() . '/channel/' . $nickname; - $pr = $a->get_baseurl() . '/profile/' . $nickname; + $url = z_root() . '/channel/' . $nickname; + $pr = z_root() . '/profile/' . $nickname; $tabs = array( array( @@ -1620,27 +1648,38 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ if ($p['view_storage']) { $tabs[] = array( 'label' => t('Photos'), - 'url' => $a->get_baseurl() . '/photos/' . $nickname, + 'url' => z_root() . '/photos/' . $nickname, 'sel' => ((argv(0) == 'photos') ? 'active' : ''), 'title' => t('Photo Albums'), 'id' => 'photo-tab', ); $tabs[] = array( 'label' => t('Files'), - 'url' => $a->get_baseurl() . '/cloud/' . $nickname, + 'url' => z_root() . '/cloud/' . $nickname, 'sel' => ((argv(0) == 'cloud' || argv(0) == 'sharedwithme') ? 'active' : ''), 'title' => t('Files and Storage'), 'id' => 'files-tab', ); } - if ($p['chat']) { + if($p['view_stream'] && $cal_link) { + $tabs[] = array( + 'label' => t('Events'), + 'url' => z_root() . $cal_link, + 'sel' => ((argv(0) == 'cal' || argv(0) == 'events') ? 'active' : ''), + 'title' => t('Events'), + 'id' => 'event-tab', + ); + } + + + if ($p['chat'] && feature_enabled($uid,'ajaxchat')) { require_once('include/chat.php'); $has_chats = chatroom_list_count($uid); if ($has_chats) { $tabs[] = array( 'label' => t('Chatrooms'), - 'url' => $a->get_baseurl() . '/chat/' . $nickname, + 'url' => z_root() . '/chat/' . $nickname, 'sel' => ((argv(0) == 'chat') ? 'active' : '' ), 'title' => t('Chatrooms'), 'id' => 'chat-tab', @@ -1653,7 +1692,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ if ($is_owner && $has_bookmarks) { $tabs[] = array( 'label' => t('Bookmarks'), - 'url' => $a->get_baseurl() . '/bookmarks', + 'url' => z_root() . '/bookmarks', 'sel' => ((argv(0) == 'bookmarks') ? 'active' : ''), 'title' => t('Saved Bookmarks'), 'id' => 'bookmarks-tab', @@ -1663,7 +1702,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ if ($p['write_pages'] && feature_enabled($uid,'webpages')) { $tabs[] = array( 'label' => t('Webpages'), - 'url' => $a->get_baseurl() . '/webpages/' . $nickname, + 'url' => z_root() . '/webpages/' . $nickname, 'sel' => ((argv(0) == 'webpages') ? 'active' : ''), 'title' => t('Manage Webpages'), 'id' => 'webpages-tab', diff --git a/include/crypto.php b/include/crypto.php index 494a2a5b9..d636c6848 100644 --- a/include/crypto.php +++ b/include/crypto.php @@ -20,7 +20,14 @@ 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) { + while($msg = openssl_error_string()) + logger('openssl_verify: ' . $msg,LOGGER_NORMAL,LOG_ERR); + btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR); + } + return $verify; } @@ -241,6 +248,7 @@ function pkcs1_encode($Modulus,$PublicExponent) { } +// http://stackoverflow.com/questions/27568570/how-to-convert-raw-modulus-exponent-to-rsa-public-key-pem-format function metopem($m,$e) { $der = pkcs8_encode($m,$e); $key = DerToPem($der,false); @@ -291,11 +299,33 @@ function metorsa($m,$e) { return $key; } + + function salmon_key($pubkey) { pemtome($pubkey,$m,$e); return 'RSA' . '.' . base64url_encode($m,true) . '.' . base64url_encode($e,true) ; } + +function convert_salmon_key($key) { + + if(strstr($key,',')) + $rawkey = substr($key,strpos($key,',')+1); + else + $rawkey = substr($key,5); + + $key_info = explode('.',$rawkey); + + $m = base64url_decode($key_info[1]); + $e = base64url_decode($key_info[2]); + + logger('key details: ' . print_r($key_info,true), LOGGER_DATA); + $salmon_key = metopem($m,$e); + return $salmon_key; + +} + + function z_obscure($s) { return json_encode(crypto_encapsulate($s,get_config('system','pubkey'))); } @@ -305,3 +335,4 @@ function z_unobscure($s) { return $s; return crypto_unencapsulate(json_decode($s,true),get_config('system','prvkey')); } + diff --git a/include/datetime.php b/include/datetime.php index 1d10e7ad7..83fb49d04 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -119,6 +119,8 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d * @return string */ function dob($dob) { + $a = get_app(); + list($year, $month, $day) = sscanf($dob, '%4d-%2d-%2d'); $f = get_config('system', 'birthday_input_format'); if (! $f) @@ -129,7 +131,15 @@ 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 = replace_macros(get_markup_template("field_input.tpl"), array('$field' => array( + 'dob', + t('Birthday'), + $value, + ((intval($value)) ? t('Age: ') . age($value,App::$user['timezone'],App::$user['timezone']) : ''), + '', + '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 +279,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 +296,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 +559,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/dir_fns.php b/include/dir_fns.php index fd2a5835d..1c3149081 100644 --- a/include/dir_fns.php +++ b/include/dir_fns.php @@ -421,7 +421,7 @@ function local_dir_update($uid, $force) { $arr = array('channel_id' => $uid, 'hash' => $hash, 'profile' => $profile); call_hooks('local_dir_update', $arr); - $address = $p[0]['channel_address'] . '@' . get_app()->get_hostname(); + $address = $p[0]['channel_address'] . '@' . App::get_hostname(); if (perm_is_allowed($uid, '', 'view_profile')) { import_directory_profile($hash, $arr['profile'], $address, 0); @@ -436,6 +436,6 @@ function local_dir_update($uid, $force) { } } - $ud_hash = random_string() . '@' . get_app()->get_hostname(); - update_modtime($hash, $ud_hash, $p[0]['channel_address'] . '@' . get_app()->get_hostname(),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); + $ud_hash = random_string() . '@' . App::get_hostname(); + update_modtime($hash, $ud_hash, $p[0]['channel_address'] . '@' . App::get_hostname(),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); } diff --git a/include/enotify.php b/include/enotify.php index c9b6e0463..d87c5af11 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -56,13 +56,13 @@ function notification($params) { $banner = t('$Projectname Notification'); $product = t('$projectname'); // PLATFORM_NAME; - $siteurl = $a->get_baseurl(true); + $siteurl = z_root(); $thanks = t('Thank You,'); $sitename = get_config('system','sitename'); $site_admin = sprintf( t('%s Administrator'), $sitename); $sender_name = $product; - $hostname = $a->get_hostname(); + $hostname = App::get_hostname(); if(strpos($hostname,':')) $hostname = substr($hostname,0,strpos($hostname,':')); @@ -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) { @@ -419,12 +419,12 @@ function notification($params) { return; } - $itemlink = $a->get_baseurl() . '/notify/view/' . $notify_id; + $itemlink = z_root() . '/notify/view/' . $notify_id; $msg = str_replace('$itemlink',$itemlink,$epreamble); // wretched hack, but we don't want to duplicate all the preamble variations and we also don't want to screw up a translation - if (($a->language === 'en' || (! $a->language)) && strpos($msg,', ')) + if ((App::$language === 'en' || (! App::$language)) && strpos($msg,', ')) $msg = substr($msg,strpos($msg,', ')+1); $r = q("update notify set msg = '%s' where id = %d and uid = %d", @@ -441,7 +441,7 @@ function notification($params) { logger('notification: sending notification email'); $hn = get_pconfig($recip['channel_id'],'system','email_notify_host'); - if($hn && (! stristr(get_app()->get_hostname(),$hn))) { + if($hn && (! stristr(App::get_hostname(),$hn))) { // this isn't the email notification host pop_lang(); return; @@ -455,7 +455,7 @@ function notification($params) { // use $_SESSION['zid_override'] to force zid() to use // the recipient address instead of the current observer - $_SESSION['zid_override'] = $recip['channel_address'] . '@' . get_app()->get_hostname(); + $_SESSION['zid_override'] = $recip['channel_address'] . '@' . App::get_hostname(); $_SESSION['zrl_override'] = z_root() . '/channel/' . $recip['channel_address']; $textversion = zidify_links($textversion); @@ -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..7a99bc746 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(App::$language). "\r\n"; if(array_key_exists('start', $ev)) $o .= format_event_ical($ev); else { @@ -361,7 +361,7 @@ function event_store_event($arr) { if(array_key_exists('external_id',$arr)) $hash = $arr['external_id']; else - $hash = random_string() . '@' . get_app()->get_hostname(); + $hash = random_string() . '@' . App::get_hostname(); $r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,start,finish,summary,description,location,type, adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, event_priority, allow_cid,allow_gid,deny_cid,deny_gid) @@ -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..38700f9f5 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('ajaxchat', t('Access Controlled Chatrooms'), t('Provide chatrooms and chat services with access control.'),true,get_config('feature_lock','ajaxchat')), + 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..70e717cfc 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]); @@ -133,26 +134,29 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $their_perms = 0; $xchan_hash = ''; - $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), dbesc($url) ); - if(! $r) { // attempt network auto-discovery - if(strpos($url,'@') && (! $is_http)) { - $d = discover_by_webbie($url); - } - elseif($is_http) { - if(get_config('system','feed_contacts')) + + $d = discover_by_webbie($url); + + if((! $d) && ($is_http)) { + + // try RSS discovery + + if(get_config('system','feed_contacts')) { $d = discover_by_url($url); + } else { $result['message'] = t('Protocol disabled.'); return $result; } } + if($d) { $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), @@ -160,6 +164,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) ); } } + + // if discovery was a success we should have an xchan record in $r + if($r) { $xchan = $r[0]; $xchan_hash = $r[0]['xchan_hash']; @@ -167,13 +174,16 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } } + if(! $xchan_hash) { $result['message'] = t('Channel discovery failed.'); logger('follow: ' . $result['message']); return $result; } - $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => 1, 'singleton' => 0); + $allowed = (($is_red || $r[0]['xchan_network'] === 'rss') ? 1 : 0); + + $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => $allowed, 'singleton' => 0); call_hooks('follow_allow',$x); @@ -183,27 +193,13 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } $singleton = intval($x['singleton']); - if((local_channel()) && $uid == local_channel()) { - $aid = get_account_id(); - $hash = get_observer_hash(); - $ch = $a->get_channel(); - $default_group = $ch['channel_default_group']; - } - else { - $r = q("select * from channel where channel_id = %d limit 1", - intval($uid) - ); - if(! $r) { - $result['message'] = t('local account not found.'); - return $result; - } - $aid = $r[0]['channel_account_id']; - $hash = $r[0]['channel_hash']; - $default_group = $r[0]['channel_default_group']; - } + $aid = $channel['channel_account_id']; + $hash = get_observer_hash(); + $default_group = $channel['channel_default_group']; - if($is_http) { + if($xchan['xchan_network'] === 'rss') { + // check service class feed limits $r = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ", intval($aid) @@ -226,6 +222,7 @@ 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 +239,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,12 +266,13 @@ 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']); } - $arr = array('channel_id' => $uid, 'abook' => $result['abook']); + $arr = array('channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook']); call_hooks('follow', $arr); diff --git a/include/group.php b/include/group.php index 0875b10f9..748ec0c13 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()) @@ -211,6 +211,22 @@ function group_get_members($gid) { return $ret; } +function group_get_members_xchan($gid) { + $ret = array(); + if(intval($gid)) { + $r = q("SELECT xchan FROM group_member WHERE gid = %d AND uid = %d", + intval($gid), + intval(local_channel()) + ); + if(count($r)) { + foreach($r as $rr) { + $ret[] = $rr['xchan']; + } + } + } + return $ret; +} + function mini_group_select($uid,$group = '') { $grps = array(); @@ -229,7 +245,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 +308,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/hubloc.php b/include/hubloc.php index a1171b0e2..695cada3c 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -134,10 +134,17 @@ function hubloc_change_primary($hubloc) { $r = q("select channel_id, channel_primary from channel where channel_hash = '%s' limit 1", dbesc($hubloc['hubloc_hash']) ); - if(($r) && (! $r[0]['channel_primary'])) { - q("update channel set channel_primary = 1 where channel_id = %d", - intval($r[0]['channel_id']) - ); + if($r) { + if(! $r[0]['channel_primary']) { + q("update channel set channel_primary = 1 where channel_id = %d", + intval($r[0]['channel_id']) + ); + } + else { + q("update channel set channel_primary = 0 where channel_id = %d", + intval($r[0]['channel_id']) + ); + } } // do we even have an xchan for this hubloc and if so is it already set as primary? diff --git a/include/identity.php b/include/identity.php index 98ba26bd8..1c899048a 100644 --- a/include/identity.php +++ b/include/identity.php @@ -174,11 +174,10 @@ function channel_total() { */ function create_identity($arr) { - $a = get_app(); $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']); @@ -275,7 +274,7 @@ function create_identity($arr) { intval($pageflags), intval($system), intval($expire), - dbesc($a->timezone) + dbesc(App::$timezone) ); $r = q("select * from channel where channel_account_id = %d @@ -302,11 +301,11 @@ function create_identity($arr) { dbesc($guid), dbesc($sig), dbesc($hash), - dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), + dbesc($ret['channel']['channel_address'] . '@' . App::get_hostname()), intval($primary), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey']))), - dbesc(get_app()->get_hostname()), + dbesc(App::get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system','pubkey')), dbesc('zot') @@ -321,10 +320,10 @@ function create_identity($arr) { dbesc($guid), dbesc($sig), dbesc($key['pubkey']), - dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"), - dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}"), - dbesc($a->get_baseurl() . "/photo/profile/s/{$newuid}"), - dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), + dbesc(z_root() . "/photo/profile/l/{$newuid}"), + dbesc(z_root() . "/photo/profile/m/{$newuid}"), + dbesc(z_root() . "/photo/profile/s/{$newuid}"), + dbesc($ret['channel']['channel_address'] . '@' . App::get_hostname()), dbesc(z_root() . '/channel/' . $ret['channel']['channel_address']), dbesc(z_root() . '/follow?f=&url=%s'), dbesc(z_root() . '/poco/' . $ret['channel']['channel_address']), @@ -347,12 +346,12 @@ function create_identity($arr) { 1, $publish, dbesc($ret['channel']['channel_name']), - dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"), - dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}") + dbesc(z_root() . "/photo/profile/l/{$newuid}"), + dbesc(z_root() . "/photo/profile/m/{$newuid}") ); 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 @@ -410,7 +409,15 @@ function create_identity($arr) { set_pconfig($ret['channel']['channel_id'],'system','photo_path', '%Y-%m'); set_pconfig($ret['channel']['channel_id'],'system','attach_path','%Y-%m'); } - + + // UNO: channel defaults, incl addons (addons specific pconfig will only work after the relevant addon is enabled by the admin). It's located here, so members can modify these defaults after the channel is created. + if(UNO) { + //diaspora protocol addon + set_pconfig($ret['channel']['channel_id'],'system','diaspora_allowed', '1'); + set_pconfig($ret['channel']['channel_id'],'system','diaspora_public_comments', '1'); + set_pconfig($ret['channel']['channel_id'],'system','prevent_tag_hijacking', '0'); + } + // auto-follow any of the hub's pre-configured channel choices. // Only do this if it's the first channel for this account; // otherwise it could get annoying. Don't make this list too big @@ -482,7 +489,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 +512,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); } @@ -537,7 +550,8 @@ function identity_basic_export($channel_id, $items = false) { if($r) $ret['config'] = $r; - $r = q("select type, data, os_storage from photo where scale = 4 and profile = 1 and uid = %d limit 1", + $r = q("select type, data, os_storage from photo where scale = 4 and photo_usage = %d and uid = %d limit 1", + intval(PHOTO_PROFILE), intval($channel_id) ); @@ -766,14 +780,14 @@ function profile_load(&$a, $nickname, $profile = '') { ); if(! $user) { - logger('profile error: ' . $a->query_string, LOGGER_DEBUG); + logger('profile error: ' . App::$query_string, LOGGER_DEBUG); notice( t('Requested channel is not available.') . EOL ); - $a->error = 404; + App::$error = 404; return; } // get the current observer - $observer = $a->get_observer(); + $observer = App::get_observer(); $can_view_profile = true; @@ -812,9 +826,9 @@ function profile_load(&$a, $nickname, $profile = '') { } if(! $p) { - logger('profile error: ' . $a->query_string, LOGGER_DEBUG); + logger('profile error: ' . App::$query_string, LOGGER_DEBUG); notice( t('Requested profile is not available.') . EOL ); - $a->error = 404; + App::$error = 404; return; } @@ -860,9 +874,8 @@ function profile_load(&$a, $nickname, $profile = '') { // fetch user tags if this isn't the default profile if(! $p[0]['is_default']) { - /** @BUG $profile_uid is undefinded for this query, so should not work. */ $x = q("select `keywords` from `profile` where uid = %d and `is_default` = 1 limit 1", - intval($profile_uid) + intval($p[0]['profile_uid']) ); if($x && $can_view_profile) $p[0]['keywords'] = $x[0]['keywords']; @@ -871,23 +884,23 @@ function profile_load(&$a, $nickname, $profile = '') { if($p[0]['keywords']) { $keywords = str_replace(array('#',',',' ',',,'),array('',' ',',',','),$p[0]['keywords']); if(strlen($keywords) && $can_view_profile) - $a->page['htmlhead'] .= '<meta name="keywords" content="' . htmlentities($keywords,ENT_COMPAT,'UTF-8') . '" />' . "\r\n" ; + App::$page['htmlhead'] .= '<meta name="keywords" content="' . htmlentities($keywords,ENT_COMPAT,'UTF-8') . '" />' . "\r\n" ; } - $a->profile = $p[0]; - $a->profile_uid = $p[0]['profile_uid']; - $a->page['title'] = $a->profile['channel_name'] . " - " . $a->profile['channel_address'] . "@" . $a->get_hostname(); + App::$profile = $p[0]; + App::$profile_uid = $p[0]['profile_uid']; + App::$page['title'] = App::$profile['channel_name'] . " - " . App::$profile['channel_address'] . "@" . App::get_hostname(); - $a->profile['permission_to_view'] = $can_view_profile; + App::$profile['permission_to_view'] = $can_view_profile; if($can_view_profile) { $online = get_online_status($nickname); - $a->profile['online_status'] = $online['result']; + App::$profile['online_status'] = $online['result']; } if(local_channel()) { - $a->profile['channel_mobile_theme'] = get_pconfig(local_channel(),'system', 'mobile_theme'); - $_SESSION['mobile_theme'] = $a->profile['channel_mobile_theme']; + App::$profile['channel_mobile_theme'] = get_pconfig(local_channel(),'system', 'mobile_theme'); + $_SESSION['mobile_theme'] = App::$profile['channel_mobile_theme']; } /* @@ -898,6 +911,54 @@ function profile_load(&$a, $nickname, $profile = '') { } +function profile_edit_menu($uid) { + + $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(z_root(). '/profiles', t('Edit Profiles'), '', t('Edit')); + $ret['menu']['cr_new'] = t('Create New Profile'); + } + else { + $ret['edit'] = array(z_root() . '/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,28 +972,27 @@ 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) { - - $a = get_app(); +function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = false) { - $observer = $a->get_observer(); + $observer = App::get_observer(); $o = ''; $location = false; $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); @@ -946,7 +1006,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { $connect_url = rconnect_url($profile['uid'],get_observer_hash()); $connect = (($connect_url) ? t('Connect') : ''); if($connect_url) - $connect_url = sprintf($connect_url,urlencode($profile['channel_address'] . '@' . $a->get_hostname())); + $connect_url = sprintf($connect_url,urlencode($profile['channel_address'] . '@' . App::get_hostname())); // premium channel - over-ride @@ -954,42 +1014,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 +1030,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 +1067,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 +1092,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); @@ -1080,7 +1108,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { */ function get_birthdays() { - $a = get_app(); $o = ''; if(! local_channel()) @@ -1127,12 +1154,12 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { $url = $rr['url']; if($rr['network'] === NETWORK_DFRN) { $sparkle = " sparkle"; - $url = $a->get_baseurl() . '/redir/' . $rr['cid']; + $url = z_root() . '/redir/' . $rr['cid']; } $rr['link'] = $url; $rr['title'] = $rr['name']; - $rr['date'] = day_translate(datetime_convert('UTC', $a->timezone, $rr['start'], $rr['adjust'] ? $bd_format : $bd_short)) . (($today) ? ' ' . t('[today]') : ''); + $rr['date'] = day_translate(datetime_convert('UTC', App::$timezone, $rr['start'], $rr['adjust'] ? $bd_format : $bd_short)) . (($today) ? ' ' . t('[today]') : ''); $rr['startime'] = Null; $rr['today'] = $today; } @@ -1140,7 +1167,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { } $tpl = get_markup_template("birthdays_reminder.tpl"); return replace_macros($tpl, array( - '$baseurl' => $a->get_baseurl(), + '$baseurl' => z_root(), '$classtoday' => $classtoday, '$count' => $total, '$event_reminders' => t('Birthday Reminders'), @@ -1159,8 +1186,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { require_once('include/bbcode.php'); - $a = get_app(); - if(! local_channel()) return $o; @@ -1182,15 +1207,15 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { if(strlen($rr['name'])) $total ++; - $strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start'],'Y-m-d'); - if($strt === datetime_convert('UTC',$a->timezone,'now','Y-m-d')) + $strt = datetime_convert('UTC',$rr['convert'] ? App::$timezone : 'UTC',$rr['start'],'Y-m-d'); + if($strt === datetime_convert('UTC',App::$timezone,'now','Y-m-d')) $istoday = true; } $classtoday = (($istoday) ? 'event-today' : ''); foreach($r as &$rr) { if($rr['adjust']) - $md = datetime_convert('UTC',$a->timezone,$rr['start'],'Y/m'); + $md = datetime_convert('UTC',App::$timezone,$rr['start'],'Y/m'); else $md = datetime_convert('UTC','UTC',$rr['start'],'Y/m'); $md .= "/#link-".$rr['id']; @@ -1199,12 +1224,12 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { if(! $title) $title = t('[No description]'); - $strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start']); - $today = ((substr($strt,0,10) === datetime_convert('UTC',$a->timezone,'now','Y-m-d')) ? true : false); + $strt = datetime_convert('UTC',$rr['convert'] ? App::$timezone : 'UTC',$rr['start']); + $today = ((substr($strt,0,10) === datetime_convert('UTC',App::$timezone,'now','Y-m-d')) ? true : false); $rr['link'] = $md; $rr['title'] = $title; - $rr['date'] = day_translate(datetime_convert('UTC', $rr['adjust'] ? $a->timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); + $rr['date'] = day_translate(datetime_convert('UTC', $rr['adjust'] ? App::$timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); $rr['startime'] = $strt; $rr['today'] = $today; } @@ -1212,7 +1237,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { $tpl = get_markup_template("events_reminder.tpl"); return replace_macros($tpl, array( - '$baseurl' => $a->get_baseurl(), + '$baseurl' => z_root(), '$classtoday' => $classtoday, '$count' => count($r), '$event_reminders' => t('Event Reminders'), @@ -1224,32 +1249,46 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { function advanced_profile(&$a) { require_once('include/text.php'); - if(! perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'view_profile')) + if(! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'view_profile')) return ''; - $o = ''; + if(App::$profile['name']) { + + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); + + $advanced = ((feature_enabled(App::$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'); $profile = array(); - $profile['fullname'] = array( t('Full Name:'), $a->profile['name'] ) ; + $profile['fullname'] = array( t('Full Name:'), App::$profile['name'] ) ; - if($a->profile['gender']) $profile['gender'] = array( t('Gender:'), $a->profile['gender'] ); + if(App::$profile['gender']) $profile['gender'] = array( t('Gender:'), App::$profile['gender'] ); $ob_hash = get_observer_hash(); - if($ob_hash && perm_is_allowed($a->profile['profile_uid'],$ob_hash,'post_like')) { + if($ob_hash && perm_is_allowed(App::$profile['profile_uid'],$ob_hash,'post_like')) { $profile['canlike'] = true; $profile['likethis'] = t('Like this channel'); - $profile['profile_guid'] = $a->profile['profile_guid']; + $profile['profile_guid'] = App::$profile['profile_guid']; } $likers = q("select liker, xchan.* from likes left join xchan on liker = xchan_hash where channel_id = %d and target_type = '%s' and verb = '%s'", - intval($a->profile['profile_uid']), + intval(App::$profile['profile_uid']), dbesc(ACTIVITY_OBJ_PROFILE), dbesc(ACTIVITY_LIKE) ); @@ -1258,90 +1297,90 @@ 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')) { + if((App::$profile['dob']) && (App::$profile['dob'] != '0000-00-00')) { $val = ''; - if((substr($a->profile['dob'],5,2) === '00') || (substr($a->profile['dob'],8,2) === '00')) - $val = substr($a->profile['dob'],0,4); + if((substr(App::$profile['dob'],5,2) === '00') || (substr(App::$profile['dob'],8,2) === '00')) + $val = substr(App::$profile['dob'],0,4); $year_bd_format = t('j F, Y'); $short_bd_format = t('j F'); if(! $val) { - $val = ((intval($a->profile['dob'])) - ? day_translate(datetime_convert('UTC','UTC',$a->profile['dob'] . ' 00:00 +00:00',$year_bd_format)) - : day_translate(datetime_convert('UTC','UTC','2001-' . substr($a->profile['dob'],5) . ' 00:00 +00:00',$short_bd_format))); + $val = ((intval(App::$profile['dob'])) + ? day_translate(datetime_convert('UTC','UTC',App::$profile['dob'] . ' 00:00 +00:00',$year_bd_format)) + : day_translate(datetime_convert('UTC','UTC','2001-' . substr(App::$profile['dob'],5) . ' 00:00 +00:00',$short_bd_format))); } $profile['birthday'] = array( t('Birthday:'), $val); } - if($age = age($a->profile['dob'],$a->profile['timezone'],'')) + if($age = age(App::$profile['dob'],App::$profile['timezone'],'')) $profile['age'] = array( t('Age:'), $age ); - if($a->profile['marital']) - $profile['marital'] = array( t('Status:'), $a->profile['marital']); + if(App::$profile['marital']) + $profile['marital'] = array( t('Status:'), App::$profile['marital']); - if($a->profile['with']) - $profile['marital']['with'] = bbcode($a->profile['with']); + if(App::$profile['with']) + $profile['marital']['with'] = bbcode(App::$profile['with']); - if(strlen($a->profile['howlong']) && $a->profile['howlong'] !== NULL_DATE) { - $profile['howlong'] = relative_date($a->profile['howlong'], t('for %1$d %2$s')); + if(strlen(App::$profile['howlong']) && App::$profile['howlong'] !== NULL_DATE) { + $profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s')); } - if($a->profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), $a->profile['sexual'] ); + if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] ); - if($a->profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify($a->profile['homepage']) ); + if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage']) ); - if($a->profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify($a->profile['hometown']) ); + if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown']) ); - if($a->profile['keywords']) $profile['keywords'] = array( t('Tags:'), $a->profile['keywords']); + if(App::$profile['keywords']) $profile['keywords'] = array( t('Tags:'), App::$profile['keywords']); - if($a->profile['politic']) $profile['politic'] = array( t('Political Views:'), $a->profile['politic']); + if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']); - if($a->profile['religion']) $profile['religion'] = array( t('Religion:'), $a->profile['religion']); + if(App::$profile['religion']) $profile['religion'] = array( t('Religion:'), App::$profile['religion']); - if($txt = prepare_text($a->profile['about'])) $profile['about'] = array( t('About:'), $txt ); + if($txt = prepare_text(App::$profile['about'])) $profile['about'] = array( t('About:'), $txt ); - if($txt = prepare_text($a->profile['interest'])) $profile['interest'] = array( t('Hobbies/Interests:'), $txt); + if($txt = prepare_text(App::$profile['interest'])) $profile['interest'] = array( t('Hobbies/Interests:'), $txt); - if($txt = prepare_text($a->profile['likes'])) $profile['likes'] = array( t('Likes:'), $txt); + if($txt = prepare_text(App::$profile['likes'])) $profile['likes'] = array( t('Likes:'), $txt); - if($txt = prepare_text($a->profile['dislikes'])) $profile['dislikes'] = array( t('Dislikes:'), $txt); + if($txt = prepare_text(App::$profile['dislikes'])) $profile['dislikes'] = array( t('Dislikes:'), $txt); - if($txt = prepare_text($a->profile['contact'])) $profile['contact'] = array( t('Contact information and Social Networks:'), $txt); + if($txt = prepare_text(App::$profile['contact'])) $profile['contact'] = array( t('Contact information and Social Networks:'), $txt); - if($txt = prepare_text($a->profile['channels'])) $profile['channels'] = array( t('My other channels:'), $txt); + if($txt = prepare_text(App::$profile['channels'])) $profile['channels'] = array( t('My other channels:'), $txt); - if($txt = prepare_text($a->profile['music'])) $profile['music'] = array( t('Musical interests:'), $txt); + if($txt = prepare_text(App::$profile['music'])) $profile['music'] = array( t('Musical interests:'), $txt); - if($txt = prepare_text($a->profile['book'])) $profile['book'] = array( t('Books, literature:'), $txt); + if($txt = prepare_text(App::$profile['book'])) $profile['book'] = array( t('Books, literature:'), $txt); - if($txt = prepare_text($a->profile['tv'])) $profile['tv'] = array( t('Television:'), $txt); + if($txt = prepare_text(App::$profile['tv'])) $profile['tv'] = array( t('Television:'), $txt); - if($txt = prepare_text($a->profile['film'])) $profile['film'] = array( t('Film/dance/culture/entertainment:'), $txt); + if($txt = prepare_text(App::$profile['film'])) $profile['film'] = array( t('Film/dance/culture/entertainment:'), $txt); - if($txt = prepare_text($a->profile['romance'])) $profile['romance'] = array( t('Love/Romance:'), $txt); + if($txt = prepare_text(App::$profile['romance'])) $profile['romance'] = array( t('Love/Romance:'), $txt); - if($txt = prepare_text($a->profile['work'])) $profile['work'] = array( t('Work/employment:'), $txt); + if($txt = prepare_text(App::$profile['work'])) $profile['work'] = array( t('Work/employment:'), $txt); - if($txt = prepare_text($a->profile['education'])) $profile['education'] = array( t('School/education:'), $txt ); + if($txt = prepare_text(App::$profile['education'])) $profile['education'] = array( t('School/education:'), $txt ); - if($a->profile['extra_fields']) { - foreach($a->profile['extra_fields'] as $f) { + if(App::$profile['extra_fields']) { + foreach(App::$profile['extra_fields'] as $f) { $x = q("select * from profdef where field_name = '%s' limit 1", dbesc($f) ); - if($x && $txt = prepare_text($a->profile[$f])) + if($x && $txt = prepare_text(App::$profile[$f])) $profile[$f] = array( $x[0]['field_desc'] . ':',$txt); } - $profile['extra_fields'] = $a->profile['extra_fields']; + $profile['extra_fields'] = App::$profile['extra_fields']; } - $things = get_things($a->profile['profile_guid'],$a->profile['profile_uid']); + $things = get_things(App::$profile['profile_guid'],App::$profile['profile_uid']); // logger('mod_profile: things: ' . print_r($things,true), LOGGER_DATA); @@ -1350,6 +1389,8 @@ function advanced_profile(&$a) { '$canlike' => (($profile['canlike'])? true : false), '$likethis' => t('Like this thing'), '$profile' => $profile, + '$fields' => $clean_fields, + '$editmenu' => profile_edit_menu(App::$profile['profile_uid']), '$things' => $things )); } @@ -1392,7 +1433,7 @@ function zid_init(&$a) { $tmp_str = get_my_address(); if(validate_email($tmp_str)) { proc_run('php','include/gprobe.php',bin2hex($tmp_str)); - $arr = array('zid' => $tmp_str, 'url' => $a->cmd); + $arr = array('zid' => $tmp_str, 'url' => App::$cmd); call_hooks('zid_init',$arr); if(! local_channel()) { $r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc limit 1", @@ -1402,7 +1443,7 @@ function zid_init(&$a) { return; logger('zid_init: not authenticated. Invoking reverse magic-auth for ' . $tmp_str); // try to avoid recursion - but send them home to do a proper magic auth - $query = $a->query_string; + $query = App::$query_string; $query = str_replace(array('?zid=','&zid='),array('?rzid=','&rzid='),$query); $dest = '/' . urlencode($query); if($r && ($r[0]['hubloc_url'] != z_root()) && (! strstr($dest,'/magic')) && (! strstr($dest,'/rmagic'))) { @@ -1583,7 +1624,7 @@ function identity_selector() { intval(get_account_id()) ); if (count($r) > 1) { - //$account = get_app()->get_account(); + //$account = App::get_account(); $o = replace_macros(get_markup_template('channel_id_select.tpl'), array( '$channels' => $r, '$selected' => local_channel() @@ -1601,7 +1642,7 @@ function is_public_profile() { return false; if(intval(get_config('system','block_public'))) return false; - $channel = get_app()->get_channel(); + $channel = App::get_channel(); if($channel && $channel['channel_r_profile'] == PERMS_PUBLIC) return true; @@ -1695,3 +1736,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'] . '@' . 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..3b5c8508c 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); } - } } } @@ -635,6 +636,7 @@ function sync_events($channel,$events) { function import_menus($channel,$menus) { + if($channel && $menus) { foreach($menus as $menu) { $m = array(); @@ -680,6 +682,8 @@ function import_menus($channel,$menus) { } } } + + } @@ -866,6 +870,257 @@ function import_mail($channel,$mails) { +function sync_files($channel,$files) { + + require_once('include/attach.php'); + + if($channel && $files) { + foreach($files as $f) { + if(! $f) + continue; + + $fetch_url = $f['fetch_url']; + $oldbase = dirname($fetch_url); + $original_channel = $f['original_channel']; + + if(! ($fetch_url && $original_channel)) + continue; + + if($f['attach']) { + $attachment_stored = false; + foreach($f['attach'] as $att) { + + if($att['deleted']) { + attach_delete($channel,$att['hash']); + continue; + } + + $attach_exists = false; + $x = attach_by_hash($att['hash']); + + if($x) { + $attach_exists = true; + $attach_id = $x[0]['id']; + } + + $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['data']); + + unset($att['id']); + $att['aid'] = $channel['channel_account_id']; + $att['uid'] = $channel['channel_id']; + + + // check for duplicate folder names with the same parent. + // If we have a duplicate that doesn't match this hash value + // change the name so that the contents won't be "covered over" + // by the existing directory. Use the same logic we use for + // duplicate files. + + if(strpos($att['filename'],'.') !== false) { + $basename = substr($att['filename'],0,strrpos($att['filename'],'.')); + $ext = substr($att['filename'],strrpos($att['filename'],'.')); + } + else { + $basename = $att['filename']; + $ext = ''; + } + + $r = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' and hash != '%s' ", + dbesc($basename . $ext), + dbesc($basename . '(%)' . $ext), + dbesc($att['folder']), + dbesc($att['hash']) + ); + + if($r) { + $x = 1; + + do { + $found = false; + foreach($r as $rr) { + if($rr['filename'] === $basename . '(' . $x . ')' . $ext) { + $found = true; + break; + } + } + if($found) + $x++; + } + while($found); + $att['filename'] = $basename . '(' . $x . ')' . $ext; + } + else + $att['filename'] = $basename . $ext; + + // end duplicate detection + +// @fixme - update attachment structures if they are modified rather than created + + $att['data'] = $newfname; + + // Note: we use $att['hash'] below after it has been escaped to + // fetch the file contents. + // If the hash ever contains any escapable chars this could cause + // problems. Currently it does not. + + dbesc_array($att); + + + if($attach_exists) { + $str = ''; + foreach($att as $k => $v) { + if($str) + $str .= ","; + $str .= " `" . $k . "` = '" . $v . "' "; + } + $r = dbq("update `attach` set " . $str . " where id = " . intval($attach_id) ); + } + else { + $r = dbq("INSERT INTO attach (`" + . implode("`, `", array_keys($att)) + . "`) VALUES ('" + . implode("', '", array_values($att)) + . "')" ); + } + + + // is this a directory? + + if($att['filetype'] === 'multipart/mixed' && $att['is_dir']) { + os_mkdir($newfname, STORAGE_DEFAULT_PERMISSIONS,true); + continue; + } + else { + + // it's a file + // for the sync version of this algorithm (as opposed to 'offline import') + // we will fetch the actual file from the source server so it can be + // streamed directly to disk and avoid consuming PHP memory if it's a huge + // audio/video file or something. + + $time = datetime_convert(); + + $parr = array('hash' => $channel['channel_hash'], + 'time' => $time, + 'resource' => $att['hash'], + 'revision' => 0, + 'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])) + ); + + $store_path = $newfname; + + $fp = fopen($newfname,'w'); + if(! $fp) { + logger('failed to open storage file.',LOGGER_NORMAL,LOG_ERR); + continue; + } + $redirects = 0; + $x = z_post_url($fetch_url,$parr,$redirects,array('filep' => $fp)); + fclose($fp); + + if($x['success']) { + $attachment_stored = true; + } + continue; + } + } + } + if(! $attachment_stored) { + // @TODO should we queue this and retry or delete everything or what? + logger('attachment store failed',LOGGER_NORMAL,LOG_ERR); + } + if($f['photo']) { + foreach($f['photo'] as $p) { + unset($p['id']); + $p['aid'] = $channel['channel_account_id']; + $p['uid'] = $channel['channel_id']; + + // if this is a profile photo, undo the profile photo bit + // for any other photo which previously held it. + + if($p['photo_usage'] == PHOTO_PROFILE) { + $e = q("update photo set photo_usage = %d where photo_usage = %d + and resource_id != '%s' and uid = %d ", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($p['resource_id']), + intval($channel['channel_id']) + ); + } + + // same for cover photos + + if($p['photo_usage'] == PHOTO_COVER) { + $e = q("update photo set photo_usage = %d where photo_usage = %d + and resource_id != '%s' and uid = %d ", + intval(PHOTO_NORMAL), + intval(PHOTO_COVER), + dbesc($p['resource_id']), + intval($channel['channel_id']) + ); + } + if($p['scale'] === 0 && $p['os_storage']) + $p['data'] = $store_path; + else + $p['data'] = base64_decode($p['data']); + + + $exists = q("select * from photo where resource_id = '%s' and scale = %d and uid = %d limit 1", + dbesc($p['resource_id']), + intval($p['scale']), + intval($channel['channel_id']) + ); + + dbesc_array($p); + + if($exists) { + $str = ''; + foreach($p as $k => $v) { + if($str) + $str .= ","; + $str .= " `" . $k . "` = '" . $v . "' "; + } + $r = dbq("update `photo` set " . $str . " where id = " . intval($exists[0]['id']) ); + } + else { + $r = dbq("INSERT INTO photo (`" + . implode("`, `", array_keys($p)) + . "`) VALUES ('" + . implode("', '", array_values($p)) + . "')" ); + } + } + } + if($f['item']) { + sync_items($channel,$f['item']); + foreach($f['item'] as $i) { + if($i['message_id'] !== $i['message_parent']) + continue; + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($i['message_id']), + intval($channel['channel_id']) + ); + if($r) { + $item = $r[0]; + item_url_replace($channel,$item,$oldbase,z_root(),$original_channel); + + dbesc_array($item); + $item_id = $item['id']; + unset($item['id']); + $str = ''; + foreach($item as $k => $v) { + if($str) + $str .= ","; + $str .= " `" . $k . "` = '" . $v . "' "; + } + + $r = dbq("update `item` set " . $str . " where id = " . $item_id ); + } + } + } + } + } +} diff --git a/include/items.php b/include/items.php index 44f9633a9..95822c0ba 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 = ''; @@ -274,7 +274,7 @@ function can_comment_on_post($observer_xchan, $item) { return true; if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'diaspora')) return true; - if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],get_app()->get_hostname())) + if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],App::get_hostname())) return true; return false; @@ -413,8 +413,8 @@ function post_activity_item($arr) { if(! array_key_exists('item_thread_top',$arr) && (! $is_comment)) $arr['item_thread_top'] = 1; - $channel = get_app()->get_channel(); - $observer = get_app()->get_observer(); + $channel = App::get_channel(); + $observer = App::get_observer(); $arr['aid'] = ((x($arr,'aid')) ? $arr['aid'] : $channel['channel_account_id']); $arr['uid'] = ((x($arr,'uid')) ? $arr['uid'] : $channel['channel_id']); @@ -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 @@ -596,7 +602,7 @@ function get_feed_for($channel, $observer_hash, $params) { 'order' => 'post', 'top' => $params['top'], 'cat' => $params['cat'] - ), $channel, $observer_hash, CLIENT_MODE_NORMAL, get_app()->module); + ), $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module); $feed_template = get_markup_template('atom_feed.tpl'); @@ -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); @@ -1136,9 +1144,8 @@ function import_author_rss($x) { $photos = import_xchan_photo($x['photo']['src'],$x['url']); if($photos) { - /** @bug $arr is undefined in this SQL query */ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_url = '%s' and xchan_network = 'rss'", - dbesc(datetime_convert('UTC', 'UTC', $arr['photo_updated'])), + dbesc(datetime_convert()), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -1181,9 +1188,8 @@ function import_author_unknown($x) { $photos = import_xchan_photo($x['photo']['src'],$x['url']); if($photos) { - /** @bug $arr is undefined in this SQL query */ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_url = '%s' and xchan_network = 'unknown'", - dbesc(datetime_convert('UTC','UTC',$arr['photo_updated'])), + dbesc(datetime_convert()), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -1317,6 +1323,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) { @@ -1353,7 +1362,7 @@ function map_scope($scope, $strip = false) { case PERMS_AUTHED: return 'authenticated'; case PERMS_SITE: - return 'site: ' . get_app()->get_hostname(); + return 'site: ' . App::get_hostname(); case PERMS_PENDING: return 'any connections'; case PERMS_CONTACTS: @@ -1427,6 +1436,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 * @@ -2058,6 +2091,10 @@ function get_atom_elements($feed, $item, &$author) { $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; } + if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) { + $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data']; + $obj['type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data']; + } if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) @@ -2091,6 +2128,10 @@ function get_atom_elements($feed, $item, &$author) { $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; } + if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) { + $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data']; + $obj['type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data']; + } if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) @@ -2115,9 +2156,6 @@ function get_atom_elements($feed, $item, &$author) { $res['target'] = $obj; } - $res['public_policy'] = 'specific'; - $res['comment_policy'] = 'none'; - $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); call_hooks('parse_atom', $arr); @@ -2129,26 +2167,27 @@ function get_atom_elements($feed, $item, &$author) { } function encode_rel_links($links) { - $o = ''; + $o = array(); if(! ((is_array($links)) && (count($links)))) return $o; foreach($links as $link) { - $o .= '<link '; + $l = array(); if($link['attribs']['']['rel']) - $o .= 'rel="' . $link['attribs']['']['rel'] . '" '; + $l['rel'] = $link['attribs']['']['rel']; if($link['attribs']['']['type']) - $o .= 'type="' . $link['attribs']['']['type'] . '" '; + $l['type'] = $link['attribs']['']['type']; if($link['attribs']['']['href']) - $o .= 'href="' . $link['attribs']['']['href'] . '" '; + $l['href'] = $link['attribs']['']['href']; if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['width']) - $o .= 'media:width="' . $link['attribs'][NAMESPACE_MEDIA]['width'] . '" '; + $l['width'] = $link['attribs'][NAMESPACE_MEDIA]['width']; if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['height']) - $o .= 'media:height="' . $link['attribs'][NAMESPACE_MEDIA]['height'] . '" '; - $o .= ' />' . "\n" ; - } + $l['height'] = $link['attribs'][NAMESPACE_MEDIA]['height']; - return xmlify($o); + if($l) + $o[] = $l; + } + return $o; } /** @@ -2160,7 +2199,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 ); @@ -2226,7 +2265,7 @@ function item_store($arr, $allow_exec = false) { $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype'])); if(local_channel() && (! $arr['sig'])) { - $channel = get_app()->get_channel(); + $channel = App::get_channel(); if($channel['channel_hash'] === $arr['author_xchan']) { $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); $arr['item_verified'] = 1; @@ -2439,6 +2478,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 +2562,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 +2592,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 +2605,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 ); @@ -2606,7 +2661,7 @@ function item_store_update($arr,$allow_exec = false) { $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype'])); if(local_channel() && (! $arr['sig'])) { - $channel = get_app()->get_channel(); + $channel = App::get_channel(); if($channel['channel_hash'] === $arr['author_xchan']) { $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); $arr['item_verified'] = 1; @@ -2737,6 +2792,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 +2840,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; @@ -2812,17 +2887,17 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, logger('storing diaspora comment signature',LOGGER_DEBUG); - $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); + $diaspora_handle = $channel['channel_address'] . '@' . App::get_hostname(); $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 +2906,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'); @@ -2890,7 +2966,7 @@ function send_status_notifications($post_id,$item) { if($unfollowed) return; - $link = get_app()->get_baseurl() . '/display/' . $item['mid']; + $link = z_root() . '/display/' . $item['mid']; $y = q("select id from notify where link = '%s' and uid = %d limit 1", dbesc($link), @@ -3436,6 +3512,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 +3728,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 +3758,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(); @@ -3764,6 +3847,11 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $author = array(); $datarray = get_atom_elements($feed,$item,$author); + if($contact['xchan_network'] === 'rss') { + $datarray['public_policy'] = 'specific'; + $datarray['comment_policy'] = 'none'; + } + if((! x($author,'author_name')) || ($author['author_is_feed'])) $author['author_name'] = $contact['xchan_name']; if((! x($author,'author_link')) || ($author['author_is_feed'])) @@ -3788,6 +3876,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { intval($importer['channel_id']) ); + // Update content if 'updated' changes if($r) { @@ -3804,6 +3893,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { } $datarray['parent_mid'] = $parent_mid; + $datarray['aid'] = $importer['channel_account_id']; $datarray['uid'] = $importer['channel_id']; logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); @@ -3820,6 +3910,12 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $author = array(); $datarray = get_atom_elements($feed,$item,$author); + if($contact['xchan_network'] === 'rss') { + $datarray['public_policy'] = 'specific'; + $datarray['comment_policy'] = 'none'; + } + + if(is_array($contact)) { if((! x($author,'author_name')) || ($author['author_is_feed'])) $author['author_name'] = $contact['xchan_name']; @@ -3836,6 +3932,16 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $datarray['author_xchan'] = ''; + if(activity_match($datarray['verb'],ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) { + $cb = array('item' => $datarray,'channel' => $importer, 'xchan' => null, 'author' => $author, 'caught' => false); + call_hooks('follow_from_feed',$cb); + if($cb['caught']) { + if($cb['return_code']) + http_status_exit($cb['return_code']); + continue; + } + } + if($author['author_link'] != $contact['xchan_url']) { $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); if($x) @@ -3846,6 +3952,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']) @@ -3869,6 +3986,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $datarray['parent_mid'] = $item_id; $datarray['uid'] = $importer['channel_id']; + $datarray['aid'] = $importer['channel_account_id']; if(! link_compare($author['owner_link'],$contact['xchan_url'])) { logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); @@ -3892,6 +4010,144 @@ 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['parent_mid'] = $parent_mid; + + $ret['author'] = array(); + + $datarray = get_atom_elements($feed,$item,$ret['author']); + + // reset policies which are restricted by default for RSS connections + // This item is likely coming from GNU-social via salmon and allows public interaction + $datarray['public_policy'] = ''; + $datarray['comment_policy'] = ''; + + $ret['item'] = $datarray; + } + } + + return $ret; +} + +/* + * Given an xml (atom) feed, find author and hub links + */ + + +function feed_meta($xml) { + require_once('library/simplepie/simplepie.inc'); + + $ret = array(); + + if(! strlen($xml)) { + logger('empty input'); + return $ret; + } + + $feed = new SimplePie(); + $feed->set_raw_data($xml); + $feed->init(); + + if($feed->error()) { + logger('Error parsing XML: ' . $feed->error()); + return $ret; + } + + $ret['hubs'] = $feed->get_links('hub'); + +// logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA); + + $author = array(); + + $found_author = $feed->get_author(); + if($found_author) { + $author['author_name'] = unxmlify($found_author->get_name()); + $author['author_link'] = unxmlify($found_author->get_link()); + + $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author'); + logger('rawauthor: ' . print_r($rawauthor,true)); + + if($rawauthor) { + if($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { + $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; + foreach($base as $link) { + if(!x($author, 'author_photo') || ! $author['author_photo']) { + if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') { + $author['author_photo'] = unxmlify($link['attribs']['']['href']); + break; + } + } + } + } + if($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']) + $author['full_name'] = unxmlify($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']); + if($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) + $author['author_uri'] = unxmlify($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); + + } + } + + if(substr($author['author_link'],-1,1) == '/') + $author['author_link'] = substr($author['author_link'],0,-1); + + $ret['author'] = $author; + + return $ret; +} + + + function update_feed_item($uid,$datarray) { logger('update_feed_item: not implemented! ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA); } @@ -3915,8 +4171,8 @@ function handle_feed($uid,$abook_id,$url) { //logger('handle_feed:' . print_r($z,true)); if($z['success']) { - consume_feed($z['body'],$channel,$x[0],0); consume_feed($z['body'],$channel,$x[0],1); + consume_feed($z['body'],$channel,$x[0],2); } } @@ -3972,15 +4228,28 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { if(($item['parent'] != $item['id']) || ($item['parent_mid'] !== $item['mid']) || (($item['thr_parent'] !== '') && ($item['thr_parent'] !== $item['mid']))) { $parent_item = (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']); - $o .= '<thr:in-reply-to ref="' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n"; + $o .= '<thr:in-reply-to ref="' . z_root() . '/display/' . 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 .= '<id>' . z_root() . '/display/' . xmlify($item['mid']) . '</id>' . "\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']) { @@ -4029,10 +4298,9 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { } function fix_private_photos($s, $uid, $item = null, $cid = 0) { - $a = get_app(); logger('fix_private_photos', LOGGER_DEBUG); - $site = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://')); + $site = substr(z_root(),strpos(z_root(),'://')); $orig_body = $s; $new_body = ''; @@ -4312,8 +4580,6 @@ function drop_items($items) { function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = false) { - $a = get_app(); - // locate item to be deleted $r = q("SELECT * FROM item WHERE id = %d LIMIT 1", @@ -4324,7 +4590,7 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal if(! $interactive) return 0; notice( t('Item not found.') . EOL); - goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); + goaway(z_root() . '/' . $_SESSION['return_url']); } $item = $r[0]; @@ -4347,7 +4613,7 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal $ok_to_delete = true; // author deletion - $observer = $a->get_observer(); + $observer = App::get_observer(); if($observer && $observer['xchan_hash'] && ($observer['xchan_hash'] === $item['author_xchan'])) $ok_to_delete = true; @@ -4397,13 +4663,13 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) proc_run('php','include/notifier.php','drop',$notify_id); - goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); + goaway(z_root() . '/' . $_SESSION['return_url']); } else { if(! $interactive) return 0; notice( t('Permission denied.') . EOL); - goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); + goaway(z_root() . '/' . $_SESSION['return_url']); } } @@ -4643,6 +4909,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 +4936,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; @@ -4788,8 +5078,6 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $result = array('success' => false); - $a = get_app(); - $sql_extra = ''; $sql_nets = ''; $sql_options = ''; @@ -4835,7 +5123,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 +5139,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 +5164,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']) { @@ -4912,8 +5200,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $pager_sql = ''; } else { $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20); - $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(get_app()->pager['itemspage']), intval(get_app()->pager['start'])); + App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); } if (isset($arr['start']) && isset($arr['records'])) @@ -5183,7 +5471,7 @@ function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, * @return boolean */ function comment_local_origin($item) { - if(stripos($item['mid'], get_app()->get_hostname()) && ($item['parent'] != $item['id'])) + if(stripos($item['mid'], App::get_hostname()) && ($item['parent'] != $item['id'])) return true; return false; @@ -5274,3 +5562,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..d6b7606ca 100644 --- a/include/language.php +++ b/include/language.php @@ -65,49 +65,56 @@ 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'); + return ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en'); } function push_lang($language) { global $a; - $a->langsave = $a->language; + App::$langsave = App::$language; - if($language === $a->language) + if($language === App::$language) return; - if(isset($a->strings) && count($a->strings)) { - $a->stringsave = $a->strings; + if(isset(App::$strings) && count(App::$strings)) { + App::$stringsave = App::$strings; } - $a->strings = array(); + App::$strings = array(); load_translation_table($language); - $a->language = $language; + App::$language = $language; } function pop_lang() { global $a; - if($a->language === $a->langsave) + if(App::$language === App::$langsave) return; - if(isset($a->stringsave)) - $a->strings = $a->stringsave; + if(isset(App::$stringsave) && is_array(App::$stringsave)) + App::$strings = App::$stringsave; else - $a->strings = array(); + App::$strings = array(); - $a->language = $a->langsave; + App::$language = App::$langsave; } /** @@ -119,7 +126,7 @@ function pop_lang() { function load_translation_table($lang, $install = false) { global $a; - $a->strings = array(); + App::$strings = array(); if(file_exists("view/$lang/hstrings.php")) { include("view/$lang/hstrings.php"); @@ -166,8 +173,8 @@ function t($s, $ctx = '') { global $a; $cs = $ctx ? '__ctx:' . $ctx . '__ ' . $s : $s; - if (x($a->strings, $cs)) { - $t = $a->strings[$cs]; + if (x(App::$strings, $cs)) { + $t = App::$strings[$cs]; return ((is_array($t)) ? translate_projectname($t[0]) : translate_projectname($t)); } @@ -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); } @@ -201,9 +208,9 @@ function tt($singular, $plural, $count, $ctx = ''){ $a = get_app(); $cs = $ctx ? "__ctx:" . $ctx . "__ " . $singular : $singular; - if (x($a->strings,$cs)) { - $t = $a->strings[$cs]; - $f = 'string_plural_select_' . str_replace('-', '_', $a->language); + if (x(App::$strings,$cs)) { + $t = App::$strings[$cs]; + $f = 'string_plural_select_' . str_replace('-', '_', App::$language); if (! function_exists($f)) $f = 'string_plural_select_default'; diff --git a/include/menu.php b/include/menu.php index 075372515..e8f1d8eb8 100644 --- a/include/menu.php +++ b/include/menu.php @@ -35,11 +35,11 @@ function menu_element($menu) { $arr['edited'] = $menu['menu']['menu_edited']; $arr['baseurl'] = z_root(); - if($menu['menu_flags']) { + if($menu['menu']['menu_flags']) { $arr['flags'] = array(); - if($menu['menu_flags'] & MENU_BOOKMARK) + if($menu['menu']['menu_flags'] & MENU_BOOKMARK) $arr['flags'][] = 'bookmark'; - if($menu['menu_flags'] & MENU_SYSTEM) + if($menu['menu']['menu_flags'] & MENU_SYSTEM) $arr['flags'][] = 'system'; } if($menu['items']) { @@ -72,7 +72,7 @@ function menu_render($menu, $class='', $edit = false, $var = array()) { if(! $menu) return ''; - $channel_id = ((is_array(get_app()->profile)) ? get_app()->profile['profile_uid'] : 0); + $channel_id = ((is_array(App::$profile)) ? App::$profile['profile_uid'] : 0); if ((! $channel_id) && (local_channel())) $channel_id = local_channel(); @@ -296,10 +296,10 @@ function menu_add_item($menu_id, $uid, $arr) { $mitem_flags = intval($arr['mitem_flags']); if(local_channel() == $uid) { - $channel = get_app()->get_channel(); + $channel = App::get_channel(); } - $acl = new AccessList($channel); + $acl = new Zotlabs\Access\AccessList($channel); $acl->set_from_array($arr); $p = $acl->get(); @@ -337,10 +337,10 @@ function menu_edit_item($menu_id, $uid, $arr) { if(local_channel() == $uid) { - $channel = get_app()->get_channel(); + $channel = 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..a7883d50e 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(); @@ -37,7 +38,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $channel = $r[0]; } else { - $channel = get_app()->get_channel(); + $channel = App::get_channel(); } if(! $channel) { @@ -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), @@ -73,7 +75,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' if($recip) $recip_handle = $recip[0]['xchan_addr']; - $sender_handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); + $sender_handle = $channel['channel_address'] . '@' . App::get_hostname(); $handles = $recip_handle . ';' . $sender_handle; @@ -122,7 +124,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $dups = false; $hash = random_string(); - $mid = $hash . '@' . get_app()->get_hostname(); + $mid = $hash . '@' . App::get_hostname(); $r = q("SELECT id FROM mail WHERE mid = '%s' LIMIT 1", dbesc($mid)); @@ -167,7 +169,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $r = attach_by_hash_nodata($hash,$rev); if($r['success']) { $attachments[] = array( - 'href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], + 'href' => z_root() . '/attach/' . $r['data']['hash'], 'length' => $r['data']['filesize'], 'type' => $r['data']['filetype'], 'title' => urlencode($r['data']['filename']), @@ -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 @@ -222,7 +225,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' if(count($images)) { foreach($images as $image) { - if(! stristr($image,$a->get_baseurl() . '/photo/')) + if(! stristr($image,z_root() . '/photo/')) continue; $image_uri = substr($image,strrpos($image,'/') + 1); $image_uri = substr($image_uri,0, strpos($image_uri,'-')); diff --git a/include/nav.php b/include/nav.php index 1630c4731..541ab3aed 100644 --- a/include/nav.php +++ b/include/nav.php @@ -8,11 +8,11 @@ function nav(&$a) { * */ - if(!(x($a->page,'nav'))) - $a->page['nav'] = ''; + if(!(x(App::$page,'nav'))) + App::$page['nav'] = ''; $base = z_root(); - $a->page['htmlhead'] .= <<< EOT + App::$page['htmlhead'] .= <<< EOT <script>$(document).ready(function() { $("#nav-search-text").search_autocomplete('$base/acl'); @@ -24,8 +24,8 @@ EOT; if(local_channel()) { - $channel = $a->get_channel(); - $observer = $a->get_observer(); + $channel = App::get_channel(); + $observer = App::get_observer(); $prof = q("select id from profile where uid = %d and is_default = 1", intval($channel['channel_id']) ); @@ -35,12 +35,12 @@ EOT; ); } elseif(remote_channel()) - $observer = $a->get_observer(); + $observer = App::get_observer(); $myident = (($channel) ? $channel['xchan_addr'] : ''); - $sitelocation = (($myident) ? $myident : $a->get_hostname()); + $sitelocation = (($myident) ? $myident : App::get_hostname()); @@ -55,8 +55,8 @@ EOT; if($banner === false) $banner = get_config('system','sitename'); - $a->page['header'] .= replace_macros(get_markup_template('hdr.tpl'), array( - '$baseurl' => $a->get_baseurl(), + App::$page['header'] .= replace_macros(get_markup_template('hdr.tpl'), array( + '$baseurl' => z_root(), '$sitelocation' => $sitelocation, '$banner' => $banner )); @@ -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'); @@ -92,18 +92,17 @@ EOT; $nav['usermenu'][] = Array('photos/' . $channel['channel_address'], t('Photos'), "", t('Your photos'),'photos_nav_btn'); $nav['usermenu'][] = Array('cloud/' . $channel['channel_address'],t('Files'),"",t('Your files'),'cloud_nav_btn'); - 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) && feature_enabled(local_channel(),'ajaxchat')) + $nav['usermenu'][] = Array('chat/' . $channel['channel_address'], 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 { @@ -137,24 +136,27 @@ EOT; $homelink = get_my_url(); if(! $homelink) { - $observer = $a->get_observer(); + $observer = App::get_observer(); $homelink = (($observer) ? $observer['xchan_url'] : ''); } - if(($a->module != 'home') && (! (local_channel()))) + if((App::$module != 'home') && (! (local_channel()))) $nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn'); - if(($a->config['system']['register_policy'] == REGISTER_OPEN) && (! local_channel()) && (! remote_channel())) + if((App::$config['system']['register_policy'] == REGISTER_OPEN) && (! local_channel()) && (! remote_channel())) $nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn'); - $help_url = z_root() . '/help?f=&cmd=' . $a->cmd; - - if(! get_config('system','hide_help')) - $nav['help'] = array($help_url, t('Help'), "", t('Help and documentation'),'help_nav_btn'); + $help_url = z_root() . '/help?f=&cmd=' . App::$cmd; + if(! get_config('system','hide_help')) { + require_once('mod/help.php'); + $context_help = load_context_help(); + $nav['help'] = array($help_url, t('Help'), "", t('Help and documentation'),'help_nav_btn',$context_help); + } - $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'); @@ -229,25 +232,25 @@ EOT; // turned off until somebody discovers this and figures out a good location for it. $powered_by = ''; -// $powered_by = '<strong>red<img class="smiley" src="' . $a->get_baseurl() . '/images/rm-16.png" alt="r#" />matrix</strong>'; +// $powered_by = '<strong>red<img class="smiley" src="' . z_root() . '/images/rm-16.png" alt="r#" />matrix</strong>'; $tpl = get_markup_template('nav.tpl'); - $a->page['nav'] .= replace_macros($tpl, array( - '$baseurl' => $a->get_baseurl(), + App::$page['nav'] .= replace_macros($tpl, array( + '$baseurl' => z_root(), '$sitelocation' => $sitelocation, '$nav' => $x['nav'], '$banner' => $banner, '$emptynotifications' => t('Loading...'), '$userinfo' => $x['usermenu'], '$localuser' => local_channel(), - '$sel' => $a->nav_sel, + '$sel' => App::$nav_sel, '$powered_by' => $powered_by, '$help' => t('@name, #tag, ?doc, content'), '$pleasewait' => t('Please wait...') )); - call_hooks('page_header', $a->page['nav']); + call_hooks('page_header', App::$page['nav']); } /* @@ -255,8 +258,7 @@ $powered_by = ''; * */ function nav_set_selected($item){ - $a = get_app(); - $a->nav_sel = array( + App::$nav_sel = array( 'community' => null, 'network' => null, 'home' => null, @@ -270,5 +272,5 @@ function nav_set_selected($item){ 'manage' => null, 'register' => null, ); - $a->nav_sel[$item] = 'active'; + App::$nav_sel[$item] = 'active'; } diff --git a/include/network.php b/include/network.php index 859a60650..ec255581d 100644 --- a/include/network.php +++ b/include/network.php @@ -27,11 +27,12 @@ function get_capath() { * * \b http_auth => username:password * * \b novalidate => do not validate SSL certs, default is to validate using our CA list * * \b nobody => only return the header + * * \b filep => stream resource to write body to. header and body are not returned when using this option. * * @return array an assoziative array with: * * \e int \b return_code => HTTP return code or 0 if timeout or failure * * \e boolean \b success => boolean true (if HTTP 2xx result) or false - * * \e string \b header => HTTP headers + * * \e string \b header => HTTP headers * * \e string \b body => fetched content */ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { @@ -40,7 +41,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); @@ -53,6 +54,11 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { if($ciphers) @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers); + if(x($opts,'filep')) { + @curl_setopt($ch, CURLOPT_FILE, $opts['filep']); + @curl_setopt($ch, CURLOPT_HEADER, $false); + } + if(x($opts,'headers')) @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); @@ -158,6 +164,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { * 'timeout' => int seconds, default system config value or 60 seconds * 'http_auth' => username:password * 'novalidate' => do not validate SSL certs, default is to validate using our CA list + * 'filep' => stream resource to write body to. header and body are not returned when using this option. * @return array an assoziative array with: * * \e int \b return_code => HTTP return code or 0 if timeout or failure * * \e boolean \b success => boolean true (if HTTP 2xx result) or false @@ -171,7 +178,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); @@ -185,9 +192,16 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { if($ciphers) @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers); - if(x($opts,'headers')) - @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); + if(x($opts,'filep')) { + @curl_setopt($ch, CURLOPT_FILE, $opts['filep']); + @curl_setopt($ch, CURLOPT_HEADER, $false); + } + if(x($opts,'headers')) { + @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); +logger('headers: ' . print_r($opts['headers'],true) . 'redir: ' . $redirects); + } + if(x($opts,'nobody')) @curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']); @@ -236,6 +250,21 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { $base = substr($base,strlen($chunk)); } + // would somebody take lighttpd and just shoot it? + + if($http_code == 417) { + curl_close($ch); + if($opts) { + if($opts['headers']) + $opts['headers'][] = 'Expect:'; + else + $opts['headers'] = array('Expect:'); + } + else + $opts = array('headers' => array('Expect:')); + return z_post_url($url,$params,++$redirects,$opts); + } + if($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) { $matches = array(); preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches); @@ -294,8 +323,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(); } @@ -585,7 +614,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false) continue; } - $hostname = str_replace('www.','',substr($a->get_baseurl(),strpos($a->get_baseurl(),'://')+3)); + $hostname = str_replace('www.','',substr(z_root(),strpos(z_root(),'://')+3)); if(stristr($mtch[3],$hostname)) continue; @@ -1043,263 +1072,436 @@ function discover_by_url($url,$arr = null) { } + function discover_by_webbie($webbie) { require_once('library/HTML5/Parser.php'); + $result = array(); + + $network = null; + + $diaspora = false; + $gnusoc = false; + $dfrn = false; + + $has_salmon = false; + $salmon_key = false; + $atom_feed = false; + $diaspora_base = ''; + $diaspora_guid = ''; + $diaspora_key = ''; + $webbie = strtolower($webbie); $x = webfinger_rfc7033($webbie,true); if($x && array_key_exists('links',$x) && $x['links']) { foreach($x['links'] as $link) { - if(array_key_exists('rel',$link) && $link['rel'] == 'http://purl.org/zot/protocol') { - logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG); - if(array_key_exists('zot',$x) && $x['zot']['success']) - $i = import_xchan($x['zot']); - else { - $z = z_fetch_url($link['href']); - if($z['success']) { - $j = json_decode($z['body'],true); - $i = import_xchan($j); - return true; + if(array_key_exists('rel',$link)) { + + // If we discover zot - don't search further; grab the info and get out of + // here. + + if($link['rel'] === PROTOCOL_ZOT) { + logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG); + if(array_key_exists('zot',$x) && $x['zot']['success']) + $i = import_xchan($x['zot']); + else { + $z = z_fetch_url($link['href']); + if($z['success']) { + $j = json_decode($z['body'],true); + $i = import_xchan($j); + return true; + } + } + } + if($link['rel'] == NAMESPACE_DFRN) { + $dfrn = $link['href']; + } + if($link['rel'] == 'magic-public-key') { + if(substr($link['href'],0,5) === 'data:') { + $salmon_key = convert_salmon_key($link['href']); } } + if($link['rel'] == 'salmon') { + $has_salmon = true; + $salmon = $link['href']; + } + if($link['rel'] == 'http://schemas.google.com/g/2010#updates-from') { + $atom_feed = $link['href']; + } } } } - $arr = array('address' => $webbie, 'success' => false); - call_hooks('discover_by_webbie', $arr); + logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO); + + $arr = array('address' => $webbie, 'success' => false, 'webfinger' => $x); + call_hooks('discover_channel_webfinger', $arr); if($arr['success']) return true; - $result = array(); - $network = null; - $diaspora = false; + $aliases = array(); + + // Now let's make some decisions on what we may need + // to obtain further info + + $probe_atom = false; + $probe_old = false; + $probe_hcard = false; + + $address = ''; + $location = ''; + $nickname = ''; + $fullname = ''; + $avatar = ''; + $pubkey = ''; + + if(is_array($x)) { + if(array_key_exists('address',$x)) + $address = $x['address']; + if(array_key_exists('location',$x)) + $location = $x['location']; + if(array_key_exists('nickname',$x)) + $nickname = $x['nickname']; + } + + if(! $x) + $probe_old = true; + + if($probe_old) { + $y = old_webfinger($webbie); + if($y) { + logger('old_webfinger: ' . print_r($x,true)); + foreach($y as $link) { + if($link['@attributes']['rel'] === NAMESPACE_DFRN) + $dfrn = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'salmon') + $notify = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === NAMESPACE_FEED) + $poll = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard') + $hcard = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') + $profile = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0') + $poco = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') { + $diaspora_base = unamp($link['@attributes']['href']); + $diaspora = true; + } + if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') { + $diaspora_guid = unamp($link['@attributes']['href']); + $diaspora = true; + } + if($link['@attributes']['rel'] === 'diaspora-public-key') { + $diaspora_key = base64_decode(unamp($link['@attributes']['href'])); + if(strstr($diaspora_key,'RSA ')) + $pubkey = rsatopem($diaspora_key); + else + $pubkey = $diaspora_key; + $diaspora = true; + } + if($link['@attributes']['rel'] == 'magic-public-key') { + if(substr($link['@attributes']['href'],0,5) === 'data:') { + $salmon_key = convert_salmon_key($link['@attributes']['href']); + } + } + if($link['@attributes']['rel'] == 'salmon') { + $has_salmon = true; + $salmon = $link['@attributes']['href']; + } - $diaspora_base = ''; - $diaspora_guid = ''; - $diaspora_key = ''; - $dfrn = false; - - $x = old_webfinger($webbie); - if($x) { - logger('old_webfinger: ' . print_r($x,true)); - foreach($x as $link) { - if($link['@attributes']['rel'] === NAMESPACE_DFRN) - $dfrn = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'salmon') - $notify = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === NAMESPACE_FEED) - $poll = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard') - $hcard = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') - $profile = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0') - $poco = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') { - $diaspora_base = unamp($link['@attributes']['href']); - $diaspora = true; - } - if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') { - $diaspora_guid = unamp($link['@attributes']['href']); - $diaspora = true; + if($link['@attributes']['rel'] == 'http://schemas.google.com/g/2010#updates-from') { + $atom_feed = $link['@attributes']['href']; + } + if($link['@attributes']['rel'] === 'alias') { + $aliases[] = $link['@attributes']['href']; + } + if($link['@attributes']['rel'] === 'subject') { + $subject = $link['@attributes']['href']; + } } - if($link['@attributes']['rel'] === 'diaspora-public-key') { - $diaspora_key = base64_decode(unamp($link['@attributes']['href'])); - if(strstr($diaspora_key,'RSA ')) - $pubkey = rsatopem($diaspora_key); - else - $pubkey = $diaspora_key; - $diaspora = true; + } + } + + if($subject || $aliases) { + if(strpos($webbie,'@')) { + $rhs = substr($webbie,strpos($webbie,'@')+1); + } + else { + $m = parse_url($webbie); + if($m) { + $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); } } - if($diaspora && $diaspora_base && $diaspora_guid) { - $guid = $diaspora_guid; - $diaspora_base = trim($diaspora_base,'/'); + $v = array('subject' => $subject,'aliases' => $aliases); + $address = find_webfinger_address($v,$rhs); + $location = find_webfinger_location($v,$rhs); + if($address) + $nickname = substr($address,0,strpos($address,'@')); - $notify = $diaspora_base . '/receive'; + } - if(strpos($webbie,'@')) { - $addr = str_replace('acct:', '', $webbie); - $hostname = substr($webbie,strpos($webbie,'@')+1); - } - $network = 'diaspora'; - // until we get a dfrn layer, we'll use diaspora protocols for Friendica, - // but give it a different network so we can go back and fix these when we get proper support. - // It really should be just 'friendica' but we also want to distinguish - // between Friendica sites that we can use D* protocols with and those we can't. - // Some Friendica sites will have Diaspora disabled. - if($dfrn) - $network = 'friendica-over-diaspora'; - if($hcard) { - $vcard = scrape_vcard($hcard); - $vcard['nick'] = substr($webbie,0,strpos($webbie,'@')); - if(! $vcard['fn']) - $vcard['fn'] = $webbie; - } - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($addr) - ); + if($salmon_key && $has_salmon && $atom_feed && (! $dfrn) && (! $diaspora)) { + $gnusoc = true; + $probe_atom = true; + } + + if(! $pubkey) + $pubkey = $salmon_key; + + if(($dfrn || $diaspora) && $hcard) + $probe_hcard = true; + + if(! $fullname) + $fullname = $nickname; + + if($probe_atom) { + $k = z_fetch_url($atom_feed); + if($k['success']) + $feed_meta = feed_meta($k['body']); + if($feed_meta) { - /** - * - * Diaspora communications are notoriously unreliable and receiving profile update messages (indeed any messages) - * are pretty much random luck. We'll check the timestamp of the xchan_name_date at a higher level and refresh - * this record once a month; because if you miss a profile update message and they update their profile photo or name - * you're otherwise stuck with stale info until they change their profile again - which could be years from now. - * - */ - - if($r) { - $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", - dbesc($vcard['fn']), - dbesc($network), - dbesc(datetime_convert()), - dbesc($addr) - ); + // stash any discovered pubsubhubbub hubs in case we need to follow them + // this will save an expensive lookup later + + if($feed_meta['hubs'] && $address) { + set_xconfig($address,'system','push_hubs',$feed_meta['hubs']); + set_xconfig($address,'system','feed_url',$atom_feed); + } + if($feed_meta['author']['author_name']) { + $fullname = $feed_meta['author']['author_name']; } - else { - - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_instance_url, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", - dbesc($addr), - dbesc($guid), - dbesc($pubkey), - dbesc($addr), - dbesc($profile), - dbesc($vcard['fn']), - dbesc($network), - dbesc(z_root()), - dbescdate(datetime_convert()) - ); + if(! $avatar) { + if($feed_meta['author']['author_photo']) + $avatar = $feed_meta['author']['author_photo']; } - $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($webbie) - ); + // for GNU-social over-ride any url aliases we may have picked up in webfinger + // The author.uri element in the feed is likely to be more accurate + + if($gnusoc && $feed_meta['author']['author_uri']) + $location = $feed_meta['author']['author_uri']; + } + } + else { + if($probe_hcard) { + $vcard = scrape_vcard($hcard); + if($vcard) { + logger('vcard: ' . print_r($vcard,true), LOGGER_DATA); + if($vcard['fn']) + $fullname = $vcard['fn']; + if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0)) + $vcard['photo'] = $diaspora_base . '/' . $vcard['photo']; + if(! $avatar) + $avatar = $vcard['photo']; - if(! $r) { - - $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", - dbesc($guid), - dbesc($addr), - dbesc($addr), - dbesc($network), - dbesc(trim($diaspora_base,'/')), - dbesc($hostname), - dbesc($notify), - dbescdate(datetime_convert()) - ); } - $photos = import_xchan_photo($vcard['photo'],$addr); - $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($addr) - ); - return true; + } + } + + if(($profile) && (! $location)) + $location = $profile; + + if($location) { + $m = parse_url($location); + $base = $m['scheme'] . '://' . $m['host']; + $host = $m['host']; + } + + + if($diaspora && $diaspora_base && $diaspora_guid) { + if($dfrn) + $network = 'friendica-over-diaspora'; + else + $network = 'diaspora'; + $base = trim($diaspora_base,'/'); + $notify = $base . '/receive'; + + } + else { + if($gnusoc) { + $network = 'gnusoc'; + $notify = $salmon; } + } - return false; -/* - $vcard['fn'] = notags($vcard['fn']); - $vcard['nick'] = str_replace(' ','',notags($vcard['nick'])); - - $result['name'] = $vcard['fn']; - $result['nick'] = $vcard['nick']; - $result['guid'] = $guid; - $result['url'] = $profile; - $result['hostname'] = $hostname; - $result['addr'] = $addr; - $result['batch'] = $batch; - $result['notify'] = $notify; - $result['poll'] = $poll; - $result['request'] = $request; - $result['confirm'] = $confirm; - $result['poco'] = $poco; - $result['photo'] = $vcard['photo']; - $result['priority'] = $priority; - $result['network'] = $network; - $result['alias'] = $alias; - $result['pubkey'] = $pubkey; - - logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG); - - return $result; - -*/ - -/* Sample Diaspora result. - -Array -( - [name] => Mike Macgirvin - [nick] => macgirvin - [guid] => a9174a618f8d269a - [url] => https://joindiaspora.com/u/macgirvin - [hostname] => joindiaspora.com - [addr] => macgirvin@joindiaspora.com - [batch] => - [notify] => https://joindiaspora.com/receive - [poll] => https://joindiaspora.com/public/macgirvin.atom - [request] => - [confirm] => - [poco] => - [photo] => https://joindiaspora.s3.amazonaws.com/uploads/images/thumb_large_fec4e6eef13ae5e56207.jpg - [priority] => - [network] => diaspora - [alias] => - [pubkey] => -----BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtihtyIuRDWkDpCA+I1UaQ -jI4S7k625+A7EEJm+pL2ZVSJxeCKiFeEgHBQENjLMNNm8l8F6blxgQqE6ZJ9Spa7f -tlaXYTRCrfxKzh02L3hR7sNA+JS/nXJaUAIo+IwpIEspmcIRbD9GB7Wv/rr+M28uH -31EeYyDz8QL6InU/bJmnCdFvmEMBQxJOw1ih9tQp7UNJAbUMCje0WYFzBz7sfcaHL -OyYcCOqOCBLdGucUoJzTQ9iDBVzB8j1r1JkIHoEb2moUoKUp+tkCylNfd/3IVELF9 -7w1Qjmit3m50OrJk2DQOXvCW9KQxaQNdpRPSwhvemIt98zXSeyZ1q/YjjOwG0DWDq -AF8aLj3/oQaZndTPy/6tMiZogKaijoxj8xFLuPYDTw5VpKquriVC0z8oxyRbv4t9v -8JZZ9BXqzmayvY3xZGGp8NulrfjW+me2bKh0/df1aHaBwpZdDTXQ6kqAiS2FfsuPN -vg57fhfHbL1yJ4oDbNNNeI0kJTGchXqerr8C20khU/cQ2Xt31VyEZtnTB665Ceugv -kp3t2qd8UpAVKl430S5Quqx2ymfUIdxdW08CEjnoRNEL3aOWOXfbf4gSVaXmPCR4i -LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+ -4afAEhRaaY+MCAwEAAQ== ------END PUBLIC KEY----- - -) -*/ + logger('network: ' . $network); + logger('address: ' . $address); + logger('fullname: ' . $fullname); + logger('pubkey: ' . $pubkey); + logger('location: ' . $location); + // if we have everything we need, let's create the records + if($network && $address && $fullname && $pubkey && $location) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($address) + ); + if($r) { + $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", + dbesc($fullname), + dbesc($network), + dbesc(datetime_convert()), + dbesc($address) + ); + } + else { + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + dbesc($address), + dbesc(($diaspora_guid) ? $diaspora_guid : $location), + dbesc($pubkey), + dbesc($address), + dbesc($location), + dbesc($fullname), + dbesc($network), + dbescdate(datetime_convert()) + ); + } + + $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($address) + ); + + if(! $r) { + $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", + dbesc(($diaspora_guid) ? $diaspora_guid : $location), + dbesc($address), + dbesc($address), + dbesc($network), + dbesc($base), + dbesc($host), + dbesc($notify), + dbescdate(datetime_convert()) + ); + } + $photos = import_xchan_photo($avatar,$address); + $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", + dbescdate(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($address) + ); + return true; } + return false; } -function webfinger_rfc7033($webbie,$zot = false) { +function webfinger_rfc7033($webbie,$zot = false) { - if(! strpos($webbie,'@')) - return false; - $lhs = substr($webbie,0,strpos($webbie,'@')); - $rhs = substr($webbie,strpos($webbie,'@')+1); - $resource = 'acct:' . $webbie; + if(strpos($webbie,'@')) { + $lhs = substr($webbie,0,strpos($webbie,'@')); + $rhs = substr($webbie,strpos($webbie,'@')+1); + $resource = 'acct:' . $webbie; + } + else { + $m = parse_url($webbie); + if($m) { + if($m['scheme'] !== 'https') + return false; + $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + $resource = urlencode($webbie); + } + else + return false; + } + logger('fetching url from resource: ' . $rhs . ':' . $webbie); $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : '')); - if($s['success']) + if($s['success']) { $j = json_decode($s['body'],true); + + // We could have a number of URL aliases and webbies + // make an executive decision about the most likely "best" of each + // by comparing against some examples from known networks we're likely to encounter. + // Otherwise we have to store every alias that we may ever encounter and + // validate every URL we ever find against every possible alias + + // @fixme pump.io is going to be a real bugger since it doesn't return subject or aliases + // or provide lookup by url + + $j['address'] = find_webfinger_address($j,$rhs); + $j['location'] = find_webfinger_location($j,$rhs); + if($j['address']) + $j['nickname'] = substr($j['address'],0,strpos($j['address'],'@')); + } else return false; + return($j); } +function find_webfinger_address($j,$rhs) { + if(is_array($j) && ($j)) { + if(strpos($j['subject'],'acct:') !== false && strpos($j['subject'],'@' . $rhs)) + return str_replace('acct:','',$j['subject']); + if($j['aliases']) { + foreach($j['aliases'] as $alias) { + if(strpos($alias,'acct:') !== false && strpos($alias,'@' . $rhs)) { + return str_replace('acct:','',$alias); + } + } + } + } + return ''; +} + + +function find_webfinger_location($j,$rhs) { + if(is_array($j) && ($j)) { + if(strpos($j['subject'],'http') === 0) { + $x = match_webfinger_location($j['subject'],$rhs); + if($x) + return $x; + } + if($j['aliases']) { + foreach($j['aliases'] as $alias) { + if(strpos($alias,'http') === 0) { + $x = match_webfinger_location($alias,$rhs); + if($x) + return($x); + } + } + } + } + return ''; +} + +function match_webfinger_location($s,$h) { + + // GNU-social and the older StatusNet - the $host/user/123 form doesn't work + if(preg_match('|' . $h . '/index.php/user/([0-9]*?)$|',$s)) + return $s; + // Redmatrix / hubzilla + if(preg_match('|' . $h . '/channel/|',$s)) + return $s; + // Friendica + if(preg_match('|' . $h . '/profile/|',$s)) + return $s; + + $arr = array('test' => $s, 'host' => $h, 'success' => false); + call_hooks('match_webfinger_location',$arr); + if($arr['success']) + return $s; + return ''; +} + + + + + + function old_webfinger($webbie) { @@ -1354,7 +1556,7 @@ function fetch_lrdd_template($host) { function fetch_xrd_links($url) { -logger('fetch_xrd_links: ' . $url); + logger('fetch_xrd_links: ' . $url, LOGGER_DEBUG); $redirects = 0; $x = z_fetch_url($url,false,$redirects,array('timeout' => 20)); @@ -1400,6 +1602,10 @@ logger('fetch_xrd_links: ' . $url); } } + if(isset($arr['xrd']['subject'])) { + $links[]['@attributes'] = array('rel' => 'subject' , 'href' => $arr['xrd']['subject']); + } + logger('fetch_xrd_links: ' . print_r($links,true), LOGGER_DATA); return $links; @@ -1451,8 +1657,25 @@ function scrape_vcard($url) { if(attribute_contains($item->getAttribute('class'), 'vcard')) { $level2 = $item->getElementsByTagName('*'); foreach($level2 as $x) { + if(attribute_contains($x->getAttribute('id'),'pod_location')) + $ret['pod_location'] = $x->textContent; if(attribute_contains($x->getAttribute('class'),'fn')) $ret['fn'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'uid')) + $ret['uid'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'nickname')) + $ret['nick'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'searchable')) + $ret['searchable'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'key')) + $ret['public_key'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'given_name')) + $ret['given_name'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'family_name')) + $ret['family_name'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'url')) + $ret['url'] = $x->textContent; + if((attribute_contains($x->getAttribute('class'),'photo')) || (attribute_contains($x->getAttribute('class'),'avatar'))) { $size = intval($x->getAttribute('width')); @@ -1461,10 +1684,6 @@ function scrape_vcard($url) { $largest_photo = $size; } } - if((attribute_contains($x->getAttribute('class'),'nickname')) - || (attribute_contains($x->getAttribute('class'),'uid'))) { - $ret['nick'] = $x->textContent; - } } } } @@ -1615,18 +1834,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,26 +1855,26 @@ 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 )); $sender_name = t('Administrator'); - $hostname = get_app()->get_hostname(); + $hostname = App::get_hostname(); if(strpos($hostname,':')) $hostname = substr($hostname,0,strpos($hostname,':')); $sender_email = 'noreply' . '@' . $hostname; @@ -1662,13 +1882,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 +1937,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 = ''; @@ -1728,11 +1948,11 @@ function get_site_info() { $admin = array(); foreach($r as $rr) { if($rr['channel_pageflags'] & PAGE_HUBADMIN) - $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . get_app()->get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); + $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . App::get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); } if(! $admin) { foreach($r as $rr) { - $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . get_app()->get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); + $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . App::get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); } } } @@ -1747,7 +1967,7 @@ function get_site_info() { $service_class = false; $visible_plugins = array(); - if(is_array($a->plugins) && count($a->plugins)) { + if(is_array(App::$plugins) && count(App::$plugins)) { $r = q("select * from addon where hidden = 0"); if(count($r)) foreach($r as $rr) @@ -1763,16 +1983,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 +2005,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(App::$config['feature_lock']) && count(App::$config['feature_lock'])) { + foreach(App::$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 +2028,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/oauth.php b/include/oauth.php index f3d144158..ec41a5dd2 100644 --- a/include/oauth.php +++ b/include/oauth.php @@ -27,7 +27,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore { ); if($r) { - get_app()->set_oauth_key($consumer_key); + App::set_oauth_key($consumer_key); return new OAuth1Consumer($r[0]['client_id'],$r[0]['pw'],$r[0]['redirect_uri']); } return null; diff --git a/include/oembed.php b/include/oembed.php index e50d34c7d..3994af0fb 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,7 +81,11 @@ function oembed_fetch_url($embedurl){ $a = get_app(); - $txt = Cache::get($a->videowidth . $embedurl); + $embedurl = str_replace('&','&', $embedurl); + +// logger('fetch: ' . $embedurl); + + $txt = Cache::get(App::$videowidth . $embedurl); if(strstr($txt,'youtu') && strstr(z_root(),'https:')) { $txt = str_replace('http:','https:',$txt); @@ -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,12 +119,12 @@ 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; - $x = z_fetch_url($href . '&maxwidth=' . $a->videowidth); + $x = z_fetch_url($href . '&maxwidth=' . App::$videowidth); $txt = $x['body']; break; } @@ -102,7 +133,7 @@ function oembed_fetch_url($embedurl){ $entries = $xpath->query("//link[@type='text/json+oembed']"); foreach($entries as $e){ $href = $e->getAttributeNode("href")->nodeValue; - $x = z_fetch_url($href . '&maxwidth=' . $a->videowidth); + $x = z_fetch_url($href . '&maxwidth=' . App::$videowidth); $txt = $x['body']; break; } @@ -111,7 +142,7 @@ function oembed_fetch_url($embedurl){ } if ($txt==false || $txt=="") { - $x = array('url' => $embedurl,'videowidth' => $a->videowidth); + $x = array('url' => $embedurl,'videowidth' => App::$videowidth); call_hooks('oembed_probe',$x); if(array_key_exists('embed',$x)) $txt = $x['embed']; @@ -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(App::$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."'>"; @@ -155,7 +195,7 @@ function oembed_format_object($j){ } $ret.=replace_macros($tpl, array( - '$baseurl' => $a->get_baseurl(), + '$baseurl' => z_root(), '$embedurl'=>$embedurl, '$escapedhtml'=>base64_encode($jhtml), '$tw'=>$tw, @@ -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..19242d29f 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -63,7 +63,7 @@ function get_perms() { */ function get_all_perms($uid, $observer_xchan, $internal_use = true) { - $api = get_app()->get_oauth_key(); + $api = App::get_oauth_key(); if($api) return get_all_api_perms($uid,$api); @@ -151,9 +151,13 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { // Check if this $uid is actually the $observer_xchan - if it's your content // you always have permission to do anything + // if you've moved elsewhere, you will only have read only access if(($observer_xchan) && ($r[0]['channel_hash'] === $observer_xchan)) { - $ret[$perm_name] = true; + if($r[0]['channel_moved'] && (! $permission[2])) + $ret[$perm_name] = false; + else + $ret[$perm_name] = true; continue; } @@ -266,7 +270,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { */ function perm_is_allowed($uid, $observer_xchan, $permission) { - $api = get_app()->get_oauth_key(); + $api = App::get_oauth_key(); if($api) return api_perm_is_allowed($uid,$api,$permission); @@ -286,7 +290,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission) { $channel_perm = $global_perms[$permission][0]; - $r = q("select %s, channel_pageflags, channel_hash from channel where channel_id = %d limit 1", + $r = q("select %s, channel_pageflags, channel_moved, channel_hash from channel where channel_id = %d limit 1", dbesc($channel_perm), intval($uid) ); @@ -325,9 +329,15 @@ function perm_is_allowed($uid, $observer_xchan, $permission) { return false; // Check if this $uid is actually the $observer_xchan + // you will have full access unless the channel was moved - + // in which case you will have read_only access - if($r[0]['channel_hash'] === $observer_xchan) - return true; + if($r[0]['channel_hash'] === $observer_xchan) { + if($r[0]['channel_moved'] && (! $global_perms[$permission][2])) + return false; + else + return true; + } if($r[0][$channel_perm] & PERMS_PUBLIC) return true; @@ -626,7 +636,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 +651,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 +874,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..3bea54fd4 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; @@ -676,9 +679,9 @@ function import_xchan_photo($photo,$xchan,$thing = false) { if($r === false) $photo_failure = true; - $photo = $a->get_baseurl() . '/photo/' . $hash . '-4'; - $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5'; - $micro = $a->get_baseurl() . '/photo/' . $hash . '-6'; + $photo = z_root() . '/photo/' . $hash . '-4'; + $thumb = z_root() . '/photo/' . $hash . '-5'; + $micro = z_root() . '/photo/' . $hash . '-6'; } else { logger('import_xchan_photo: invalid image from ' . $photo); @@ -686,9 +689,9 @@ function import_xchan_photo($photo,$xchan,$thing = false) { } } if($photo_failure) { - $photo = $a->get_baseurl() . '/' . get_default_profile_photo(); - $thumb = $a->get_baseurl() . '/' . get_default_profile_photo(80); - $micro = $a->get_baseurl() . '/' . get_default_profile_photo(48); + $photo = z_root() . '/' . get_default_profile_photo(); + $thumb = z_root() . '/' . get_default_profile_photo(80); + $micro = z_root() . '/' . get_default_profile_photo(48); $type = 'image/png'; } 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..943d7d503 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)) @@ -194,7 +194,7 @@ function photo_upload($channel, $observer, $args) { $link[0] = array( 'rel' => 'alternate', 'type' => 'text/html', - 'href' => $url = rawurlencode(z_root() . '/photo/' . $photo_hash . '-0.' . $ph->getExt()), + 'href' => z_root() . '/photo/' . $photo_hash . '-0.' . $ph->getExt(), 'width' => $ph->getWidth(), 'height' => $ph->getHeight() ); @@ -212,7 +212,7 @@ function photo_upload($channel, $observer, $args) { $link[1] = array( 'rel' => 'alternate', 'type' => 'text/html', - 'href' => $url = rawurlencode(z_root() . '/photo/' . $photo_hash . '-1.' . $ph->getExt()), + 'href' => z_root() . '/photo/' . $photo_hash . '-1.' . $ph->getExt(), 'width' => $ph->getWidth(), 'height' => $ph->getHeight() ); @@ -227,7 +227,7 @@ function photo_upload($channel, $observer, $args) { $link[2] = array( 'rel' => 'alternate', 'type' => 'text/html', - 'href' => $url = rawurlencode(z_root() . '/photo/' . $photo_hash . '-2.' . $ph->getExt()), + 'href' => z_root() . '/photo/' . $photo_hash . '-2.' . $ph->getExt(), 'width' => $ph->getWidth(), 'height' => $ph->getHeight() ); @@ -242,7 +242,7 @@ function photo_upload($channel, $observer, $args) { $link[3] = array( 'rel' => 'alternate', 'type' => 'text/html', - 'href' => $url = rawurlencode(z_root() . '/photo/' . $photo_hash . '-3.' . $ph->getExt()), + 'href' => z_root() . '/photo/' . $photo_hash . '-3.' . $ph->getExt(), 'width' => $ph->getWidth(), 'height' => $ph->getHeight() ); @@ -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]' @@ -312,7 +312,7 @@ function photo_upload($channel, $observer, $args) { 'title' => $title, 'created' => $p['created'], 'edited' => $p['edited'], - 'id' => rawurlencode(z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash), + 'id' => z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash, 'link' => $link, 'body' => $obj_body ); @@ -320,7 +320,7 @@ function photo_upload($channel, $observer, $args) { $target = array( 'type' => ACTIVITY_OBJ_ALBUM, 'title' => (($album) ? $album : '/'), - 'id' => rawurlencode(z_root() . '/photos/' . $channel['channel_address'] . '/album/' . bin2hex($album)) + 'id' => z_root() . '/photos/' . $channel['channel_address'] . '/album/' . bin2hex($album) ); // Create item container @@ -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. @@ -490,12 +490,12 @@ function photos_album_widget($channelx,$observer,$albums = null) { $o = ''; // If we weren't passed an album list, see if the photos module - // dropped one for us to find in $a->data['albums']. + // dropped one for us to find in App::$data['albums']. // If all else fails, load it. if(! $albums) { - if(array_key_exists('albums', get_app()->data)) - $albums = get_app()->data['albums']; + if(array_key_exists('albums', App::$data)) + $albums = App::$data['albums']; else $albums = photos_albums_list($channelx,$observer); } diff --git a/include/plugin.php b/include/plugin.php index 4a35a0170..8dceb8fb1 100755 --- a/include/plugin.php +++ b/include/plugin.php @@ -219,7 +219,7 @@ function unregister_hook($hook, $file, $function) { // -// It might not be obvious but themes can manually add hooks to the $a->hooks +// It might not be obvious but themes can manually add hooks to the App::$hooks // array in their theme_init() and use this to customise the app behaviour. // UPDATE: use insert_hook($hookname,$function_name) to do this // @@ -227,19 +227,19 @@ function unregister_hook($hook, $file, $function) { function load_hooks() { $a = get_app(); -// if(! is_array($a->hooks)) - $a->hooks = array(); +// if(! is_array(App::$hooks)) + App::$hooks = array(); $r = q("SELECT * FROM hook WHERE true ORDER BY priority DESC"); if($r) { foreach($r as $rr) { - if(! array_key_exists($rr['hook'],$a->hooks)) - $a->hooks[$rr['hook']] = array(); + if(! array_key_exists($rr['hook'],App::$hooks)) + App::$hooks[$rr['hook']] = array(); - $a->hooks[$rr['hook']][] = array($rr['file'],$rr['function']); + App::$hooks[$rr['hook']][] = array($rr['file'],$rr['function']); } } -//logger('hooks: ' . print_r($a->hooks,true)); +//logger('hooks: ' . print_r(App::$hooks,true)); } /** @@ -261,13 +261,13 @@ function load_hooks() { */ function insert_hook($hook, $fn) { $a = get_app(); - if(! is_array($a->hooks)) - $a->hooks = array(); + if(! is_array(App::$hooks)) + App::$hooks = array(); - if(! array_key_exists($hook, $a->hooks)) - $a->hooks[$hook] = array(); + if(! array_key_exists($hook, App::$hooks)) + App::$hooks[$hook] = array(); - $a->hooks[$hook][] = array('', $fn); + App::$hooks[$hook][] = array('', $fn); } /** @@ -282,8 +282,8 @@ function insert_hook($hook, $fn) { function call_hooks($name, &$data = null) { $a = get_app(); - if((is_array($a->hooks)) && (array_key_exists($name, $a->hooks))) { - foreach($a->hooks[$name] as $hook) { + if((is_array(App::$hooks)) && (array_key_exists($name, App::$hooks))) { + foreach(App::$hooks[$name] as $hook) { if($hook[0]) @include_once($hook[0]); @@ -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,App::$plugins)) + $found = false; + } + } + if(! $found) + return false; + } + + return true; +} + + + /** * @brief Parse theme comment in search of theme infos. @@ -451,10 +495,10 @@ function get_theme_screenshot($theme) { $exts = array('.png', '.jpg'); foreach($exts as $ext) { if(file_exists('view/theme/' . $theme . '/img/screenshot' . $ext)) - return($a->get_baseurl() . '/view/theme/' . $theme . '/img/screenshot' . $ext); + return(z_root() . '/view/theme/' . $theme . '/img/screenshot' . $ext); } - return($a->get_baseurl() . '/images/blank.png'); + return(z_root() . '/images/blank.png'); } /** @@ -464,19 +508,19 @@ function get_theme_screenshot($theme) { * @param string $media change media attribute (default to 'screen') */ function head_add_css($src, $media = 'screen') { - get_app()->css_sources[] = array($src, $media); + App::$css_sources[] = array($src, $media); } function head_remove_css($src, $media = 'screen') { $a = get_app(); - $index = array_search(array($src, $media), $a->css_sources); + $index = array_search(array($src, $media), App::$css_sources); if ($index !== false) - unset($a->css_sources[$index]); + unset(App::$css_sources[$index]); } function head_get_css() { $str = ''; - $sources = get_app()->css_sources; + $sources = App::$css_sources; if (count($sources)) { foreach ($sources as $source) $str .= format_css_if_exists($source); @@ -516,7 +560,7 @@ function script_path() { // Some proxy setups may require using http_host - if(intval(get_app()->config['system']['script_path_use_http_host'])) + if(intval(App::$config['system']['script_path_use_http_host'])) $server_var = 'HTTP_HOST'; else $server_var = 'SERVER_NAME'; @@ -532,19 +576,19 @@ function script_path() { } function head_add_js($src) { - get_app()->js_sources[] = $src; + App::$js_sources[] = $src; } function head_remove_js($src) { $a = get_app(); - $index = array_search($src, $a->js_sources); + $index = array_search($src, App::$js_sources); if($index !== false) - unset($a->js_sources[$index]); + unset(App::$js_sources[$index]); } function head_get_js() { $str = ''; - $sources = get_app()->js_sources; + $sources = App::$js_sources; if(count($sources)) foreach($sources as $source) { if($source === 'main.js') @@ -580,7 +624,7 @@ function theme_include($file, $root = '') { if($root !== '' && $root[strlen($root)-1] !== '/') $root = $root . '/'; - $theme_info = $a->theme_info; + $theme_info = App::$theme_info; if(array_key_exists('extends',$theme_info)) $parent = $theme_info['extends']; @@ -612,7 +656,7 @@ function theme_include($file, $root = '') { function get_intltext_template($s, $root = '') { $a = get_app(); - $t = $a->template_engine(); + $t = App::template_engine(); $template = $t->get_intltext_template($s, $root); return $template; @@ -621,22 +665,11 @@ function get_intltext_template($s, $root = '') { function get_markup_template($s, $root = '') { $a = get_app(); - $t = $a->template_engine(); + $t = App::template_engine(); $template = $t->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..abf21b86d 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -19,13 +19,10 @@ */ 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'); /** * @brief Returns an array with viewable channels. @@ -51,7 +48,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 +164,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 +201,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 +271,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 +290,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..38045c8a9 100644 --- a/include/security.php +++ b/include/security.php @@ -14,37 +14,38 @@ */ function authenticate_success($user_record, $login_initial = false, $interactive = false, $return = false, $update_lastlog = false) { - $a = get_app(); - $_SESSION['addr'] = $_SERVER['REMOTE_ADDR']; + $lastlog_updated = false; + if(x($user_record, 'account_id')) { - $a->account = $user_record; + App::$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']) - : intval($a->account['account_default_channel']) + : intval(App::$account['account_default_channel']) ); if($uid_to_load) { 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']) + ); + App::$account['account_lastlog'] = datetime_convert(); + $lastlog_updated = true; + call_hooks('logged_in', App::$account); + } + } - if($login_initial) { + if(($login_initial) && (! $lastlog_updated)) { call_hooks('logged_in', $user_record); @@ -56,7 +57,7 @@ function authenticate_success($user_record, $login_initial = false, $interactive return; } - if(($a->module !== 'home') && x($_SESSION,'login_return_url') && strlen($_SESSION['login_return_url'])) { + if((App::$module !== 'home') && x($_SESSION,'login_return_url') && strlen($_SESSION['login_return_url'])) { $return_url = $_SESSION['login_return_url']; // don't let members get redirected to a raw ajax page update - this can happen @@ -65,14 +66,14 @@ function authenticate_success($user_record, $login_initial = false, $interactive $return_url = ''; unset($_SESSION['login_return_url']); - goaway($a->get_baseurl() . '/' . $return_url); + goaway(z_root() . '/' . $return_url); } /* This account has never created a channel. Send them to new_channel by default */ - if($a->module === 'login') { + if(App::$module === 'login') { $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0 ", - intval($a->account['account_id']) + intval(App::$account['account_id']) ); if(($r) && (! $r[0]['total'])) goaway(z_root() . '/new_channel'); @@ -113,7 +114,7 @@ function change_channel($change_channel) { if($r) { $hash = $r[0]['channel_hash']; $_SESSION['uid'] = intval($r[0]['channel_id']); - get_app()->set_channel($r[0]); + App::set_channel($r[0]); $_SESSION['theme'] = $r[0]['channel_theme']; $_SESSION['mobile_theme'] = get_pconfig(local_channel(),'system', 'mobile_theme'); date_default_timezone_set($r[0]['channel_timezone']); @@ -124,10 +125,10 @@ function change_channel($change_channel) { ); if($x) { $_SESSION['my_url'] = $x[0]['xchan_url']; - $_SESSION['my_address'] = $r[0]['channel_address'] . '@' . substr(get_app()->get_baseurl(), strpos(get_app()->get_baseurl(), '://') + 3); + $_SESSION['my_address'] = $r[0]['channel_address'] . '@' . substr(z_root(), strpos(z_root(), '://') + 3); - get_app()->set_observer($x[0]); - get_app()->set_perms(get_all_perms(local_channel(), $hash)); + App::set_observer($x[0]); + App::set_perms(get_all_perms(local_channel(), $hash)); } if(! is_dir('store/' . $r[0]['channel_address'])) @os_mkdir('store/' . $r[0]['channel_address'], STORAGE_DEFAULT_PERMISSIONS,true); @@ -145,7 +146,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 +156,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 +183,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 +195,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 . '>%')), @@ -286,7 +291,7 @@ function scopes_sql($uid,$observer) { if(! is_foreigner($observer)) $str .= " or public_policy = 'network: red' "; if(local_channel()) - $str .= " or public_policy = 'site: " . get_app()->get_hostname() . "' "; + $str .= " or public_policy = 'site: " . App::get_hostname() . "' "; $ab = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($observer), @@ -313,7 +318,7 @@ function scopes_sql($uid,$observer) { */ function public_permissions_sql($observer_hash) { - //$observer = get_app()->get_observer(); + //$observer = App::get_observer(); $groups = init_groups_visitor($observer_hash); $gs = '<<>>'; // should be impossible to match @@ -353,10 +358,9 @@ function public_permissions_sql($observer_hash) { * so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types). */ function get_form_security_token($typename = '') { - $a = get_app(); $timestamp = time(); - $sec_hash = hash('whirlpool', $a->user['guid'] . $a->user['prvkey'] . session_id() . $timestamp . $typename); + $sec_hash = hash('whirlpool', App::$observer['xchan_guid'] . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $timestamp . $typename); return $timestamp . '.' . $sec_hash; } @@ -367,12 +371,10 @@ function check_form_security_token($typename = '', $formname = 'form_security_to $max_livetime = 10800; // 3 hours - $a = get_app(); - $x = explode('.', $hash); if (time() > (IntVal($x[0]) + $max_livetime)) return false; - $sec_hash = hash('whirlpool', $a->user['guid'] . $a->user['prvkey'] . session_id() . $x[0] . $typename); + $sec_hash = hash('whirlpool', App::$observer['xchan_guid'] . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $x[0] . $typename); return ($sec_hash == $x[1]); } @@ -382,17 +384,15 @@ function check_form_security_std_err_msg() { } function check_form_security_token_redirectOnErr($err_redirect, $typename = '', $formname = 'form_security_token') { if (!check_form_security_token($typename, $formname)) { - $a = get_app(); - logger('check_form_security_token failed: user ' . $a->user['guid'] . ' - form element ' . $typename); + logger('check_form_security_token failed: user ' . App::$observer['xchan_name'] . ' - form element ' . $typename); logger('check_form_security_token failed: _REQUEST data: ' . print_r($_REQUEST, true), LOGGER_DATA); notice( check_form_security_std_err_msg() ); - goaway($a->get_baseurl() . $err_redirect ); + goaway(z_root() . $err_redirect ); } } function check_form_security_token_ForbiddenOnErr($typename = '', $formname = 'form_security_token') { if (!check_form_security_token($typename, $formname)) { - $a = get_app(); - logger('check_form_security_token failed: user ' . $a->user['guid'] . ' - form element ' . $typename); + logger('check_form_security_token failed: user ' . App::$observer['xchan_name'] . ' - form element ' . $typename); logger('check_form_security_token failed: _REQUEST data: ' . print_r($_REQUEST, true), LOGGER_DATA); header('HTTP/1.1 403 Forbidden'); killme(); @@ -408,7 +408,7 @@ function init_groups_visitor($contact_id) { $r = q("SELECT hash FROM `groups` left join group_member on groups.id = group_member.gid WHERE xchan = '%s' ", dbesc($contact_id) ); - if(count($r)) { + if($r) { foreach($r as $rr) $groups[] = $rr['hash']; } diff --git a/include/session.php b/include/session.php deleted file mode 100644 index 92004bc18..000000000 --- a/include/session.php +++ /dev/null @@ -1,120 +0,0 @@ -<?php -/** - * @file include/session.php - * - * @brief This file includes session related functions. - * - * Session management functions. These provide database storage of PHP - * session info. - */ - -$session_exists = 0; -$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. - - session_set_cookie_params($time); - session_regenerate_id(false); - - q("UPDATE session SET sid = '%s' WHERE sid = '%s'", - dbesc(session_id()), - dbesc($old_sid) - ); - - if (x($_COOKIE, 'jsAvailable')) { - if ($time) { - $expires = time() + $time; - } else { - $expires = 0; - } - setcookie('jsAvailable', $_COOKIE['jsAvailable'], $expires); - } -} - - -function ref_session_open ($s, $n) { - return true; -} - - -function ref_session_read ($id) { - global $session_exists; - if(x($id)) - $r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id)); - - if(count($r)) { - $session_exists = true; - return $r[0]['data']; - } - - return ''; -} - - -function ref_session_write ($id, $data) { - global $session_exists, $session_expire; - - if(! $id || ! $data) { - return false; - } - - $expire = time() + $session_expire; - $default_expire = time() + 300; - - if($session_exists) { - q("UPDATE `session` - SET `data` = '%s', `expire` = '%s' WHERE `sid` = '%s'", - dbesc($data), - dbesc($expire), - dbesc($id) - ); - } else { - q("INSERT INTO `session` (sid, expire, data) values ('%s', '%s', '%s')", - //SET `sid` = '%s', `expire` = '%s', `data` = '%s'", - dbesc($id), - dbesc($default_expire), - dbesc($data) - ); - } - - return true; -} - - -function ref_session_close() { - return true; -} - - -function ref_session_destroy ($id) { - q("DELETE FROM `session` WHERE `sid` = '%s'", dbesc($id)); - return true; -} - - -function ref_session_gc($expire) { - q("DELETE FROM session WHERE expire < %d", dbesc(time())); - return true; -} - -$gc_probability = 50; - -ini_set('session.gc_probability', $gc_probability); -ini_set('session.use_only_cookies', 1); -ini_set('session.cookie_httponly', 1); - -/* - * PHP function which sets our user-level session storage functions. - */ -session_set_save_handler( - 'ref_session_open', - 'ref_session_close', - 'ref_session_read', - 'ref_session_write', - 'ref_session_destroy', - 'ref_session_gc' -);
\ No newline at end of file diff --git a/include/smarty.php b/include/smarty.php index 99f143db1..3812c6021 100755 --- a/include/smarty.php +++ b/include/smarty.php @@ -16,19 +16,19 @@ class FriendicaSmarty extends Smarty { // setTemplateDir can be set to an array, which Smarty will parse in order. // The order is thus very important here $template_dirs = array('theme' => "view/theme/$theme/tpl/"); - if( x($a->theme_info,"extends") ) - $template_dirs = $template_dirs + array('extends' => "view/theme/".$a->theme_info["extends"]."/tpl/"); + if( x(App::$theme_info,"extends") ) + $template_dirs = $template_dirs + array('extends' => "view/theme/".App::$theme_info["extends"]."/tpl/"); $template_dirs = $template_dirs + array('base' => 'view/tpl/'); $this->setTemplateDir($template_dirs); - $basecompiledir = $a->config['system']['smarty3_folder']; + $basecompiledir = App::$config['system']['smarty3_folder']; $this->setCompileDir($basecompiledir.'/compiled/'); $this->setConfigDir($basecompiledir.'/config/'); $this->setCacheDir($basecompiledir.'/cache/'); - $this->left_delimiter = $a->get_template_ldelim('smarty3'); - $this->right_delimiter = $a->get_template_rdelim('smarty3'); + $this->left_delimiter = App::get_template_ldelim('smarty3'); + $this->right_delimiter = App::get_template_rdelim('smarty3'); // Don't report errors so verbosely $this->error_reporting = E_ALL & ~E_NOTICE; @@ -53,7 +53,7 @@ class FriendicaSmartyEngine implements ITemplateEngine { // Cannot use get_config() here because it is called during installation when there is no DB. // FIXME: this may leak private information such as system pathnames. - $basecompiledir = ((array_key_exists('smarty3_folder',$a->config['system'])) ? $a->config['system']['smarty3_folder'] : ''); + $basecompiledir = ((array_key_exists('smarty3_folder',App::$config['system'])) ? App::$config['system']['smarty3_folder'] : ''); if (!$basecompiledir) $basecompiledir = dirname(__dir__) . "/" . TEMPLATE_BUILD_PATH; if (!is_dir($basecompiledir)) { echo "<b>ERROR:</b> folder <tt>$basecompiledir</tt> does not exist."; killme(); @@ -61,7 +61,7 @@ class FriendicaSmartyEngine implements ITemplateEngine { if(!is_writable($basecompiledir)){ echo "<b>ERROR:</b> folder <tt>$basecompiledir</tt> must be writable by webserver."; killme(); } - $a->config['system']['smarty3_folder'] = $basecompiledir; + App::$config['system']['smarty3_folder'] = $basecompiledir; } // ITemplateEngine interface @@ -94,8 +94,8 @@ class FriendicaSmartyEngine implements ITemplateEngine { public function get_intltext_template($file, $root='') { $a = get_app(); - if(file_exists("view/{$a->language}/$file")) - $template_file = "view/{$a->language}/$file"; + if(file_exists("view/{App::$language}/$file")) + $template_file = "view/{App::$language}/$file"; elseif(file_exists("view/en/$file")) $template_file = "view/en/$file"; else diff --git a/include/socgraph.php b/include/socgraph.php index e44a8ea9a..1b1bccf20 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -409,7 +409,7 @@ function poco($a,$extended = false) { http_status_exit(401); } - $observer = $a->get_observer(); + $observer = App::get_observer(); if(argc() > 1) { $user = notags(trim(argv(1))); diff --git a/include/taxonomy.php b/include/taxonomy.php index 0bf89a7c1..71ed6e91d 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -299,7 +299,7 @@ function dir_tagblock($link,$r) { if(! $r) - $r = get_app()->data['directory_keywords']; + $r = App::$data['directory_keywords']; if($r) { $o = '<div class="dirtagblock widget"><h3>' . t('Keywords') . '</h3><div class="tags" align="center">'; @@ -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..0a7f84b01 100644 --- a/include/text.php +++ b/include/text.php @@ -27,7 +27,7 @@ function replace_macros($s, $r) { $arr = array('template' => $s, 'params' => $r); call_hooks('replace_macros', $arr); - $t = $a->template_engine(); + $t = App::template_engine(); $output = $t->replace_macros($arr['template'],$arr['params']); return $output; @@ -99,7 +99,7 @@ function z_input_filter($channel_id,$s,$type = 'text/bbcode') { return escape_tags($s); $a = get_app(); - if($a->is_sys) { + if(App::$is_sys) { return $s; } @@ -368,34 +368,34 @@ function hex2bin($s) { // Automatic pagination. // To use, get the count of total items. -// Then call $a->set_pager_total($number_items); -// Optionally call $a->set_pager_itemspage($n) to the number of items to display on each page +// Then call App::set_pager_total($number_items); +// Optionally call App::set_pager_itemspage($n) to the number of items to display on each page // Then call paginate($a) after the end of the display loop to insert the pager block on the page // (assuming there are enough items to paginate). -// When using with SQL, the setting LIMIT %d, %d => $a->pager['start'],$a->pager['itemspage'] +// When using with SQL, the setting LIMIT %d, %d => App::$pager['start'],App::$pager['itemspage'] // will limit the results to the correct items for the current page. // The actual page handling is then accomplished at the application layer. function paginate(&$a) { $o = ''; - $stripped = preg_replace('/(&page=[0-9]*)/','',$a->query_string); + $stripped = preg_replace('/(&page=[0-9]*)/','',App::$query_string); // $stripped = preg_replace('/&zid=(.*?)([\?&]|$)/ism','',$stripped); $stripped = str_replace('q=','',$stripped); $stripped = trim($stripped,'/'); - $pagenum = $a->pager['page']; - $url = $a->get_baseurl() . '/' . $stripped; + $pagenum = App::$pager['page']; + $url = z_root() . '/' . $stripped; - if($a->pager['total'] > $a->pager['itemspage']) { + if(App::$pager['total'] > App::$pager['itemspage']) { $o .= '<div class="pager">'; - if($a->pager['page'] != 1) - $o .= '<span class="pager_prev">'."<a href=\"$url".'&page='.($a->pager['page'] - 1).'">' . t('prev') . '</a></span> '; + if(App::$pager['page'] != 1) + $o .= '<span class="pager_prev">'."<a href=\"$url".'&page='.(App::$pager['page'] - 1).'">' . t('prev') . '</a></span> '; $o .= "<span class=\"pager_first\"><a href=\"$url"."&page=1\">" . t('first') . "</a></span> "; - $numpages = $a->pager['total'] / $a->pager['itemspage']; + $numpages = App::$pager['total'] / App::$pager['itemspage']; $numstart = 1; $numstop = $numpages; @@ -406,15 +406,15 @@ function paginate(&$a) { } for($i = $numstart; $i <= $numstop; $i++){ - if($i == $a->pager['page']) + if($i == App::$pager['page']) $o .= '<span class="pager_current">'.(($i < 10) ? ' '.$i : $i); else $o .= "<span class=\"pager_n\"><a href=\"$url"."&page=$i\">".(($i < 10) ? ' '.$i : $i)."</a>"; $o .= '</span> '; } - if(($a->pager['total'] % $a->pager['itemspage']) != 0) { - if($i == $a->pager['page']) + if((App::$pager['total'] % App::$pager['itemspage']) != 0) { + if($i == App::$pager['page']) $o .= '<span class="pager_current">'.(($i < 10) ? ' '.$i : $i); else $o .= "<span class=\"pager_n\"><a href=\"$url"."&page=$i\">".(($i < 10) ? ' '.$i : $i)."</a>"; @@ -424,8 +424,8 @@ function paginate(&$a) { $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages); $o .= "<span class=\"pager_last\"><a href=\"$url"."&page=$lastpage\">" . t('last') . "</a></span> "; - if(($a->pager['total'] - ($a->pager['itemspage'] * $a->pager['page'])) > 0) - $o .= '<span class="pager_next">'."<a href=\"$url"."&page=".($a->pager['page'] + 1).'">' . t('next') . '</a></span>'; + if((App::$pager['total'] - (App::$pager['itemspage'] * App::$pager['page'])) > 0) + $o .= '<span class="pager_next">'."<a href=\"$url"."&page=".(App::$pager['page'] + 1).'">' . t('next') . '</a></span>'; $o .= '</div>'."\r\n"; } return $o; @@ -439,20 +439,20 @@ function alt_pager(&$a, $i, $more = '', $less = '') { if(! $less) $less = t('newer'); - $stripped = preg_replace('/(&page=[0-9]*)/','',$a->query_string); + $stripped = preg_replace('/(&page=[0-9]*)/','',App::$query_string); $stripped = str_replace('q=','',$stripped); $stripped = trim($stripped,'/'); - //$pagenum = $a->pager['page']; - $url = $a->get_baseurl() . '/' . $stripped; + //$pagenum = App::$pager['page']; + $url = z_root() . '/' . $stripped; return replace_macros(get_markup_template('alt_pager.tpl'), array( - '$has_less' => (($a->pager['page'] > 1) ? true : false), - '$has_more' => (($i > 0 && $i >= $a->pager['itemspage']) ? true : false), + '$has_less' => ((App::$pager['page'] > 1) ? true : false), + '$has_more' => (($i > 0 && $i >= App::$pager['itemspage']) ? true : false), '$less' => $less, '$more' => $more, '$url' => $url, - '$prevpage' => $a->pager['page'] - 1, - '$nextpage' => $a->pager['page'] + 1, + '$prevpage' => App::$pager['page'] - 1, + '$nextpage' => App::$pager['page'] + 1, )); } @@ -470,7 +470,7 @@ function item_message_id() { do { $dups = false; $hash = random_string(); - $mid = $hash . '@' . get_app()->get_hostname(); + $mid = $hash . '@' . App::get_hostname(); $r = q("SELECT id FROM item WHERE mid = '%s' LIMIT 1", dbesc($mid)); @@ -536,14 +536,15 @@ 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; - if(($a->module == 'install') || (! ($db && $db->connected))) + if((App::$module == 'install') || (! ($db && $db->connected))) return; $debugging = get_config('system', 'debugging'); @@ -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,42 @@ function logger($msg, $level = 0) { @file_put_contents($pluginfo['filename'], $pluginfo['message'], FILE_APPEND); } +// like logger() but with a function backtrace to pinpoint certain classes +// of problems which show up deep in the calling stack + + +function btlogger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) { + + logger($msg, $level, $priority); + if(version_compare(PHP_VERSION, '5.4.0') >= 0) { + $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + if($stack) { + for($x = 1; $x < count($stack); $x ++) { + logger('stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()',$level, $priority); + } + } + } +} + + + +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. * @@ -588,7 +625,7 @@ function dlogger($msg, $level = 0) { global $a; global $db; - if(($a->module == 'install') || (! ($db && $db->connected))) + if((App::$module == 'install') || (! ($db && $db->connected))) return; $debugging = get_config('system','debugging'); @@ -748,20 +785,20 @@ function contact_block() { $o = ''; $a = get_app(); - if(! $a->profile['uid']) + if(! App::$profile['uid']) return; - if(! perm_is_allowed($a->profile['uid'],get_observer_hash(),'view_contacts')) + if(! perm_is_allowed(App::$profile['uid'],get_observer_hash(),'view_contacts')) return; - $shown = get_pconfig($a->profile['uid'],'system','display_friend_count'); + $shown = get_pconfig(App::$profile['uid'],'system','display_friend_count'); if($shown === false) $shown = 25; if($shown == 0) return; - $is_owner = ((local_channel() && local_channel() == $a->profile['uid']) ? true : false); + $is_owner = ((local_channel() && local_channel() == App::$profile['uid']) ? true : false); $sql_extra = ''; $abook_flags = " and abook_pending = 0 and abook_self = 0 "; @@ -771,12 +808,12 @@ function contact_block() { $sql_extra = " and xchan_hidden = 0 "; } - if((! is_array($a->profile)) || ($a->profile['hide_friends'])) + if((! is_array(App::$profile)) || (App::$profile['hide_friends'])) return $o; $r = q("SELECT COUNT(abook_id) AS total FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra", - intval($a->profile['uid']) + intval(App::$profile['uid']) ); if(count($r)) { $total = intval($r[0]['total']); @@ -789,12 +826,12 @@ function contact_block() { $randfunc = db_getfunc('RAND'); $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d $abook_flags and abook_archived = 0 and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ORDER BY $randfunc LIMIT %d", - intval($a->profile['uid']), + intval(App::$profile['uid']), intval($shown) ); 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); @@ -806,8 +843,8 @@ function contact_block() { $tpl = get_markup_template('contact_block.tpl'); $o = replace_macros($tpl, array( '$contacts' => $contacts, - '$nickname' => $a->profile['channel_address'], - '$viewconnections' => t('View Connections'), + '$nickname' => App::$profile['channel_address'], + '$viewconnections' => (($total > $shown) ? sprintf(t('View all %s connections'),$total) : ''), '$micropro' => $micropro, )); @@ -863,7 +900,7 @@ function search($s,$id='search-box',$url='/search',$save = false) { return replace_macros(get_markup_template('searchbox.tpl'),array( '$s' => $s, '$id' => $id, - '$action_url' => $a->get_baseurl((stristr($url,'network')) ? true : false) . $url, + '$action_url' => z_root() . $url, '$search_label' => t('Search'), '$save_label' => t('Save'), '$savedsearch' => feature_enabled(local_channel(),'savedsearch') @@ -950,16 +987,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 +1017,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'), @@ -1036,41 +1081,41 @@ function list_smilies() { ); $icons = array( - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="</3" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="<\\3" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-smile.gif" alt=":-)" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-wink.gif" alt=";-)" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-frown.gif" alt=":-(" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-tongue-out.gif" alt=":-P" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-tongue-out.gif" alt=":-p" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-\"" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-\"" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-x" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-X" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-laughing.gif" alt=":-D" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt="8-|" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt="8-O" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt=":-O" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-thumbsup.gif" alt="\\o/" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-Oo.gif" alt="o.O" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-Oo.gif" alt="O.o" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-Oo.gif" alt="o_O" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-Oo.gif" alt="O_o" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-cry.gif" alt=":\'(" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-foot-in-mouth.gif" alt=":-!" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-undecided.gif" alt=":-/" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-embarassed.gif" alt=":-[" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-cool.gif" alt="8-)" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/beer_mug.gif" alt=":beer" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/beer_mug.gif" alt=":homebrew" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/coffee.gif" alt=":coffee" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-facepalm.gif" alt=":facepalm" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/like.gif" alt=":like" />', - '<img class="smiley" src="' . $a->get_baseurl() . '/images/dislike.gif" alt=":dislike" />', - '<a href="http://getzot.com"><strong>red<img class="smiley bb_rm-logo" src="' . $a->get_baseurl() . '/images/rm-32.png" alt="' . urlencode('red#matrix') . '" />matrix</strong></a>', - '<a href="http://getzot.com"><strong>red<img class="smiley bb_rm-logo" src="' . $a->get_baseurl() . '/images/rm-32.png" alt="' . urlencode('red#') . '" />matrix</strong></a>', - '<a href="http://getzot.com"><strong>red<img class="smiley bb_rm-logo" src="' . $a->get_baseurl() . '/images/rm-32.png" alt="r#" />matrix</strong></a>' + '<img class="smiley" src="' . z_root() . '/images/smiley-heart.gif" alt="<3" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-brokenheart.gif" alt="</3" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-brokenheart.gif" alt="<\\3" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-smile.gif" alt=":-)" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-wink.gif" alt=";-)" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-frown.gif" alt=":-(" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-tongue-out.gif" alt=":-P" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-tongue-out.gif" alt=":-p" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-kiss.gif" alt=":-\"" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-kiss.gif" alt=":-\"" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-kiss.gif" alt=":-x" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-kiss.gif" alt=":-X" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-laughing.gif" alt=":-D" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-surprised.gif" alt="8-|" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-surprised.gif" alt="8-O" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-surprised.gif" alt=":-O" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-thumbsup.gif" alt="\\o/" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-Oo.gif" alt="o.O" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-Oo.gif" alt="O.o" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-Oo.gif" alt="o_O" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-Oo.gif" alt="O_o" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-cry.gif" alt=":\'(" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-foot-in-mouth.gif" alt=":-!" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-undecided.gif" alt=":-/" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-embarassed.gif" alt=":-[" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-cool.gif" alt="8-)" />', + '<img class="smiley" src="' . z_root() . '/images/beer_mug.gif" alt=":beer" />', + '<img class="smiley" src="' . z_root() . '/images/beer_mug.gif" alt=":homebrew" />', + '<img class="smiley" src="' . z_root() . '/images/coffee.gif" alt=":coffee" />', + '<img class="smiley" src="' . z_root() . '/images/smiley-facepalm.gif" alt=":facepalm" />', + '<img class="smiley" src="' . z_root() . '/images/like.gif" alt=":like" />', + '<img class="smiley" src="' . z_root() . '/images/dislike.gif" alt=":dislike" />', + '<a href="http://getzot.com"><strong>red<img class="smiley bb_rm-logo" src="' . z_root() . '/images/rm-32.png" alt="' . urlencode('red#matrix') . '" />matrix</strong></a>', + '<a href="http://getzot.com"><strong>red<img class="smiley bb_rm-logo" src="' . z_root() . '/images/rm-32.png" alt="' . urlencode('red#') . '" />matrix</strong></a>', + '<a href="http://getzot.com"><strong>red<img class="smiley bb_rm-logo" src="' . z_root() . '/images/rm-32.png" alt="r#" />matrix</strong></a>' ); @@ -1147,7 +1192,7 @@ function preg_heart($x) { $t = ''; for($cnt = 0; $cnt < strlen($x[1]); $cnt ++) - $t .= '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />'; + $t .= '<img class="smiley" src="' . z_root() . '/images/smiley-heart.gif" alt="<3" />'; $r = str_replace($x[0],$t,$x[0]); @@ -1418,7 +1463,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 +1473,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 +1483,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); @@ -1675,12 +1720,12 @@ function feed_hublinks() { function feed_salmonlinks($nick) { $a = get_app(); - $salmon = '<link rel="salmon" href="' . xmlify($a->get_baseurl() . '/salmon/' . $nick) . '" />' . "\n" ; + $salmon = '<link rel="salmon" href="' . xmlify(z_root() . '/salmon/' . $nick) . '" />' . "\n" ; // old style links that status.net still needed as of 12/2010 - $salmon .= ' <link rel="http://salmon-protocol.org/ns/salmon-replies" href="' . xmlify($a->get_baseurl() . '/salmon/' . $nick) . '" />' . "\n" ; - $salmon .= ' <link rel="http://salmon-protocol.org/ns/salmon-mention" href="' . xmlify($a->get_baseurl() . '/salmon/' . $nick) . '" />' . "\n" ; + $salmon .= ' <link rel="http://salmon-protocol.org/ns/salmon-replies" href="' . xmlify(z_root() . '/salmon/' . $nick) . '" />' . "\n" ; + $salmon .= ' <link rel="http://salmon-protocol.org/ns/salmon-mention" href="' . xmlify(z_root() . '/salmon/' . $nick) . '" />' . "\n" ; return $salmon; } @@ -1742,7 +1787,7 @@ function mimetype_select($channel_id, $current = 'text/bbcode') { ); $a = get_app(); - if($a->is_sys) { + if(App::$is_sys) { $x[] = 'application/x-php'; } else { @@ -1793,7 +1838,7 @@ function lang_selector() { } $ll = substr($l,5); $ll = substr($ll,0,strrpos($ll,'/')); - $selected = (($ll === $a->language && (x($_SESSION, 'language'))) ? $ll : $selected); + $selected = (($ll === App::$language && (x($_SESSION, 'language'))) ? $ll : $selected); $lang_options[$ll] = get_language_name($ll, $ll) . " ($ll)"; } } @@ -2215,10 +2260,10 @@ function json_decode_plus($s) { */ function design_tools() { - $channel = get_app()->get_channel(); + $channel = App::get_channel(); $sys = false; - if(get_app()->is_sys && is_site_admin()) { + if(App::$is_sys && is_site_admin()) { require_once('include/identity.php'); $channel = get_sys_channel(); $sys = true; @@ -2328,8 +2373,8 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d $basetag = str_replace('_',' ',substr($tag,1)); //create text for link - $url = $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag); - $newtag = '#[zrl=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/zrl]'; + $url = z_root() . '/search?tag=' . rawurlencode($basetag); + $newtag = '#[zrl=' . z_root() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/zrl]'; //replace tag by the link. Make sure to not replace something in the middle of a word // The '=' is needed to not replace color codes if the code is also used as a tag // Much better would be to somehow completely avoiding things in e.g. [color]-tags. @@ -2475,7 +2520,7 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d // $r is set if we found something - $channel = get_app()->get_channel(); + $channel = App::get_channel(); if($r) { $profile = $r[0]['xchan_url']; @@ -2505,7 +2550,7 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d if($g && $exclusive) { $access_tag .= 'gid:' . $g[0]['hash']; } - $channel = get_app()->get_channel(); + $channel = App::get_channel(); if($channel) { $newtag = '@' . (($exclusive) ? '!' : '') . '[zrl=' . z_root() . '/channel/' . $channel['channel_address'] . ']' . $newname . '[/zrl]'; $body = str_replace('@' . (($exclusive) ? '!' : '') . $name, $newtag, $body); @@ -2563,7 +2608,7 @@ function linkify_tags($a, &$body, $uid, $diaspora = false) { if($fullnametagged) continue; - $success = handle_tag($a, $body, $access_tag, $str_tags, ($uid) ? $uid : $a->profile_uid , $tag, $diaspora); + $success = handle_tag($a, $body, $access_tag, $str_tags, ($uid) ? $uid : App::$profile_uid , $tag, $diaspora); $results[] = array('success' => $success, 'access_tag' => $access_tag); if($success['replaced']) $tagged[] = $tag; } @@ -2685,18 +2730,95 @@ function json_url_replace($old,$new,&$s) { } -function item_url_replace($channel,&$item,$old,$new) { +function item_url_replace($channel,&$item,$old,$new,$oldnick = '') { - if($item['attach']) + if($item['attach']) { json_url_replace($old,$new,$item['attach']); - if($item['object']) + if($oldnick) + json_url_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['attach']); + } + if($item['object']) { json_url_replace($old,$new,$item['object']); - if($item['target']) + if($oldnick) + json_url_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['object']); + } + if($item['target']) { json_url_replace($old,$new,$item['target']); + if($oldnick) + json_url_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['target']); + } if(string_replace($old,$new,$item['body'])) { $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); $item['item_verified'] = 1; } + + $item['plink'] = str_replace($old,$new,$item['plink']); + if($oldnick) + $item['plink'] = str_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['plink']); + + $item['llink'] = str_replace($old,$new,$item['llink']); + if($oldnick) + $item['llink'] = str_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$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..0355ebd8c 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -8,14 +8,24 @@ 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(); + $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false); - return profile_sidebar($a->profile, $block, true); + return profile_sidebar(App::$profile, $block, true); } +function widget_zcard($args) { + + $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false); + $channel = channelx_by_n(App::$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. @@ -23,8 +33,8 @@ function widget_tagcloud($args) { $o = ''; //$tab = 0; - $a = get_app(); - $uid = $a->profile_uid; + + $uid = App::$profile_uid; $count = ((x($args,'count')) ? intval($args['count']) : 24); $flags = 0; $type = TERM_CATEGORY; @@ -75,7 +85,7 @@ function widget_collections($args) { $each = 'group'; $edit = false; $current = 0; - $abook_id = get_app()->poi['abook_xchan']; + $abook_id = App::$poi['abook_xchan']; $wmode = 1; break; default: @@ -154,8 +164,7 @@ function widget_follow($args) { if(! local_channel()) return ''; - $a = get_app(); - $uid =$a->channel['channel_id']; + $uid = App::$channel['channel_id']; $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", intval($uid) ); @@ -170,8 +179,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 )); @@ -200,8 +209,6 @@ function widget_savedsearch($arr) { if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch'))) return ''; - $a = get_app(); - $search = ((x($_GET,'search')) ? $_GET['search'] : ''); if(x($_GET,'searchsave') && $search) { @@ -228,7 +235,7 @@ function widget_savedsearch($arr) { $search = ''; } - $srchurl = $a->query_string; + $srchurl = App::$query_string; $srchurl = rtrim(preg_replace('/searchsave\=[^\&].*?(\&|$)/is','',$srchurl),'&'); $hasq = ((strpos($srchurl,'?') !== false) ? true : false); @@ -285,7 +292,6 @@ function widget_filer($arr) { if(! local_channel()) return ''; - $a = get_app(); $selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : ''); @@ -306,20 +312,19 @@ function widget_filer($arr) { '$sel_all' => (($selected == '') ? 'selected' : ''), '$all' => t('Everything'), '$terms' => $terms, - '$base' => z_root() . '/' . $a->cmd + '$base' => z_root() . '/' . App::$cmd )); } function widget_archive($arr) { $o = ''; - $a = get_app(); - if(! $a->profile_uid) { + if(! App::$profile_uid) { return ''; } - $uid = $a->profile_uid; + $uid = App::$profile_uid; if(! feature_enabled($uid,'archives')) return ''; @@ -335,7 +340,7 @@ function widget_archive($arr) { if(! $visible_years) $visible_years = 5; - $url = z_root() . '/' . $a->cmd; + $url = z_root() . '/' . App::$cmd; $ret = list_post_dates($uid,$wall,$mindate); @@ -360,23 +365,34 @@ function widget_archive($arr) { function widget_fullprofile($arr) { - $a = get_app(); - if(! $a->profile['profile_uid']) + + if(! App::$profile['profile_uid']) return; $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false); - return profile_sidebar($a->profile, $block); + return profile_sidebar(App::$profile, $block); } +function widget_shortprofile($arr) { + + if(! App::$profile['profile_uid']) + return; + + $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false); + + return profile_sidebar(App::$profile, $block, true, true); +} + + function widget_categories($arr) { - $a = get_app(); - if($a->profile['profile_uid'] && (! perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'view_stream'))) + + if(App::$profile['profile_uid'] && (! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'view_stream'))) return ''; $cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : ''); - $srchurl = $a->query_string; + $srchurl = App::$query_string; $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&'); $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); @@ -385,31 +401,31 @@ function widget_categories($arr) { } function widget_tagcloud_wall($arr) { - $a = get_app(); - if((! $a->profile['profile_uid']) || (! $a->profile['channel_hash'])) + + if((! App::$profile['profile_uid']) || (! App::$profile['channel_hash'])) return ''; - if(! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_stream')) + if(! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_stream')) return ''; $limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 50); - if(feature_enabled($a->profile['profile_uid'], 'tagadelic')) - return wtagblock($a->profile['profile_uid'], $limit, '', $a->profile['channel_hash'], 'wall'); + if(feature_enabled(App::$profile['profile_uid'], 'tagadelic')) + return wtagblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash'], 'wall'); return ''; } function widget_catcloud_wall($arr) { - $a = get_app(); - if((! $a->profile['profile_uid']) || (! $a->profile['channel_hash'])) + + if((! App::$profile['profile_uid']) || (! App::$profile['channel_hash'])) return ''; - if(! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_stream')) + if(! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_stream')) return ''; $limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50); - return catblock($a->profile['profile_uid'], $limit, '', $a->profile['channel_hash'], 'wall'); + return catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash'], 'wall'); } @@ -465,8 +481,8 @@ function widget_settings_menu($arr) { if(! local_channel()) return; - $a = get_app(); - $channel = $a->get_channel(); + + $channel = App::get_channel(); $abook_self_id = 0; @@ -480,55 +496,74 @@ function widget_settings_menu($arr) { if($abk) $abook_self_id = $abk[0]['abook_id']; + $hublocs = q("select count(*) as total from hubloc where hubloc_hash = '%s'", + dbesc($channel['channel_hash']) + ); + + $hublocs = (($hublocs[0]['total'] > 1) ? true : false); + $tabs = array( array( 'label' => t('Account settings'), - 'url' => $a->get_baseurl(true).'/settings/account', + 'url' => z_root().'/settings/account', 'selected' => ((argv(1) === 'account') ? 'active' : ''), ), array( 'label' => t('Channel settings'), - 'url' => $a->get_baseurl(true).'/settings/channel', + 'url' => z_root().'/settings/channel', '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' => z_root().'/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' => z_root().'/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' => z_root().'/settings/display', + 'selected' => ((argv(1) === 'display') ? 'active' : ''), + ); - array( + if($hublocs) { + $tabs[] = array( + 'label' => t('Manage locations'), + 'url' => z_root() . '/locs', + 'selected' => ((argv(1) === 'locs') ? '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', + 'url' => z_root() . '/uexport', 'selected' => '' - ), + ); + } + $tabs[] = array( + 'label' => t('Connected apps'), + 'url' => z_root() . '/settings/oauth', + 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), ); if($role === false || $role === 'custom') { $tabs[] = array( 'label' => t('Connection Default Permissions'), - 'url' => $a->get_baseurl(true) . '/connedit/' . $abook_self_id, + 'url' => z_root() . '/connedit/' . $abook_self_id, 'selected' => '' ); } @@ -536,7 +571,7 @@ function widget_settings_menu($arr) { if(feature_enabled(local_channel(),'premium_channel')) { $tabs[] = array( 'label' => t('Premium Channel Settings'), - 'url' => $a->get_baseurl(true) . '/connect/' . $channel['channel_address'], + 'url' => z_root() . '/connect/' . $channel['channel_address'], 'selected' => '' ); } @@ -544,7 +579,7 @@ function widget_settings_menu($arr) { if(feature_enabled(local_channel(),'channel_sources')) { $tabs[] = array( 'label' => t('Channel Sources'), - 'url' => $a->get_baseurl(true) . '/sources', + 'url' => z_root() . '/sources', 'selected' => '' ); } @@ -562,28 +597,27 @@ function widget_mailmenu($arr) { if (! local_channel()) return; - $a = get_app(); return replace_macros(get_markup_template('message_side.tpl'), array( '$title' => t('Private Mail Menu'), '$combined'=>array( 'label' => t('Combined View'), - 'url' => $a->get_baseurl(true) . '/mail/combined', + 'url' => z_root() . '/mail/combined', 'sel' => (argv(1) == 'combined'), ), '$inbox'=>array( 'label' => t('Inbox'), - 'url' => $a->get_baseurl(true) . '/mail/inbox', + 'url' => z_root() . '/mail/inbox', 'sel' => (argv(1) == 'inbox'), ), '$outbox'=>array( 'label' => t('Outbox'), - 'url' => $a->get_baseurl(true) . '/mail/outbox', + 'url' => z_root() . '/mail/outbox', 'sel' => (argv(1) == 'outbox'), ), '$new'=>array( 'label' => t('New Message'), - 'url' => $a->get_baseurl(true) . '/mail/new', + 'url' => z_root() . '/mail/new', 'sel'=> (argv(1) == 'new'), ) )); @@ -594,8 +628,6 @@ function widget_conversations($arr) { if (! local_channel()) return; - $a = get_app(); - if(argc() > 1) { switch(argv(1)) { @@ -620,7 +652,7 @@ function widget_conversations($arr) { require_once('include/message.php'); // private_messages_list() can do other more complicated stuff, for now keep it simple - $r = private_messages_list(local_channel(), $mailbox, $a->pager['start'], $a->pager['itemspage']); + $r = private_messages_list(local_channel(), $mailbox, App::$pager['start'], App::$pager['itemspage']); if(! $r) { info( t('No messages.') . EOL); @@ -695,8 +727,8 @@ function widget_design_tools($arr) { // mod menu doesn't load a profile. For any modules which load a profile, check it. // otherwise local_channel() is sufficient for permissions. - if($a->profile['profile_uid']) - if(($a->profile['profile_uid'] != local_channel()) && (! $a->is_sys)) + if(App::$profile['profile_uid']) + if((App::$profile['profile_uid'] != local_channel()) && (! App::$is_sys)) return ''; if(! local_channel()) @@ -712,22 +744,21 @@ function widget_findpeople($arr) { function widget_photo_albums($arr) { - $a = get_app(); - if(! $a->profile['profile_uid']) + if(! App::$profile['profile_uid']) return ''; - $channelx = channelx_by_n($a->profile['profile_uid']); - if((! $channelx) || (! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_storage'))) + $channelx = channelx_by_n(App::$profile['profile_uid']); + if((! $channelx) || (! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_storage'))) return ''; require_once('include/photos.php'); - return photos_album_widget($channelx, $a->get_observer()); + return photos_album_widget($channelx, App::get_observer()); } function widget_vcard($arr) { require_once ('include/Contact.php'); - return vcard_from_xchan('', get_app()->get_observer()); + return vcard_from_xchan('', App::get_observer()); } @@ -745,27 +776,43 @@ function widget_dirtags($arr) { } function widget_menu_preview($arr) { - if(! get_app()->data['menu_item']) + if(! App::$data['menu_item']) return; require_once('include/menu.php'); - return menu_render(get_app()->data['menu_item']); + return menu_render(App::$data['menu_item']); } function widget_chatroom_list($arr) { - $a = get_app(); + require_once("include/chat.php"); - $r = chatroom_list($a->profile['profile_uid']); - return replace_macros(get_markup_template('chatroomlist.tpl'), array( - '$header' => t('Chat Rooms'), - '$baseurl' => z_root(), - '$nickname' => $a->profile['channel_address'], - '$items' => $r, + $r = chatroom_list(App::$profile['profile_uid']); + + if($r) { + return replace_macros(get_markup_template('chatroomlist.tpl'), array( + '$header' => t('Chatrooms'), + '$baseurl' => z_root(), + '$nickname' => App::$profile['channel_address'], + '$items' => $r, + '$overview' => t('Overview') + )); + } +} + +function widget_chatroom_members() { + $o = replace_macros(get_markup_template('chatroom_members.tpl'), array( + '$header' => t('Chat Members') )); + + return $o; } function widget_bookmarkedchats($arr) { + + if(! feature_enabled(App::$profile['profile_uid'],'ajaxchat')) + return ''; + $h = get_observer_hash(); if(! $h) return; @@ -785,6 +832,9 @@ function widget_bookmarkedchats($arr) { function widget_suggestedchats($arr) { + if(! feature_enabled(App::$profile['profile_uid'],'ajaxchat')) + return ''; + // probably should restrict this to your friends, but then the widget will only work // if you are logged in locally. @@ -804,21 +854,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 = 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 +980,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 +1001,60 @@ function widget_photo($arr) { } +function widget_cover_photo($arr) { + + require_once('include/identity.php'); + $o = ''; + + if(App::$module == 'channel' && $_REQUEST['mid']) + return ''; + + $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 = App::$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'); @@ -947,13 +1069,13 @@ function widget_photo_rand($arr) { 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; + $channel_id = App::$profile_uid; if(! $channel_id) return ''; $scale = ((array_key_exists('scale',$arr)) ? intval($arr['scale']) : 0); - $ret = photos_list_photos(array('channel_id' => $channel_id),get_app()->get_observer(),$album); + $ret = photos_list_photos(array('channel_id' => $channel_id),App::get_observer(),$album); $filtered = array(); if($ret['success'] && $ret['photos']) @@ -997,7 +1119,7 @@ function widget_random_block($arr) { 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; + $channel_id = App::$profile_uid; if(! $channel_id) return ''; @@ -1033,7 +1155,7 @@ function widget_random_block($arr) { function widget_rating($arr) { - $a = get_app(); + $poco_rating = get_config('system','poco_rating_enable'); if((! $poco_rating) && ($poco_rating !== false)) { @@ -1043,7 +1165,7 @@ function widget_rating($arr) { if($arr['target']) $hash = $arr['target']; else - $hash = $a->poi['xchan_hash']; + $hash = App::$poi['xchan_hash']; if(! $hash) return; @@ -1052,7 +1174,7 @@ function widget_rating($arr) { $remote = false; if(remote_channel() && ! local_channel()) { - $ob = $a->get_observer(); + $ob = App::get_observer(); if($ob && $ob['xchan_url']) { $p = parse_url($ob['xchan_url']); if($p) { @@ -1066,7 +1188,7 @@ function widget_rating($arr) { $self = false; if(local_channel()) { - $channel = $a->get_channel(); + $channel = App::get_channel(); if($hash == $channel['channel_hash']) $self = true; @@ -1075,16 +1197,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; @@ -1093,7 +1217,7 @@ function widget_rating($arr) { // used by site ratings pages to provide a return link function widget_pubsites($arr) { - if(get_app()->poi) + if(App::$poi) return; return '<div class="widget"><ul class="nav nav-pills"><li><a href="pubsites">' . t('Public Hubs') . '</a></li></ul></div>'; } @@ -1101,8 +1225,6 @@ function widget_pubsites($arr) { function widget_forums($arr) { - $a = get_app(); - if(! local_channel()) return ''; @@ -1119,7 +1241,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()) @@ -1204,20 +1326,20 @@ function widget_admin($arr) { return login(false); } - - $a = get_app(); $o = ''; // array( url, name, extra css classes ) $aside = array( 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), - 'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users'), + 'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users', 'pending-update', t('Member registrations waiting for confirmation')), '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') ); @@ -1226,24 +1348,29 @@ function widget_admin($arr) { $r = q("SELECT * FROM addon WHERE plugin_admin = 1"); - $aside['plugins_admin'] = array(); + $plugins = array(); if($r) { foreach ($r as $h){ $plugin = $h['name']; - $aside['plugins_admin'][] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin'); + $plugins[] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin'); // temp plugins with admin - $a->plugins_admin[] = $plugin; + App::$plugins_admin[] = $plugin; } } - $aside['logs'] = array(z_root() . '/admin/logs/', t('Logs'), 'logs'); + $logs = array(z_root() . '/admin/logs/', t('Logs'), 'logs'); + + $arr = array('links' => $aside,'plugins' => $plugins,'logs' => $logs); + call_hooks('admin_aside',$arr); $o .= replace_macros(get_markup_template('admin_aside.tpl'), array( '$admin' => $aside, '$admtxt' => t('Admin'), '$plugadmtxt' => t('Plugin Features'), + '$plugins' => $plugins, '$logtxt' => t('Logs'), - '$h_pending' => t('User registrations waiting for confirmation'), + '$logs' => $logs, + '$h_pending' => t('Member registrations waiting for confirmation'), '$admurl'=> z_root() . '/admin/' )); @@ -1255,7 +1382,7 @@ function widget_admin($arr) { function widget_album($args) { - $owner_uid = get_app()->profile_uid; + $owner_uid = App::$profile_uid; $sql_extra = permissions_sql($owner_uid); @@ -1314,7 +1441,7 @@ function widget_album($args) { $imgalt_e = $rr['filename']; $desc_e = $rr['description']; - $imagelink = (z_root() . '/photos/' . get_app()->profile['channel_address'] . '/image/' . $rr['resource_id']); + $imagelink = (z_root() . '/photos/' . App::$profile['channel_address'] . '/image/' . $rr['resource_id']); $photos[] = array( @@ -1340,7 +1467,7 @@ function widget_album($args) { '$album_id' => rand(), '$album_edit' => array(t('Edit Album'), $album_edit), '$can_post' => false, - '$upload' => array(t('Upload'), z_root() . '/photos/' . get_app()->profile['channel_address'] . '/upload/' . bin2hex($album)), + '$upload' => array(t('Upload'), z_root() . '/photos/' . App::$profile['channel_address'] . '/upload/' . bin2hex($album)), '$order' => false, '$upload_form' => $upload_form, '$usage' => $usage_message diff --git a/include/zot.php b/include/zot.php index 922637bc1..0cdf7fc87 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 @@ -182,7 +181,7 @@ function zot_finger($webbie, $channel = null, $autofallback = true) { if (strpos($webbie,'@') === false) { $address = $webbie; - $host = get_app()->get_hostname(); + $host = App::get_hostname(); } else { $address = substr($webbie,0,strpos($webbie,'@')); $host = substr($webbie,strpos($webbie,'@')+1); @@ -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; } @@ -937,7 +941,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { } if(($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { - $guid = random_string() . '@' . get_app()->get_hostname(); + $guid = random_string() . '@' . App::get_hostname(); update_modtime($xchan_hash,$guid,$address,$ud_flags); logger('import_xchan: changed: ' . $what,LOGGER_DEBUG); } @@ -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']; @@ -1523,7 +1527,7 @@ function allowed_public_recips($msg) { return $recips; if(strpos($scope,'site:') === 0) { - if(($scope === 'site: ' . get_app()->get_hostname()) && ($msg['notify']['sender']['url'] === z_root())) + if(($scope === 'site: ' . App::get_hostname()) && ($msg['notify']['sender']['url'] === z_root())) return $recips; else return array(); @@ -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']) @@ -1602,7 +1606,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $ } $channel = $r[0]; - $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . App::get_hostname() . '>'); /* blacklisted channels get a permission denied, no special message to tip them off */ @@ -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']) @@ -2081,7 +2085,7 @@ function process_mail_delivery($sender, $arr, $deliveries) { } $channel = $r[0]; - $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . App::get_hostname() . '>'); /* blacklisted channels get a permission denied, no special message to tip them off */ @@ -2223,13 +2227,69 @@ function process_location_delivery($sender,$arr,$deliveries) { $x = sync_locations($sender,$arr,true); logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DEBUG); if($x['changed']) { - $guid = random_string() . '@' . get_app()->get_hostname(); + $guid = random_string() . '@' . App::get_hostname(); update_modtime($sender['hash'],$sender['guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED); } } } /** + * @brief checks for a moved UNO channel and sets the channel_moved flag + * + * Currently the effect of this flag is to turn the channel into 'read-only' mode. + * New content will not be processed (there was still an issue with blocking the + * ability to post comments as of 10-Mar-2016). + * We do not physically remove the channel at this time. The hub admin may choose + * to do so, but is encouraged to allow a grace period of several days in case there + * are any issues migrating content. This packet will generally be received by the + * original site when the basic channel import has been processed. + * + * This will only be executed on the UNO system which is the old location + * if a new location is reported and there is only one location record. + * The rest of the hubloc syncronisation will be handled within + * sync_locations + */ + + + +function check_location_move($sender_hash,$locations) { + + if(! $locations) + return; + + if(! UNO) + return; + + if(count($locations) != 1) + return; + + $loc = $locations[0]; + + $r = q("select * from channel where channel_hash = '%s' limit 1", + dbesc($sender_hash) + ); + + if(! $r) + return; + + if($loc['url'] !== z_root()) { + $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1", + dbesc($loc['url']), + dbesc($sender_hash) + ); + + // federation plugins may wish to notify connections + // of the move on singleton networks + + $arr = array('channel' => $r[0],'locations' => $locations); + call_hooks('location_move',$arr); + + } + +} + + +/** * @brief Synchronises locations. * * @param array $sender @@ -2243,6 +2303,10 @@ function sync_locations($sender, $arr, $absolute = false) { if($arr['locations']) { + if($absolute) + check_location_move($sender['hash'],$arr['locations']); + + $xisting = q("select hubloc_id, hubloc_url, hubloc_sitekey from hubloc where hubloc_hash = '%s'", dbesc($sender['hash']) ); @@ -2626,7 +2690,7 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA call_hooks('import_directory_profile', $d); if (($d['update']) && (! $suppress_update)) - update_modtime($arr['xprof_hash'],random_string() . '@' . get_app()->get_hostname(), $addr, $ud_flags); + update_modtime($arr['xprof_hash'],random_string() . '@' . App::get_hostname(), $addr, $ud_flags); return $d['update']; } @@ -2868,12 +2932,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(); @@ -2902,7 +2969,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { $synchubs = array(); foreach($h as $x) { - if($x['hubloc_host'] == $a->get_hostname()) + if($x['hubloc_host'] == App::get_hostname()) continue; $synchubs[] = $x; @@ -2924,8 +2991,8 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { $info['type'] = 'channel_sync'; $info['encoding'] = 'red'; // note: not zot, this packet is very red specific - if(array_key_exists($uid,$a->config) && array_key_exists('transient',$a->config[$uid])) { - $settings = $a->config[$uid]['transient']; + if(array_key_exists($uid,App::$config) && array_key_exists('transient',App::$config[$uid])) { + $settings = App::$config[$uid]['transient']; if($settings) { $info['config'] = $settings; } @@ -2967,7 +3034,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 +3051,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 +3068,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. */ @@ -3064,6 +3138,9 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { if(array_key_exists('menu',$arr) && $arr['menu']) sync_menus($channel,$arr['menu']); + if(array_key_exists('file',$arr) && $arr['file']) + sync_files($channel,$arr['file']); + if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) { if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) { @@ -3115,6 +3192,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 +3268,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 +3287,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 +3491,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->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $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'] . '@' . 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,14 +3914,14 @@ 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'); $a = get_app(); $visible_plugins = array(); - if(is_array($a->plugins) && count($a->plugins)) { + if(is_array(App::$plugins) && count(App::$plugins)) { $r = q("select * from addon where hidden = 0"); if($r) foreach($r as $rr) @@ -3848,7 +3934,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 +3950,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 @@ -3900,11 +3986,11 @@ function check_zotinfo($channel,$locations,&$ret) { dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_hash']), - dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + dbesc($channel['channel_address'] . '@' . App::get_hostname()), intval(1), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))), - dbesc(get_app()->get_hostname()), + dbesc(App::get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system','pubkey')), dbesc('zot') @@ -3924,6 +4010,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 +4174,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; @@ -4200,9 +4289,7 @@ function zot_reply_auth_check($data,$encrypted_packet) { // the web server. We should probably convert this to webserver time rather than DB time so // that the different clocks won't affect it and allow us to keep the time short. - q("delete from verify where type = 'auth' and created < %s - INTERVAL %s", - db_utcnow(), db_quoteinterval('30 MINUTE') - ); + Zotlabs\Zot\Verify::purge('auth','30 MINUTE'); $y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", dbesc($sender_hash) @@ -4241,19 +4328,13 @@ function zot_reply_auth_check($data,$encrypted_packet) { // This additionally checks for forged sites since we already stored the expected result in meta // and we've already verified that this is them via zot_gethub() and that their key signed our token - $z = q("select id from verify where channel = %d and type = 'auth' and token = '%s' and meta = '%s' limit 1", - intval($c[0]['channel_id']), - dbesc($data['secret']), - dbesc($data['sender']['url']) - ); + + $z = Zotlabs\Zot\Verify::match('auth',$c[0]['channel_id'],$data['secret'],$data['sender']['url']); if (! $z) { logger('mod_zot: auth_check: verification key not found.'); $ret['message'] .= 'verification key not found' . EOL; json_return_and_die($ret); } - $r = q("delete from verify where id = %d", - intval($z[0]['id']) - ); $u = q("select account_service_class from account where account_id = %d limit 1", intval($c[0]['channel_account_id']) |