Merge pull request #883 from dawnbreak/docu

💡 Improving Doxygen documentation.
This commit is contained in:
git-marijus 2017-11-04 10:25:27 +01:00 committed by GitHub
commit d31df715fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 2149 additions and 1250 deletions

View file

@ -1,12 +1,21 @@
<?php <?php
namespace Zotlabs\Access; namespace Zotlabs\Access;
use Zotlabs\Lib as Zlib; /**
* @brief PermissionRoles class.
*
* @see Permissions
*/
class PermissionRoles { class PermissionRoles {
/**
* @brief PermissionRoles version.
*
* This must match the version in Permissions.php before permission updates can run.
*
* @return number
*/
static public function version() { static public function version() {
return 2; return 2;
} }
@ -23,12 +32,13 @@ class PermissionRoles {
$ret['default_collection'] = false; $ret['default_collection'] = false;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = true; $ret['online'] = true;
$ret['perms_connect'] = [ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments', 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
'post_mail', 'chat', 'post_like', 'republish' ]; 'post_mail', 'chat', 'post_like', 'republish'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
case 'social_restricted': case 'social_restricted':
@ -36,11 +46,11 @@ class PermissionRoles {
$ret['default_collection'] = true; $ret['default_collection'] = true;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = true; $ret['online'] = true;
$ret['perms_connect'] = [ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments', 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
'post_mail', 'chat', 'post_like' ]; 'post_mail', 'chat', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
@ -50,10 +60,11 @@ class PermissionRoles {
$ret['default_collection'] = true; $ret['default_collection'] = true;
$ret['directory_publish'] = false; $ret['directory_publish'] = false;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments', 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
'post_mail', 'post_like' ]; 'post_mail', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC; $ret['limits']['view_contacts'] = PERMS_SPECIFIC;
$ret['limits']['view_storage'] = PERMS_SPECIFIC; $ret['limits']['view_storage'] = PERMS_SPECIFIC;
@ -65,12 +76,13 @@ class PermissionRoles {
$ret['default_collection'] = false; $ret['default_collection'] = false;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver', 'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver',
'post_mail', 'post_like' , 'republish', 'chat' ]; 'post_mail', 'post_like' , 'republish', 'chat'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
case 'forum_restricted': case 'forum_restricted':
@ -78,11 +90,10 @@ class PermissionRoles {
$ret['default_collection'] = true; $ret['default_collection'] = true;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver', 'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver',
'post_mail', 'post_like' , 'chat' ]; 'post_mail', 'post_like' , 'chat' ];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
@ -92,12 +103,11 @@ class PermissionRoles {
$ret['default_collection'] = true; $ret['default_collection'] = true;
$ret['directory_publish'] = false; $ret['directory_publish'] = false;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'view_pages', 'view_wiki', 'post_wall', 'post_comments',
'post_mail', 'post_like' , 'chat' ]; 'post_mail', 'post_like' , 'chat'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_profile'] = PERMS_SPECIFIC; $ret['limits']['view_profile'] = PERMS_SPECIFIC;
$ret['limits']['view_contacts'] = PERMS_SPECIFIC; $ret['limits']['view_contacts'] = PERMS_SPECIFIC;
@ -112,12 +122,11 @@ class PermissionRoles {
$ret['default_collection'] = false; $ret['default_collection'] = false;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments', 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
'post_mail', 'post_like' , 'republish' ]; 'post_mail', 'post_like' , 'republish'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
@ -127,11 +136,11 @@ class PermissionRoles {
$ret['default_collection'] = true; $ret['default_collection'] = true;
$ret['directory_publish'] = false; $ret['directory_publish'] = false;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments', 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
'post_mail', 'post_like' , 'republish' ]; 'post_mail', 'post_like' , 'republish'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
@ -141,11 +150,10 @@ class PermissionRoles {
$ret['default_collection'] = false; $ret['default_collection'] = false;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_like' , 'republish' ]; 'view_pages', 'view_wiki', 'post_like' , 'republish'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
@ -155,13 +163,13 @@ class PermissionRoles {
$ret['default_collection'] = false; $ret['default_collection'] = false;
$ret['directory_publish'] = true; $ret['directory_publish'] = true;
$ret['online'] = false; $ret['online'] = false;
$ret['perms_connect'] = [
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'write_storage', 'write_pages', 'post_wall', 'post_comments', 'tag_deliver', 'view_pages', 'view_wiki', 'write_storage', 'write_pages', 'post_wall', 'post_comments', 'tag_deliver',
'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki' ]; 'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki'
];
$ret['limits'] = PermissionLimits::Std_Limits(); $ret['limits'] = PermissionLimits::Std_Limits();
break; break;
case 'custom': case 'custom':
@ -170,11 +178,15 @@ class PermissionRoles {
} }
$x = get_config('system','role_perms'); $x = get_config('system','role_perms');
// let system settings over-ride any or all // let system settings over-ride any or all
if($x && is_array($x) && array_key_exists($role,$x)) if($x && is_array($x) && array_key_exists($role,$x))
$ret = array_merge($ret,$x[$role]); $ret = array_merge($ret,$x[$role]);
call_hooks('get_role_perms',$ret); /**
* @hooks get_role_perms
* * \e array
*/
call_hooks('get_role_perms', $ret);
return $ret; return $ret;
} }
@ -187,10 +199,10 @@ class PermissionRoles {
// \Zotlabs\Access\PermissionLimits::Set($uid,$perm,1); // \Zotlabs\Access\PermissionLimits::Set($uid,$perm,1);
if($perm === 'view_wiki') if($perm === 'view_wiki')
\Zotlabs\Access\PermissionLimits::Set($uid,$perm,PERMS_PUBLIC); \Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_PUBLIC);
if($perm === 'write_wiki') if($perm === 'write_wiki')
\Zotlabs\Access\PermissionLimits::Set($uid,$perm,PERMS_SPECIFIC); \Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_SPECIFIC);
// set autoperms here if applicable // set autoperms here if applicable
@ -213,8 +225,6 @@ class PermissionRoles {
if($c) { if($c) {
set_abconfig($uid,$c['channel_hash'],'autoperms',$perm,$value); set_abconfig($uid,$c['channel_hash'],'autoperms',$perm,$value);
} }
} }
// now set something for all existing connections. // now set something for all existing connections.
@ -242,38 +252,44 @@ class PermissionRoles {
} }
} }
/**
* @brief Array with translated role names and grouping.
*
* Return an associative array with grouped role names that can be used
* to create select groups like in \e field_select_grouped.tpl.
*
* @return array
*/
static public function roles() { static public function roles() {
$roles = [ $roles = [
t('Social Networking') => [ t('Social Networking') => [
'social' => t('Social - Mostly Public'), 'social' => t('Social - Mostly Public'),
'social_restricted' => t('Social - Restricted'), 'social_restricted' => t('Social - Restricted'),
'social_private' => t('Social - Private') 'social_private' => t('Social - Private')
], ],
t('Community Forum') => [ t('Community Forum') => [
'forum' => t('Forum - Mostly Public'), 'forum' => t('Forum - Mostly Public'),
'forum_restricted' => t('Forum - Restricted'), 'forum_restricted' => t('Forum - Restricted'),
'forum_private' => t('Forum - Private') 'forum_private' => t('Forum - Private')
], ],
t('Feed Republish') => [ t('Feed Republish') => [
'feed' => t('Feed - Mostly Public'), 'feed' => t('Feed - Mostly Public'),
'feed_restricted' => t('Feed - Restricted') 'feed_restricted' => t('Feed - Restricted')
], ],
t('Special Purpose') => [ t('Special Purpose') => [
'soapbox' => t('Special - Celebrity/Soapbox'), 'soapbox' => t('Special - Celebrity/Soapbox'),
'repository' => t('Special - Group Repository') 'repository' => t('Special - Group Repository')
], ],
t('Other') => [ t('Other') => [
'custom' => t('Custom/Expert Mode') 'custom' => t('Custom/Expert Mode')
] ]
]; ];
return $roles; return $roles;
} }
} }

View file

@ -33,19 +33,22 @@ use Zotlabs\Lib as Zlib;
*/ */
class Permissions { class Permissions {
/**
* @brief Permissions version.
*
* This must match the version in PermissionRoles.php before permission updates can run.
*
* @return number
*/
static public function version() { static public function version() {
// This must match the version in PermissionRoles.php before permission updates can run.
return 2; return 2;
} }
/** /**
* @brief Return an array with Permissions. * @brief Return an array with Permissions.
* *
* @hooks permissions_list * @param string $filter (optional) only passed to hook permissions_list
* * \e array \b permissions * @return array Associative array with permissions and short description.
* * \e string \b filter
* @param string $filter (optional) only passed to hook permission_list
* @return Associative array with permissions and short description.
*/ */
static public function Perms($filter = '') { static public function Perms($filter = '') {
@ -74,6 +77,11 @@ class Permissions {
'permissions' => $perms, 'permissions' => $perms,
'filter' => $filter 'filter' => $filter
]; ];
/**
* @hooks permissions_list
* * \e array \b permissions
* * \e string \b filter
*/
call_hooks('permissions_list', $x); call_hooks('permissions_list', $x);
return($x['permissions']); return($x['permissions']);
@ -84,9 +92,7 @@ class Permissions {
* *
* e.g. you must be authenticated. * e.g. you must be authenticated.
* *
* @hooks write_perms * @return array Associative array with permissions and short description.
* * \e array \b permissions
* @return Associative array with permissions and short description.
*/ */
static public function BlockedAnonPerms() { static public function BlockedAnonPerms() {
@ -99,6 +105,10 @@ class Permissions {
} }
$x = ['permissions' => $res]; $x = ['permissions' => $res];
/**
* @hooks write_perms
* * \e array \b permissions
*/
call_hooks('write_perms', $x); call_hooks('write_perms', $x);
return($x['permissions']); return($x['permissions']);
@ -138,7 +148,7 @@ class Permissions {
* to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ] * to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ]
* *
* @param array $arr associative perms array 'view_stream' => 1 * @param array $arr associative perms array 'view_stream' => 1
* @return Indexed array with elements that look like * @return array Indexed array with elements that look like
* * \e string \b name the perm name (e.g. view_stream) * * \e string \b name the perm name (e.g. view_stream)
* * \e int \b value the value of the perm (e.g. 1) * * \e int \b value the value of the perm (e.g. 1)
*/ */
@ -197,11 +207,10 @@ class Permissions {
* @brief * @brief
* *
* @param int $channel_id A channel id * @param int $channel_id A channel id
* @return associative array * @return array Associative array with
* * \e array \b perms Permission array * * \e array \b perms Permission array
* * \e int \b automatic 0 or 1 * * \e int \b automatic 0 or 1
*/ */
static public function connect_perms($channel_id) { static public function connect_perms($channel_id) {
$my_perms = []; $my_perms = [];

View file

@ -2,7 +2,12 @@
namespace Zotlabs\Extend; namespace Zotlabs\Extend;
use App;
/**
* @brief Hook class.
*
*/
class Hook { class Hook {
static public function register($hook,$file,$function,$version = 1,$priority = 0) { static public function register($hook,$file,$function,$version = 1,$priority = 0) {
@ -64,11 +69,14 @@ class Hook {
return $r; return $r;
} }
// unregister all hooks with this file component. /**
// Useful for addon upgrades where you want to clean out old interfaces. * @brief Unregister all hooks with this file component.
*
* Useful for addon upgrades where you want to clean out old interfaces.
*
* @param string $file
*/
static public function unregister_by_file($file) { static public function unregister_by_file($file) {
$r = q("DELETE FROM hook WHERE file = '%s' ", $r = q("DELETE FROM hook WHERE file = '%s' ",
dbesc($file) dbesc($file)
); );
@ -76,7 +84,6 @@ class Hook {
return $r; return $r;
} }
/** /**
* @brief Inserts a hook into a page request. * @brief Inserts a hook into a page request.
* *
@ -98,7 +105,6 @@ class Hook {
* @param int $priority * @param int $priority
* currently not implemented in this function, would require the hook array to be resorted * currently not implemented in this function, would require the hook array to be resorted
*/ */
static public function insert($hook, $fn, $version = 0, $priority = 0) { static public function insert($hook, $fn, $version = 0, $priority = 0) {
if(is_array($fn)) { if(is_array($fn)) {
$fn = serialize($fn); $fn = serialize($fn);

View file

@ -2,6 +2,11 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
/**
* @brief ActivityStreams class.
*
* Parses an ActivityStream JSON string.
*/
class ActivityStreams { class ActivityStreams {
public $data; public $data;
@ -19,9 +24,16 @@ class ActivityStreams {
public $recips = null; public $recips = null;
public $raw_recips = null; public $raw_recips = null;
/**
* @brief Constructor for ActivityStreams.
*
* Takes a JSON string as parameter, decodes it and sets up this object.
*
* @param string $string
*/
function __construct($string) { function __construct($string) {
$this->data = json_decode($string,true); $this->data = json_decode($string, true);
if($this->data) { if($this->data) {
$this->valid = true; $this->valid = true;
} }
@ -50,6 +62,11 @@ class ActivityStreams {
} }
} }
/**
* @brief Return if instantiated ActivityStream is valid.
*
* @return boolean Return true if the JSON string could be decoded.
*/
function is_valid() { function is_valid() {
return $this->valid; return $this->valid;
} }
@ -58,18 +75,26 @@ class ActivityStreams {
$this->saved_recips = $arr; $this->saved_recips = $arr;
} }
function collect_recips($base = '',$namespace = '') { /**
* @brief Collects all recipients.
*
* @param string $base
* @param string $namespace (optional) default empty
* @return array
*/
function collect_recips($base = '', $namespace = '') {
$x = []; $x = [];
$fields = [ 'to','cc','bto','bcc','audience']; $fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
foreach($fields as $f) { foreach($fields as $f) {
$y = $this->get_compound_property($f,$base,$namespace); $y = $this->get_compound_property($f, $base, $namespace);
if($y) { if($y) {
$x = array_merge($x,$y); $x = array_merge($x, $y);
if(! is_array($this->raw_recips)) if(! is_array($this->raw_recips))
$this->raw_recips = []; $this->raw_recips = [];
$this->raw_recips[$f] = $x; $this->raw_recips[$f] = $x;
} }
} }
// not yet ready for prime time // not yet ready for prime time
// $x = $this->expand($x,$base,$namespace); // $x = $this->expand($x,$base,$namespace);
return $x; return $x;
@ -96,23 +121,30 @@ class ActivityStreams {
} }
} }
// @fixme de-duplicate /// @fixme de-duplicate
return $ret; return $ret;
} }
function get_namespace($base,$namespace) { /**
* @brief
*
* @param array $base
* @param string $namespace if not set return empty string
* @return string|NULL
*/
function get_namespace($base, $namespace) {
if(! $namespace) if(! $namespace)
return ''; return '';
$key = null; $key = null;
foreach( [ $this->data, $base ] as $b ) { foreach( [ $this->data, $base ] as $b ) {
if(! $b) if(! $b)
continue; continue;
if(array_key_exists('@context',$b)) {
if(array_key_exists('@context', $b)) {
if(is_array($b['@context'])) { if(is_array($b['@context'])) {
foreach($b['@context'] as $ns) { foreach($b['@context'] as $ns) {
if(is_array($ns)) { if(is_array($ns)) {
@ -135,19 +167,35 @@ class ActivityStreams {
} }
} }
} }
return $key; return $key;
} }
/**
function get_property_obj($property,$base = '',$namespace = '' ) { * @brief
$prefix = $this->get_namespace($base,$namespace); *
* @param string $property
* @param array $base (optional)
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_property_obj($property, $base = '', $namespace = '') {
$prefix = $this->get_namespace($base, $namespace);
if($prefix === null) if($prefix === null)
return null; return null;
$base = (($base) ? $base : $this->data); $base = (($base) ? $base : $this->data);
$propname = (($prefix) ? $prefix . ':' : '') . $property; $propname = (($prefix) ? $prefix . ':' : '') . $property;
return ((array_key_exists($propname,$base)) ? $base[$propname] : null);
return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
} }
/**
* @brief Fetches a property from an URL.
*
* @param string $url
* @return NULL|mixed
*/
function fetch_property($url) { function fetch_property($url) {
$redirects = 0; $redirects = 0;
if(! check_siteallowed($url)) { if(! check_siteallowed($url)) {
@ -155,44 +203,70 @@ class ActivityStreams {
return null; return null;
} }
$x = z_fetch_url($url,true,$redirects, $x = z_fetch_url($url, true, $redirects,
['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json' ]]); ['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json' ]]);
if($x['success']) if($x['success'])
return json_decode($x['body'],true); return json_decode($x['body'], true);
return null; return null;
} }
function get_compound_property($property,$base = '',$namespace = '') { /**
$x = $this->get_property_obj($property,$base,$namespace); * @brief
*
* @param string $property
* @param array $base
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_compound_property($property, $base = '', $namespace = '') {
$x = $this->get_property_obj($property, $base, $namespace);
if($this->is_url($x)) { if($this->is_url($x)) {
$x = $this->fetch_property($x); $x = $this->fetch_property($x);
} }
return $x; return $x;
} }
/**
* @brief Check if string starts with http.
*
* @param string $url
* @return boolean
*/
function is_url($url) { function is_url($url) {
if(($url) && (! is_array($url)) && (strpos($url,'http') === 0)) { if(($url) && (! is_array($url)) && (strpos($url, 'http') === 0)) {
return true; return true;
} }
return false; return false;
} }
function get_primary_type($base = '',$namespace = '') { /**
* @brief Gets the type property.
*
* @param array $base
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_primary_type($base = '', $namespace = '') {
if(! $base) if(! $base)
$base = $this->data; $base = $this->data;
$x = $this->get_property_obj('type',$base,$namespace);
$x = $this->get_property_obj('type', $base, $namespace);
if(is_array($x)) { if(is_array($x)) {
foreach($x as $y) { foreach($x as $y) {
if(strpos($y,':') === false) { if(strpos($y, ':') === false) {
return $y; return $y;
} }
} }
} }
return $x; return $x;
} }
function debug() { function debug() {
$x = var_export($this,true); $x = var_export($this, true);
return $x; return $x;
} }

View file

@ -2,22 +2,18 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
/** /**
* @brief Chat related functions. * @brief A class with chatroom related static methods.
*/ */
class Chatroom { class Chatroom {
/** /**
* @brief Creates a chatroom. * @brief Creates a chatroom.
* *
* @param array $channel * @param array $channel
* @param array $arr * @param array $arr
* @return An associative array containing: * @return array An associative array containing:
* - success: A boolean * * \e boolean \b success - A boolean success status
* - message: (optional) A string * * \e string \b message - (optional) A string
*/ */
static public function create($channel, $arr) { static public function create($channel, $arr) {
$ret = array('success' => false); $ret = array('success' => false);
@ -150,8 +146,8 @@ class Chatroom {
} }
if(intval($x[0]['cr_expire'])) { if(intval($x[0]['cr_expire'])) {
$r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d", $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d",
db_utcnow(), db_utcnow(),
db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ), db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ),
intval($x[0]['cr_id']) intval($x[0]['cr_id'])
); );
@ -225,10 +221,16 @@ class Chatroom {
} }
/** /**
* create a chat message via API. * @brief Create a chat message via API.
*
* It is the caller's responsibility to enter the room. * It is the caller's responsibility to enter the room.
*/ *
* @param int $uid
* @param int $room_id
* @param string $xchan
* @param string $text
* @return array
*/
static public function message($uid, $room_id, $xchan, $text) { static public function message($uid, $room_id, $xchan, $text) {
$ret = array('success' => false); $ret = array('success' => false);
@ -245,12 +247,18 @@ class Chatroom {
if(! $r) if(! $r)
return $ret; return $ret;
$arr = array( $arr = [
'chat_room' => $room_id, 'chat_room' => $room_id,
'chat_xchan' => $xchan, 'chat_xchan' => $xchan,
'chat_text' => $text 'chat_text' => $text
); ];
/**
* @hooks chat_message
* Called to create a chat message.
* * \e int \b chat_room
* * \e string \b chat_xchan
* * \e string \b chat_text
*/
call_hooks('chat_message', $arr); call_hooks('chat_message', $arr);
$x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text )

View file

@ -1,4 +1,4 @@
<?php /** @file */ <?php
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
@ -14,7 +14,6 @@ class Config {
* @param string $family * @param string $family
* The category of the configuration value * The category of the configuration value
*/ */
static public function Load($family) { static public function Load($family) {
if(! array_key_exists($family, \App::$config)) if(! array_key_exists($family, \App::$config))
\App::$config[$family] = array(); \App::$config[$family] = array();
@ -30,7 +29,7 @@ class Config {
} }
\App::$config[$family]['config_loaded'] = true; \App::$config[$family]['config_loaded'] = true;
} }
} }
} }
/** /**
@ -47,8 +46,7 @@ class Config {
* @return mixed * @return mixed
* Return the set value, or false if the database update failed * Return the set value, or false if the database update failed
*/ */
static public function Set($family, $key, $value) {
static public function Set($family,$key,$value) {
// manage array value // manage array value
$dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
@ -76,8 +74,8 @@ class Config {
\App::$config[$family][$key] = $value; \App::$config[$family][$key] = $value;
$ret = $value; $ret = $value;
} }
return $ret;
return $ret;
} }
/** /**
@ -88,25 +86,25 @@ class Config {
* $key from a cached storage in App::$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 * 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. * do not have to hit the DB again for this item.
* *
* Returns false if not set. * Returns false if not set.
* *
* @param string $family * @param string $family
* The category of the configuration value * The category of the configuration value
* @param string $key * @param string $key
* The configuration key to query * The configuration key to query
* @param string $default (optional) default false
* @return mixed Return value or false on error or if not set * @return mixed Return value or false on error or if not set
*/ */
static public function Get($family, $key, $default = false) {
static public function Get($family,$key,$default = false) {
if((! array_key_exists($family, \App::$config)) || (! array_key_exists('config_loaded', \App::$config[$family]))) if((! array_key_exists($family, \App::$config)) || (! array_key_exists('config_loaded', \App::$config[$family])))
self::Load($family); self::Load($family);
if(array_key_exists('config_loaded', \App::$config[$family])) { if(array_key_exists('config_loaded', \App::$config[$family])) {
if(! array_key_exists($key, \App::$config[$family])) { if(! array_key_exists($key, \App::$config[$family])) {
return $default; return $default;
} }
return ((! is_array(\App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$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]) ? unserialize(\App::$config[$family][$key])
: \App::$config[$family][$key] : \App::$config[$family][$key]
); );
@ -127,17 +125,18 @@ class Config {
* The configuration key to delete * The configuration key to delete
* @return mixed * @return mixed
*/ */
static public function Delete($family, $key) {
static public function Delete($family,$key) {
$ret = false; $ret = false;
if(array_key_exists($family, \App::$config) && array_key_exists($key, \App::$config[$family])) if(array_key_exists($family, \App::$config) && array_key_exists($key, \App::$config[$family]))
unset(\App::$config[$family][$key]); unset(\App::$config[$family][$key]);
$ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
$ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
dbesc($family), dbesc($family),
dbesc($key) dbesc($key)
); );
return $ret; return $ret;
} }
@ -154,12 +153,12 @@ class Config {
* The configuration key to query * The configuration key to query
* @return mixed * @return mixed
*/ */
static private function get_from_storage($family,$key) { static private function get_from_storage($family,$key) {
$ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1", $ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
dbesc($family), dbesc($family),
dbesc($key) dbesc($key)
); );
return $ret; return $ret;
} }

View file

@ -1,8 +1,21 @@
<?php /** @file */ <?php
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
/**
* @brief Class for handling channel specific configurations.
*
* <b>PConfig</b> is used for channel specific configurations and takes a
* <i>channel_id</i> as identifier. It stores for example which features are
* enabled per channel. The storage is of size MEDIUMTEXT.
*
* @code{.php}$var = Zotlabs\Lib\PConfig::Get('uid', 'category', 'key');
* // with default value for non existent key
* $var = Zotlabs\Lib\PConfig::Get('uid', 'category', 'unsetkey', 'defaultvalue');@endcode
*
* The old (deprecated?) way to access a PConfig value is:
* @code{.php}$var = get_pconfig(local_channel(), 'category', 'key');@endcode
*/
class PConfig { class PConfig {
/** /**
@ -13,9 +26,8 @@ class PConfig {
* *
* @param string $uid * @param string $uid
* The channel_id * The channel_id
* @return void|false Nothing or false if $uid is false * @return void|false Nothing or false if $uid is null or false
*/ */
static public function Load($uid) { static public function Load($uid) {
if(is_null($uid) || $uid === false) if(is_null($uid) || $uid === false)
return false; return false;
@ -64,11 +76,11 @@ class PConfig {
* The category of the configuration value * The category of the configuration value
* @param string $key * @param string $key
* The configuration key to query * The configuration key to query
* @param boolean $instore (deprecated, without function) * @param mixed $default (optional, default false)
* Default value to return if key does not exist
* @return mixed Stored value or false if it does not exist * @return mixed Stored value or false if it does not exist
*/ */
static public function Get($uid, $family, $key, $default = false) {
static public function Get($uid,$family,$key,$default = false) {
if(is_null($uid) || $uid === false) if(is_null($uid) || $uid === false)
return $default; return $default;
@ -79,11 +91,10 @@ class PConfig {
if((! array_key_exists($family, \App::$config[$uid])) || (! array_key_exists($key, \App::$config[$uid][$family]))) if((! array_key_exists($family, \App::$config[$uid])) || (! array_key_exists($key, \App::$config[$uid][$family])))
return $default; return $default;
return ((! is_array(\App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$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]) ? unserialize(\App::$config[$uid][$family][$key])
: \App::$config[$uid][$family][$key] : \App::$config[$uid][$family][$key]
); );
} }
/** /**
@ -102,12 +113,11 @@ class PConfig {
* The value to store * The value to store
* @return mixed Stored $value or false * @return mixed Stored $value or false
*/ */
static public function Set($uid, $family, $key, $value) { static public function Set($uid, $family, $key, $value) {
// this catches subtle errors where this function has been called // this catches subtle errors where this function has been called
// with local_channel() when not logged in (which returns false) // with local_channel() when not logged in (which returns false)
// and throws an error in array_key_exists below. // and throws an error in array_key_exists below.
// we provide a function backtrace in the logs so that we can find // we provide a function backtrace in the logs so that we can find
// and fix the calling function. // and fix the calling function.
@ -132,7 +142,6 @@ class PConfig {
dbesc($key), dbesc($key),
dbesc($dbvalue) dbesc($dbvalue)
); );
} }
else { else {
@ -142,7 +151,6 @@ class PConfig {
dbesc($family), dbesc($family),
dbesc($key) dbesc($key)
); );
} }
// keep a separate copy for all variables which were // keep a separate copy for all variables which were
@ -178,7 +186,6 @@ class PConfig {
* The configuration key to delete * The configuration key to delete
* @return mixed * @return mixed
*/ */
static public function Delete($uid, $family, $key) { static public function Delete($uid, $family, $key) {
if(is_null($uid) || $uid === false) if(is_null($uid) || $uid === false)
@ -186,12 +193,12 @@ class PConfig {
$ret = false; $ret = false;
if(array_key_exists($uid,\App::$config) if(array_key_exists($uid,\App::$config)
&& is_array(\App::$config['uid']) && is_array(\App::$config['uid'])
&& array_key_exists($family,\App::$config['uid']) && array_key_exists($family,\App::$config['uid'])
&& array_key_exists($key, \App::$config[$uid][$family])) && array_key_exists($key, \App::$config[$uid][$family]))
unset(\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'", $ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
intval($uid), intval($uid),
dbesc($family), dbesc($family),
@ -202,4 +209,3 @@ class PConfig {
} }
} }

View file

@ -2,8 +2,11 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
// account configuration storage is built on top of the under-utilised xconfig /**
* @brief Account configuration storage is built on top of the under-utilised xconfig.
*
* @see XConfig
*/
class SConfig { class SConfig {
static public function Load($server_id) { static public function Load($server_id) {

View file

@ -2,7 +2,26 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
/**
* @brief Class for handling observer's config.
*
* <b>XConfig</b> is comparable to <i>PConfig</i>, except that it uses <i>xchan</i>
* (an observer hash) as an identifier.
*
* <b>XConfig</b> is used for observer specific configurations and takes a
* <i>xchan</i> as identifier.
* The storage is of size MEDIUMTEXT.
*
* @code{.php}$var = Zotlabs\Lib\XConfig::Get('xchan', 'category', 'key');
* // with default value for non existent key
* $var = Zotlabs\Lib\XConfig::Get('xchan', 'category', 'unsetkey', 'defaultvalue');@endcode
*
* The old (deprecated?) way to access a XConfig value is:
* @code{.php}$observer = App::get_observer_hash();
* if ($observer) {
* $var = get_xconfig($observer, 'category', 'key');
* }@endcode
*/
class XConfig { class XConfig {
/** /**
@ -15,7 +34,6 @@ class XConfig {
* The observer's hash * The observer's hash
* @return void|false Returns false if xchan is not set * @return void|false Returns false if xchan is not set
*/ */
static public function Load($xchan) { static public function Load($xchan) {
if(! $xchan) if(! $xchan)
@ -56,9 +74,9 @@ class XConfig {
* The category of the configuration value * The category of the configuration value
* @param string $key * @param string $key
* The configuration key to query * The configuration key to query
* @param boolean $default (optional) default false
* @return mixed Stored $value or false if it does not exist * @return mixed Stored $value or false if it does not exist
*/ */
static public function Get($xchan, $family, $key, $default = false) { static public function Get($xchan, $family, $key, $default = false) {
if(! $xchan) if(! $xchan)
@ -70,7 +88,7 @@ class XConfig {
if((! array_key_exists($family, \App::$config[$xchan])) || (! array_key_exists($key, \App::$config[$xchan][$family]))) if((! array_key_exists($family, \App::$config[$xchan])) || (! array_key_exists($key, \App::$config[$xchan][$family])))
return $default; return $default;
return ((! is_array(\App::$config[$xchan][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$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]) ? unserialize(\App::$config[$xchan][$family][$key])
: \App::$config[$xchan][$family][$key] : \App::$config[$xchan][$family][$key]
); );
@ -82,7 +100,6 @@ class XConfig {
* Stores a config value ($value) in the category ($family) under the key ($key) * Stores a config value ($value) in the category ($family) under the key ($key)
* for the observer's $xchan hash. * for the observer's $xchan hash.
* *
*
* @param string $xchan * @param string $xchan
* The observer's hash * The observer's hash
* @param string $family * @param string $family
@ -93,7 +110,6 @@ class XConfig {
* The value to store * The value to store
* @return mixed Stored $value or false * @return mixed Stored $value or false
*/ */
static public function Set($xchan, $family, $key, $value) { static public function Set($xchan, $family, $key, $value) {
// manage array value // manage array value
@ -106,7 +122,7 @@ class XConfig {
if(! array_key_exists($family, \App::$config[$xchan])) if(! array_key_exists($family, \App::$config[$xchan]))
\App::$config[$xchan][$family] = array(); \App::$config[$xchan][$family] = array();
$ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' ) ", $ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' )",
dbesc($xchan), dbesc($xchan),
dbesc($family), dbesc($family),
dbesc($key), dbesc($key),
@ -126,6 +142,7 @@ class XConfig {
if($ret) if($ret)
return $value; return $value;
return $ret; return $ret;
} }
@ -143,11 +160,11 @@ class XConfig {
* The configuration key to delete * The configuration key to delete
* @return mixed * @return mixed
*/ */
static public function Delete($xchan, $family, $key) { static public function Delete($xchan, $family, $key) {
if(x(\App::$config[$xchan][$family], $key)) if(x(\App::$config[$xchan][$family], $key))
unset(\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'", $ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",
dbesc($xchan), dbesc($xchan),
dbesc($family), dbesc($family),

View file

@ -5,10 +5,20 @@ namespace Zotlabs\Render;
require_once('include/security.php'); require_once('include/security.php');
require_once('include/menu.php'); require_once('include/menu.php');
/**
* @brief Comanche Page Description Language.
*
* Comanche is a markup language similar to bbcode with which to create elaborate
* and complex web pages by assembling them from a series of components - some of
* which are pre-built and others which can be defined on the fly. Comanche uses
* a Page Decription Language to create these pages.
*
* Comanche primarily chooses what content will appear in various regions of the
* page. The various regions have names and these names can change depending on
* what layout template you choose.
*/
class Comanche { class Comanche {
function parse($s, $pass = 0) { function parse($s, $pass = 0) {
$matches = array(); $matches = array();
@ -18,13 +28,13 @@ class Comanche {
$s = str_replace($mtch[0], '', $s); $s = str_replace($mtch[0], '', $s);
} }
} }
/* /*
* This section supports the "switch" statement of the form given by the following * This section supports the "switch" statement of the form given by the following
* example. The [default][/default] block must be the last in the arbitrary * example. The [default][/default] block must be the last in the arbitrary
* list of cases. The first case that matches the switch variable is used * list of cases. The first case that matches the switch variable is used
* and the rest are not evaluated. * and the rest are not evaluated.
* *
* [switch observer.language] * [switch observer.language]
* [case de] * [case de]
* [block]german-content[/block] * [block]german-content[/block]
@ -37,7 +47,7 @@ class Comanche {
* [/default] * [/default]
* [/switch] * [/switch]
*/ */
$cnt = preg_match_all("/\[switch (.*?)\](.*?)\[default\](.*?)\[\/default\]\s*\[\/switch\]/ism", $s, $matches, PREG_SET_ORDER); $cnt = preg_match_all("/\[switch (.*?)\](.*?)\[default\](.*?)\[\/default\]\s*\[\/switch\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) { if($cnt) {
foreach($matches as $mtch) { foreach($matches as $mtch) {
@ -60,7 +70,7 @@ class Comanche {
} }
} }
} }
$cnt = preg_match_all("/\[if (.*?)\](.*?)\[else\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER); $cnt = preg_match_all("/\[if (.*?)\](.*?)\[else\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) { if($cnt) {
foreach($matches as $mtch) { foreach($matches as $mtch) {
@ -89,7 +99,6 @@ class Comanche {
$this->parse_pass0($s); $this->parse_pass0($s);
else else
$this->parse_pass1($s); $this->parse_pass1($s);
} }
function parse_pass0($s) { function parse_pass0($s) {
@ -103,7 +112,7 @@ class Comanche {
$cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches); $cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches);
if($cnt) { if($cnt) {
\App::$page['template'] = trim($matches[2]); \App::$page['template'] = trim($matches[2]);
\App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1]; \App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1];
} }
$cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches); $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches);
@ -145,20 +154,23 @@ class Comanche {
} }
/** /**
* Currently supported condition variables: * @brief Replace conditional variables with real values.
* *
* $config.xxx.yyy - get_config with cat = xxx and k = yyy * Currently supported condition variables:
* $request - request uri for this page * * $config.xxx.yyy - get_config with cat = xxx and k = yyy
* $observer.language - viewer's preferred language (closest match) * * $request - request uri for this page
* $observer.address - xchan_addr or false * * $observer.language - viewer's preferred language (closest match)
* $observer.name - xchan_name or false * * $observer.address - xchan_addr or false
* $observer - xchan_hash of observer or empty string * * $observer.name - xchan_name or false
* $local_channel - logged in channel_id or false * * $observer - xchan_hash of observer or empty string
* * $local_channel - logged in channel_id or false
*
* @param string $v The conditional variable name
* @return string|boolean
*/ */
function get_condition_var($v) { function get_condition_var($v) {
if($v) { if($v) {
$x = explode('.',$v); $x = explode('.', $v);
if($x[0] == 'config') if($x[0] == 'config')
return get_config($x[1],$x[2]); return get_config($x[1],$x[2]);
elseif($x[0] === 'request') elseif($x[0] === 'request')
@ -179,6 +191,7 @@ class Comanche {
return $y['xchan_name']; return $y['xchan_name'];
elseif($x[1] == 'webname') elseif($x[1] == 'webname')
return substr($y['xchan_addr'],0,strpos($y['xchan_addr'],'@')); return substr($y['xchan_addr'],0,strpos($y['xchan_addr'],'@'));
return false; return false;
} }
return get_observer_hash(); return get_observer_hash();
@ -186,30 +199,39 @@ class Comanche {
else else
return false; return false;
} }
return false; return false;
} }
/**
* @brief Test for Conditional Execution conditions.
*
* This is extensible. The first version of variable testing supports tests of the forms:
*
* - [if $config.system.foo ~= baz] which will check if get_config('system','foo') contains the string 'baz';
* - [if $config.system.foo == baz] which will check if get_config('system','foo') is the string 'baz';
* - [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz';
* - [if $config.system.foo >= 3] which will check if get_config('system','foo') is greater than or equal to 3;
* - [if $config.system.foo > 3] which will check if get_config('system','foo') is greater than 3;
* - [if $config.system.foo <= 3] which will check if get_config('system','foo') is less than or equal to 3;
* - [if $config.system.foo < 3] which will check if get_config('system','foo') is less than 3;
*
* - [if $config.system.foo {} baz] which will check if 'baz' is an array element in get_config('system','foo')
* - [if $config.system.foo {*} baz] which will check if 'baz' is an array key in get_config('system','foo')
* - [if $config.system.foo] which will check for a return of a true condition for get_config('system','foo');
*
* The values 0, '', an empty array, and an unset value will all evaluate to false.
*
* @param int|string $s
* @return boolean
*/
function test_condition($s) { function test_condition($s) {
// This is extensible. The first version of variable testing supports tests of the forms:
// [if $config.system.foo ~= baz] which will check if get_config('system','foo') contains the string 'baz';
// [if $config.system.foo == baz] which will check if get_config('system','foo') is the string 'baz';
// [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz';
// [if $config.system.foo >= 3] which will check if get_config('system','foo') is greater than or equal to 3;
// [if $config.system.foo > 3] which will check if get_config('system','foo') is greater than 3;
// [if $config.system.foo <= 3] which will check if get_config('system','foo') is less than or equal to 3;
// [if $config.system.foo < 3] which will check if get_config('system','foo') is less than 3;
// [if $config.system.foo {} baz] which will check if 'baz' is an array element in get_config('system','foo')
// [if $config.system.foo {*} baz] which will check if 'baz' is an array key in get_config('system','foo')
// [if $config.system.foo] which will check for a return of a true condition for get_config('system','foo');
// The values 0, '', an empty array, and an unset value will all evaluate to false.
if(preg_match('/[\$](.*?)\s\~\=\s(.*?)$/',$s,$matches)) { if(preg_match('/[\$](.*?)\s\~\=\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if(stripos($x,trim($matches[2])) !== false) if(stripos($x,trim($matches[2])) !== false)
return true; return true;
return false; return false;
} }
@ -217,6 +239,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x == trim($matches[2])) if($x == trim($matches[2]))
return true; return true;
return false; return false;
} }
@ -224,6 +247,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x != trim($matches[2])) if($x != trim($matches[2]))
return true; return true;
return false; return false;
} }
@ -231,24 +255,31 @@ class Comanche {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x >= trim($matches[2])) if($x >= trim($matches[2]))
return true; return true;
return false; return false;
} }
if(preg_match('/[\$](.*?)\s\<\=\s(.*?)$/',$s,$matches)) { if(preg_match('/[\$](.*?)\s\<\=\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x <= trim($matches[2])) if($x <= trim($matches[2]))
return true; return true;
return false; return false;
} }
if(preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) { if(preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x > trim($matches[2])) if($x > trim($matches[2]))
return true; return true;
return false; return false;
} }
if(preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) { if(preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x < trim($matches[2])) if($x < trim($matches[2]))
return true; return true;
return false; return false;
} }
@ -256,6 +287,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if(is_array($x) && in_array(trim($matches[2]),$x)) if(is_array($x) && in_array(trim($matches[2]),$x))
return true; return true;
return false; return false;
} }
@ -263,6 +295,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if(is_array($x) && array_key_exists(trim($matches[2]),$x)) if(is_array($x) && array_key_exists(trim($matches[2]),$x))
return true; return true;
return false; return false;
} }
@ -270,13 +303,21 @@ class Comanche {
$x = $this->get_condition_var($matches[1]); $x = $this->get_condition_var($matches[1]);
if($x) if($x)
return true; return true;
return false; return false;
} }
return false;
return false;
} }
/**
* @brief Return rendered menu for current channel_id.
*
* @see menu_render()
* @param string $s
* @param string $class (optional) default empty
* @return string
*/
function menu($s, $class = '') { function menu($s, $class = '') {
$channel_id = $this->get_channel_id(); $channel_id = $this->get_channel_id();
@ -291,7 +332,7 @@ class Comanche {
} }
if($channel_id) { if($channel_id) {
$m = menu_fetch($name,$channel_id, get_observer_hash()); $m = menu_fetch($name, $channel_id, get_observer_hash());
return menu_render($m, $class, $edit = false, $var); return menu_render($m, $class, $edit = false, $var);
} }
} }
@ -309,9 +350,8 @@ class Comanche {
* Returns the channel_id of the profile owner of the page, or the local_channel * Returns the channel_id of the profile owner of the page, or the local_channel
* if there is no profile owner. Otherwise returns 0. * if there is no profile owner. Otherwise returns 0.
* *
* @return channel_id * @return int channel_id
*/ */
function get_channel_id() { function get_channel_id() {
$channel_id = ((is_array(\App::$profile)) ? \App::$profile['profile_uid'] : 0); $channel_id = ((is_array(\App::$profile)) ? \App::$profile['profile_uid'] : 0);
@ -321,6 +361,13 @@ class Comanche {
return $channel_id; return $channel_id;
} }
/**
* @brief Returns a parsed block.
*
* @param string $s
* @param string $class (optional) default empty
* @return string parsed HTML of block
*/
function block($s, $class = '') { function block($s, $class = '') {
$var = array(); $var = array();
$matches = array(); $matches = array();
@ -339,7 +386,7 @@ class Comanche {
$channel_id = $this->get_channel_id(); $channel_id = $this->get_channel_id();
if($channel_id) { if($channel_id) {
$r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d $r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d
and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' and iconfig.v = '%s' limit 1", and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' and iconfig.v = '%s' limit 1",
intval($channel_id), intval($channel_id),
dbesc($name) dbesc($name)
@ -381,6 +428,12 @@ class Comanche {
return $o; return $o;
} }
/**
* @brief Include JS depending on framework.
*
* @param string $s
* @return string
*/
function js($s) { function js($s) {
switch($s) { switch($s) {
@ -401,9 +454,14 @@ class Comanche {
$ret .= $init; $ret .= $init;
return $ret; return $ret;
} }
/**
* @brief Include CSS depending on framework.
*
* @param string $s
* @return string
*/
function css($s) { function css($s) {
switch($s) { switch($s) {
@ -418,17 +476,22 @@ class Comanche {
$ret = '<link rel="stylesheet" href="' . z_root() . '/' . $path . '" type="text/css" media="screen">'; $ret = '<link rel="stylesheet" href="' . z_root() . '/' . $path . '" type="text/css" media="screen">';
return $ret; return $ret;
} }
// This doesn't really belong in Comanche, but it could also be argued that it is the perfect place. /**
// We need to be able to select what kind of template and decoration to use for the webpage at the heart of our content. * This doesn't really belong in Comanche, but it could also be argued that it is the perfect place.
// For now we'll allow an '[authored]' element which defaults to name and date, or 'none' to remove these, and perhaps * We need to be able to select what kind of template and decoration to use for the webpage at the heart of our content.
// 'full' to provide a social network style profile photo. * For now we'll allow an '[authored]' element which defaults to name and date, or 'none' to remove these, and perhaps
// But leave it open to have richer templating options and perhaps ultimately discard this one, once we have a better idea * 'full' to provide a social network style profile photo.
// of what template and webpage options we might desire. *
* But leave it open to have richer templating options and perhaps ultimately discard this one, once we have a better idea
function webpage(&$a,$s) { * of what template and webpage options we might desire.
*
* @param[in,out] array $a
* @param string $s
* @return array
*/
function webpage(&$a, $s) {
$ret = array(); $ret = array();
$matches = array(); $matches = array();
@ -438,22 +501,20 @@ class Comanche {
$ret['authored'] = $mtch[1]; $ret['authored'] = $mtch[1];
} }
} }
return $ret; return $ret;
} }
/** /**
* Render a widget * @brief Render a widget.
* *
* @param string $name * @param string $name
* @param string $text * @param string $text
*/ */
function widget($name, $text) { function widget($name, $text) {
$vars = array(); $vars = array();
$matches = array(); $matches = array();
$cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $text, $matches, PREG_SET_ORDER); $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $text, $matches, PREG_SET_ORDER);
if ($cnt) { if ($cnt) {
foreach ($matches as $mtch) { foreach ($matches as $mtch) {
@ -480,7 +541,7 @@ class Comanche {
if(method_exists($x,$f)) { if(method_exists($x,$f)) {
return $x->$f($vars); return $x->$f($vars);
} }
} }
$func = 'widget_' . trim($name); $func = 'widget_' . trim($name);
@ -563,9 +624,9 @@ class Comanche {
} }
/* /**
* @function register_page_template($arr) * @brief Registers a page template/variant for use by Comanche selectors.
* Registers a page template/variant for use by Comanche selectors *
* @param array $arr * @param array $arr
* 'template' => template name * 'template' => template name
* 'variant' => array( * 'variant' => array(
@ -577,8 +638,6 @@ class Comanche {
* ) * )
* ) * )
*/ */
function register_page_template($arr) { function register_page_template($arr) {
\App::$page_layouts[$arr['template']] = array($arr['variant']); \App::$page_layouts[$arr['template']] = array($arr['variant']);
return; return;

View file

@ -2,6 +2,8 @@
namespace Zotlabs\Web; namespace Zotlabs\Web;
use Exception;
/** /**
* *
* We have already parsed the server path into App::$argc and App::$argv * We have already parsed the server path into App::$argc and App::$argv
@ -34,7 +36,7 @@ class Router {
private $controller = null; private $controller = null;
/** /**
* @brief Router constructor * @brief Router constructor.
* *
* @param[in,out] App &$a * @param[in,out] App &$a
* @throws Exception module not found * @throws Exception module not found
@ -98,15 +100,23 @@ class Router {
} }
} }
/* $x = [
* This provides a place for plugins to register module handlers which don't otherwise exist 'module' => $module,
* on the system, or to completely over-ride an existing module. 'installed' => \App::$module_loaded,
* If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if 'controller' => $this->controller
* there is no specific module file or matching plugin name. ];
* The plugin should catch at least one of the module hooks for this URL. /**
* @hooks module_loaded
* Called when a module has been successfully locate to server a URL request.
* This provides a place for plugins to register module handlers which don't otherwise exist
* on the system, or to completely over-ride an existing module.
* If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if
* there is no specific module file or matching plugin name.
* The plugin should catch at least one of the module hooks for this URL.
* * \e string \b module
* * \e boolean \b installed
* * \e mixed \b controller - The initialized module object
*/ */
$x = array('module' => $module, 'installed' => \App::$module_loaded, 'controller' => $this->controller);
call_hooks('module_loaded', $x); call_hooks('module_loaded', $x);
if($x['installed']) { if($x['installed']) {
\App::$module_loaded = true; \App::$module_loaded = true;
@ -131,14 +141,14 @@ class Router {
} }
} }
$x = [ $x = [
'module' => $module, 'module' => $module,
'installed' => \App::$module_loaded, 'installed' => \App::$module_loaded,
'controller' => $this->controller 'controller' => $this->controller
]; ];
call_hooks('page_not_found',$x); call_hooks('page_not_found',$x);
// Stupid browser tried to pre-fetch our Javascript img template. // Stupid browser tried to pre-fetch our Javascript img template.
// Don't log the event or return anything - just quietly exit. // Don't log the event or return anything - just quietly exit.
if((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) { if((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
@ -147,8 +157,8 @@ class Router {
if(get_config('system','log_404',true)) { if(get_config('system','log_404',true)) {
logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING); logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING);
logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] logger('index.php: page not found: ' . $_SERVER['REQUEST_URI']
. ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: '
. $_SERVER['QUERY_STRING'], LOGGER_DEBUG); . $_SERVER['QUERY_STRING'], LOGGER_DEBUG);
} }

View file

@ -26,12 +26,11 @@ class Verify {
q("delete from verify where id = %d", q("delete from verify where id = %d",
intval($r[0]['id']) intval($r[0]['id'])
); );
return true; return true;
} }
return false; return false;
} }
function get_meta($type,$channel_id,$token) { function get_meta($type,$channel_id,$token) {
$r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1", $r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
dbesc($type), dbesc($type),
@ -42,12 +41,18 @@ class Verify {
q("delete from verify where id = %d", q("delete from verify where id = %d",
intval($r[0]['id']) intval($r[0]['id'])
); );
return $r[0]['meta']; return $r[0]['meta'];
} }
return false; return false;
} }
function purge($type,$interval) { /**
* @brief Purge entries of a verify-type older than interval.
*
* @param string $type Verify type
* @param string $interval SQL compatible time interval
*/
function purge($type, $interval) {
q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s", q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s",
dbesc($type), dbesc($type),
db_utcnow(), db_utcnow(),

215
boot.php
View file

@ -1,7 +1,8 @@
<?php <?php
/** @file boot.php /**
* @file boot.php
* *
* This file defines some global constants and includes the central App class. * @brief This file defines some global constants and includes the central App class.
*/ */
/** /**
@ -95,10 +96,9 @@ $DIRECTORY_FALLBACK_SERVERS = array(
* App::$config['system']['jpeg_quality'] = n; * App::$config['system']['jpeg_quality'] = n;
* in .htconfig.php, where n is netween 1 and 100, and with very poor results * in .htconfig.php, where n is netween 1 and 100, and with very poor results
* below about 50 * below about 50
*
*/ */
define ( 'JPEG_QUALITY', 100 ); define ( 'JPEG_QUALITY', 100 );
/** /**
* App::$config['system']['png_quality'] from 0 (uncompressed) to 9 * App::$config['system']['png_quality'] from 0 (uncompressed) to 9
*/ */
@ -107,7 +107,6 @@ define ( 'PNG_QUALITY', 8 );
/** /**
* Language detection parameters * Language detection parameters
*/ */
define ( 'LANGUAGE_DETECT_MIN_LENGTH', 128 ); define ( 'LANGUAGE_DETECT_MIN_LENGTH', 128 );
define ( 'LANGUAGE_DETECT_MIN_CONFIDENCE', 0.01 ); define ( 'LANGUAGE_DETECT_MIN_CONFIDENCE', 0.01 );
@ -264,7 +263,6 @@ define ( 'NETWORK_LINKEDIN', 'lnkd'); // LinkedIn
define ( 'NETWORK_XMPP', 'xmpp'); // XMPP define ( 'NETWORK_XMPP', 'xmpp'); // XMPP
define ( 'NETWORK_MYSPACE', 'mysp'); // MySpace define ( 'NETWORK_MYSPACE', 'mysp'); // MySpace
define ( 'NETWORK_GPLUS', 'goog'); // Google+ define ( 'NETWORK_GPLUS', 'goog'); // Google+
define ( 'NETWORK_PHANTOM', 'unkn'); // Place holder define ( 'NETWORK_PHANTOM', 'unkn'); // Place holder
@ -455,8 +453,8 @@ define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' );
define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' ); define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' );
define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' ); define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
// We should be using versioned jsonld contexts so that signatures will be slightly more reliable. // We should be using versioned jsonld contexts so that signatures will be slightly more reliable.
// Why signatures are unreliable by design is a problem nobody seems to care about // Why signatures are unreliable by design is a problem nobody seems to care about
// "because it's a proposed W3C standard". . // "because it's a proposed W3C standard". .
// Anyway, if you use versioned contexts, communication with Mastodon fails. Have not yet investigated // Anyway, if you use versioned contexts, communication with Mastodon fails. Have not yet investigated
@ -642,7 +640,7 @@ function sys_boot() {
unset($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);
/** /*
* Load configs from db. Overwrite configs from .htconfig.php * Load configs from db. Overwrite configs from .htconfig.php
*/ */
@ -652,20 +650,21 @@ function sys_boot() {
App::$session = new Zotlabs\Web\Session(); App::$session = new Zotlabs\Web\Session();
App::$session->init(); App::$session->init();
load_hooks(); load_hooks();
/**
* @hooks init_1
*/
call_hooks('init_1'); call_hooks('init_1');
} }
} }
/** /**
* @brief Reverse the effect of magic_quotes_gpc if it is enabled.
* *
* Reverse the effect of magic_quotes_gpc if it is enabled.
* Please disable magic_quotes_gpc so we don't have to do this. * Please disable magic_quotes_gpc so we don't have to do this.
* See http://php.net/manual/en/security.magicquotes.disabling.php * See http://php.net/manual/en/security.magicquotes.disabling.php
* *
*/ */
function startup() { function startup() {
error_reporting(E_ERROR | E_WARNING | E_PARSE); error_reporting(E_ERROR | E_WARNING | E_PARSE);
@ -709,20 +708,18 @@ function startup() {
* which is now static (although currently constructed at startup). We are only converting * which is now static (although currently constructed at startup). We are only converting
* 'system' config settings. * 'system' config settings.
*/ */
class miniApp { class miniApp {
public $config = array('system' => array()); public $config = array('system' => array());
public function convert() { public function convert() {
if($this->config['system']) { if($this->config['system']) {
foreach($this->config['system'] as $k => $v) foreach($this->config['system'] as $k => $v)
App::$config['system'][$k] = $v; App::$config['system'][$k] = $v;
} }
} }
} }
/** /**
* class: App * class: App
* *
@ -886,11 +883,11 @@ class App {
if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443)
self::$hostname .= ':' . $_SERVER['SERVER_PORT']; self::$hostname .= ':' . $_SERVER['SERVER_PORT'];
/**
/*
* Figure out if we are running at the top of a domain * Figure out if we are running at the top of a domain
* or in a sub-directory and adjust accordingly * or in a sub-directory and adjust accordingly
*/ */
$path = trim(dirname($_SERVER['SCRIPT_NAME']),'/\\'); $path = trim(dirname($_SERVER['SCRIPT_NAME']),'/\\');
if(isset($path) && strlen($path) && ($path != self::$path)) if(isset($path) && strlen($path) && ($path != self::$path))
self::$path = $path; self::$path = $path;
@ -922,7 +919,7 @@ class App {
* *
* There will always be one argument. If provided a naked domain * There will always be one argument. If provided a naked domain
* URL, self::$argv[0] is set to "home". * URL, self::$argv[0] is set to "home".
* *
* If $argv[0] has a period in it, for example foo.json; rewrite * If $argv[0] has a period in it, for example foo.json; rewrite
* to module = 'foo' and set $_REQUEST['module_format'] = 'json'; * to module = 'foo' and set $_REQUEST['module_format'] = 'json';
*/ */
@ -1147,7 +1144,12 @@ class App {
head_add_link(['rel' => 'shortcut icon', 'href' => head_get_icon()]); head_add_link(['rel' => 'shortcut icon', 'href' => head_get_icon()]);
$x = [ 'header' => '' ]; $x = [ 'header' => '' ];
call_hooks('build_pagehead',$x); /**
* @hooks build_pagehead
* Called when creating the HTML page header.
* * \e string \b header - Return the HTML header which should be added
*/
call_hooks('build_pagehead', $x);
/* put the head template at the beginning of page['htmlhead'] /* put the head template at the beginning of page['htmlhead']
* since the code added by the modules frequently depends on it * since the code added by the modules frequently depends on it
@ -1178,8 +1180,10 @@ class App {
} }
/** /**
* register template engine class * @brief Register template engine class.
* if $name is "", is used class static property $class::$name *
* If $name is "", is used class static property $class::$name.
*
* @param string $class * @param string $class
* @param string $name * @param string $name
*/ */
@ -1198,8 +1202,9 @@ class App {
} }
/** /**
* return template engine instance. If $name is not defined, * @brief Return template engine instance.
* return engine defined by theme, or default *
* If $name is not defined, return engine defined by theme, or default.
* *
* @param string $name Template engine name * @param string $name Template engine name
* *
@ -1302,8 +1307,11 @@ function x($s, $k = null) {
} }
// called from db initialisation if db is dead. /**
* @brief Called from db initialisation if db is dead.
*
* @ref include/system_unavailable.php will handle everything further.
*/
function system_unavailable() { function system_unavailable() {
include('include/system_unavailable.php'); include('include/system_unavailable.php');
system_down(); system_down();
@ -1359,7 +1367,12 @@ function os_mkdir($path, $mode = 0777, $recursive = false) {
} }
// recursively delete a directory /**
* @brief Recursively delete a directory.
*
* @param string $path
* @return boolean
*/
function rrmdir($path) { function rrmdir($path) {
if(is_dir($path) === true) { if(is_dir($path) === true) {
$files = array_diff(scandir($path), array('.', '..')); $files = array_diff(scandir($path), array('.', '..'));
@ -1386,10 +1399,11 @@ function is_ajax() {
} }
// Primarily involved with database upgrade, but also sets the /**
// base url for use in cmdline programs which don't have * Primarily involved with database upgrade, but also sets the
// $_SERVER variables, and synchronising the state of installed plugins. * base url for use in cmdline programs which don't have
* $_SERVER variables, and synchronising the state of installed plugins.
*/
function check_config() { function check_config() {
$saved = get_config('system','urlverify'); $saved = get_config('system','urlverify');
@ -1600,15 +1614,23 @@ function fix_system_urls($oldurl, $newurl) {
); );
} }
} }
} }
// wrapper for adding a login box. If $register == true provide a registration /**
// link. This will most always depend on the value of App::$config['system']['register_policy']. * @brief Wrapper for adding a login box.
// returns the complete html for inserting into the page *
* If $register == true provide a registration link. This will most always depend
function login($register = false, $form_id = 'main-login', $hiddens=false, $login_page = true) { * on the value of App::$config['system']['register_policy'].
* Returns the complete html for inserting into the page
*
* @param boolean $register (optional) default false
* @param string $form_id (optional) default \e main-login
* @param boolean $hiddens (optional) default false
* @param boolean $login_page (optional) default true
* @return string Parsed HTML code.
*/
function login($register = false, $form_id = 'main-login', $hiddens = false, $login_page = true) {
$o = ''; $o = '';
$reg = false; $reg = false;
$reglink = get_config('system', 'register_link'); $reglink = get_config('system', 'register_link');
@ -1648,6 +1670,11 @@ function login($register = false, $form_id = 'main-login', $hiddens=false, $logi
'$lostlink' => t('Password Reset'), '$lostlink' => t('Password Reset'),
)); ));
/**
* @hooks login_hook
* Called when generating the login form.
* * \e string with parsed HTML
*/
call_hooks('login_hook', $o); call_hooks('login_hook', $o);
return $o; return $o;
@ -1736,9 +1763,13 @@ function remote_channel() {
} }
/** /**
* @brief Show an error or alert text on next page load.
*
* Contents of $s are displayed prominently on the page the next time * Contents of $s are displayed prominently on the page the next time
* a page is loaded. Usually used for errors or alerts. * a page is loaded. Usually used for errors or alerts.
* *
* For informational text use info().
*
* @param string $s Text to display * @param string $s Text to display
*/ */
function notice($s) { function notice($s) {
@ -1751,18 +1782,20 @@ function notice($s) {
// - typically seen as multiple 'permission denied' messages // - typically seen as multiple 'permission denied' messages
// as a result of auto-reloading a protected page with &JS=1 // as a result of auto-reloading a protected page with &JS=1
if(in_array($s,$_SESSION['sysmsg'])) if(in_array($s, $_SESSION['sysmsg']))
return; return;
if(App::$interactive) { if(App::$interactive) {
$_SESSION['sysmsg'][] = $s; $_SESSION['sysmsg'][] = $s;
} }
} }
/** /**
* @brief Show an information text on next page load.
*
* Contents of $s are displayed prominently on the page the next time a page is * Contents of $s are displayed prominently on the page the next time a page is
* loaded. Usually used for information. * loaded. Usually used for information.
*
* For error and alerts use notice(). * For error and alerts use notice().
* *
* @param string $s Text to display * @param string $s Text to display
@ -1777,7 +1810,7 @@ function info($s) {
} }
/** /**
* @brief Wrapper around config to limit the text length of an incoming message * @brief Wrapper around config to limit the text length of an incoming message.
* *
* @return int * @return int
*/ */
@ -1787,15 +1820,15 @@ function get_max_import_size() {
/** /**
* * @brief Wrap calls to proc_close(proc_open()) and call hook
* Wrap calls to proc_close(proc_open()) and call hook
* so plugins can take part in process :) * so plugins can take part in process :)
* *
* args: * args:
* $cmd program to run * $cmd program to run
* next args are passed as $cmd command line * next args are passed as $cmd command line
* *
* e.g.: proc_run("ls","-la","/tmp"); * e.g.:
* @code{.php}proc_run("ls", "-la", "/tmp");@endcode
* *
* $cmd and string args are surrounded with "" * $cmd and string args are surrounded with ""
*/ */
@ -1810,8 +1843,16 @@ function proc_run(){
$args = flatten_array_recursive($args); $args = flatten_array_recursive($args);
$arr = array('args' => $args, 'run_cmd' => true); $arr = [
'args' => $args,
'run_cmd' => true
];
/**
* @hooks proc_run
* Called when invoking PHP sub processes.
* * \e array \b args
* * \e boolean \b run_cmd
*/
call_hooks('proc_run', $arr); call_hooks('proc_run', $arr);
if(! $arr['run_cmd']) if(! $arr['run_cmd'])
@ -1873,7 +1914,6 @@ function is_windows() {
* *
* @return bool true if user is an admin * @return bool true if user is an admin
*/ */
function is_site_admin() { function is_site_admin() {
if(! session_id()) if(! session_id())
@ -1943,7 +1983,6 @@ function load_contact_links($uid) {
* *
* @return string * @return string
*/ */
function build_querystring($params, $name = null) { function build_querystring($params, $name = null) {
$ret = ''; $ret = '';
foreach($params as $key => $val) { foreach($params as $key => $val) {
@ -1962,12 +2001,14 @@ function build_querystring($params, $name = null) {
} }
} }
} }
return $ret; return $ret;
} }
// much better way of dealing with c-style args /*
* @brief Much better way of dealing with c-style args.
*/
function argc() { function argc() {
return App::$argc; return App::$argc;
} }
@ -1986,9 +2027,8 @@ function dba_timer() {
/** /**
* @brief Returns xchan_hash from the observer. * @brief Returns xchan_hash from the observer.
* *
* @return empty string if no observer, otherwise xchan_hash from observer * @return string xchan_hash from observer, otherwise empty string if no observer
*/ */
function get_observer_hash() { function get_observer_hash() {
$observer = App::get_observer(); $observer = App::get_observer();
if(is_array($observer)) if(is_array($observer))
@ -1999,19 +2039,24 @@ function get_observer_hash() {
/** /**
* Returns the complete URL of the current page, e.g.: http(s)://something.com/network * @brief Returns the complete URL of the current page, e.g.: http(s)://something.com/network
* *
* Taken from http://webcheatsheet.com/php/get_current_page_url.php * Taken from http://webcheatsheet.com/php/get_current_page_url.php
*
* @return string
*/ */
function curPageURL() { function curPageURL() {
$pageURL = 'http'; $pageURL = 'http';
if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";} if ($_SERVER["HTTPS"] == "on") {
$pageURL .= "s";
}
$pageURL .= "://"; $pageURL .= "://";
if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") { if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") {
$pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"]; $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
} else { } else {
$pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"]; $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
} }
return $pageURL; return $pageURL;
} }
@ -2022,7 +2067,6 @@ function curPageURL() {
* *
* @todo not fully implemented yet * @todo not fully implemented yet
* *
* @param App $a global application object
* @param string $navname * @param string $navname
* *
* @return mixed * @return mixed
@ -2046,8 +2090,17 @@ function load_pdl() {
if (! count(App::$layout)) { if (! count(App::$layout)) {
$arr = array('module' => App::$module, 'layout' => ''); $arr = [
call_hooks('load_pdl',$arr); 'module' => App::$module,
'layout' => ''
];
/**
* @hooks load_pdl
* Called when we load a PDL file or description.
* * \e string \b module
* * \e string \b layout
*/
call_hooks('load_pdl', $arr);
$layout = $arr['layout']; $layout = $arr['layout'];
$n = 'mod_' . App::$module . '.pdl' ; $n = 'mod_' . App::$module . '.pdl' ;
@ -2096,7 +2149,7 @@ function construct_page() {
if($uid) { if($uid) {
$navbar = get_pconfig($uid,'system','navbar',$navbar); $navbar = get_pconfig($uid,'system','navbar',$navbar);
} }
if($comanche && App::$layout['navbar']) { if($comanche && App::$layout['navbar']) {
$navbar = App::$layout['navbar']; $navbar = App::$layout['navbar'];
} }
@ -2150,7 +2203,17 @@ function construct_page() {
// layout completely with a new layout definition, or replace/remove existing content. // layout completely with a new layout definition, or replace/remove existing content.
if($comanche) { if($comanche) {
$arr = array('module' => App::$module, 'layout' => App::$layout); $arr = [
'module' => App::$module,
'layout' => App::$layout
];
/**
* @hooks construct_page
* General purpose hook to provide content to certain page regions.
* Called when constructing the Comanche page.
* * \e string \b module
* * \e string \b layout
*/
call_hooks('construct_page', $arr); call_hooks('construct_page', $arr);
App::$layout = $arr['layout']; App::$layout = $arr['layout'];
@ -2294,10 +2357,13 @@ function get_directory_primary() {
/** /**
* @brief return relative date of last completed poller execution. * @brief Return relative date of last completed poller execution.
*
* @return string relative date of last completed poller execution
*/ */
function get_poller_runtime() { function get_poller_runtime() {
$t = get_config('system', 'lastpoll'); $t = get_config('system', 'lastpoll');
return relative_date($t); return relative_date($t);
} }
@ -2307,6 +2373,7 @@ function z_get_upload_dir() {
$upload_dir = ini_get('upload_tmp_dir'); $upload_dir = ini_get('upload_tmp_dir');
if(! $upload_dir) if(! $upload_dir)
$upload_dir = sys_get_temp_dir(); $upload_dir = sys_get_temp_dir();
return $upload_dir; return $upload_dir;
} }
@ -2314,16 +2381,22 @@ function z_get_temp_dir() {
$temp_dir = get_config('system','tempdir'); $temp_dir = get_config('system','tempdir');
if(! $temp_dir) if(! $temp_dir)
$temp_dir = sys_get_temp_dir(); $temp_dir = sys_get_temp_dir();
return $upload_dir; return $upload_dir;
} }
function z_check_cert() {
if(strpos(z_root(),'https://') !== false) { /**
* @brief Check if server certificate is valid.
*
* Notify admin if not.
*/
function z_check_cert() {
if(strpos(z_root(), 'https://') !== false) {
$x = z_fetch_url(z_root() . '/siteinfo.json'); $x = z_fetch_url(z_root() . '/siteinfo.json');
if(! $x['success']) { if(! $x['success']) {
$recurse = 0; $recurse = 0;
$y = z_fetch_url(z_root() . '/siteinfo.json',false,$recurse,array('novalidate' => true)); $y = z_fetch_url(z_root() . '/siteinfo.json', false, $recurse, ['novalidate' => true]);
if($y['success']) if($y['success'])
cert_bad_email(); cert_bad_email();
} }
@ -2336,7 +2409,6 @@ function z_check_cert() {
* *
* If a hub is available over https it must have a publicly valid certificate. * If a hub is available over https it must have a publicly valid certificate.
*/ */
function cert_bad_email() { function cert_bad_email() {
return z_mail( return z_mail(
[ [
@ -2345,7 +2417,7 @@ function cert_bad_email() {
'textVersion' => replace_macros(get_intltext_template('cert_bad_eml.tpl'), 'textVersion' => replace_macros(get_intltext_template('cert_bad_eml.tpl'),
[ [
'$sitename' => App::$config['system']['sitename'], '$sitename' => App::$config['system']['sitename'],
'$siteurl' => z_root(), '$siteurl' => z_root(),
'$error' => t('Website SSL certificate is not valid. Please correct.') '$error' => t('Website SSL certificate is not valid. Please correct.')
] ]
) )
@ -2407,7 +2479,6 @@ function check_for_new_perms() {
\Zotlabs\Access\PermissionLimits::Set($cc['channel_id'],$p,0); \Zotlabs\Access\PermissionLimits::Set($cc['channel_id'],$p,0);
} }
$set = ((array_key_exists('perms_connect',$rp) && in_array($p,$rp['perms_connect'])) ? 1 : 0); $set = ((array_key_exists('perms_connect',$rp) && in_array($p,$rp['perms_connect'])) ? 1 : 0);
// foreach connection set to the perms_connect value // foreach connection set to the perms_connect value
if($x) { if($x) {
@ -2426,11 +2497,9 @@ function check_for_new_perms() {
// We should probably call perms_refresh here, but this should get pushed in 24 hours and there is no urgency // We should probably call perms_refresh here, but this should get pushed in 24 hours and there is no urgency
if($found_new_perm) if($found_new_perm)
set_config('system','perms',$pcurrent); set_config('system','perms',$pcurrent);
} }
/** /**
* @brief Send warnings every 3-5 days if cron is not running. * @brief Send warnings every 3-5 days if cron is not running.
*/ */
@ -2479,11 +2548,15 @@ function check_cron_broken() {
} }
/**
* @brief
*
* @param boolean $allow_account (optional) default false
* @return boolean
*/
function observer_prohibited($allow_account = false) { function observer_prohibited($allow_account = false) {
if($allow_account) if($allow_account)
return (((get_config('system','block_public')) && (! get_account_id()) && (! remote_channel())) ? true : false ); return (((get_config('system', 'block_public')) && (! get_account_id()) && (! remote_channel())) ? true : false );
return (((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) ? true : false );
return (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false );
} }

View file

@ -110,7 +110,7 @@ function fixacl(&$item) {
* *
* @param array $defaults Optional access control list for the initial state of the dialog. * @param array $defaults Optional access control list for the initial state of the dialog.
* @param boolean $show_jotnets Whether plugins for federated networks should be included in the permissions dialog * @param boolean $show_jotnets Whether plugins for federated networks should be included in the permissions dialog
* @param PermissionDescription $emptyACL_description - An optional description for the permission implied by selecting an empty ACL. Preferably an instance of PermissionDescription. * @param \Zotlabs\Lib\PermissionDescription $emptyACL_description - An optional description for the permission implied by selecting an empty ACL. Preferably an instance of PermissionDescription.
* @param string $dialog_description Optional message to include at the top of the dialog. E.g. "Warning: Post permissions cannot be changed once sent". * @param string $dialog_description Optional message to include at the top of the dialog. E.g. "Warning: Post permissions cannot be changed once sent".
* @param string $context_help Allows the dialog to present a help icon. E.g. "acl_dialog_post" * @param string $context_help Allows the dialog to present a help icon. E.g. "acl_dialog_post"
* @param boolean $readonly Not implemented yet. When implemented, the dialog will use acl_readonly.tpl instead, so that permissions may be viewed for posts that can no longer have their permissions changed. * @param boolean $readonly Not implemented yet. When implemented, the dialog will use acl_readonly.tpl instead, so that permissions may be viewed for posts that can no longer have their permissions changed.
@ -172,7 +172,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
if(count($allow_cid) === 1 && $channel && $allow_cid[0] = $channel['channel_hash'] && (! $allow_gid) && (! $deny_gid) && (! $deny_cid)) { if(count($allow_cid) === 1 && $channel && $allow_cid[0] = $channel['channel_hash'] && (! $allow_gid) && (! $deny_gid) && (! $deny_cid)) {
$just_me = true; $just_me = true;
$custom = false; $custom = false;
} }
$r = q("SELECT id, profile_guid, profile_name from profile where is_default = 0 and uid = %d order by profile_name", $r = q("SELECT id, profile_guid, profile_name from profile where is_default = 0 and uid = %d order by profile_name",
intval(local_channel()) intval(local_channel())

View file

@ -21,7 +21,7 @@ require_once('include/group.php');
* This function takes a file name and guess the mimetype from the * This function takes a file name and guess the mimetype from the
* filename extension. * filename extension.
* *
* @param $filename a string filename * @param string $filename a string filename
* @return string The mimetype according to a file ending. * @return string The mimetype according to a file ending.
*/ */
function z_mime_content_type($filename) { function z_mime_content_type($filename) {
@ -412,6 +412,10 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
require_once('include/photos.php'); require_once('include/photos.php');
/**
* @hooks photo_upload_begin
* Called when attempting to upload a photo.
*/
call_hooks('photo_upload_begin', $arr); call_hooks('photo_upload_begin', $arr);
$ret = array('success' => false); $ret = array('success' => false);
@ -486,14 +490,36 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$x = attach_mkdir($channel,$observer_hash,$arr); $x = attach_mkdir($channel,$observer_hash,$arr);
if($x['message']) if($x['message'])
logger('import_directory: ' . $x['message']); logger('import_directory: ' . $x['message']);
return; return;
} }
} }
elseif($options !== 'update') { elseif($options !== 'update') {
$f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => ''); $f = [
'src' => '',
'filename' => '',
'filesize' => 0,
'type' => ''
];
call_hooks('photo_upload_file',$f); /**
call_hooks('attach_upload_file',$f); * @hooks photo_upload_file
* Called to generate alternate filenames for an upload.
* * \e string \b src - return value, default empty
* * \e string \b filename - return value, default empty
* * \e number \b filesize - return value, default 0
* * \e string \b type - return value, default empty
*/
call_hooks('photo_upload_file', $f);
/**
* @hooks attach_upload_file
* Called when uploading a file.
* * \e string \b src - return value, default empty
* * \e string \b filename - return value, default empty
* * \e number \b filesize - return value, default 0
* * \e string \b type - return value, default empty
*/
call_hooks('attach_upload_file', $f);
if (x($f,'src') && x($f,'filesize')) { if (x($f,'src') && x($f,'filesize')) {
$src = $f['src']; $src = $f['src'];
@ -680,7 +706,13 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize); $ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize);
if($remove_when_processed) if($remove_when_processed)
@unlink($src); @unlink($src);
call_hooks('photo_upload_end',$ret);
/**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
@ -695,7 +727,12 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if($remove_when_processed) if($remove_when_processed)
@unlink($src); @unlink($src);
call_hooks('photo_upload_end',$ret); /**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
} }
@ -773,7 +810,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
); );
} }
elseif($options === 'update') { elseif($options === 'update') {
$r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, os_path = '%s', $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, os_path = '%s',
display_path = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d", display_path = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d",
dbesc((array_key_exists('filename',$arr)) ? $arr['filename'] : $x[0]['filename']), dbesc((array_key_exists('filename',$arr)) ? $arr['filename'] : $x[0]['filename']),
dbesc((array_key_exists('filetype',$arr)) ? $arr['filetype'] : $x[0]['filetype']), dbesc((array_key_exists('filetype',$arr)) ? $arr['filetype'] : $x[0]['filetype']),
@ -862,7 +899,13 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if(! $r) { if(! $r) {
$ret['message'] = t('File upload failed. Possible system limit or action terminated.'); $ret['message'] = t('File upload failed. Possible system limit or action terminated.');
call_hooks('photo_upload_end',$ret);
/**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
@ -875,15 +918,25 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if(! $r) { if(! $r) {
$ret['message'] = t('Stored file could not be verified. Upload failed.'); $ret['message'] = t('Stored file could not be verified. Upload failed.');
call_hooks('photo_upload_end',$ret);
/**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
$ret['success'] = true; $ret['success'] = true;
$ret['data'] = $r[0]; $ret['data'] = $r[0];
if(! $is_photo) { if(! $is_photo) {
// This would've been called already with a success result in photos_upload() if it was a photo. /**
call_hooks('photo_upload_end',$ret); * @hooks photo_upload_end
* Called when a photo upload has been processed.
* This would've been called already with a success result in photos_upload() if it was a photo.
*/
call_hooks('photo_upload_end', $ret);
} }
if($dosync) { if($dosync) {
@ -986,7 +1039,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
$os_basepath = 'store/' . $channel['channel_address']; $os_basepath = 'store/' . $channel['channel_address'];
logger('attach_mkdir: basepath: ' . $os_basepath); logger('basepath: ' . $os_basepath);
if(! is_dir($os_basepath)) if(! is_dir($os_basepath))
os_mkdir($os_basepath,STORAGE_DEFAULT_PERMISSIONS, true); os_mkdir($os_basepath,STORAGE_DEFAULT_PERMISSIONS, true);
@ -1055,7 +1108,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
return $ret; return $ret;
} }
$dpath = $r[0]['filename'] . (($dpath) ? '/' . $dpath : ''); $dpath = $r[0]['filename'] . (($dpath) ? '/' . $dpath : '');
if($lfile) if($lfile)
$lpath = $r[0]['hash'] . (($lpath) ? '/' . $lpath : ''); $lpath = $r[0]['hash'] . (($lpath) ? '/' . $lpath : '');
@ -1154,7 +1207,7 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
$basepath = 'store/' . $channel['channel_address']; $basepath = 'store/' . $channel['channel_address'];
logger('attach_mkdirp: basepath: ' . $basepath); logger('basepath: ' . $basepath);
if(! is_dir($basepath)) if(! is_dir($basepath))
os_mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS, true); os_mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS, true);
@ -1180,6 +1233,7 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
foreach($paths as $p) { foreach($paths as $p) {
if(! $p) if(! $p)
continue; continue;
$arx = array( $arx = array(
'filename' => $p, 'filename' => $p,
'folder' => $current_parent, 'folder' => $current_parent,
@ -1308,7 +1362,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
); );
if(! $r) { if(! $r) {
attach_drop_photo($channel_id,$resource); attach_drop_photo($channel_id,$resource);
return; return;
} }
@ -1501,6 +1555,13 @@ function find_folder_hash_by_attach_hash($channel_id, $attachHash, $recurse = fa
return $hash; return $hash;
} }
/**
* @brief Return the hash of an attachment's folder.
*
* @param int $channel_id
* @param string $path
* @return string
*/
function find_folder_hash_by_path($channel_id, $path) { function find_folder_hash_by_path($channel_id, $path) {
if(! $path) if(! $path)
@ -1530,7 +1591,6 @@ function find_folder_hash_by_path($channel_id, $path) {
return ''; return '';
return $parent_hash; return $parent_hash;
} }
/** /**
@ -1557,9 +1617,11 @@ function find_filename_by_hash($channel_id, $attachHash) {
} }
/** /**
* @brief Pipes $in to $out in 16MB chunks.
* *
* @param $in * @param resource $in File pointer of input
* @param $out * @param resource $out File pointer of output
* @return number with the size
*/ */
function pipe_streams($in, $out) { function pipe_streams($in, $out) {
$size = 0; $size = 0;
@ -1726,11 +1788,12 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
} }
/** /**
* @brief Create file activity object * @brief Create file activity object.
* *
* @param int $channel_id * @param int $channel_id
* @param string $hash * @param string $hash
* @param string $cloudpath * @param string $url
* @return array An associative array for the specified file.
*/ */
function get_file_activity_object($channel_id, $hash, $url) { function get_file_activity_object($channel_id, $hash, $url) {
@ -2257,7 +2320,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if($r[0]['is_photo']) { if($r[0]['is_photo']) {
$t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s' $t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
where resource_id = '%s' and uid = %d", where resource_id = '%s' and uid = %d",
dbesc($newdirname), dbesc($newdirname),
dbesc($filename), dbesc($filename),
@ -2349,8 +2412,6 @@ function attach_syspaths($channel_id,$attach_hash) {
while($attach_hash); while($attach_hash);
return [ 'os_path' => $os_path, 'path' => $path ]; return [ 'os_path' => $os_path, 'path' => $path ];
} }
@ -2386,7 +2447,7 @@ function save_chunk($channel,$start,$end,$len) {
$tmp_path = $_FILES['files']['tmp_name']; $tmp_path = $_FILES['files']['tmp_name'];
$new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp'; $new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true); os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true);
$new_path = $new_base . '/' . $_FILES['files']['name']; $new_path = $new_base . '/' . $_FILES['files']['name'];
if(! file_exists($new_path)) { if(! file_exists($new_path)) {
@ -2417,20 +2478,19 @@ function save_chunk($channel,$start,$end,$len) {
} }
/* /**
* chunkloader * @brief Submit handler for chunked uploads.
* Submit handler for chunked uploads *
* * @param array $channel
* @param array $arr
* @return array
*/ */
function chunkloader($channel, $arr) {
function chunkloader($channel,$arr) {
logger('request: ' . print_r($arr,true), LOGGER_DEBUG); logger('request: ' . print_r($arr,true), LOGGER_DEBUG);
logger('files: ' . print_r($_FILES,true), LOGGER_DEBUG); logger('files: ' . print_r($_FILES,true), LOGGER_DEBUG);
$result = []; $result = [];
$tmp_path = $_FILES['file']['tmp_name']; $tmp_path = $_FILES['file']['tmp_name'];
$new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp'; $new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
@ -2439,7 +2499,7 @@ function chunkloader($channel,$arr) {
$new_path = $new_base . '/' . $arr['resumableFilename']; $new_path = $new_base . '/' . $arr['resumableFilename'];
rename($tmp_path,$new_path . '.' . intval($arr['resumableChunkNumber'])); rename($tmp_path,$new_path . '.' . intval($arr['resumableChunkNumber']));
$missing_parts = false; $missing_parts = false;
for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) { for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) {
if(! file_exists($new_path . '.' . $x)) { if(! file_exists($new_path . '.' . $x)) {
@ -2475,7 +2535,7 @@ function chunkloader($channel,$arr) {
$result['error'] = 0; $result['error'] = 0;
$result['size'] = $arr['resumableTotalSize']; $result['size'] = $arr['resumableTotalSize'];
$result['complete'] = true; $result['complete'] = true;
return $result;
return $result;
} }

View file

@ -1,6 +1,7 @@
<?php <?php
/** /**
* @file include/channel.php * @file include/channel.php
* @brief Channel related functions.
*/ */
require_once('include/zot.php'); require_once('include/zot.php');
@ -58,10 +59,8 @@ function identity_check_service_class($account_id) {
* Plugins can set additional policies such as full name requirements, character * Plugins can set additional policies such as full name requirements, character
* sets, multi-byte length, etc. * sets, multi-byte length, etc.
* *
* @hooks validate_channelname
* * \e array \b name
* @param string $name * @param string $name
* @returns nil return if name is valid, or string describing the error state. * @return string describing the error state, or nil return if name is valid
*/ */
function validate_channelname($name) { function validate_channelname($name) {
@ -72,6 +71,12 @@ function validate_channelname($name) {
return t('Name too long'); return t('Name too long');
$arr = ['name' => $name]; $arr = ['name' => $name];
/**
* @hooks validate_channelname
* Used to validate the names used by a channel.
* * \e string \b name
* * \e string \b message - return error message
*/
call_hooks('validate_channelname', $arr); call_hooks('validate_channelname', $arr);
if (x($arr, 'message')) if (x($arr, 'message'))
@ -259,7 +264,6 @@ function create_identity($arr) {
'channel_system' => intval($system), 'channel_system' => intval($system),
'channel_expire_days' => intval($expire), 'channel_expire_days' => intval($expire),
'channel_timezone' => App::$timezone 'channel_timezone' => App::$timezone
] ]
); );
@ -280,9 +284,19 @@ function create_identity($arr) {
$photo_type = null; $photo_type = null;
$z = [ 'account' => $a[0], 'channel' => $r[0], 'photo_url' => '' ]; $z = [
call_hooks('create_channel_photo',$z); 'account' => $a[0],
'channel' => $r[0],
'photo_url' => ''
];
/**
* @hooks create_channel_photo
* * \e array \b account
* * \e array \b channel
* * \e string \b photo_url - Return value
*/
call_hooks('create_channel_photo', $z);
if($z['photo_url']) { if($z['photo_url']) {
$photo_type = import_channel_photo_from_url($z['photo_url'],$arr['account_id'],$r[0]['channel_id']); $photo_type = import_channel_photo_from_url($z['photo_url'],$arr['account_id'],$r[0]['channel_id']);
} }
@ -322,7 +336,7 @@ function create_identity($arr) {
] ]
); );
if(! $r) if(! $r)
logger('create_identity: Unable to store hub location'); logger('Unable to store hub location');
$newuid = $ret['channel']['channel_id']; $newuid = $ret['channel']['channel_id'];
@ -454,12 +468,18 @@ function create_identity($arr) {
require_once('include/follow.php'); require_once('include/follow.php');
if(! is_array($accts)) if(! is_array($accts))
$accts = array($accts); $accts = array($accts);
foreach($accts as $acct) { foreach($accts as $acct) {
if(trim($acct)) if(trim($acct))
new_contact($newuid,trim($acct),$ret['channel'],false); new_contact($newuid,trim($acct),$ret['channel'],false);
} }
} }
/**
* @hooks create_identity
* Called when creating a channel.
* * \e int - The UID of the created identity
*/
call_hooks('create_identity', $newuid); call_hooks('create_identity', $newuid);
Zotlabs\Daemon\Master::Summon(array('Directory', $ret['channel']['channel_id'])); Zotlabs\Daemon\Master::Summon(array('Directory', $ret['channel']['channel_id']));
@ -576,14 +596,14 @@ function channel_change_address($channel,$new_address) {
$old_address = $channel['channel_address']; $old_address = $channel['channel_address'];
if($new_address === 'sys') { if($new_address === 'sys') {
$ret['message'] = t('Reserved nickname. Please choose another.'); $ret['message'] = t('Reserved nickname. Please choose another.');
return $ret; return $ret;
} }
if(check_webbie(array($new_address)) !== $new_address) { if(check_webbie(array($new_address)) !== $new_address) {
$ret['message'] = t('Nickname has unsupported characters or is already being used on this site.'); $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
return $ret; return $ret;
} }
$r = q("update channel set channel_address = '%s' where channel_id = %d", $r = q("update channel set channel_address = '%s' where channel_id = %d",
dbesc($new_address), dbesc($new_address),
@ -644,7 +664,7 @@ function channel_change_address($channel,$new_address) {
); );
} }
} }
} }
Zotlabs\Daemon\Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id'])); Zotlabs\Daemon\Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
@ -653,10 +673,6 @@ function channel_change_address($channel,$new_address) {
} }
/** /**
* @brief Set default channel to be used on login. * @brief Set default channel to be used on login.
* *
@ -664,9 +680,9 @@ function channel_change_address($channel,$new_address) {
* login account * login account
* @param int $channel_id * @param int $channel_id
* channel id to set as default for this account * channel id to set as default for this account
* @param boolean $force * @param boolean $force (optional) default true
* if true, set this default unconditionally * - if true, set this default unconditionally
* if $force is false only do this if there is no existing default * - if $force is false only do this if there is no existing default
*/ */
function set_default_login_identity($account_id, $channel_id, $force = true) { function set_default_login_identity($account_id, $channel_id, $force = true) {
$r = q("select account_default_channel from account where account_id = %d limit 1", $r = q("select account_default_channel from account where account_id = %d limit 1",
@ -685,8 +701,6 @@ function set_default_login_identity($account_id, $channel_id, $force = true) {
/** /**
* @brief Return an array with default list of sections to export. * @brief Return an array with default list of sections to export.
* *
* @hooks get_default_export_sections
* * \e array \b sections
* @return array with default section names to export * @return array with default section names to export
*/ */
function get_default_export_sections() { function get_default_export_sections() {
@ -703,6 +717,11 @@ function get_default_export_sections() {
]; ];
$cb = [ 'sections' => $sections ]; $cb = [ 'sections' => $sections ];
/**
* @hooks get_default_export_sections
* Called to get the default list of functional data groups to export in identity_basic_export().
* * \e array \b sections - return value
*/
call_hooks('get_default_export_sections', $cb); call_hooks('get_default_export_sections', $cb);
return $cb['sections']; return $cb['sections'];
@ -714,15 +733,11 @@ function get_default_export_sections() {
* which would be necessary to create a nomadic identity clone. This includes * which would be necessary to create a nomadic identity clone. This includes
* most channel resources and connection information with the exception of content. * most channel resources and connection information with the exception of content.
* *
* @hooks identity_basic_export
* * \e int \b channel_id
* * \e array \b sections
* * \e array \b data
* @param int $channel_id * @param int $channel_id
* Channel_id to export * Channel_id to export
* @param array $sections (optional) * @param array $sections (optional)
* Which sections to include in the export, default see get_default_export_sections() * Which sections to include in the export, default see get_default_export_sections()
* @returns array * @return array
* See function for details * See function for details
*/ */
function identity_basic_export($channel_id, $sections = null) { function identity_basic_export($channel_id, $sections = null) {
@ -967,7 +982,7 @@ function identity_basic_export($channel_id, $sections = null) {
} }
} }
if(in_array('items',$sections)) { if(in_array('items', $sections)) {
/** @warning this may run into memory limits on smaller systems */ /** @warning this may run into memory limits on smaller systems */
/** export three months of posts. If you want to export and import all posts you have to start with /** export three months of posts. If you want to export and import all posts you have to start with
@ -991,22 +1006,42 @@ function identity_basic_export($channel_id, $sections = null) {
} }
} }
$addon = [ 'channel_id' => $channel_id, 'sections' => $sections, 'data' => $ret]; $addon = [
call_hooks('identity_basic_export',$addon); 'channel_id' => $channel_id,
'sections' => $sections,
'data' => $ret
];
/**
* @hooks identity_basic_export
* Called when exporting a channel's basic information for backup or transfer.
* * \e number \b channel_id - The channel ID
* * \e array \b sections
* * \e array \b data - The data will get returned
*/
call_hooks('identity_basic_export', $addon);
$ret = $addon['data']; $ret = $addon['data'];
return $ret; return $ret;
} }
/**
function identity_export_year($channel_id,$year,$month = 0) { * @brief Export items for a year, or a month of a year.
*
* @param int $channel_id The channel ID
* @param number $year YYYY
* @param number $month (optional) 0-12, default 0 complete year
* @return array An associative array
* * \e array \b relocate - (optional)
* * \e array \b item - array with items encoded_item()
*/
function identity_export_year($channel_id, $year, $month = 0) {
if(! $year) if(! $year)
return array(); return array();
if($month && $month <= 12) { if($month && $month <= 12) {
$target_month = sprintf('%02d',$month); $target_month = sprintf('%02d', $month);
$target_month_plus = sprintf('%02d',$month+1); $target_month_plus = sprintf('%02d', $month+1);
} }
else else
$target_month = '01'; $target_month = '01';
@ -1017,13 +1052,13 @@ function identity_export_year($channel_id,$year,$month = 0) {
if($ch) { if($ch) {
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()]; $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
} }
$mindate = datetime_convert('UTC','UTC',$year . '-' . $target_month . '-01 00:00:00'); $mindate = datetime_convert('UTC', 'UTC', $year . '-' . $target_month . '-01 00:00:00');
if($month && $month < 12) if($month && $month < 12)
$maxdate = datetime_convert('UTC','UTC',$year . '-' . $target_month_plus . '-01 00:00:00'); $maxdate = datetime_convert('UTC', 'UTC', $year . '-' . $target_month_plus . '-01 00:00:00');
else else
$maxdate = datetime_convert('UTC','UTC',$year+1 . '-01-01 00:00:00'); $maxdate = datetime_convert('UTC', 'UTC', $year+1 . '-01-01 00:00:00');
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' and resource_type = '' order by created", $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' and resource_type = '' order by created",
intval(ITEM_TYPE_POST), intval(ITEM_TYPE_POST),
intval($channel_id), intval($channel_id),
dbesc($mindate), dbesc($mindate),
@ -1033,9 +1068,9 @@ function identity_export_year($channel_id,$year,$month = 0) {
if($r) { if($r) {
$ret['item'] = array(); $ret['item'] = array();
xchan_query($r); xchan_query($r);
$r = fetch_post_tags($r,true); $r = fetch_post_tags($r, true);
foreach($r as $rr) foreach($r as $rr)
$ret['item'][] = encode_item($rr,true); $ret['item'][] = encode_item($rr, true);
} }
return $ret; return $ret;
@ -1274,6 +1309,7 @@ function profile_edit_menu($uid) {
foreach($r as $rr) { foreach($r as $rr) {
if(!($multi_profiles || $rr['is_default'])) if(!($multi_profiles || $rr['is_default']))
continue; continue;
$ret['menu']['entries'][] = array( $ret['menu']['entries'][] = array(
'photo' => $rr['thumb'], 'photo' => $rr['thumb'],
'id' => $rr['id'], 'id' => $rr['id'],
@ -1298,8 +1334,8 @@ function profile_edit_menu($uid) {
* *
* @param array $profile * @param array $profile
* @param int $block * @param int $block
* @param boolean $show_connect * @param boolean $show_connect (optional) default true
* @param mixed $zcard * @param mixed $zcard (optional) default false
* *
* @return HTML string suitable for sidebar inclusion * @return HTML string suitable for sidebar inclusion
* Exceptions: Returns empty string if passed $profile is wrong type or not populated * Exceptions: Returns empty string if passed $profile is wrong type or not populated
@ -1327,6 +1363,10 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
$profile['picdate'] = urlencode($profile['picdate']); $profile['picdate'] = urlencode($profile['picdate']);
/**
* @hooks profile_sidebar_enter
* Called before generating the 'channel sidebar' or mini-profile.
*/
call_hooks('profile_sidebar_enter', $profile); call_hooks('profile_sidebar_enter', $profile);
if($show_connect) { if($show_connect) {
@ -1409,22 +1449,30 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
'$reddress' => $reddress, '$reddress' => $reddress,
'$rating' => '', '$rating' => '',
'$contact_block' => $contact_block, '$contact_block' => $contact_block,
'$editmenu' => profile_edit_menu($profile['uid']) '$editmenu' => profile_edit_menu($profile['uid'])
)); ));
$arr = array('profile' => $profile, 'entry' => $o); $arr = [
'profile' => $profile,
'entry' => $o
];
/**
* @hooks profile_sidebar
* Called when generating the 'channel sidebar' or mini-profile.
* * \e array \b profile
* * \e string \b entry - The parsed HTML template
*/
call_hooks('profile_sidebar', $arr); call_hooks('profile_sidebar', $arr);
return $arr['entry']; return $arr['entry'];
} }
function gender_icon($gender) { function gender_icon($gender) {
// logger('gender: ' . $gender); // logger('gender: ' . $gender);
// This can easily get throw off if the observer language is different // This can easily get throw off if the observer language is different
// than the channel owner language. // than the channel owner language.
if(strpos(strtolower($gender),strtolower(t('Female'))) !== false) if(strpos(strtolower($gender),strtolower(t('Female'))) !== false)
@ -1622,16 +1670,21 @@ function get_my_address() {
* If somebody arrives at our site using a zid, add their xchan to our DB if we * If somebody arrives at our site using a zid, add their xchan to our DB if we
* don't have it already. * don't have it already.
* And if they aren't already authenticated here, attempt reverse magic auth. * And if they aren't already authenticated here, attempt reverse magic auth.
*
* @hooks zid_init
* * \e string \b zid - their zid
* * \e string \b url - the destination url
*/ */
function zid_init() { function zid_init() {
$tmp_str = get_my_address(); $tmp_str = get_my_address();
if(validate_email($tmp_str)) { if(validate_email($tmp_str)) {
$arr = array('zid' => $tmp_str, 'url' => App::$cmd); $arr = [
call_hooks('zid_init',$arr); 'zid' => $tmp_str,
'url' => App::$cmd
];
/**
* @hooks zid_init
* * \e string \b zid - their zid
* * \e string \b url - the destination url
*/
call_hooks('zid_init', $arr);
if(! local_channel()) { if(! local_channel()) {
$r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc limit 1", $r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc limit 1",
dbesc($tmp_str) dbesc($tmp_str)
@ -1641,7 +1694,8 @@ function zid_init() {
} }
if($r && remote_channel() && remote_channel() === $r[0]['hubloc_hash']) if($r && remote_channel() && remote_channel() === $r[0]['hubloc_hash'])
return; return;
logger('zid_init: not authenticated. Invoking reverse magic-auth for ' . $tmp_str);
logger('Not authenticated. Invoking reverse magic-auth for ' . $tmp_str);
// try to avoid recursion - but send them home to do a proper magic auth // try to avoid recursion - but send them home to do a proper magic auth
$query = App::$query_string; $query = App::$query_string;
$query = str_replace(array('?zid=','&zid='),array('?rzid=','&rzid='),$query); $query = str_replace(array('?zid=','&zid='),array('?rzid=','&rzid='),$query);
@ -1650,7 +1704,7 @@ function zid_init() {
goaway($r[0]['hubloc_url'] . '/magic' . '?f=&rev=1&owa=1&dest=' . z_root() . $dest); goaway($r[0]['hubloc_url'] . '/magic' . '?f=&rev=1&owa=1&dest=' . z_root() . $dest);
} }
else else
logger('zid_init: no hubloc found.'); logger('No hubloc found.');
} }
} }
} }
@ -1673,21 +1727,23 @@ function zat_init() {
} }
/**
* @brief Used from within PCSS themes to set theme parameters.
// Used from within PCSS themes to set theme parameters. If there's a *
// puid request variable, that is the "page owner" and normally their theme * If there's a puid request variable, that is the "page owner" and normally
// settings take precedence; unless a local user sets the "always_my_theme" * their theme settings take precedence; unless a local user sets the "always_my_theme"
// system pconfig, which means they don't want to see anybody else's theme * system pconfig, which means they don't want to see anybody else's theme
// settings except their own while on this site. * settings except their own while on this site.
*
* @return int
*/
function get_theme_uid() { function get_theme_uid() {
$uid = (($_REQUEST['puid']) ? intval($_REQUEST['puid']) : 0); $uid = (($_REQUEST['puid']) ? intval($_REQUEST['puid']) : 0);
if(local_channel()) { if(local_channel()) {
if((get_pconfig(local_channel(),'system','always_my_theme')) || (! $uid)) if((get_pconfig(local_channel(),'system','always_my_theme')) || (! $uid))
return local_channel(); return local_channel();
} }
if(! $uid) { if(! $uierd) {
$x = get_sys_channel(); $x = get_sys_channel();
if($x) if($x)
return $x['channel_id']; return $x['channel_id'];
@ -1700,9 +1756,9 @@ function get_theme_uid() {
* @brief Retrieves the path of the default_profile_photo for this system * @brief Retrieves the path of the default_profile_photo for this system
* with the specified size. * with the specified size.
* *
* @param int $size * @param int $size (optional) default 300
* one of (300, 80, 48) * one of (300, 80, 48)
* @returns string with path to profile photo * @return string with path to profile photo
*/ */
function get_default_profile_photo($size = 300) { function get_default_profile_photo($size = 300) {
$scheme = get_config('system','default_profile_photo'); $scheme = get_config('system','default_profile_photo');
@ -1715,9 +1771,9 @@ function get_default_profile_photo($size = 300) {
/** /**
* @brief Test whether a given identity is NOT a member of the Hubzilla. * @brief Test whether a given identity is NOT a member of the Hubzilla.
* *
* @param string $s; * @param string $s
* xchan_hash of the identity in question * xchan_hash of the identity in question
* @returns boolean true or false * @return boolean true or false
*/ */
function is_foreigner($s) { function is_foreigner($s) {
return((strpbrk($s, '.:@')) ? true : false); return((strpbrk($s, '.:@')) ? true : false);
@ -1726,14 +1782,21 @@ function is_foreigner($s) {
/** /**
* @brief Test whether a given identity is a member of the Hubzilla. * @brief Test whether a given identity is a member of the Hubzilla.
* *
* @param string $s; * @param string $s
* xchan_hash of the identity in question * xchan_hash of the identity in question
* @returns boolean true or false * @return boolean true or false
*/ */
function is_member($s) { function is_member($s) {
return((is_foreigner($s)) ? false : true); return((is_foreigner($s)) ? false : true);
} }
/**
* @brief Get chatpresence status for nick.
*
* @param string $nick
* @return array An associative array with
* * \e bool \b result
*/
function get_online_status($nick) { function get_online_status($nick) {
$ret = array('result' => false); $ret = array('result' => false);
@ -1748,6 +1811,7 @@ function get_online_status($nick) {
$hide = get_pconfig($r[0]['channel_id'],'system','hide_online_status'); $hide = get_pconfig($r[0]['channel_id'],'system','hide_online_status');
if($hide) if($hide)
return $ret; return $ret;
$x = q("select cp_status from chatpresence where cp_xchan = '%s' and cp_room = 0 limit 1", $x = q("select cp_status from chatpresence where cp_xchan = '%s' and cp_room = 0 limit 1",
dbesc($r[0]['channel_hash']) dbesc($r[0]['channel_hash'])
); );
@ -1759,6 +1823,12 @@ function get_online_status($nick) {
} }
/**
* @brief
*
* @param string $webbie
* @return array|boolean|string
*/
function remote_online_status($webbie) { function remote_online_status($webbie) {
$result = false; $result = false;
@ -1782,11 +1852,10 @@ function remote_online_status($webbie) {
/** /**
* @brief * @brief Return the parsed identity selector HTML template.
* *
* @return string * @return string with parsed HTML channel_id_selet template
*/ */
function identity_selector() { function identity_selector() {
if(local_channel()) { if(local_channel()) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ", $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ",
@ -1798,6 +1867,7 @@ function identity_selector() {
'$channels' => $r, '$channels' => $r,
'$selected' => local_channel() '$selected' => local_channel()
)); ));
return $o; return $o;
} }
} }
@ -1809,14 +1879,17 @@ function identity_selector() {
function is_public_profile() { function is_public_profile() {
if(! local_channel()) if(! local_channel())
return false; return false;
if(intval(get_config('system','block_public'))) if(intval(get_config('system','block_public')))
return false; return false;
$channel = App::get_channel(); $channel = App::get_channel();
if($channel) { if($channel) {
$perm = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'); $perm = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile');
if($perm == PERMS_PUBLIC) if($perm == PERMS_PUBLIC)
return true; return true;
} }
return false; return false;
} }
@ -1861,7 +1934,7 @@ function get_profile_fields_advanced($filter = 0) {
* *
* @param int $channel_id * @param int $channel_id
* The channel to disable notifications for * The channel to disable notifications for
* @returns int * @return int
* Current notification flag value. Send this to notifications_on() to restore the channel settings when finished * Current notification flag value. Send this to notifications_on() to restore the channel settings when finished
* with the activity requiring notifications_off(); * with the activity requiring notifications_off();
*/ */
@ -1993,13 +2066,14 @@ function get_cover_photo($channel_id,$format = 'bbcode', $res = PHOTO_RES_COVER_
return $output; return $output;
} }
/** /**
* @brief * @brief Return parsed HTML zcard template.
* *
* @param array $channel * @param array $channel
* @param string $observer_hash * @param string $observer_hash (optional)
* @param array $args * @param array $args (optional)
* @return string * @return string parsed HTML from \e zcard template
*/ */
function get_zcard($channel, $observer_hash = '', $args = array()) { function get_zcard($channel, $observer_hash = '', $args = array()) {
@ -2067,6 +2141,14 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
} }
/**
* @brief Return parsed HTML embed zcard template.
*
* @param array $channel
* @param string $observer_hash (optional)
* @param array $args (optional)
* @return string parsed HTML from \e zcard_embed template
*/
function get_zcard_embed($channel, $observer_hash = '', $args = array()) { function get_zcard_embed($channel, $observer_hash = '', $args = array()) {
logger('get_zcard_embed'); logger('get_zcard_embed');
@ -2133,10 +2215,12 @@ function get_zcard_embed($channel, $observer_hash = '', $args = array()) {
} }
/** /**
* @brief * @brief Get a channel array from a channel nickname.
* *
* @param string $nick * @param string $nick - A channel_address nickname
* @return mixed * @return array|boolean
* - array with channel entry
* - false if no channel with $nick was found
*/ */
function channelx_by_nick($nick) { function channelx_by_nick($nick) {
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1", $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1",
@ -2147,10 +2231,10 @@ function channelx_by_nick($nick) {
} }
/** /**
* @brief * @brief Get a channel array by a channel_hash.
* *
* @param string $hash * @param string $hash
* @return mixed * @return array|boolean false if channel ID not found, otherwise the channel array
*/ */
function channelx_by_hash($hash) { function channelx_by_hash($hash) {
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and channel_removed = 0 LIMIT 1", $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and channel_removed = 0 LIMIT 1",
@ -2161,13 +2245,13 @@ function channelx_by_hash($hash) {
} }
/** /**
* @brief * @brief Get a channel array by a channel ID.
* *
* @param int $id * @param int $id A channel ID
* @return mixed * @return array|boolean false if channel ID not found, otherwise the channel array
*/ */
function channelx_by_n($id) { function channelx_by_n($id) {
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_id = %d and channel_removed = 0 LIMIT 1", $r = q("SELECT * FROM channel LEFT JOIN xchan ON channel_hash = xchan_hash WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
dbesc($id) dbesc($id)
); );
@ -2177,7 +2261,7 @@ function channelx_by_n($id) {
/** /**
* @brief * @brief
* *
* @param string $channel * @param array $channel
* @return string * @return string
*/ */
function channel_reddress($channel) { function channel_reddress($channel) {
@ -2188,67 +2272,77 @@ function channel_reddress($channel) {
} }
/**
* @brief Get manual channel conversation update config.
*
* Check the channel config \e manual_conversation_update, if not set fall back
* to global system config, defaults to 1 if nothing set.
*
* @param int $channel_id
* @return int
*/
function channel_manual_conv_update($channel_id) { function channel_manual_conv_update($channel_id) {
$x = get_pconfig($channel_id, 'system','manual_conversation_update'); $x = get_pconfig($channel_id, 'system', 'manual_conversation_update');
if($x === false) if($x === false)
$x = get_config('system','manual_conversation_update', 1); $x = get_config('system', 'manual_conversation_update', 1);
return intval($x); return intval($x);
} }
/**
* @brief Return parsed HTML remote_login template.
*
* @return string with parsed HTML from \e remote_login template
*/
function remote_login() { function remote_login() {
$o = replace_macros(get_markup_template('remote_login.tpl'),array(
'$title' => t('Remote Authentication'),
'$desc' => t('Enter your channel address (e.g. channel@example.com)'),
'$submit' => t('Authenticate')
));
$o = replace_macros(get_markup_template('remote_login.tpl'),array( return $o;
'$title' => t('Remote Authentication'),
'$desc' => t('Enter your channel address (e.g. channel@example.com)'),
'$submit' => t('Authenticate')
));
return $o;
} }
function channel_store_lowlevel($arr) { function channel_store_lowlevel($arr) {
$store = [ $store = [
'channel_account_id' => ((array_key_exists('channel_account_id',$arr)) ? $arr['channel_account_id'] : '0'), 'channel_account_id' => ((array_key_exists('channel_account_id',$arr)) ? $arr['channel_account_id'] : '0'),
'channel_primary' => ((array_key_exists('channel_primary',$arr)) ? $arr['channel_primary'] : '0'), 'channel_primary' => ((array_key_exists('channel_primary',$arr)) ? $arr['channel_primary'] : '0'),
'channel_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''), 'channel_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''),
'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''), 'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''),
'channel_guid' => ((array_key_exists('channel_guid',$arr)) ? $arr['channel_guid'] : ''), 'channel_guid' => ((array_key_exists('channel_guid',$arr)) ? $arr['channel_guid'] : ''),
'channel_guid_sig' => ((array_key_exists('channel_guid_sig',$arr)) ? $arr['channel_guid_sig'] : ''), 'channel_guid_sig' => ((array_key_exists('channel_guid_sig',$arr)) ? $arr['channel_guid_sig'] : ''),
'channel_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''), 'channel_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''),
'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'), 'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'),
'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''), 'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''),
'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''), 'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''),
'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''), 'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''),
'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''), 'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''),
'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''), 'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''),
'channel_notifyflags' => ((array_key_exists('channel_notifyflags',$arr)) ? $arr['channel_notifyflags'] : '65535'), 'channel_notifyflags' => ((array_key_exists('channel_notifyflags',$arr)) ? $arr['channel_notifyflags'] : '65535'),
'channel_pageflags' => ((array_key_exists('channel_pageflags',$arr)) ? $arr['channel_pageflags'] : '0'), 'channel_pageflags' => ((array_key_exists('channel_pageflags',$arr)) ? $arr['channel_pageflags'] : '0'),
'channel_dirdate' => ((array_key_exists('channel_dirdate',$arr)) ? $arr['channel_dirdate'] : NULL_DATE), 'channel_dirdate' => ((array_key_exists('channel_dirdate',$arr)) ? $arr['channel_dirdate'] : NULL_DATE),
'channel_lastpost' => ((array_key_exists('channel_lastpost',$arr)) ? $arr['channel_lastpost'] : NULL_DATE), 'channel_lastpost' => ((array_key_exists('channel_lastpost',$arr)) ? $arr['channel_lastpost'] : NULL_DATE),
'channel_deleted' => ((array_key_exists('channel_deleted',$arr)) ? $arr['channel_deleted'] : NULL_DATE), 'channel_deleted' => ((array_key_exists('channel_deleted',$arr)) ? $arr['channel_deleted'] : NULL_DATE),
'channel_max_anon_mail' => ((array_key_exists('channel_max_anon_mail',$arr)) ? $arr['channel_max_anon_mail'] : '10'), 'channel_max_anon_mail' => ((array_key_exists('channel_max_anon_mail',$arr)) ? $arr['channel_max_anon_mail'] : '10'),
'channel_max_friend_req' => ((array_key_exists('channel_max_friend_req',$arr)) ? $arr['channel_max_friend_req'] : '10'), 'channel_max_friend_req' => ((array_key_exists('channel_max_friend_req',$arr)) ? $arr['channel_max_friend_req'] : '10'),
'channel_expire_days' => ((array_key_exists('channel_expire_days',$arr)) ? $arr['channel_expire_days'] : '0'), 'channel_expire_days' => ((array_key_exists('channel_expire_days',$arr)) ? $arr['channel_expire_days'] : '0'),
'channel_passwd_reset' => ((array_key_exists('channel_passwd_reset',$arr)) ? $arr['channel_passwd_reset'] : ''), 'channel_passwd_reset' => ((array_key_exists('channel_passwd_reset',$arr)) ? $arr['channel_passwd_reset'] : ''),
'channel_default_group' => ((array_key_exists('channel_default_group',$arr)) ? $arr['channel_default_group'] : ''), 'channel_default_group' => ((array_key_exists('channel_default_group',$arr)) ? $arr['channel_default_group'] : ''),
'channel_allow_cid' => ((array_key_exists('channel_allow_cid',$arr)) ? $arr['channel_allow_cid'] : ''), 'channel_allow_cid' => ((array_key_exists('channel_allow_cid',$arr)) ? $arr['channel_allow_cid'] : ''),
'channel_allow_gid' => ((array_key_exists('channel_allow_gid',$arr)) ? $arr['channel_allow_gid'] : ''), 'channel_allow_gid' => ((array_key_exists('channel_allow_gid',$arr)) ? $arr['channel_allow_gid'] : ''),
'channel_deny_cid' => ((array_key_exists('channel_deny_cid',$arr)) ? $arr['channel_deny_cid'] : ''), 'channel_deny_cid' => ((array_key_exists('channel_deny_cid',$arr)) ? $arr['channel_deny_cid'] : ''),
'channel_deny_gid' => ((array_key_exists('channel_deny_gid',$arr)) ? $arr['channel_deny_gid'] : ''), 'channel_deny_gid' => ((array_key_exists('channel_deny_gid',$arr)) ? $arr['channel_deny_gid'] : ''),
'channel_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '0'), 'channel_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '0'),
'channel_system' => ((array_key_exists('channel_system',$arr)) ? $arr['channel_system'] : '0'), 'channel_system' => ((array_key_exists('channel_system',$arr)) ? $arr['channel_system'] : '0'),
'channel_moved' => ((array_key_exists('channel_moved',$arr)) ? $arr['channel_moved'] : ''), 'channel_moved' => ((array_key_exists('channel_moved',$arr)) ? $arr['channel_moved'] : ''),
'channel_password' => ((array_key_exists('channel_password',$arr)) ? $arr['channel_password'] : ''), 'channel_password' => ((array_key_exists('channel_password',$arr)) ? $arr['channel_password'] : ''),
'channel_salt' => ((array_key_exists('channel_salt',$arr)) ? $arr['channel_salt'] : '') 'channel_salt' => ((array_key_exists('channel_salt',$arr)) ? $arr['channel_salt'] : '')
]; ];
return create_table_from_array('channel',$store); return create_table_from_array('channel', $store);
} }
function profile_store_lowlevel($arr) { function profile_store_lowlevel($arr) {
@ -2304,16 +2398,22 @@ function profile_store_lowlevel($arr) {
} }
// Included here for completeness, but this is a very dangerous operation. /**
// It is the caller's responsibility to confirm the requestor's intent and * Included here for completeness, but this is a very dangerous operation.
// authorisation to do this. * It is the caller's responsibility to confirm the requestor's intent and
* authorisation to do this.
function account_remove($account_id,$local = true,$unset_session = true) { *
* @param int $account_id
* @param boolean $local (optional) default true
* @param boolean $unset_session (optional) default true
* @return boolean|array
*/
function account_remove($account_id, $local = true, $unset_session = true) {
logger('account_remove: ' . $account_id); logger('account_remove: ' . $account_id);
if(! intval($account_id)) { if(! intval($account_id)) {
logger('account_remove: no account.'); logger('No account.');
return false; return false;
} }
@ -2334,7 +2434,7 @@ function account_remove($account_id,$local = true,$unset_session = true) {
$account_email=$r[0]['account_email']; $account_email=$r[0]['account_email'];
if(! $r) { if(! $r) {
logger('account_remove: No account with id: ' . $account_id); logger('No account with id: ' . $account_id);
return false; return false;
} }
@ -2351,7 +2451,6 @@ function account_remove($account_id,$local = true,$unset_session = true) {
intval($account_id) intval($account_id)
); );
if ($unset_session) { if ($unset_session) {
App::$session->nuke(); App::$session->nuke();
notice( sprintf(t('Account \'%s\' deleted'),$account_email) . EOL); notice( sprintf(t('Account \'%s\' deleted'),$account_email) . EOL);
@ -2364,8 +2463,6 @@ function account_remove($account_id,$local = true,$unset_session = true) {
/** /**
* @brief Removes a channel. * @brief Removes a channel.
* *
* @hooks channel_remove
* * \e array \b entry from channel tabel for $channel_id
* @param int $channel_id * @param int $channel_id
* @param boolean $local default true * @param boolean $local default true
* @param boolean $unset_session default false * @param boolean $unset_session default false
@ -2386,6 +2483,11 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
$channel = $r[0]; $channel = $r[0];
/**
* @hooks channel_remove
* Called when removing a channel.
* * \e array with entry from channel tabel for $channel_id
*/
call_hooks('channel_remove', $r[0]); call_hooks('channel_remove', $r[0]);
if(! $local) { if(! $local) {
@ -2457,6 +2559,7 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
$rr = q("update account set account_default_channel = %d where account_id = %d", $rr = q("update account set account_default_channel = %d where account_id = %d",
intval($r[0]['channel_id']), intval($r[0]['channel_id']),
intval(App::$account['account_id'])); intval(App::$account['account_id']));
logger("Default channel deleted, changing default to channel_id " . $r[0]['channel_id']); logger("Default channel deleted, changing default to channel_id " . $r[0]['channel_id']);
} }
else { else {
@ -2531,20 +2634,30 @@ function channel_codeallowed($channel_id) {
return true; return true;
return false; return false;
} }
function anon_identity_init($reqvars) { function anon_identity_init($reqvars) {
$x = [ 'request_vars' => $reqvars, 'xchan' => null, 'success' => 'unset' ]; $x = [
call_hooks('anon_identity_init',$x); 'request_vars' => $reqvars,
'xchan' => null,
'success' => 'unset'
];
/**
* @hooks anon_identity_init
* * \e array \b request_vars
* * \e string \b xchan - return value
* * \e string|int \b success - Must be a number, so xchan return value gets used
*/
call_hooks('anon_identity_init', $x);
if($x['success'] !== 'unset' && intval($x['success']) && $x['xchan']) if($x['success'] !== 'unset' && intval($x['success']) && $x['xchan'])
return $x['xchan']; return $x['xchan'];
// allow a captcha handler to over-ride // allow a captcha handler to over-ride
if($x['success'] !== 'unset' && (intval($x['success']) === 0)) if($x['success'] !== 'unset' && (intval($x['success']) === 0))
return false; return false;
$anon_name = strip_tags(trim($reqvars['anonname'])); $anon_name = strip_tags(trim($reqvars['anonname']));
$anon_email = strip_tags(trim($reqvars['anonmail'])); $anon_email = strip_tags(trim($reqvars['anonmail']));
@ -2571,7 +2684,7 @@ function anon_identity_init($reqvars) {
); );
if(! $x) { if(! $x) {
xchan_store_lowlevel([ xchan_store_lowlevel([
'xchan_guid' => $anon_email, 'xchan_guid' => $anon_email,
'xchan_hash' => $hash, 'xchan_hash' => $hash,
'xchan_name' => $anon_name, 'xchan_name' => $anon_name,
@ -2579,7 +2692,7 @@ function anon_identity_init($reqvars) {
'xchan_network' => 'unknown', 'xchan_network' => 'unknown',
'xchan_name_date' => datetime_convert() 'xchan_name_date' => datetime_convert()
]); ]);
$x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1", $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1",
dbesc($anon_email), dbesc($anon_email),
@ -2597,13 +2710,18 @@ function anon_identity_init($reqvars) {
dbesc($anon_email), dbesc($anon_email),
dbesc($hash) dbesc($hash)
); );
} }
return $x[0]; return $x[0];
} }
/**
* @brief Create a channel array from proxy channel (pchan).
*
* @param array $pchan The proxy channel
* @return array channel array
*/
function pchan_to_chan($pchan) { function pchan_to_chan($pchan) {
$chan = $pchan; $chan = $pchan;
$chan['channel_address'] = $pchan['pchan_guid']; $chan['channel_address'] = $pchan['pchan_guid'];
@ -2611,5 +2729,7 @@ function pchan_to_chan($pchan) {
$chan['channel_pubkey'] = $pchan['pchan_pubkey']; $chan['channel_pubkey'] = $pchan['pchan_pubkey'];
$chan['channel_prvkey'] = $pchan['pchan_prvkey']; $chan['channel_prvkey'] = $pchan['pchan_prvkey'];
$chan['channel_name'] = $pchan['xchan_name']; $chan['channel_name'] = $pchan['xchan_name'];
return $chan; return $chan;
} }

View file

@ -8,6 +8,8 @@
/** /**
* @brief Two-level sort for timezones. * @brief Two-level sort for timezones.
* *
* Can be used in usort() to sort timezones.
*
* @param string $a * @param string $a
* @param string $b * @param string $b
* @return number * @return number
@ -27,13 +29,14 @@ function timezone_cmp($a, $b) {
function is_null_date($s) { function is_null_date($s) {
if($s === '0000-00-00 00:00:00' || $s === '0001-01-01 00:00:00') if($s === '0000-00-00 00:00:00' || $s === '0001-01-01 00:00:00')
return true; return true;
return false; return false;
} }
/** /**
* @brief Return timezones grouped (primarily) by continent. * @brief Return timezones grouped (primarily) by continent.
* *
* @see timezone_cmp()
* @return array * @return array
*/ */
function get_timezones( ){ function get_timezones( ){
@ -54,7 +57,7 @@ function get_timezones( ){
$city = $ex[0]; $city = $ex[0];
$continent = t('Miscellaneous'); $continent = t('Miscellaneous');
} }
$city = str_replace('_', ' ', t($city)); $city = str_replace('_', ' ', t($city));
if (!x($continents, $ex[0])) $continents[$ex[0]] = array(); if (!x($continents, $ex[0])) $continents[$ex[0]] = array();
$continents[$continent][$value] = $city; $continents[$continent][$value] = $city;
@ -109,7 +112,7 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
try { try {
$d = new DateTime($s, $from_obj); $d = new DateTime($s, $from_obj);
} catch(Exception $e) { } catch(Exception $e) {
logger('datetime_convert: exception: ' . $e->getMessage()); logger('exception: ' . $e->getMessage());
$d = new DateTime('now', $from_obj); $d = new DateTime('now', $from_obj);
} }
@ -128,7 +131,7 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
* @brief Wrapper for date selector, tailored for use in birthday fields. * @brief Wrapper for date selector, tailored for use in birthday fields.
* *
* @param string $dob Date of Birth * @param string $dob Date of Birth
* @return string * @return string Parsed HTML with selector
*/ */
function dob($dob) { function dob($dob) {
@ -161,59 +164,62 @@ function dob($dob) {
} }
/** /**
* returns a date selector * @brief Returns a date selector.
* @param $format *
* format string, e.g. 'ymd' or 'mdy'. Not currently supported * @see datetimesel()
* @param $min * @param string $format
* unix timestamp of minimum date * format string, e.g. 'ymd' or 'mdy'. Not currently supported
* @param $max * @param DateTime $min
* unix timestap of maximum date * unix timestamp of minimum date
* @param $default * @param DateTime $max
* unix timestamp of default date * unix timestap of maximum date
* @param $id * @param DateTime $default
* id and name of datetimepicker (defaults to "datetimepicker") * unix timestamp of default date
* @param string $id
* id and name of datetimepicker (defaults to "datetimepicker")
*/ */
function datesel($format, $min, $max, $default, $id = 'datepicker') { function datesel($format, $min, $max, $default, $id = 'datepicker') {
return datetimesel($format, $min, $max, $default, '', $id,true, false, '', ''); return datetimesel($format, $min, $max, $default, '', $id, true, false, '', '');
} }
/** /**
* returns a time selector * @brief Returns a time selector.
* @param $format *
* format string, e.g. 'ymd' or 'mdy'. Not currently supported * @param string $format
* @param $h * format string, e.g. 'ymd' or 'mdy'. Not currently supported
* already selected hour * @param string $h
* @param $m * already selected hour
* @param string $m
* already selected minute * already selected minute
* @param $id * @param string $id
* id and name of datetimepicker (defaults to "timepicker") * id and name of datetimepicker (defaults to "timepicker")
*/ */
function timesel($format, $h, $m, $id='timepicker') { function timesel($format, $h, $m, $id='timepicker') {
return datetimesel($format,new DateTime(),new DateTime(),new DateTime("$h:$m"),'', $id,false,true); return datetimesel($format, new DateTime(), new DateTime(), new DateTime("$h:$m"), '', $id, false, true);
} }
/** /**
* @brief Returns a datetime selector. * @brief Returns a datetime selector.
* *
* @param string $format * @param string $format
* format string, e.g. 'ymd' or 'mdy'. Not currently supported * format string, e.g. 'ymd' or 'mdy'. Not currently supported
* @param $min * @param DateTime $min
* unix timestamp of minimum date * unix timestamp of minimum date
* @param $max * @param DateTime $max
* unix timestap of maximum date * unix timestap of maximum date
* @param $default * @param DateTime $default
* unix timestamp of default date * unix timestamp of default date
* @param string $label * @param string $label
* @param string $id * @param string $id
* id and name of datetimepicker (defaults to "datetimepicker") * id and name of datetimepicker (defaults to "datetimepicker")
* @param boolean $pickdate * @param boolean $pickdate
* true to show date picker (default) * true to show date picker (default)
* @param boolean $picktime * @param boolean $picktime
* true to show time picker (default) * true to show time picker (default)
* @param $minfrom * @param DateTime $minfrom
* set minimum date from picker with id $minfrom (none by default) * set minimum date from picker with id $minfrom (none by default)
* @param $maxfrom * @param DateTime $maxfrom
* set maximum date from picker with id $maxfrom (none by default) * set maximum date from picker with id $maxfrom (none by default)
* @param boolean $required default false * @param boolean $required default false
* @param int $first_day (optional) default 0 * @param int $first_day (optional) default 0
* @return string Parsed HTML output. * @return string Parsed HTML output.
@ -343,9 +349,6 @@ function plural_dates($k,$n) {
} }
} }
/** /**
* @brief Returns timezone correct age in years. * @brief Returns timezone correct age in years.
* *
@ -418,7 +421,7 @@ function get_dim($y, $m) {
* *
* @param int $y Year * @param int $y Year
* @param int $m Month (1=January, 12=December) * @param int $m Month (1=January, 12=December)
* @return day 0 = Sunday through 6 = Saturday * @return string day 0 = Sunday through 6 = Saturday
*/ */
function get_first_dim($y, $m) { function get_first_dim($y, $m) {
$d = sprintf('%04d-%02d-01 00:00', intval($y), intval($m)); $d = sprintf('%04d-%02d-01 00:00', intval($y), intval($m));

View file

@ -1,15 +1,16 @@
<?php <?php
/**
* @file include/event.php
* @brief Event related functions.
*/
use Sabre\VObject; use Sabre\VObject;
/** /**
* @file include/event.php * @brief Returns an event as HTML.
*/
/**
* @brief Returns an event as HTML
* *
* @param array $ev * @param array $ev
* @return string * @return string HTML formatted event
*/ */
function format_event_html($ev) { function format_event_html($ev) {
@ -21,7 +22,7 @@ function format_event_html($ev) {
$bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8:01 AM $bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8:01 AM
//todo: move this to template /// @TODO move this to template
$o = '<div class="vevent">' . "\r\n"; $o = '<div class="vevent">' . "\r\n";
@ -29,27 +30,27 @@ function format_event_html($ev) {
$o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span>&nbsp;<span class="dtstart" title="' $o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span>&nbsp;<span class="dtstart" title="'
. datetime_convert('UTC', 'UTC', $ev['dtstart'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )) . datetime_convert('UTC', 'UTC', $ev['dtstart'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
. '" >' . '" >'
. (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
$ev['dtstart'] , $bd_format )) $ev['dtstart'] , $bd_format ))
: day_translate(datetime_convert('UTC', 'UTC', : day_translate(datetime_convert('UTC', 'UTC',
$ev['dtstart'] , $bd_format))) $ev['dtstart'] , $bd_format)))
. '</span></div>' . "\r\n"; . '</span></div>' . "\r\n";
if(! $ev['nofinish']) if(! $ev['nofinish'])
$o .= '<div class="event-end" ><span class="event-label">' . t('Finishes:') . '</span>&nbsp;<span class="dtend" title="' $o .= '<div class="event-end" ><span class="event-label">' . t('Finishes:') . '</span>&nbsp;<span class="dtend" title="'
. datetime_convert('UTC','UTC',$ev['dtend'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )) . datetime_convert('UTC','UTC',$ev['dtend'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
. '" >' . '" >'
. (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
$ev['dtend'] , $bd_format )) $ev['dtend'] , $bd_format ))
: day_translate(datetime_convert('UTC', 'UTC', : day_translate(datetime_convert('UTC', 'UTC',
$ev['dtend'] , $bd_format ))) $ev['dtend'] , $bd_format )))
. '</span></div>' . "\r\n"; . '</span></div>' . "\r\n";
$o .= '<div class="event-description">' . zidify_links(smilies(bbcode($ev['description']))) . '</div>' . "\r\n"; $o .= '<div class="event-description">' . zidify_links(smilies(bbcode($ev['description']))) . '</div>' . "\r\n";
if(strlen($ev['location'])) if(strlen($ev['location']))
$o .= '<div class="event-location"><span class="event-label"> ' . t('Location:') . '</span>&nbsp;<span class="location">' $o .= '<div class="event-location"><span class="event-label"> ' . t('Location:') . '</span>&nbsp;<span class="location">'
. zidify_links(smilies(bbcode($ev['location']))) . zidify_links(smilies(bbcode($ev['location'])))
. '</span></div>' . "\r\n"; . '</span></div>' . "\r\n";
@ -123,9 +124,9 @@ function format_event_ical($ev) {
$o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z'); $o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z');
$o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); $o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
$o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); $o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
if($ev['dtstart']) if($ev['dtstart'])
$o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['dtend'] && ! $ev['nofinish']) if($ev['dtend'] && ! $ev['nofinish'])
$o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); $o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['summary']) { if($ev['summary']) {
$o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']); $o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']);
@ -143,7 +144,7 @@ function format_event_ical($ev) {
$o .= "\r\nPRIORITY:" . intval($ev['event_priority']); $o .= "\r\nPRIORITY:" . intval($ev['event_priority']);
$o .= "\r\nUID:" . $ev['event_hash'] ; $o .= "\r\nUID:" . $ev['event_hash'] ;
$o .= "\r\nEND:VEVENT\r\n"; $o .= "\r\nEND:VEVENT\r\n";
return $o; return $o;
} }
@ -156,9 +157,9 @@ function format_todo_ical($ev) {
$o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z'); $o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z');
$o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); $o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
$o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); $o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
if($ev['dtstart']) if($ev['dtstart'])
$o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['dtend'] && ! $ev['nofinish']) if($ev['dtend'] && ! $ev['nofinish'])
$o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); $o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['summary']) { if($ev['summary']) {
$o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']); $o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']);
@ -170,8 +171,8 @@ function format_todo_ical($ev) {
$o .= "\r\nCOMPLETED:" . datetime_convert('UTC','UTC', $ev['event_status_date'],'Ymd\\THis\\Z'); $o .= "\r\nCOMPLETED:" . datetime_convert('UTC','UTC', $ev['event_status_date'],'Ymd\\THis\\Z');
} }
if(intval($ev['event_percent'])) if(intval($ev['event_percent']))
$o .= "\r\nPERCENT-COMPLETE:" . $ev['event_percent']; $o .= "\r\nPERCENT-COMPLETE:" . $ev['event_percent'];
if(intval($ev['event_sequence'])) if(intval($ev['event_sequence']))
$o .= "\r\nSEQUENCE:" . $ev['event_sequence']; $o .= "\r\nSEQUENCE:" . $ev['event_sequence'];
if($ev['location']) { if($ev['location']) {
$o .= "\r\nLOCATION:" . format_ical_text($ev['location']); $o .= "\r\nLOCATION:" . format_ical_text($ev['location']);
@ -196,12 +197,13 @@ function format_ical_text($s) {
$s = html2plain(bbcode($s)); $s = html2plain(bbcode($s));
$s = str_replace(["\r\n","\n"],["",""],$s); $s = str_replace(["\r\n","\n"],["",""],$s);
return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
} }
function format_ical_sourcetext($s) { function format_ical_sourcetext($s) {
$s = base64_encode($s); $s = base64_encode($s);
return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true)); return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
} }
@ -225,7 +227,7 @@ function format_event_bbcode($ev) {
if(($ev['dtend']) && (! $ev['nofinish'])) if(($ev['dtend']) && (! $ev['nofinish']))
$o .= '[event-finish]' . $ev['dtend'] . '[/event-finish]'; $o .= '[event-finish]' . $ev['dtend'] . '[/event-finish]';
if($ev['location']) if($ev['location'])
$o .= '[event-location]' . $ev['location'] . '[/event-location]'; $o .= '[event-location]' . $ev['location'] . '[/event-location]';
@ -253,7 +255,6 @@ function bbtoevent($s) {
$ev = array(); $ev = array();
$match = ''; $match = '';
if(preg_match("/\[event\](.*?)\[\/event\]/is",$s,$match)) { if(preg_match("/\[event\](.*?)\[\/event\]/is",$s,$match)) {
// only parse one object per event tag // only parse one object per event tag
@ -306,7 +307,7 @@ function bbtoevent($s) {
* *
* @see ev_compare() * @see ev_compare()
* @param array $arr * @param array $arr
* @return sorted array * @return array Date sorted array of events
*/ */
function sort_by_date($arr) { function sort_by_date($arr) {
if (is_array($arr)) if (is_array($arr))
@ -318,6 +319,8 @@ function sort_by_date($arr) {
/** /**
* @brief Compare function for events. * @brief Compare function for events.
* *
* This function can be used in usort() to sort events by date.
*
* @see sort_by_date() * @see sort_by_date()
* @param array $a * @param array $a
* @param array $b * @param array $b
@ -375,8 +378,19 @@ function event_store_event($arr) {
} }
} }
$hook_info = [ 'event' => $arr, 'existing_event' => $existing_event, 'cancel' => false ]; $hook_info = [
call_hooks('event_store_event',$hook_info); 'event' => $arr,
'existing_event' => $existing_event,
'cancel' => false
];
/**
* @hooks event_store_event
* Called when an event record is created or updated.
* * \e array \b event
* * \e array \b existing_event
* * \e boolean \b cancel - default false
*/
call_hooks('event_store_event', $hook_info);
if($hook_info['cancel']) if($hook_info['cancel'])
return false; return false;
@ -386,7 +400,7 @@ function event_store_event($arr) {
if($existing_event) { if($existing_event) {
if($existing_event['edited'] >= $arr['edited']) { if($existing_event['edited'] >= $arr['edited']) {
// Nothing has changed. // Nothing has changed.
return $existing_event; return $existing_event;
} }
@ -444,7 +458,6 @@ function event_store_event($arr) {
// New event. Store it. // New event. Store it.
if(array_key_exists('external_id',$arr)) if(array_key_exists('external_id',$arr))
$hash = $arr['external_id']; $hash = $arr['external_id'];
elseif(array_key_exists('event_hash',$arr)) elseif(array_key_exists('event_hash',$arr))
@ -531,7 +544,7 @@ function event_addtocal($item_id, $uid) {
} }
if($ev->private) if($ev->private)
$ev['allow_cid'] = '<' . $channel['channel_hash'] . '>'; $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
else { else {
$acl = new Zotlabs\Access\AccessList($channel); $acl = new Zotlabs\Access\AccessList($channel);
$x = $acl->get(); $x = $acl->get();
@ -596,14 +609,12 @@ function ical_to_ev($s) {
date_default_timezone_set($saved_timezone); date_default_timezone_set($saved_timezone);
return $ev; return $ev;
} }
function parse_vobject($ical, $type) { function parse_vobject($ical, $type) {
$ev = []; $ev = [];
if(! isset($ical->DTSTART)) { if(! isset($ical->DTSTART)) {
@ -698,10 +709,8 @@ function parse_vobject($ical, $type) {
function parse_ical_file($f,$uid) { function parse_ical_file($f,$uid) {
require_once('vendor/autoload.php'); require_once('vendor/autoload.php');
$s = @file_get_contents($f); $s = @file_get_contents($f);
@ -731,6 +740,7 @@ require_once('vendor/autoload.php');
if($ical) if($ical)
return true; return true;
return false; return false;
} }
@ -779,7 +789,6 @@ function event_import_ical($ical, $uid) {
$ev['created'] = datetime_convert('UTC','UTC',$created->format(\DateTime::W3C)); $ev['created'] = datetime_convert('UTC','UTC',$created->format(\DateTime::W3C));
} }
if(isset($ical->{'LAST-MODIFIED'})) { if(isset($ical->{'LAST-MODIFIED'})) {
$edited = $ical->{'LAST-MODIFIED'}->getDateTime(); $edited = $ical->{'LAST-MODIFIED'}->getDateTime();
$ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C)); $ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C));
@ -814,7 +823,7 @@ function event_import_ical($ical, $uid) {
else else
$ev['external_id'] = $evuid; $ev['external_id'] = $evuid;
} }
if($ev['summary'] && $ev['dtstart']) { if($ev['summary'] && $ev['dtstart']) {
$ev['event_xchan'] = $channel['channel_hash']; $ev['event_xchan'] = $channel['channel_hash'];
$ev['uid'] = $channel['channel_id']; $ev['uid'] = $channel['channel_id'];
@ -822,7 +831,7 @@ function event_import_ical($ical, $uid) {
$ev['private'] = 1; $ev['private'] = 1;
$ev['allow_cid'] = '<' . $channel['channel_hash'] . '>'; $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
logger('storing event: ' . print_r($ev,true), LOGGER_ALL); logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev); $event = event_store_event($ev);
if($event) { if($event) {
$item_id = event_store_item($ev,$event); $item_id = event_store_item($ev,$event);
@ -831,7 +840,6 @@ function event_import_ical($ical, $uid) {
} }
return false; return false;
} }
function event_ical_get_sourcetext($s) { function event_ical_get_sourcetext($s) {
@ -931,7 +939,7 @@ function event_import_ical_task($ical, $uid) {
if(isset($ical->SEQUENCE)) { if(isset($ical->SEQUENCE)) {
$ev['event_sequence'] = (string) $ical->SEQUENCE; $ev['event_sequence'] = (string) $ical->SEQUENCE;
// see if our stored event is more current than the one we're importing // see if our stored event is more current than the one we're importing
if((intval($ev['event_sequence']) <= intval($stored_event['event_sequence'])) if((intval($ev['event_sequence']) <= intval($stored_event['event_sequence']))
&& ($ev['edited'] <= $stored_event['edited'])) && ($ev['edited'] <= $stored_event['edited']))
return false; return false;
} }
@ -958,7 +966,7 @@ function event_import_ical_task($ical, $uid) {
$ev['private'] = 1; $ev['private'] = 1;
$ev['allow_cid'] = '<' . $channel['channel_hash'] . '>'; $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
logger('storing event: ' . print_r($ev,true), LOGGER_ALL); logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev); $event = event_store_event($ev);
if($event) { if($event) {
$item_id = event_store_item($ev,$event); $item_id = event_store_item($ev,$event);
@ -967,14 +975,10 @@ function event_import_ical_task($ical, $uid) {
} }
return false; return false;
} }
function event_store_item($arr, $event) { function event_store_item($arr, $event) {
require_once('include/datetime.php'); require_once('include/datetime.php');
@ -995,7 +999,6 @@ function event_store_item($arr, $event) {
} }
$item_arr = array(); $item_arr = array();
$prefix = ''; $prefix = '';
// $birthday = false; // $birthday = false;
@ -1008,9 +1011,9 @@ function event_store_item($arr, $event) {
$prefix = t('This event has been added to your calendar.'); $prefix = t('This event has been added to your calendar.');
// $birthday = true; // $birthday = true;
// The event is created on your own site by the system, but appears to belong // The event is created on your own site by the system, but appears to belong
// to the birthday person. It also isn't propagated - so we need to prevent // to the birthday person. It also isn't propagated - so we need to prevent
// folks from trying to comment on it. If you're looking at this and trying to // folks from trying to comment on it. If you're looking at this and trying to
// fix it, you'll need to completely change the way birthday events are created // fix it, you'll need to completely change the way birthday events are created
// and send them out from the source. This has its own issues. // and send them out from the source. This has its own issues.
@ -1048,9 +1051,10 @@ function event_store_item($arr, $event) {
$private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0); $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
// @FIXME can only update sig if we have the author's channel on this site /**
// Until fixed, set it to nothing so it won't give us signature errors * @FIXME can only update sig if we have the author's channel on this site
* Until fixed, set it to nothing so it won't give us signature errors.
*/
$sig = ''; $sig = '';
q("UPDATE item SET title = '%s', body = '%s', obj = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d", q("UPDATE item SET title = '%s', body = '%s', obj = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d",
@ -1090,6 +1094,10 @@ function event_store_item($arr, $event) {
} }
$item_id = $r[0]['id']; $item_id = $r[0]['id'];
/**
* @hooks event_updated
* Called when an event record is modified.
*/
call_hooks('event_updated', $event['id']); call_hooks('event_updated', $event['id']);
return $item_id; return $item_id;
@ -1103,7 +1111,7 @@ function event_store_item($arr, $event) {
$item_wall = 0; $item_wall = 0;
$item_origin = 0; $item_origin = 0;
$item_thread_top = 0; $item_thread_top = 0;
if($item) { if($item) {
$item_arr['id'] = $item['id']; $item_arr['id'] = $item['id'];
@ -1196,6 +1204,10 @@ function event_store_item($arr, $event) {
$item_id = $res['item_id']; $item_id = $res['item_id'];
/**
* @hooks event_created
* Called when an event record is created.
*/
call_hooks('event_created', $event['id']); call_hooks('event_created', $event['id']);
return $item_id; return $item_id;
@ -1216,25 +1228,24 @@ function todo_stat() {
function tasks_fetch($arr) { function tasks_fetch($arr) {
if(! local_channel()) if(! local_channel())
return; return;
$ret = array(); $ret = array();
$sql_extra = " and event_status != 'COMPLETED' "; $sql_extra = " and event_status != 'COMPLETED' ";
if($arr && $arr['all'] == 1) if($arr && $arr['all'] == 1)
$sql_extra = ''; $sql_extra = '';
$r = q("select * from event where etype = 'task' and uid = %d $sql_extra order by created desc", $r = q("select * from event where etype = 'task' and uid = %d $sql_extra order by created desc",
intval(local_channel()) intval(local_channel())
); );
$ret['success'] = (($r) ? true : false); $ret['success'] = (($r) ? true : false);
if($r) { if($r) {
$ret['tasks'] = $r; $ret['tasks'] = $r;
} }
return $ret; return $ret;
} }
function cdav_principal($uri) { function cdav_principal($uri) {

View file

@ -1,5 +1,8 @@
<?php <?php
/**
* @file include/feedutils.php
* @brief Some functions to work with XML feeds.
*/
/** /**
* @brief Return an Atom feed for channel. * @brief Return an Atom feed for channel.
@ -57,7 +60,6 @@ function get_public_feed($channel, $params) {
* @param array $params * @param array $params
* @return string with an atom feed * @return string with an atom feed
*/ */
function get_feed_for($channel, $observer_hash, $params) { function get_feed_for($channel, $observer_hash, $params) {
if(! $channel) if(! $channel)
@ -105,12 +107,28 @@ function get_feed_for($channel, $observer_hash, $params) {
)); ));
$x = [ 'xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params ]; $x = [
call_hooks('atom_feed_top',$x); 'xml' => $atom,
'channel' => $channel,
'observer_hash' => $observer_hash,
'params' => $params
];
/**
* @hooks atom_feed_top
* * \e string \b xml - the generated feed and what will get returned from the hook
* * \e array \b channel
* * \e string \b observer_hash
* * \e array \b params
*/
call_hooks('atom_feed_top', $x);
$atom = $x['xml']; $atom = $x['xml'];
// a much simpler interface /**
* @hooks atom_feed
* A much simpler interface than atom_feed_top.
* * \e string - the feed after atom_feed_top hook
*/
call_hooks('atom_feed', $atom); call_hooks('atom_feed', $atom);
$items = items_fetch( $items = items_fetch(
@ -135,11 +153,14 @@ function get_feed_for($channel, $observer_hash, $params) {
if($item['item_private']) if($item['item_private'])
continue; continue;
/** @BUG $owner is undefined in this call */
$atom .= atom_entry($item, $type, null, $owner, true, '', $params['compat']); $atom .= atom_entry($item, $type, null, $owner, true, '', $params['compat']);
} }
} }
/**
* @hooks atom_feed_end
* \e string - The created XML feed as a string without closing tag
*/
call_hooks('atom_feed_end', $atom); call_hooks('atom_feed_end', $atom);
$atom .= '</feed>' . "\r\n"; $atom .= '</feed>' . "\r\n";
@ -344,6 +365,7 @@ function get_atom_elements($feed, $item, &$author) {
} }
} }
// check for a yahoo media element (github etc.) // check for a yahoo media element (github etc.)
if(! $author['author_photo']) { if(! $author['author_photo']) {
@ -356,7 +378,6 @@ function get_atom_elements($feed, $item, &$author) {
// No photo/profile-link on the item - look at the feed level // No photo/profile-link on the item - look at the feed level
if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) { if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
$rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author'); $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
@ -396,7 +417,7 @@ function get_atom_elements($feed, $item, &$author) {
// new style // new style
$ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['attribs']['']['ref'])); $ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['attribs']['']['ref']));
if(! $ostatus_conversation) { if(! $ostatus_conversation) {
// old style // old style
$ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['data'])); $ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['data']));
} }
if($ostatus_conversation) { if($ostatus_conversation) {
@ -406,7 +427,7 @@ function get_atom_elements($feed, $item, &$author) {
} }
$ostatus_protocol = (($ostatus_conversation) ? true : false); $ostatus_protocol = (($ostatus_conversation) ? true : false);
$mastodon = (($item->get_item_tags('http://mastodon.social/schema/1.0','scope')) ? true : false); $mastodon = (($item->get_item_tags('http://mastodon.social/schema/1.0','scope')) ? true : false);
if($mastodon) { if($mastodon) {
$ostatus_protocol = true; $ostatus_protocol = true;
@ -645,7 +666,7 @@ function get_atom_elements($feed, $item, &$author) {
$res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title ); $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title );
} }
} }
$rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object'); $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
@ -723,7 +744,6 @@ function get_atom_elements($feed, $item, &$author) {
$res['target'] = $obj; $res['target'] = $obj;
} }
if(array_key_exists('verb',$res) && $res['verb'] === ACTIVITY_SHARE if(array_key_exists('verb',$res) && $res['verb'] === ACTIVITY_SHARE
&& array_key_exists('obj_type',$res) && in_array($res['obj_type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_COMMENT, ACTIVITY_OBJ_ACTIVITY ] )) { && array_key_exists('obj_type',$res) && in_array($res['obj_type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_COMMENT, ACTIVITY_OBJ_ACTIVITY ] )) {
@ -737,7 +757,13 @@ function get_atom_elements($feed, $item, &$author) {
'author' => $author, 'author' => $author,
'result' => $res 'result' => $res
]; ];
/**
* @hooks parse_atom
* * \e SimplePie \b feed - The original SimplePie feed
* * \e array \b item
* * \e array \b author
* * \e array \b result - the result array that will also get returned
*/
call_hooks('parse_atom', $arr); call_hooks('parse_atom', $arr);
logger('author: ' .print_r($arr['author'], true), LOGGER_DATA); logger('author: ' .print_r($arr['author'], true), LOGGER_DATA);
@ -782,7 +808,7 @@ function feed_get_reshare(&$res,$item) {
$share['avatar'] = z_root() . '/' . get_default_profile_photo(80); $share['avatar'] = z_root() . '/' . get_default_profile_photo(80);
if(! $share['profile']) if(! $share['profile'])
$share['profile'] = z_root(); $share['profile'] = z_root();
$child = $rawobj[0]['child']; $child = $rawobj[0]['child'];
@ -809,7 +835,7 @@ function feed_get_reshare(&$res,$item) {
$body = html2bbcode($body); $body = html2bbcode($body);
} }
} }
$attach = $share['links']; $attach = $share['links'];
if($attach) { if($attach) {
@ -845,16 +871,16 @@ function feed_get_reshare(&$res,$item) {
} }
} }
} }
if((! $body) && ($share['alternate'])) { if((! $body) && ($share['alternate'])) {
$body = $share['alternate']; $body = $share['alternate'];
} }
$res['body'] = "[share author='" . urlencode($share['author']) . $res['body'] = "[share author='" . urlencode($share['author']) .
"' profile='" . $share['profile'] . "' profile='" . $share['profile'] .
"' avatar='" . $share['avatar'] . "' avatar='" . $share['avatar'] .
"' link='" . $share['alternate'] . "' link='" . $share['alternate'] .
"' posted='" . $share['created'] . "' posted='" . $share['created'] .
"' message_id='" . $share['message_id'] . "']"; "' message_id='" . $share['message_id'] . "']";
$res['body'] .= $body; $res['body'] .= $body;
@ -864,7 +890,6 @@ function feed_get_reshare(&$res,$item) {
} }
/** /**
* @brief Encodes SimplePie_Item link arrays. * @brief Encodes SimplePie_Item link arrays.
* *
@ -940,7 +965,7 @@ function process_feed_tombstones($feed,$importer,$contact,$pass) {
* *
* @param string $xml * @param string $xml
* The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds. * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
* @param $importer * @param array $importer
* The contact_record (joined to user_record) of the local user who owns this * 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. * relationship. It is this person's stuff that is going to be updated.
* @param[in,out] array $contact * @param[in,out] array $contact
@ -1103,7 +1128,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Update content if 'updated' changes // Update content if 'updated' changes
if($r) { if($r) {
if(activity_match($datarray['verb'],ACTIVITY_DELETE) if(activity_match($datarray['verb'],ACTIVITY_DELETE)
&& $datarray['author_xchan'] === $r[0]['author_xchan']) { && $datarray['author_xchan'] === $r[0]['author_xchan']) {
if(! intval($r[0]['item_deleted'])) { if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG); logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
@ -1147,6 +1172,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$datarray['parent_mid'] = $pmid; $datarray['parent_mid'] = $pmid;
} }
} }
if(($item_parent_mid) && (! $pmid)) { if(($item_parent_mid) && (! $pmid)) {
logger('find_parent: matched in-reply-to: ' . $parent_mid, LOGGER_DEBUG); logger('find_parent: matched in-reply-to: ' . $parent_mid, LOGGER_DEBUG);
$pmid = $item_parent_mid[0]['parent_mid']; $pmid = $item_parent_mid[0]['parent_mid'];
@ -1172,7 +1198,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
dbesc($parent_mid), dbesc($parent_mid),
intval($importer['channel_id']) intval($importer['channel_id'])
); );
if($x) { if($x) {
$item_parent_mid = $x; $item_parent_mid = $x;
$pmid = $x[0]['parent_mid']; $pmid = $x[0]['parent_mid'];
@ -1205,7 +1231,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
); );
if($r) { if($r) {
$parent_item = $r[0]; $parent_item = $r[0];
if(intval($parent_item['item_nocomment']) || $parent_item['comment_policy'] === 'none' if(intval($parent_item['item_nocomment']) || $parent_item['comment_policy'] === 'none'
|| ($parent_item['comments_closed'] > NULL_DATE && $parent_item['comments_closed'] < datetime_convert())) { || ($parent_item['comments_closed'] > NULL_DATE && $parent_item['comments_closed'] < datetime_convert())) {
logger('comments disabled for post ' . $parent_item['mid']); logger('comments disabled for post ' . $parent_item['mid']);
continue; continue;
@ -1215,7 +1241,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$allowed = false; $allowed = false;
if($parent_item) { if($parent_item) {
if($parent_item['owner_xchan'] == $importer['channel_hash']) if($parent_item['owner_xchan'] == $importer['channel_hash'])
$allowed = perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments'); $allowed = perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments');
else else
$allowed = true; $allowed = true;
@ -1230,16 +1256,17 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// interactive feeds (such as OStatus) downstream to our followers // interactive feeds (such as OStatus) downstream to our followers
// We do not want to set it for non-interactive feeds or conversations we do not own // We do not want to set it for non-interactive feeds or conversations we do not own
if(array_key_exists('send_downstream',$importer) && intval($importer['send_downstream']) if(array_key_exists('send_downstream',$importer) && intval($importer['send_downstream'])
&& ($parent_item['owner_xchan'] == $importer['channel_hash'])) { && ($parent_item['owner_xchan'] == $importer['channel_hash'])) {
$send_downstream = true; $send_downstream = true;
} }
} }
else { else {
if((! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $importer['system'])) { if((! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $importer['system'])) {
// @fixme check for and process ostatus autofriend /**
// otherwise * @fixme check for and process ostatus autofriend
* otherwise ignore this author.
*/
logger('Ignoring this author.'); logger('Ignoring this author.');
continue; continue;
} }
@ -1249,13 +1276,13 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// immediate parent wasn't found. Turn into a top-level post if permissions allow // immediate parent wasn't found. Turn into a top-level post if permissions allow
// but save the thread_parent in case we need to refer to it later. // but save the thread_parent in case we need to refer to it later.
if(! post_is_importable($datarray, $contact)) if(! post_is_importable($datarray, $contact))
continue; continue;
$datarray['parent_mid'] = $datarray['mid']; $datarray['parent_mid'] = $datarray['mid'];
set_iconfig($datarray,'system','parent_mid',$parent_mid,true); set_iconfig($datarray,'system','parent_mid',$parent_mid,true);
} }
// allow likes of comments // allow likes of comments
@ -1306,7 +1333,6 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
} }
// if we have everything but a photo, provide the default profile photo // if we have everything but a photo, provide the default profile photo
if($author['author_name'] && $author['author_link'] && (! $author['author_photo'])) if($author['author_name'] && $author['author_link'] && (! $author['author_photo']))
@ -1364,7 +1390,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Update content if 'updated' changes // Update content if 'updated' changes
if($r) { if($r) {
if(activity_match($datarray['verb'],ACTIVITY_DELETE) if(activity_match($datarray['verb'],ACTIVITY_DELETE)
&& $datarray['author_xchan'] === $r[0]['author_xchan']) { && $datarray['author_xchan'] === $r[0]['author_xchan']) {
if(! intval($r[0]['item_deleted'])) { if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG); logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
@ -1426,12 +1452,12 @@ function feed_conversation_fetch($importer,$contact,$parent_link) {
// GNU-Social flavoured feeds // GNU-Social flavoured feeds
if(strpos($parent_link,'/notice/')) { if(strpos($parent_link,'/notice/')) {
$link = str_replace('/notice/','/api/statuses/show/',$parent_link) . '.atom'; $link = str_replace('/notice/','/api/statuses/show/',$parent_link) . '.atom';
} }
// Mastodon flavoured feeds // Mastodon flavoured feeds
if(strpos($parent_link,'/users/') && strpos($parent_link,'/updates/')) { if(strpos($parent_link,'/users/') && strpos($parent_link,'/updates/')) {
$link = $parent_link . '.atom'; $link = $parent_link . '.atom';
} }
if(! $link) if(! $link)
return false; return false;
@ -1446,21 +1472,21 @@ function feed_conversation_fetch($importer,$contact,$parent_link) {
$data = $fetch['body']; $data = $fetch['body'];
// We will probably receive an atom 'entry' and not an atom 'feed'. Unfortunately // We will probably receive an atom 'entry' and not an atom 'feed'. Unfortunately
// our parser is a bit strict about compliance so we'll insert just enough of a feed // our parser is a bit strict about compliance so we'll insert just enough of a feed
// tag to trick it into believing it's a compliant feed. // tag to trick it into believing it's a compliant feed.
if(! strstr($data,'<feed')) { if(! strstr($data,'<feed')) {
$data = str_replace('<entry ','<feed xmlns="http://www.w3.org/2005/Atom"><entry ',$data); $data = str_replace('<entry ','<feed xmlns="http://www.w3.org/2005/Atom"><entry ',$data);
$data .= '</feed>'; $data .= '</feed>';
} }
consume_feed($data,$importer,$contact,1); consume_feed($data,$importer,$contact,1);
consume_feed($data,$importer,$contact,2); consume_feed($data,$importer,$contact,2);
return true; return true;
} }
/** /**
* @brief Normalise an id. * @brief Normalise an id.
* *
@ -1479,7 +1505,7 @@ function normalise_id($id) {
* *
* @param string $xml * @param string $xml
* The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds. * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
* @param $importer * @param array $importer (unused)
* The contact_record (joined to user_record) of the local user who owns this * 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. * relationship. It is this person's stuff that is going to be updated.
*/ */
@ -1617,6 +1643,7 @@ function feed_meta($xml) {
return $ret; return $ret;
} }
/** /**
* @brief Not yet implemented function to update feed item. * @brief Not yet implemented function to update feed item.
* *
@ -1627,6 +1654,7 @@ function update_feed_item($uid, $datarray) {
item_store_update($datarray); item_store_update($datarray);
} }
/** /**
* @brief Fetch the content of a feed and further consume it. * @brief Fetch the content of a feed and further consume it.
* *
@ -1659,6 +1687,7 @@ function handle_feed($uid, $abook_id, $url) {
} }
} }
/** /**
* @brief Return a XML tag with author information. * @brief Return a XML tag with author information.
* *
@ -1695,8 +1724,8 @@ function atom_author($tag, $nick, $name, $uri, $h, $w, $type, $photo) {
/** /**
* @hooks atom_author * @hooks atom_author
* Possibility to add further tags to returned XML string. * Possibility to add further tags to returned XML string
* * \e string The created XML tag as a string without closing tag * * \e string - The created XML tag as a string without closing tag
*/ */
call_hooks('atom_author', $o); call_hooks('atom_author', $o);
@ -1752,7 +1781,7 @@ function compat_photos_list($s) {
$found = preg_match_all('/\[[zi]mg(.*?)\](.*?)\[/ism',$s,$matches,PREG_SET_ORDER); $found = preg_match_all('/\[[zi]mg(.*?)\](.*?)\[/ism',$s,$matches,PREG_SET_ORDER);
if($found) { if($found) {
foreach($matches as $match) { foreach($matches as $match) {
$ret[] = [ $ret[] = [
'href' => $match[2], 'href' => $match[2],
'length' => 0, 'length' => 0,
@ -1766,7 +1795,6 @@ function compat_photos_list($s) {
} }
/** /**
* @brief Create an item for the Atom feed. * @brief Create an item for the Atom feed.
* *
@ -1778,11 +1806,11 @@ function compat_photos_list($s) {
* @param array $owner * @param array $owner
* @param string $comment default false * @param string $comment default false
* @param number $cid default 0 * @param number $cid default 0
* @param boolean $compat default false
* @return void|string * @return void|string
*/ */
function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $compat = false) { function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $compat = false) {
if(! $item['parent']) if(! $item['parent'])
return; return;
@ -1934,9 +1962,17 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $
'abook_id' => $cid, 'abook_id' => $cid,
'entry' => $o 'entry' => $o
]; ];
/**
* @hooks atom_entry
* * \e array \b item
* * \e string \b type
* * \e array \b author
* * \e array \b owner
* * \e string \b comment
* * \e number \b abook_id
* * \e string \b entry - The generated entry and what will get returned
*/
call_hooks('atom_entry', $x); call_hooks('atom_entry', $x);
return $x['entry']; return $x['entry'];
} }

View file

@ -1,6 +1,7 @@
<?php <?php
/** /**
* @file include/items.php * @file include/items.php
* @brief Items related functions.
*/ */
use Zotlabs\Lib as Zlib; use Zotlabs\Lib as Zlib;
@ -208,7 +209,7 @@ function is_item_normal($item) {
} }
/** /**
* @brief * @brief Decide if current observer has sufficient privileges to comment on item.
* *
* This function examines the comment_policy attached to an item and decides if the current observer has * This function examines the comment_policy attached to an item and decides if the current observer has
* sufficient privileges to comment. This will normally be called on a remote site where perm_is_allowed() * sufficient privileges to comment. This will normally be called on a remote site where perm_is_allowed()
@ -224,10 +225,20 @@ function is_item_normal($item) {
*/ */
function can_comment_on_post($observer_xchan, $item) { function can_comment_on_post($observer_xchan, $item) {
// logger('can_comment_on_post: comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG); // logger('Comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
$x = [ 'observer_hash' => $observer_xchan, 'item' => $item, 'allowed' => 'unset' ]; $x = [
call_hooks('can_comment_on_post',$x); 'observer_hash' => $observer_xchan,
'item' => $item,
];
/**
* @hooks can_comment_on_post
* Called when deciding whether or not to present a comment box for a post.
* * \e string \b observer_hash
* * \e array \b item
* * \e boolean \b allowed - return value
*/
call_hooks('can_comment_on_post', $x);
if($x['allowed'] !== 'unset') if($x['allowed'] !== 'unset')
return $x['allowed']; return $x['allowed'];
@ -386,10 +397,14 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$_REQUEST['api_source'] = 1; $_REQUEST['api_source'] = 1;
call_hooks('post_local',$arr); /**
* @hooks post_local
* Called when an item has been posted on this machine via mod/item.php (also via API).
*/
call_hooks('post_local', $arr);
if(x($arr,'cancel')) { if(x($arr, 'cancel')) {
logger('post_activity_item: post cancelled by plugin.'); logger('Post cancelled by plugin.');
return $ret; return $ret;
} }
@ -400,6 +415,12 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$ret['success'] = true; $ret['success'] = true;
$ret['item_id'] = $post_id; $ret['item_id'] = $post_id;
$ret['activity'] = $post['item']; $ret['activity'] = $post['item'];
/**
* @hooks post_local_end
* Called after a local post operation has completed.
* * \e array - the item returned from item_store()
*/
call_hooks('post_local_end', $ret['activity']); call_hooks('post_local_end', $ret['activity']);
} }
@ -407,8 +428,8 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id)); Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id));
} }
$ret['success'] = true; $ret['success'] = true;
return $ret; return $ret;
} }
@ -430,7 +451,6 @@ function validate_item_elements($message,$arr) {
$result['success'] = true; $result['success'] = true;
return $result; return $result;
} }
@ -469,7 +489,7 @@ function limit_body_size($body) {
if( ($textlen + $img_start) > $maxlen ) { if( ($textlen + $img_start) > $maxlen ) {
if($textlen < $maxlen) { if($textlen < $maxlen) {
logger('limit_body_size: the limit happens before an embedded image', LOGGER_DEBUG); logger('The limit happens before an embedded image', LOGGER_DEBUG);
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen); $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen; $textlen = $maxlen;
} }
@ -799,8 +819,17 @@ function get_item_elements($x,$allow_code = false) {
function import_author_xchan($x) { function import_author_xchan($x) {
$arr = array('xchan' => $x, 'xchan_hash' => ''); $arr = [
call_hooks('import_author_xchan',$arr); 'xchan' => $x,
'xchan_hash' => ''
];
/**
* @hooks import_author_xchan
* Called when looking up an author of a post by xchan_hash to ensure they have an xchan record on our site.
* * \e array \b xchan
* * \e string \b xchan_hash - Thre returned value
*/
call_hooks('import_author_xchan', $arr);
if($arr['xchan_hash']) if($arr['xchan_hash'])
return $arr['xchan_hash']; return $arr['xchan_hash'];
@ -823,7 +852,6 @@ function import_author_xchan($x) {
} }
return($y); return($y);
} }
/** /**
@ -835,7 +863,6 @@ function import_author_xchan($x) {
* * \e string \b guid * * \e string \b guid
* @return boolean|string * @return boolean|string
*/ */
function import_author_rss($x) { function import_author_rss($x) {
if(! $x['url']) if(! $x['url'])
return false; return false;
@ -844,7 +871,7 @@ function import_author_rss($x) {
dbesc($x['url']) dbesc($x['url'])
); );
if($r) { if($r) {
logger('import_author_rss: in cache' , LOGGER_DEBUG); logger('In cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash']; return $r[0]['xchan_hash'];
} }
$name = trim($x['name']); $name = trim($x['name']);
@ -883,7 +910,15 @@ function import_author_rss($x) {
function import_author_unknown($x) { function import_author_unknown($x) {
$arr = [ 'author' => $x, 'result' => false ]; $arr = [
'author' => $x,
'result' => false
];
/**
* @hooks import_author
* * \e array \b author
* * \e boolean|string \b result - Return value, default false
*/
call_hooks('import_author', $arr); call_hooks('import_author', $arr);
if($arr['result']) if($arr['result'])
return $arr['result']; return $arr['result'];
@ -895,7 +930,7 @@ function import_author_unknown($x) {
dbesc($x['url']) dbesc($x['url'])
); );
if($r) { if($r) {
logger('import_author_unknown: in cache' , LOGGER_DEBUG); logger('In cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash']; return $r[0]['xchan_hash'];
} }
@ -1469,8 +1504,11 @@ function get_profile_elements($x) {
} }
/**
* @brief Signs an item body.
*
* @param[in,out] array $item
*/
function item_sign(&$item) { function item_sign(&$item) {
if(array_key_exists('sig',$item) && $item['sig']) if(array_key_exists('sig',$item) && $item['sig'])
@ -1483,14 +1521,13 @@ function item_sign(&$item) {
if(! $r) if(! $r)
return; return;
$item['sig'] = base64url_encode(rsa_sign($item['body'],$r[0]['channel_prvkey'])); $item['sig'] = base64url_encode(rsa_sign($item['body'], $r[0]['channel_prvkey']));
$item['item_verified'] = 1; $item['item_verified'] = 1;
} }
/** /**
* @brief * @brief Stores an item type record.
* *
* @param array $arr * @param array $arr
* @param boolean $allow_exec (optional) default false * @param boolean $allow_exec (optional) default false
@ -1502,8 +1539,17 @@ function item_sign(&$item) {
*/ */
function item_store($arr, $allow_exec = false, $deliver = true) { function item_store($arr, $allow_exec = false, $deliver = true) {
$d = array('item' => $arr, 'allow_exec' => $allow_exec); $d = [
call_hooks('item_store', $d ); 'item' => $arr,
'allow_exec' => $allow_exec
];
/**
* @hooks item_store
* Called when item_store() stores a record of type item.
* * \e array \b item
* * \e boolean \b allow_exec
*/
call_hooks('item_store', $d);
$arr = $d['item']; $arr = $d['item'];
$allow_exec = $d['allow_exec']; $allow_exec = $d['allow_exec'];
@ -1548,7 +1594,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
return $ret; return $ret;
} }
$arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : '');
@ -1566,7 +1611,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 ); $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 );
$arr['lang'] = detect_language($arr['body']); $arr['lang'] = detect_language($arr['body']);
// apply the input filter here // apply the input filter here
@ -1581,10 +1625,23 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages'); $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) { if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
$translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false); $translate = [
'item' => $arr,
'from' => $arr['lang'],
'to' => $allowed_languages,
'translated' => false
];
/**
* @hooks item_translate
* Called from item_store and item_store_update after the post language has been autodetected.
* * \e array \b item
* * \e string \b from
* * \e string \b to
* * \e boolean \b translated
*/
call_hooks('item_translate', $translate); call_hooks('item_translate', $translate);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) { if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']); logger('language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
$ret['message'] = 'language not accepted'; $ret['message'] = 'language not accepted';
return $ret; return $ret;
} }
@ -1776,18 +1833,26 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
intval($arr['revision']) intval($arr['revision'])
); );
if($r) { if($r) {
logger('item_store: duplicate item ignored. ' . print_r($arr,true)); logger('duplicate item ignored. ' . print_r($arr,true));
$ret['message'] = 'duplicate post.'; $ret['message'] = 'duplicate post.';
return $ret; return $ret;
} }
call_hooks('item_store',$arr); /**
* @hooks item_store
* Called when item_store() stores a record of type item.
*/
call_hooks('item_store', $arr);
// This hook remains for backward compatibility. /**
call_hooks('post_remote',$arr); * @hooks post_remote
* Called when an activity arrives from another site.
* This hook remains for backward compatibility.
*/
call_hooks('post_remote', $arr);
if(x($arr,'cancel')) { if(x($arr, 'cancel')) {
logger('item_store: post cancelled by plugin.'); logger('Post cancelled by plugin.');
$ret['message'] = 'cancelled.'; $ret['message'] = 'cancelled.';
return $ret; return $ret;
} }
@ -1894,7 +1959,11 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$ret['item'] = $arr; $ret['item'] = $arr;
call_hooks('post_remote_end',$arr); /**
* @hooks post_remote_end
* Called after processing a remote post.
*/
call_hooks('post_remote_end', $arr);
// update the commented timestamp on the parent - unless this is potentially a clone of an older item // update the commented timestamp on the parent - unless this is potentially a clone of an older item
// which we don't wish to bring to the surface. As the queue only holds deliveries for 3 days, it's // which we don't wish to bring to the surface. As the queue only holds deliveries for 3 days, it's
@ -1931,11 +2000,28 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
} }
/**
* @brief Update a stored item.
*
* @param array $arr an item
* @param boolean $allow_exec (optional) default false
* @param boolean $deliver (optional) default true
* @return array
*/
function item_store_update($arr, $allow_exec = false, $deliver = true) {
function item_store_update($arr,$allow_exec = false, $deliver = true) { $d = [
'item' => $arr,
$d = array('item' => $arr, 'allow_exec' => $allow_exec); 'allow_exec' => $allow_exec
call_hooks('item_store_update', $d ); ];
/**
* @hooks item_store_update
* Called when item_store_update() is called to update a stored item. It
* overwrites the function's parameters $arr and $allow_exec.
* * \e array \b item
* * \e boolean \b allow_exec
*/
call_hooks('item_store_update', $d);
$arr = $d['item']; $arr = $d['item'];
$allow_exec = $d['allow_exec']; $allow_exec = $d['allow_exec'];
@ -1947,12 +2033,12 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
} }
if(! intval($arr['uid'])) { if(! intval($arr['uid'])) {
logger('item_store_update: no uid'); logger('no uid');
$ret['message'] = 'no uid.'; $ret['message'] = 'no uid.';
return $ret; return $ret;
} }
if(! intval($arr['id'])) { if(! intval($arr['id'])) {
logger('item_store_update: no id'); logger('no id');
$ret['message'] = 'no id.'; $ret['message'] = 'no id.';
return $ret; return $ret;
} }
@ -1965,7 +2051,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
intval($uid) intval($uid)
); );
if(! $orig) { if(! $orig) {
logger('item_store_update: original post not found: ' . $orig_post_id); logger('Original post not found: ' . $orig_post_id);
$ret['message'] = 'no original'; $ret['message'] = 'no original';
return $ret; return $ret;
} }
@ -1997,7 +2083,20 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages'); $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) { if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
$translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false); $translate = [
'item' => $arr,
'from' => $arr['lang'],
'to' => $allowed_languages,
'translated' => false
];
/**
* @hooks item_translate
* Called from item_store() and item_store_update() after the post language has been autodetected.
* * \e array \b item - returned value
* * \e string \b from
* * \e string \b to
* * \e boolean \b translated - default false, set true if hook translated it and provide it in item
*/
call_hooks('item_translate', $translate); call_hooks('item_translate', $translate);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) { if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']); logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
@ -2097,18 +2196,20 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['item_pending_remove'] = ((array_key_exists('item_pending_remove',$arr)) ? intval($arr['item_pending_remove']) : $orig[0]['item_pending_remove'] ); $arr['item_pending_remove'] = ((array_key_exists('item_pending_remove',$arr)) ? intval($arr['item_pending_remove']) : $orig[0]['item_pending_remove'] );
$arr['item_blocked'] = ((array_key_exists('item_blocked',$arr)) ? intval($arr['item_blocked']) : $orig[0]['item_blocked'] ); $arr['item_blocked'] = ((array_key_exists('item_blocked',$arr)) ? intval($arr['item_blocked']) : $orig[0]['item_blocked'] );
$arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : ''); $arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
$arr['layout_mid'] = ((array_key_exists('layout_mid',$arr)) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid'] ); $arr['layout_mid'] = ((array_key_exists('layout_mid',$arr)) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid'] );
$arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : $orig[0]['public_policy'] ); $arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : $orig[0]['public_policy'] );
$arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : $orig[0]['comment_policy'] ); $arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : $orig[0]['comment_policy'] );
call_hooks('post_remote_update',$arr); /**
* @hooks post_remote_update
* Called when processing a remote post that involved an edit or update.
*/
call_hooks('post_remote_update', $arr);
if(x($arr,'cancel')) { if(x($arr, 'cancel')) {
logger('item_store_update: post cancelled by plugin.'); logger('Post cancelled by plugin.');
$ret['message'] = 'cancelled.'; $ret['message'] = 'cancelled.';
return $ret; return $ret;
} }
@ -2145,9 +2246,9 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$r = dbq("update item set " . $str . " where id = " . $orig_post_id ); $r = dbq("update item set " . $str . " where id = " . $orig_post_id );
if($r) if($r)
logger('item_store_update: updated item ' . $orig_post_id, LOGGER_DEBUG); logger('Updated item ' . $orig_post_id, LOGGER_DEBUG);
else { else {
logger('item_store_update: could not update item'); logger('Could not update item');
$ret['message'] = 'DB update failed.'; $ret['message'] = 'DB update failed.';
return $ret; return $ret;
} }
@ -2194,7 +2295,11 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$ret['item'] = $arr; $ret['item'] = $arr;
call_hooks('post_remote_update_end',$arr); /**
* @hooks post_remote_update_end
* Called after processing a remote post that involved an edit or update.
*/
call_hooks('post_remote_update_end', $arr);
if($deliver) { if($deliver) {
send_status_notifications($orig_post_id,$arr); send_status_notifications($orig_post_id,$arr);
@ -2427,7 +2532,7 @@ function tag_deliver($uid, $item_id) {
} }
} }
else else
logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']); logger('Tag permission denied for ' . $u[0]['channel_address']);
} }
/* /*
@ -2463,7 +2568,7 @@ function tag_deliver($uid, $item_id) {
$terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM)); $terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM));
if($terms) if($terms)
logger('tag_deliver: post mentions: ' . print_r($terms,true), LOGGER_DATA); logger('Post mentions: ' . print_r($terms,true), LOGGER_DATA);
$link = normalise_link($u[0]['xchan_url']); $link = normalise_link($u[0]['xchan_url']);
@ -2477,7 +2582,7 @@ function tag_deliver($uid, $item_id) {
} }
if($mention) { if($mention) {
logger('tag_deliver: mention found for ' . $u[0]['channel_name']); logger('Mention found for ' . $u[0]['channel_name']);
$r = q("update item set item_mentionsme = 1 where id = %d", $r = q("update item set item_mentionsme = 1 where id = %d",
intval($item_id) intval($item_id)
@ -2543,12 +2648,23 @@ function tag_deliver($uid, $item_id) {
} }
if(! ($tagged || $plustagged)) { if(! ($tagged || $plustagged)) {
logger('tag_deliver: mention was in a reshare or exceeded max_tagged_forums - ignoring'); logger('Mention was in a reshare or exceeded max_tagged_forums - ignoring');
return; return;
} }
$arr = array('channel_id' => $uid, 'item' => $item, 'body' => $body); $arr = [
call_hooks('tagged',$arr); 'channel_id' => $uid,
'item' => $item,
'body' => $body
];
/**
* @hooks tagged
* Called when a delivery is processed which results in you being tagged.
* * \e number \b channel_id
* * \e array \b item
* * \e string \b body
*/
call_hooks('tagged', $arr);
/* /*
* Kill two birds with one stone. As long as we're here, send a mention notification. * Kill two birds with one stone. As long as we're here, send a mention notification.
@ -2567,7 +2683,7 @@ function tag_deliver($uid, $item_id) {
// Just a normal tag? // Just a normal tag?
if(! $plustagged) { if(! $plustagged) {
logger('tag_deliver: not a plus tag', LOGGER_DEBUG); logger('Not a plus tag', LOGGER_DEBUG);
return; return;
} }
@ -2580,7 +2696,7 @@ function tag_deliver($uid, $item_id) {
} }
if((! $mention) && (! $union)) { if((! $mention) && (! $union)) {
logger('tag_deliver: no mention for ' . $u[0]['channel_name'] . ' and no union.'); logger('No mention for ' . $u[0]['channel_name'] . ' and no union.');
return; return;
} }
@ -2590,11 +2706,11 @@ function tag_deliver($uid, $item_id) {
if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) { if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) {
logger('tag_deliver: item was local or a comment. rejected.'); logger('Item was local or a comment. rejected.');
return; return;
} }
logger('tag_deliver: creating second delivery chain.'); logger('Creating second delivery chain.');
start_delivery_chain($u[0],$item,$item_id,null); start_delivery_chain($u[0],$item,$item_id,null);
} }
@ -2605,8 +2721,12 @@ function tag_deliver($uid, $item_id) {
* This is so that the channel with tag_delivery enabled can receive the post even if they turn off * This is so that the channel with tag_delivery enabled can receive the post even if they turn off
* permissions for the sender to send their stream. tag_deliver() can't be called until the post is actually stored. * permissions for the sender to send their stream. tag_deliver() can't be called until the post is actually stored.
* By then it would be too late to reject it. * By then it would be too late to reject it.
*
* @param number $uid A chnnel_id
* @param array $item
* @return boolean
*/ */
function tgroup_check($uid,$item) { function tgroup_check($uid, $item) {
$mention = false; $mention = false;
@ -2731,8 +2851,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
if($sourced) { if($sourced) {
$r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1", $r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1",
intval($channel['channel_id']), intval($channel['channel_id']),
dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan']) dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan'])
); );
if($r) { if($r) {
$t = trim($r[0]['src_tag']); $t = trim($r[0]['src_tag']);
if($t) { if($t) {
@ -2741,15 +2861,15 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
foreach($tags as $tt) { foreach($tags as $tt) {
$tt = trim($tt); $tt = trim($tt);
if($tt) { if($tt) {
q("insert into term (uid,oid,otype,ttype,term,url) q("insert into term (uid,oid,otype,ttype,term,url)
values(%d,%d,%d,%d,'%s','%s') ", values(%d,%d,%d,%d,'%s','%s') ",
intval($channel['channel_id']), intval($channel['channel_id']),
intval($item_id), intval($item_id),
intval(TERM_OBJ_POST), intval(TERM_OBJ_POST),
intval(TERM_CATEGORY), intval(TERM_CATEGORY),
dbesc($tt), dbesc($tt),
dbesc(z_root() . '/channel/' . $channel['channel_address'] . '?f=&cat=' . urlencode($tt)) dbesc(z_root() . '/channel/' . $channel['channel_address'] . '?f=&cat=' . urlencode($tt))
); );
} }
} }
} }
@ -3014,7 +3134,6 @@ function mail_store($arr) {
$arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 ); $arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 );
$arr['mail_raw'] = ((x($arr,'mail_raw')) ? intval($arr['mail_raw']) : 0 ); $arr['mail_raw'] = ((x($arr,'mail_raw')) ? intval($arr['mail_raw']) : 0 );
if($arr['parent_mid']) { if($arr['parent_mid']) {
$parent_item = q("select * from mail where mid = '%s' and channel_id = %d limit 1", $parent_item = q("select * from mail where mid = '%s' and channel_id = %d limit 1",
@ -3022,7 +3141,7 @@ function mail_store($arr) {
intval($arr['channel_id']) intval($arr['channel_id'])
); );
if(($parent_item) && (! $arr['conv_guid'])) { if(($parent_item) && (! $arr['conv_guid'])) {
$arr['conv_guid'] = $parent_item[0]['conv_guid']; $arr['conv_guid'] = $parent_item[0]['conv_guid'];
} }
} }
else { else {
@ -3048,19 +3167,23 @@ function mail_store($arr) {
); );
if($r) { if($r) {
logger('mail_store: duplicate item ignored. ' . print_r($arr,true)); logger('Duplicate item ignored. ' . print_r($arr,true));
return 0; return 0;
} }
if(! $r && $arr['mail_recalled'] == 1) { if(! $r && $arr['mail_recalled'] == 1) {
logger('mail_store: recalled item not found. ' . print_r($arr,true)); logger('Recalled item not found. ' . print_r($arr,true));
return 0; return 0;
} }
call_hooks('post_mail',$arr); /**
* @hooks post_mail
* Called when a mail message has been composed.
*/
call_hooks('post_mail', $arr);
if(x($arr,'cancel')) { if(x($arr,'cancel')) {
logger('mail_store: post cancelled by plugin.'); logger('Post cancelled by plugin.');
return 0; return 0;
} }
@ -3077,15 +3200,15 @@ function mail_store($arr) {
if($r) { if($r) {
$current_post = $r[0]['id']; $current_post = $r[0]['id'];
logger('mail_store: created item ' . $current_post, LOGGER_DEBUG); logger('Created item ' . $current_post, LOGGER_DEBUG);
$arr['id'] = $current_post; // for notification $arr['id'] = $current_post; // for notification
} }
else { else {
logger('mail_store: could not locate created item'); logger('Could not locate created item');
return 0; return 0;
} }
if(count($r) > 1) { if(count($r) > 1) {
logger('mail_store: duplicated post occurred. Removing duplicates.'); logger('Duplicated post occurred. Removing duplicates.');
q("DELETE FROM mail WHERE mid = '%s' AND channel_id = %d AND id != %d ", q("DELETE FROM mail WHERE mid = '%s' AND channel_id = %d AND id != %d ",
$arr['mid'], $arr['mid'],
intval($arr['channel_id']), intval($arr['channel_id']),
@ -3114,7 +3237,11 @@ function mail_store($arr) {
); );
} }
call_hooks('post_mail_end',$arr); /**
* @hooks post_mail_end
* Called when a mail message has been delivered.
*/
call_hooks('post_mail_end', $arr);
return $current_post; return $current_post;
} }
@ -3135,7 +3262,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
$img_st_close++; // make it point to AFTER the closing bracket $img_st_close++; // make it point to AFTER the closing bracket
$image = substr($orig_body, $img_start + $img_st_close, $img_len); $image = substr($orig_body, $img_start + $img_st_close, $img_len);
logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG); logger('Found photo ' . $image, LOGGER_DEBUG);
if(stristr($image , $site . '/photo/')) { if(stristr($image , $site . '/photo/')) {
// Only embed locally hosted photos // Only embed locally hosted photos
@ -3179,7 +3306,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
// If a custom width and height were specified, apply before embedding // If a custom width and height were specified, apply before embedding
if(preg_match("/\[zmg\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) { if(preg_match("/\[zmg\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) {
logger('fix_private_photos: scaling photo', LOGGER_DEBUG); logger('Scaling photo', LOGGER_DEBUG);
$width = intval($match[1]); $width = intval($match[1]);
$height = intval($match[2]); $height = intval($match[2]);
@ -3192,9 +3319,9 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
} }
} }
logger('fix_private_photos: replacing photo', LOGGER_DEBUG); logger('Replacing photo', LOGGER_DEBUG);
$image = 'data:' . $type . ';base64,' . base64_encode($data); $image = 'data:' . $type . ';base64,' . base64_encode($data);
logger('fix_private_photos: replaced: ' . $image, LOGGER_DATA); logger('Replaced: ' . $image, LOGGER_DATA);
} }
} }
} }
@ -3451,8 +3578,16 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
); );
} }
$arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage); $arr = [
call_hooks('drop_item', $arr ); 'item' => $item,
'interactive' => $interactive,
'stage' => $stage
];
/**
* @hooks drop_item
* Called when an 'item' is removed.
*/
call_hooks('drop_item', $arr);
$notify_id = intval($item['id']); $notify_id = intval($item['id']);
@ -3602,8 +3737,14 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
return true; return true;
} }
/**
function first_post_date($uid,$wall = false) { * @brief Return the first post date.
*
* @param int $uid
* @param boolean $wall (optional) default false
* @return string|boolean date string, otherwise false
*/
function first_post_date($uid, $wall = false) {
$wall_sql = (($wall) ? " and item_wall = 1 " : "" ); $wall_sql = (($wall) ? " and item_wall = 1 " : "" );
$item_normal = item_normal(); $item_normal = item_normal();
@ -3612,7 +3753,6 @@ function first_post_date($uid,$wall = false) {
where uid = %d and id = parent $item_normal $wall_sql where uid = %d and id = parent $item_normal $wall_sql
order by created asc limit 1", order by created asc limit 1",
intval($uid) intval($uid)
); );
if($r) { if($r) {
// logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA); // logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA);
@ -3628,8 +3768,8 @@ function first_post_date($uid,$wall = false) {
* current flat list of all representative dates. * current flat list of all representative dates.
* *
* @param int $uid * @param int $uid
* @param unknown $wall * @param boolean $wall
* @param unknown $mindate * @param string $mindate
* @return array * @return array
*/ */
function list_post_dates($uid, $wall, $mindate) { function list_post_dates($uid, $wall, $mindate) {
@ -3700,8 +3840,14 @@ function posted_dates($uid,$wall) {
return $ret; return $ret;
} }
/**
function fetch_post_tags($items,$link = false) { * @brief Extend an item array with the associated tags of the posts.
*
* @param array $items
* @param boolean $link (optional) default false
* @return array Return the provided $items array after extended the posts with tags
*/
function fetch_post_tags($items, $link = false) {
$tag_finder = array(); $tag_finder = array();
if($items) { if($items) {
@ -3720,7 +3866,6 @@ function fetch_post_tags($items,$link = false) {
} }
$tag_finder_str = implode(', ', $tag_finder); $tag_finder_str = implode(', ', $tag_finder);
if(strlen($tag_finder_str)) { if(strlen($tag_finder_str)) {
$tags = q("select * from term where oid in ( %s ) and otype = %d", $tags = q("select * from term where oid in ( %s ) and otype = %d",
dbesc($tag_finder_str), dbesc($tag_finder_str),
@ -3729,7 +3874,6 @@ function fetch_post_tags($items,$link = false) {
$imeta = q("select * from iconfig where iid in ( %s )", $imeta = q("select * from iconfig where iid in ( %s )",
dbesc($tag_finder_str) dbesc($tag_finder_str)
); );
} }
for($x = 0; $x < count($items); $x ++) { for($x = 0; $x < count($items); $x ++) {
@ -3779,8 +3923,15 @@ function fetch_post_tags($items,$link = false) {
} }
/**
function zot_feed($uid,$observer_hash,$arr) { * @brief
*
* @param int $uid
* @param string $observer_hash
* @param array $arr
* @return array
*/
function zot_feed($uid, $observer_hash, $arr) {
$result = array(); $result = array();
$mindate = null; $mindate = null;
@ -3990,24 +4141,23 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
} }
if($arr['search']) { if($arr['search']) {
if(strpos($arr['search'],'#') === 0)
$sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG,TERM_COMMUNITYTAG);
else
$sql_extra .= sprintf(" AND item.body like '%s' ",
dbesc(protect_sprintf('%' . $arr['search'] . '%'))
);
}
if(strpos($arr['search'],'#') === 0) if(strlen($arr['file'])) {
$sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG,TERM_COMMUNITYTAG); $sql_extra .= term_query('item',$arr['files'],TERM_FILE);
else }
$sql_extra .= sprintf(" AND item.body like '%s' ",
dbesc(protect_sprintf('%' . $arr['search'] . '%'))
);
}
if(strlen($arr['file'])) { if($arr['conv'] && $channel) {
$sql_extra .= term_query('item',$arr['files'],TERM_FILE); $sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ",
} dbesc(protect_sprintf($uidhash))
);
if($arr['conv'] && $channel) { }
$sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ",
dbesc(protect_sprintf($uidhash))
);
}
if (($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) { if (($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) {
// only setup pagination on initial page view // only setup pagination on initial page view
@ -4042,9 +4192,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
} }
} }
$simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : ''); $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : '');
if($client_mode & CLIENT_MODE_LOAD) if($client_mode & CLIENT_MODE_LOAD)
$simple_update = ''; $simple_update = '';
//$start = dba_timer(); //$start = dba_timer();
@ -4087,27 +4237,26 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) { if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) {
// Fetch a page full of parent items for this page // Fetch a page full of parent items for this page
$r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item $r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item
left join abook on item.author_xchan = abook.abook_xchan left join abook on item.author_xchan = abook.abook_xchan
WHERE $item_uids $item_restrict WHERE $item_uids $item_restrict
AND item.parent = item.id AND item.parent = item.id
and (abook.abook_blocked = 0 or abook.abook_flags is null) and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra3 $sql_extra $sql_nets $sql_extra3 $sql_extra $sql_nets
ORDER BY item.$ordering DESC $pager_sql " ORDER BY item.$ordering DESC $pager_sql "
); );
}
} else {
else { // update
// update $r = q("SELECT item.parent AS item_id FROM item
$r = q("SELECT item.parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan
left join abook on item.author_xchan = abook.abook_xchan WHERE $item_uids $item_restrict $simple_update
WHERE $item_uids $item_restrict $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null)
and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra3 $sql_extra $sql_nets "
$sql_extra3 $sql_extra $sql_nets " );
); }
}
//$first = dba_timer(); //$first = dba_timer();
@ -4167,12 +4316,11 @@ function webpage_to_namespace($webpage) {
$page_type = 'docfile'; $page_type = 'docfile';
else else
$page_type = 'unknown'; $page_type = 'unknown';
return $page_type; return $page_type;
} }
function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) { function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
if(! $post_id) if(! $post_id)
@ -4296,7 +4444,6 @@ function comment_local_origin($item) {
function send_profile_photo_activity($channel,$photo,$profile) { function send_profile_photo_activity($channel,$photo,$profile) {
// for now only create activities for the default profile // for now only create activities for the default profile
@ -4345,8 +4492,6 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['author_xchan'] = $channel['channel_hash']; $arr['author_xchan'] = $channel['channel_hash'];
post_activity_item($arr); post_activity_item($arr);
} }
@ -4549,7 +4694,6 @@ function item_create_edit_activity($post) {
)); ));
$x = post_activity_item($new_item); $x = post_activity_item($new_item);
$post_id = $x['id']; $post_id = $x['id'];
@ -4565,5 +4709,4 @@ function item_create_edit_activity($post) {
} }
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_activity', $post_id)); \Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_activity', $post_id));
} }

View file

@ -14,27 +14,25 @@ require_once("include/bbcode.php");
/** /**
* @brief * @brief Convert Markdown to bbcode.
* *
* We don't want to support a bbcode specific markdown interpreter * We don't want to support a bbcode specific markdown interpreter
* and the markdown library we have is pretty good, but provides HTML output. * and the markdown library we have is pretty good, but provides HTML output.
* So we'll use that to convert to HTML, then convert the HTML back to bbcode, * So we'll use that to convert to HTML, then convert the HTML back to bbcode,
* and then clean up a few Diaspora specific constructs. * and then clean up a few Diaspora specific constructs.
* *
* @param string $s * @param string $s The message as Markdown
* @param boolean $use_zrl default false * @param boolean $use_zrl default false
* @return string * @param array $options default empty
* @return string The message converted to bbcode
*/ */
function markdown_to_bb($s, $use_zrl = false, $options = []) { function markdown_to_bb($s, $use_zrl = false, $options = []) {
if(is_array($s)) { if(is_array($s)) {
btlogger('markdown_to_bb called with array. ' . print_r($s,true), LOGGER_NORMAL, LOG_WARNING); btlogger('markdown_to_bb called with array. ' . print_r($s, true), LOGGER_NORMAL, LOG_WARNING);
return ''; return '';
} }
$s = str_replace("&#xD;","\r",$s); $s = str_replace("&#xD;","\r",$s);
$s = str_replace("&#xD;\n&gt;","",$s); $s = str_replace("&#xD;\n&gt;","",$s);
@ -43,9 +41,18 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
// if empty link text replace with the url // if empty link text replace with the url
$s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s); $s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s);
$x = [ 'text' => $s , 'zrl' => $use_zrl, 'options' => $options ]; $x = [
'text' => $s,
call_hooks('markdown_to_bb_init',$x); 'zrl' => $use_zrl,
'options' => $options
];
/**
* @hooks markdown_to_bb_init
* * \e string \b text - The message as Markdown and what will get returned
* * \e boolean \b zrl
* * \e array \b options
*/
call_hooks('markdown_to_bb_init', $x);
$s = $x['text']; $s = $x['text'];
@ -67,7 +74,7 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
// Convert everything that looks like a link to a link // Convert everything that looks like a link to a link
if($use_zrl) { if($use_zrl) {
$s = str_replace(array('[img','/img]'),array('[zmg','/zmg]'),$s); $s = str_replace(['[img', '/img]'], ['[zmg', '/zmg]'], $s);
$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]',$s); $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]',$s);
} }
else { else {
@ -80,13 +87,22 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
// Don't show link to full picture (until it is fixed) // Don't show link to full picture (until it is fixed)
$s = scale_external_images($s, false); $s = scale_external_images($s, false);
call_hooks('markdown_to_bb',$s); /**
* @hooks markdown_to_bb
* * \e string - The already converted message as bbcode
*/
call_hooks('markdown_to_bb', $s);
return $s; return $s;
} }
/**
* @brief
*
* @param array $match
* @return string
*/
function bb_to_markdown_share($match) { function bb_to_markdown_share($match) {
$matches = array(); $matches = array();
@ -153,17 +169,22 @@ function bb_to_markdown_share($match) {
} }
/**
* @brief Convert bbcode to Markdown.
*
* @param string $Text The message as bbcode
* @param array $options default empty
* @return string The message converted to Markdown
*/
function bb_to_markdown($Text, $options = []) { function bb_to_markdown($Text, $options = []) {
/* /*
* Transform #tags, strip off the [url] and replace spaces with underscore * Transform #tags, strip off the [url] and replace spaces with underscore
*/ */
$Text = preg_replace_callback('/#\[([zu])rl\=(.*?)\](.*?)\[\/[(zu)]rl\]/i', $Text = preg_replace_callback('/#\[([zu])rl\=(.*?)\](.*?)\[\/[(zu)]rl\]/i',
create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'), $Text); create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'), $Text);
$Text = preg_replace('/#\^\[([zu])rl\=(.*?)\](.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text); $Text = preg_replace('/#\^\[([zu])rl\=(.*?)\](.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text);
// Converting images with size parameters to simple images. Markdown doesn't know it. // Converting images with size parameters to simple images. Markdown doesn't know it.
@ -173,7 +194,12 @@ function bb_to_markdown($Text, $options = []) {
$x = [ 'bbcode' => $Text, 'options' => $options ]; $x = [ 'bbcode' => $Text, 'options' => $options ];
call_hooks('bb_to_markdown_bb',$x); /**
* @hooks bb_to_markdown_bb
* * \e string \b bbcode - The message as bbcode and what will get returned
* * \e array \b options
*/
call_hooks('bb_to_markdown_bb', $x);
$Text = $x['bbcode']; $Text = $x['bbcode'];
@ -202,14 +228,16 @@ function bb_to_markdown($Text, $options = []) {
$Text = trim($Text); $Text = trim($Text);
/**
* @hooks bb_to_markdown
* * \e string - The already converted message as bbcode and what will get returned
*/
call_hooks('bb_to_markdown', $Text); call_hooks('bb_to_markdown', $Text);
return $Text; return $Text;
} }
/** /**
* @brief Convert a HTML text into Markdown. * @brief Convert a HTML text into Markdown.
* *
@ -217,8 +245,6 @@ function bb_to_markdown($Text, $options = []) {
* *
* If the HTML text can not get parsed it will return an empty string. * If the HTML text can not get parsed it will return an empty string.
* *
* @see HTMLToMarkdown
*
* @param string $html The HTML code to convert * @param string $html The HTML code to convert
* @return string Markdown representation of the given HTML text, empty on error * @return string Markdown representation of the given HTML text, empty on error
*/ */
@ -232,8 +258,5 @@ function html2markdown($html) {
logger("Invalid HTML. HTMLToMarkdown library threw an exception."); logger("Invalid HTML. HTMLToMarkdown library threw an exception.");
} }
// The old html 2 markdown library "pixel418/markdownify": "^2.2",
//$md = new HtmlConverter();
//$markdown = $md->convert($Text);
return $markdown; return $markdown;
} }

View file

@ -1,6 +1,7 @@
<?php <?php
/** /**
* @file include/network.php * @file include/network.php
* @brief Network related functions.
*/ */
/** /**
@ -189,7 +190,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
/** /**
* @brief * @brief Does a curl post request.
* *
* @param string $url * @param string $url
* URL to post * URL to post
@ -214,7 +215,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
* * \e string \b body => content * * \e string \b body => content
* * \e string \b debug => from curl_info() * * \e string \b debug => from curl_info()
*/ */
function z_post_url($url,$params, $redirects = 0, $opts = array()) { function z_post_url($url, $params, $redirects = 0, $opts = array()) {
// logger('url: ' . $url); // logger('url: ' . $url);
// logger('params: ' . print_r($params,true)); // logger('params: ' . print_r($params,true));
@ -276,13 +277,10 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']); @curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
} }
if(x($opts,'cookiejar')) if(x($opts,'cookiejar'))
@curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']); @curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
if(x($opts,'cookiefile')) if(x($opts,'cookiefile'))
@curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']); @curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
if(x($opts,'cookie')) if(x($opts,'cookie'))
@curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']); @curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
@ -423,7 +421,7 @@ function http_status($val, $msg = '') {
* integer HTTP status result value * integer HTTP status result value
* @param string $msg * @param string $msg
* optional message * optional message
* @return does not return, process is terminated * @return void does not return, process is terminated
*/ */
function http_status_exit($val, $msg = '') { function http_status_exit($val, $msg = '') {
http_status($val, $msg); http_status($val, $msg);
@ -431,10 +429,10 @@ function http_status_exit($val, $msg = '') {
} }
/** /**
* @brief convert an XML document to a normalised, case-corrected array used by webfinger. * @brief Convert an XML document to a normalised, case-corrected array used by webfinger.
* *
* @param string|array|SimpleXMLElement $xml_element * @param string|array|SimpleXMLElement $xml_element
* @param int $recursion_depth[in,out] * @param[in,out] int $recursion_depth
* @return NULL|string|array * @return NULL|string|array
*/ */
function convert_xml_element_to_array($xml_element, &$recursion_depth=0) { function convert_xml_element_to_array($xml_element, &$recursion_depth=0) {
@ -501,14 +499,14 @@ function z_dns_check($h,$check_mx = 0) {
} }
/** /**
* @brief Validates a given URL * @brief Validates a given URL.
* *
* Take a URL from the wild, prepend http:// if necessary and check DNS to see * Take a URL from the wild, prepend http:// if necessary and check DNS to see
* if it's real (or check if is a valid IP address). * if it's real (or check if is a valid IP address).
* *
* @see z_dns_check() * @see z_dns_check()
* *
* @param string $url[in,out] URL to check * @param[in,out] string $url URL to check
* @return boolean Return true if it's OK, false if something is wrong with it * @return boolean Return true if it's OK, false if something is wrong with it
*/ */
function validate_url(&$url) { function validate_url(&$url) {
@ -593,6 +591,7 @@ function allowed_url($url) {
} }
} }
} }
return $found; return $found;
} }
@ -658,7 +657,7 @@ function allowed_email($email) {
function parse_xml_string($s,$strict = true) { function parse_xml_string($s, $strict = true) {
if($strict) { if($strict) {
if(! strstr($s,'<?xml')) if(! strstr($s,'<?xml'))
return false; return false;
@ -683,14 +682,21 @@ function parse_xml_string($s,$strict = true) {
return $x; return $x;
} }
/**
* @brief Scales an external image.
*
* @param string $s
* @param string $include_link default true
* @param string $scale_replace default false
* @return string
*/
function scale_external_images($s, $include_link = true, $scale_replace = false) { function scale_external_images($s, $include_link = true, $scale_replace = false) {
// Picture addresses can contain special characters // Picture addresses can contain special characters
$s = htmlspecialchars_decode($s, ENT_COMPAT); $s = htmlspecialchars_decode($s, ENT_COMPAT);
$matches = null; $matches = null;
$c = preg_match_all('/\[([zi])mg(.*?)\](.*?)\[\/[zi]mg\]/ism',$s,$matches,PREG_SET_ORDER); $c = preg_match_all('/\[([zi])mg(.*?)\](.*?)\[\/[zi]mg\]/ism', $s, $matches, PREG_SET_ORDER);
if($c) { if($c) {
require_once('include/photo/photo_driver.php'); require_once('include/photo/photo_driver.php');
@ -717,22 +723,21 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
else else
$scaled = $mtch[3]; $scaled = $mtch[3];
if(! strpbrk(substr($scaled,0,1),'zhfmt')) if(! strpbrk(substr($scaled, 0, 1), 'zhfmt'))
continue; continue;
$i = z_fetch_url($scaled,true); $i = z_fetch_url($scaled, true);
$cache = get_config('system', 'itemcache');
$cache = get_config('system','itemcache');
if (($cache != '') and is_dir($cache)) { if (($cache != '') and is_dir($cache)) {
$cachefile = $cache."/".hash("md5", $scaled); $cachefile = $cache . '/' . hash('md5', $scaled);
file_put_contents($cachefile, $i['body']); file_put_contents($cachefile, $i['body']);
} }
// guess mimetype from headers or filename // guess mimetype from headers or filename
$type = guess_image_type($mtch[3],$i['header']); $type = guess_image_type($mtch[3], $i['header']);
if(strpos($type,'image') === false) if(strpos($type, 'image') === false)
continue; continue;
if($i['success']) { if($i['success']) {
@ -764,7 +769,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
// replace the special char encoding // replace the special char encoding
$s = htmlspecialchars($s,ENT_COMPAT,'UTF-8'); $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
return $s; return $s;
} }
@ -1141,7 +1146,14 @@ function discover_by_url($url, $arr = null) {
return true; return true;
} }
function discover_by_webbie($webbie,$protocol = '') { /**
* @brief
*
* @param string $webbie
* @param string $protocol (optional) default empty
* @return boolean
*/
function discover_by_webbie($webbie, $protocol = '') {
$result = []; $result = [];
@ -1149,7 +1161,7 @@ function discover_by_webbie($webbie,$protocol = '') {
// $webbie = strtolower($webbie); // $webbie = strtolower($webbie);
$x = webfinger_rfc7033($webbie,true); $x = webfinger_rfc7033($webbie, true);
if($x && array_key_exists('links',$x) && $x['links']) { if($x && array_key_exists('links',$x) && $x['links']) {
foreach($x['links'] as $link) { foreach($x['links'] as $link) {
if(array_key_exists('rel',$link)) { if(array_key_exists('rel',$link)) {
@ -1158,7 +1170,7 @@ function discover_by_webbie($webbie,$protocol = '') {
// here. // here.
if($link['rel'] === PROTOCOL_ZOT && ((! $protocol) || (strtolower($protocol) === 'zot'))) { if($link['rel'] === PROTOCOL_ZOT && ((! $protocol) || (strtolower($protocol) === 'zot'))) {
logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG); logger('zot found for ' . $webbie, LOGGER_DEBUG);
if(array_key_exists('zot',$x) && $x['zot']['success']) { if(array_key_exists('zot',$x) && $x['zot']['success']) {
$i = import_xchan($x['zot']); $i = import_xchan($x['zot']);
return true; return true;
@ -1178,16 +1190,35 @@ function discover_by_webbie($webbie,$protocol = '') {
logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO); logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO);
$arr = array('address' => $webbie, 'protocol' => $protocol, 'success' => false, 'webfinger' => $x); $arr = [
'address' => $webbie,
'protocol' => $protocol,
'success' => false,
'webfinger' => $x
];
/**
* @hooks discover_channel_webfinger
* Called when performing a webfinger lookup.
* * \e string \b address - The webbie
* * \e string \b protocol
* * \e array \b webfinger - The result from webfinger_rfc7033()
* * \e boolean \b success - The return value, default false
*/
call_hooks('discover_channel_webfinger', $arr); call_hooks('discover_channel_webfinger', $arr);
if($arr['success']) if($arr['success'])
return true; return true;
return false; return false;
} }
function webfinger_rfc7033($webbie,$zot = false) { /**
* @brief Fetch and return a webfinger for a webbie.
*
* @param string $webbie - The webbie
* @param boolean $zot (optional) default false
* @return boolean|string false or associative array from result JSON
*/
function webfinger_rfc7033($webbie, $zot = false) {
if(strpos($webbie,'@')) { if(strpos($webbie,'@')) {
$lhs = substr($webbie,0,strpos($webbie,'@')); $lhs = substr($webbie,0,strpos($webbie,'@'));
@ -1199,6 +1230,7 @@ function webfinger_rfc7033($webbie,$zot = false) {
if($m) { if($m) {
if($m['scheme'] !== 'https') if($m['scheme'] !== 'https')
return false; return false;
$rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
$resource = urlencode($webbie); $resource = urlencode($webbie);
} }
@ -1211,20 +1243,19 @@ function webfinger_rfc7033($webbie,$zot = false) {
// and results in a 406 (Not Acceptable) response, and will also incorrectly produce an XML // and results in a 406 (Not Acceptable) response, and will also incorrectly produce an XML
// document if you use 'application/jrd+json, */*'. We could set this to application/jrd+json, // document if you use 'application/jrd+json, */*'. We could set this to application/jrd+json,
// but some test webfinger servers may not explicitly set the content type and they would be // but some test webfinger servers may not explicitly set the content type and they would be
// blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is
// accomplished by setting it to nothing. // accomplished by setting it to nothing.
$counter = 0; $counter = 0;
$s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''), $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''),
false, $counter, [ 'headers' => [ 'Accept:' ] ]); false, $counter, [ 'headers' => [ 'Accept:' ] ]);
if($s['success']) { if($s['success']) {
$j = json_decode($s['body'],true); $j = json_decode($s['body'], true);
return($j); return($j);
} }
return false; return false;
} }
function old_webfinger($webbie) { function old_webfinger($webbie) {
@ -1604,7 +1635,13 @@ function check_siteallowed($url) {
$retvalue = true; $retvalue = true;
$arr = array('url' => $url); $arr = array('url' => $url);
call_hooks('check_siteallowed',$arr); /**
* @hooks check_siteallowed
* Used to over-ride or bypass the site black/white block lists.
* * \e string \b url
* * \e boolean \b allowed - optional return value set in hook
*/
call_hooks('check_siteallowed', $arr);
if(array_key_exists('allowed',$arr)) if(array_key_exists('allowed',$arr))
return $arr['allowed']; return $arr['allowed'];
@ -1643,7 +1680,13 @@ function check_channelallowed($hash) {
$retvalue = true; $retvalue = true;
$arr = array('hash' => $hash); $arr = array('hash' => $hash);
call_hooks('check_channelallowed',$arr); /**
* @hooks check_channelallowed
* Used to over-ride or bypass the channel black/white block lists.
* * \e string \b hash
* * \e boolean \b allowed - optional return value set in hook
*/
call_hooks('check_channelallowed', $arr);
if(array_key_exists('allowed',$arr)) if(array_key_exists('allowed',$arr))
return $arr['allowed']; return $arr['allowed'];
@ -1732,6 +1775,10 @@ function network_to_name($s) {
NETWORK_MYSPACE => t('MySpace'), NETWORK_MYSPACE => t('MySpace'),
); );
/**
* @hooks network_to_name
* @deprecated
*/
call_hooks('network_to_name', $nets); call_hooks('network_to_name', $nets);
$search = array_keys($nets); $search = array_keys($nets);
@ -1743,7 +1790,7 @@ function network_to_name($s) {
/** /**
* @brief Send a text email message. * @brief Send a text email message.
* *
* @param array $params an assoziative array with: * @param array $params an associative array with:
* * \e string \b fromName name of the sender * * \e string \b fromName name of the sender
* * \e string \b fromEmail email of the sender * * \e string \b fromEmail email of the sender
* * \e string \b replyTo replyTo address to direct responses * * \e string \b replyTo replyTo address to direct responses
@ -1774,6 +1821,10 @@ function z_mail($params) {
$params['sent'] = false; $params['sent'] = false;
$params['result'] = false; $params['result'] = false;
/**
* @hooks email_send
* * \e params @see z_mail()
*/
call_hooks('email_send', $params); call_hooks('email_send', $params);
if($params['sent']) { if($params['sent']) {
@ -1921,60 +1972,78 @@ function service_plink($contact, $guid) {
$plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid; $plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid;
$x = [ 'xchan' => $contact, 'guid' => $guid, 'url' => $url, 'plink' => $plink ]; $x = [ 'xchan' => $contact, 'guid' => $guid, 'url' => $url, 'plink' => $plink ];
/**
* @hooks service_plink
* * \e array \b xchan
* * \e string \b guid
* * \e string \b url
* * \e string \b plink will get returned
*/
call_hooks('service_plink', $x); call_hooks('service_plink', $x);
return $x['plink']; return $x['plink'];
} }
/**
* @brief
*
* @param array $mimeTypes
* @param string $acceptedTypes by default false will use $_SERVER['HTTP_ACCEPT']
* @return array|NULL
*/
function getBestSupportedMimeType($mimeTypes = null, $acceptedTypes = false) { function getBestSupportedMimeType($mimeTypes = null, $acceptedTypes = false) {
// Values will be stored in this array // Values will be stored in this array
$AcceptTypes = [];
if($acceptedTypes === false) if($acceptedTypes === false)
$acceptedTypes = $_SERVER['HTTP_ACCEPT']; $acceptedTypes = $_SERVER['HTTP_ACCEPT'];
$AcceptTypes = Array (); // Accept header is case insensitive, and whitespace isnt important
$accept = strtolower(str_replace(' ', '', $acceptedTypes));
// divide it into parts in the place of a ","
$accept = explode(',', $accept);
foreach ($accept as $a) {
// the default quality is 1.
$q = 1;
// check if there is a different quality
if (strpos($a, ';q=')) {
// divide "mime/type;q=X" into two parts: "mime/type" i "X"
list($a, $q) = explode(';q=', $a);
}
// mime-type $a is accepted with the quality $q
// WARNING: $q == 0 means, that mime-type isnt supported!
$AcceptTypes[$a] = $q;
}
arsort($AcceptTypes);
// Accept header is case insensitive, and whitespace isnt important // if no parameter was passed, just return parsed data
$accept = strtolower(str_replace(' ', '', $acceptedTypes)); if (!$mimeTypes) return $AcceptTypes;
// divide it into parts in the place of a ","
$accept = explode(',', $accept);
foreach ($accept as $a) {
// the default quality is 1.
$q = 1;
// check if there is a different quality
if (strpos($a, ';q=')) {
// divide "mime/type;q=X" into two parts: "mime/type" i "X"
list($a, $q) = explode(';q=', $a);
}
// mime-type $a is accepted with the quality $q
// WARNING: $q == 0 means, that mime-type isnt supported!
$AcceptTypes[$a] = $q;
}
arsort($AcceptTypes);
// if no parameter was passed, just return parsed data $mimeTypes = array_map('strtolower', (array)$mimeTypes);
if (!$mimeTypes) return $AcceptTypes;
$mimeTypes = array_map('strtolower', (array)$mimeTypes); // lets check our supported types:
foreach ($AcceptTypes as $mime => $q) {
if ($q && in_array($mime, $mimeTypes)) return $mime;
}
// lets check our supported types: // no mime-type found
foreach ($AcceptTypes as $mime => $q) { return null;
if ($q && in_array($mime, $mimeTypes)) return $mime;
}
// no mime-type found
return null;
} }
/**
* @brief Perform caching for jsonld normaliser.
*
* @param string $url
* @return mixed|boolean|array
*/
function jsonld_document_loader($url) { function jsonld_document_loader($url) {
// perform caching for jsonld normaliser
require_once('library/jsonld/jsonld.php'); require_once('library/jsonld/jsonld.php');
$cachepath = 'store/[data]/ldcache'; $cachepath = 'store/[data]/ldcache';
if(! is_dir($cachepath)) if(! is_dir($cachepath))
os_mkdir($cachepath,STORAGE_DEFAULT_PERMISSIONS,true); os_mkdir($cachepath, STORAGE_DEFAULT_PERMISSIONS, true);
$filename = $cachepath . '/' . urlencode($url); $filename = $cachepath . '/' . urlencode($url);
if(file_exists($filename) && filemtime($filename) > time() - (12 * 60 * 60)) { if(file_exists($filename) && filemtime($filename) > time() - (12 * 60 * 60)) {
@ -1983,7 +2052,7 @@ function jsonld_document_loader($url) {
$r = jsonld_default_document_loader($url); $r = jsonld_default_document_loader($url);
if($r) { if($r) {
file_put_contents($filename,json_encode($r)); file_put_contents($filename, json_encode($r));
return $r; return $r;
} }
@ -1993,5 +2062,4 @@ function jsonld_document_loader($url) {
} }
return []; return [];
} }

View file

@ -10,14 +10,13 @@ require_once('include/photo/photo_driver.php');
require_once('include/text.php'); require_once('include/text.php');
/** /**
* @brief * @brief Upload a photo.
* *
* @param array $channel * @param array $channel
* @param array $observer * @param array $observer
* @param array $args * @param array $args
* @return array * @return array
*/ */
function photo_upload($channel, $observer, $args) { function photo_upload($channel, $observer, $args) {
$ret = array('success' => false); $ret = array('success' => false);
@ -118,25 +117,33 @@ function photo_upload($channel, $observer, $args) {
if (! $type) if (! $type)
$type=guess_image_type($filename); $type=guess_image_type($filename);
logger('photo_upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes', LOGGER_DEBUG); logger('Received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes', LOGGER_DEBUG);
$maximagesize = get_config('system','maximagesize'); $maximagesize = get_config('system','maximagesize');
if (($maximagesize) && ($filesize > $maximagesize)) { if (($maximagesize) && ($filesize > $maximagesize)) {
$ret['message'] = sprintf ( t('Image exceeds website size limit of %lu bytes'), $maximagesize); $ret['message'] = sprintf ( t('Image exceeds website size limit of %lu bytes'), $maximagesize);
@unlink($src); @unlink($src);
call_hooks('photo_upload_end',$ret); /**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
if (! $filesize) { if (! $filesize) {
$ret['message'] = t('Image file is empty.'); $ret['message'] = t('Image file is empty.');
@unlink($src); @unlink($src);
call_hooks('photo_post_end',$ret); /**
* @hooks photo_post_end
* Called after uploading a photo.
*/
call_hooks('photo_post_end', $ret);
return $ret; return $ret;
} }
logger('photo_upload: loading the contents of ' . $src , LOGGER_DEBUG); logger('Loading the contents of ' . $src , LOGGER_DEBUG);
$imagedata = @file_get_contents($src); $imagedata = @file_get_contents($src);
} }
@ -149,7 +156,11 @@ function photo_upload($channel, $observer, $args) {
if (($r) && ($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) { if (($r) && ($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) {
$ret['message'] = upgrade_message(); $ret['message'] = upgrade_message();
@unlink($src); @unlink($src);
call_hooks('photo_post_end',$ret); /**
* @hooks photo_post_end
* Called after uploading a photo.
*/
call_hooks('photo_post_end', $ret);
return $ret; return $ret;
} }
@ -157,9 +168,13 @@ function photo_upload($channel, $observer, $args) {
if (! $ph->is_valid()) { if (! $ph->is_valid()) {
$ret['message'] = t('Unable to process image'); $ret['message'] = t('Unable to process image');
logger('photo_upload: unable to process image'); logger('unable to process image');
@unlink($src); @unlink($src);
call_hooks('photo_upload_end',$ret); /**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
@ -269,8 +284,12 @@ function photo_upload($channel, $observer, $args) {
intval($channel_id) intval($channel_id)
); );
$ret['message'] = t('Photo storage failed.'); $ret['message'] = t('Photo storage failed.');
logger('photo_upload: photo store failed.'); logger('Photo store failed.');
call_hooks('photo_upload_end',$ret); /**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
@ -296,8 +315,6 @@ function photo_upload($channel, $observer, $args) {
$width = $link[1]['width']; $width = $link[1]['width'];
$height = $link[1]['height']; $height = $link[1]['height'];
$tag = (($r1) ? '[zmg=' . $width . 'x' . $height . ']' : '[zmg]'); $tag = (($r1) ? '[zmg=' . $width . 'x' . $height . ']' : '[zmg]');
} }
else { else {
$scale = 2; $scale = 2;
@ -355,7 +372,6 @@ function photo_upload($channel, $observer, $args) {
$item['target'] = json_encode($target); $item['target'] = json_encode($target);
$force = true; $force = true;
} }
$r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']), dbesc($item['mid']),
@ -423,7 +439,6 @@ function photo_upload($channel, $observer, $args) {
$arr['item_private'] = 1; $arr['item_private'] = 1;
$result = item_store($arr,false,$deliver); $result = item_store($arr,false,$deliver);
$item_id = $result['item_id']; $item_id = $result['item_id'];
@ -437,7 +452,11 @@ function photo_upload($channel, $observer, $args) {
$ret['resource_id'] = $photo_hash; $ret['resource_id'] = $photo_hash;
$ret['photoitem_id'] = $item_id; $ret['photoitem_id'] = $item_id;
call_hooks('photo_upload_end',$ret); /**
* @hooks photo_upload_end
* Called when a photo upload has been processed.
*/
call_hooks('photo_upload_end', $ret);
return $ret; return $ret;
} }
@ -502,10 +521,8 @@ function photo_calculate_1600_scale($arr) {
} }
return $dest_width . 'x' . $dest_height; return $dest_width . 'x' . $dest_height;
} }
/** /**
* @brief Returns a list with all photo albums observer is allowed to see. * @brief Returns a list with all photo albums observer is allowed to see.
* *
@ -520,7 +537,6 @@ function photo_calculate_1600_scale($arr) {
* * \e boolean \b success * * \e boolean \b success
* * \e array \b albums * * \e array \b albums
*/ */
function photos_albums_list($channel, $observer, $sort_key = 'display_path', $direction = 'asc') { function photos_albums_list($channel, $observer, $sort_key = 'display_path', $direction = 'asc') {
$channel_id = $channel['channel_id']; $channel_id = $channel['channel_id'];
@ -613,14 +629,13 @@ function photos_album_widget($channelx,$observer,$sortkey = 'display_path',$dire
} }
/** /**
* @brief * @brief Return an array of photos.
* *
* @param array $channel * @param array $channel
* @param array $observer * @param array $observer
* @param string $album default empty * @param string $album (optional) default empty
* @return boolean|array * @return boolean|array
*/ */
function photos_list_photos($channel, $observer, $album = '') { function photos_list_photos($channel, $observer, $album = '') {
$channel_id = $channel['channel_id']; $channel_id = $channel['channel_id'];
@ -657,21 +672,20 @@ function photos_list_photos($channel, $observer, $album = '') {
* @brief Check if given photo album exists in channel. * @brief Check if given photo album exists in channel.
* *
* @param int $channel_id id of the channel * @param int $channel_id id of the channel
* @param string $observer_hash
* @param string $album name of the album * @param string $album name of the album
* @return boolean * @return boolean
*/ */
function photos_album_exists($channel_id, $observer_hash, $album) { function photos_album_exists($channel_id, $observer_hash, $album) {
$sql_extra = permissions_sql($channel_id,$observer_hash); $sql_extra = permissions_sql($channel_id, $observer_hash);
$r = q("SELECT folder, hash, is_dir, filename, os_path, display_path FROM attach WHERE hash = '%s' AND is_dir = 1 AND uid = %d $sql_extra limit 1", $r = q("SELECT folder, hash, is_dir, filename, os_path, display_path FROM attach WHERE hash = '%s' AND is_dir = 1 AND uid = %d $sql_extra limit 1",
dbesc($album), dbesc($album),
intval($channel_id) intval($channel_id)
); );
// partial backward compatibility with Hubzilla < 2.4 when we used the filename only // partial backward compatibility with Hubzilla < 2.4 when we used the filename only
// (ambiguous which would get chosen if you had two albums of the same name in different directories) // (ambiguous which would get chosen if you had two albums of the same name in different directories)
if(!$r && ctype_xdigit($album)) { if(!$r && ctype_xdigit($album)) {
$r = q("SELECT folder, hash, is_dir, filename, os_path, display_path FROM attach WHERE filename = '%s' AND is_dir = 1 AND uid = %d $sql_extra limit 1", $r = q("SELECT folder, hash, is_dir, filename, os_path, display_path FROM attach WHERE filename = '%s' AND is_dir = 1 AND uid = %d $sql_extra limit 1",
@ -693,7 +707,6 @@ function photos_album_exists($channel_id, $observer_hash, $album) {
* @param string $newname The new name of the album * @param string $newname The new name of the album
* @return bool|array * @return bool|array
*/ */
function photos_album_rename($channel_id, $oldname, $newname) { function photos_album_rename($channel_id, $oldname, $newname) {
return q("UPDATE photo SET album = '%s' WHERE album = '%s' AND uid = %d", return q("UPDATE photo SET album = '%s' WHERE album = '%s' AND uid = %d",
dbesc($newname), dbesc($newname),
@ -702,17 +715,14 @@ function photos_album_rename($channel_id, $oldname, $newname) {
); );
} }
/** /**
* @brief * @brief
* *
* @param int $channel_id * @param int $channel_id
* @param string $album * @param string $album
* @param string $remote_xchan * @param string $remote_xchan (optional) default empty
* @return string|boolean * @return string|boolean
*/ */
function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') { function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') {
if($remote_xchan) { if($remote_xchan) {
@ -746,15 +756,13 @@ function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') {
* @param array $channel * @param array $channel
* @param string $creator_hash * @param string $creator_hash
* @param array $photo * @param array $photo
* @param boolean $visible default false * @param boolean $visible (optional) default false
* @return int item_id * @return int item_id
*/ */
function photos_create_item($channel, $creator_hash, $photo, $visible = false) { function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
// Create item container // Create item container
$item_hidden = (($visible) ? 0 : 1 ); $item_hidden = (($visible) ? 0 : 1 );
$mid = item_message_id(); $mid = item_message_id();
@ -794,36 +802,36 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
function getGps($exifCoord, $hemi) { function getGps($exifCoord, $hemi) {
$degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0; $degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
$minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0; $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;
$seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0; $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;
$flip = ($hemi == 'W' or $hemi == 'S') ? -1 : 1; $flip = ($hemi == 'W' or $hemi == 'S') ? -1 : 1;
return floatval($flip * ($degrees + ($minutes / 60) + ($seconds / 3600))); return floatval($flip * ($degrees + ($minutes / 60) + ($seconds / 3600)));
} }
function getGpstimestamp($exifCoord) { function getGpstimestamp($exifCoord) {
$hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0; $hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
$minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0; $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;
$seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0; $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;
return sprintf('%02d:%02d:%02d',$hours,$minutes,$seconds); return sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
} }
function gps2Num($coordPart) { function gps2Num($coordPart) {
$parts = explode('/', $coordPart); $parts = explode('/', $coordPart);
if (count($parts) <= 0) if (count($parts) <= 0)
return 0; return 0;
if (count($parts) == 1) if (count($parts) == 1)
return $parts[0]; return $parts[0];
return floatval($parts[0]) / floatval($parts[1]); return floatval($parts[0]) / floatval($parts[1]);
} }
@ -835,7 +843,7 @@ function photo_profile_setperms($channel_id,$resource_id,$profile_id) {
$r = q("select profile_guid, is_default from profile where id = %d and uid = %d limit 1", $r = q("select profile_guid, is_default from profile where id = %d and uid = %d limit 1",
dbesc($profile_id), dbesc($profile_id),
intval($channel_id) intval($channel_id)
); );
if(! $r) if(! $r)
return; return;
@ -844,26 +852,26 @@ function photo_profile_setperms($channel_id,$resource_id,$profile_id) {
$profile_guid = $r[0]['profile_guid']; $profile_guid = $r[0]['profile_guid'];
if($is_default) { if($is_default) {
$r = q("update photo set allow_cid = '', allow_gid = '', deny_cid = '', deny_gid = '' $r = q("update photo set allow_cid = '', allow_gid = '', deny_cid = '', deny_gid = ''
where resource_id = '%s' and uid = %d", where resource_id = '%s' and uid = %d",
dbesc($resource_id), dbesc($resource_id),
intval($channel_id) intval($channel_id)
); );
$r = q("update attach set allow_cid = '', allow_gid = '', deny_cid = '', deny_gid = '' $r = q("update attach set allow_cid = '', allow_gid = '', deny_cid = '', deny_gid = ''
where hash = '%s' and uid = %d", where hash = '%s' and uid = %d",
dbesc($resource_id), dbesc($resource_id),
intval($channel_id) intval($channel_id)
); );
} }
else { else {
$r = q("update photo set allow_cid = '', allow_gid = '%s', deny_cid = '', deny_gid = '' $r = q("update photo set allow_cid = '', allow_gid = '%s', deny_cid = '', deny_gid = ''
where resource_id = '%s' and uid = %d", where resource_id = '%s' and uid = %d",
dbesc('<vp.' . $profile_guid . '>'), dbesc('<vp.' . $profile_guid . '>'),
dbesc($resource_id), dbesc($resource_id),
intval($channel_id) intval($channel_id)
); );
$r = q("update attach set allow_cid = '', allow_gid = '%s', deny_cid = '', deny_gid = '' $r = q("update attach set allow_cid = '', allow_gid = '%s', deny_cid = '', deny_gid = ''
where hash = '%s' and uid = %d", where hash = '%s' and uid = %d",
dbesc('<vp.' . $profile_guid . '>'), dbesc('<vp.' . $profile_guid . '>'),
dbesc($resource_id), dbesc($resource_id),
@ -872,71 +880,72 @@ function photo_profile_setperms($channel_id,$resource_id,$profile_id) {
} }
} }
/**
* @brief
*
* @param int $uid
* @param int|string $profileid
*/
function profile_photo_set_profile_perms($uid, $profileid = 0) { function profile_photo_set_profile_perms($uid, $profileid = 0) {
$allowcid = ''; $allowcid = '';
if($profileid) { if($profileid) {
$r = q("SELECT photo, profile_guid, id, is_default, uid
FROM profile WHERE uid = %d and ( profile.id = %d OR profile.profile_guid = '%s') LIMIT 1",
intval($uid),
intval($profileid),
dbesc($profileid)
);
}
else {
logger('Resetting permissions on default-profile-photo for user'.local_channel());
$r = q("SELECT photo, profile_guid, id, is_default, uid $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile
FROM profile WHERE uid = %d and ( profile.id = %d OR profile.profile_guid = '%s') LIMIT 1", WHERE profile.uid = %d AND is_default = 1 LIMIT 1",
intval($uid), intval($uid)
intval($profileid), ); //If no profile is given, we update the default profile
dbesc($profileid) }
if(! $r)
return;
$profile = $r[0];
if($profile['id'] && $profile['photo']) {
preg_match("@\w*(?=-\d*$)@i", $profile['photo'], $resource_id);
$resource_id = $resource_id[0];
if (! intval($profile['is_default'])) {
$r0 = q("SELECT channel_hash FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
);
//Should not be needed in future. Catches old int-profile-ids.
$r1 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%d' ",
intval($profile['id'])
);
$r2 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%s'",
dbesc($profile['profile_guid'])
);
$allowcid = "<" . $r0[0]['channel_hash'] . ">";
foreach ($r1 as $entry) {
$allowcid .= "<" . $entry['abook_xchan'] . ">";
}
foreach ($r2 as $entry) {
$allowcid .= "<" . $entry['abook_xchan'] . ">";
}
q("UPDATE photo SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",
dbesc($allowcid),
dbesc($resource_id),
intval($uid)
); );
} }
else { else {
logger('Resetting permissions on default-profile-photo for user'.local_channel()); //Reset permissions on default profile picture to public
q("UPDATE photo SET allow_cid = '' WHERE photo_usage = %d AND uid = %d",
$r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile intval(PHOTO_PROFILE),
WHERE profile.uid = %d AND is_default = 1 LIMIT 1",
intval($uid) intval($uid)
); //If no profile is given, we update the default profile );
} }
if(! $r)
return;
$profile = $r[0];
if($profile['id'] && $profile['photo']) {
preg_match("@\w*(?=-\d*$)@i", $profile['photo'], $resource_id);
$resource_id = $resource_id[0];
if (! intval($profile['is_default'])) {
$r0 = q("SELECT channel_hash FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
);
//Should not be needed in future. Catches old int-profile-ids.
$r1 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%d' ",
intval($profile['id'])
);
$r2 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%s'",
dbesc($profile['profile_guid'])
);
$allowcid = "<" . $r0[0]['channel_hash'] . ">";
foreach ($r1 as $entry) {
$allowcid .= "<" . $entry['abook_xchan'] . ">";
}
foreach ($r2 as $entry) {
$allowcid .= "<" . $entry['abook_xchan'] . ">";
}
q("UPDATE photo SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",
dbesc($allowcid),
dbesc($resource_id),
intval($uid)
);
}
else {
//Reset permissions on default profile picture to public
q("UPDATE photo SET allow_cid = '' WHERE photo_usage = %d AND uid = %d",
intval(PHOTO_PROFILE),
intval($uid)
);
}
}
return;
} }
}

View file

@ -7,7 +7,7 @@
/** /**
* @brief unloads an addon. * @brief Unloads an addon.
* *
* @param string $plugin name of the addon * @param string $plugin name of the addon
*/ */
@ -22,7 +22,7 @@ function unload_plugin($plugin){
} }
/** /**
* @brief uninstalls an addon. * @brief Uninstalls an addon.
* *
* @param string $plugin name of the addon * @param string $plugin name of the addon
* @return boolean * @return boolean
@ -110,6 +110,13 @@ function load_plugin($plugin) {
} }
} }
/**
* @brief Check if addon is installed.
*
* @param string $name
* @return boolean
*/
function plugin_is_installed($name) { function plugin_is_installed($name) {
$r = q("select aname from addon where aname = '%s' and installed = 1 limit 1", $r = q("select aname from addon where aname = '%s' and installed = 1 limit 1",
dbesc($name) dbesc($name)
@ -121,8 +128,9 @@ function plugin_is_installed($name) {
} }
// reload all updated plugins /**
* @brief Reload all updated plugins.
*/
function reload_plugins() { function reload_plugins() {
$plugins = get_config('system', 'addon'); $plugins = get_config('system', 'addon');
if(strlen($plugins)) { if(strlen($plugins)) {
@ -167,13 +175,18 @@ function reload_plugins() {
} }
} }
/**
* @brief Get a list of non hidden addons.
*
* @return array
*/
function visible_plugin_list() { function visible_plugin_list() {
$r = q("select * from addon where hidden = 0 order by aname asc"); $r = q("select * from addon where hidden = 0 order by aname asc");
return(($r) ? ids_to_array($r,'aname') : array()); return(($r) ? ids_to_array($r,'aname') : array());
} }
/** /**
* @brief registers a hook. * @brief registers a hook.
* *
@ -282,7 +295,7 @@ function insert_hook($hook, $fn, $version = 0, $priority = 0) {
* the provided data. * the provided data.
* *
* @param string $name of the hook to call * @param string $name of the hook to call
* @param string|array &$data to transmit to the callback handler * @param[in,out] string|array &$data to transmit to the callback handler
*/ */
function call_hooks($name, &$data = null) { function call_hooks($name, &$data = null) {
$a = 0; $a = 0;
@ -414,8 +427,8 @@ function check_plugin_versions($info) {
|| stristr($info['serverroles'],'any') || stristr($info['serverroles'],'any')
|| stristr($info['serverroles'],$role))) { || stristr($info['serverroles'],$role))) {
logger('serverrole limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING); logger('serverrole limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING);
return false;
return false;
} }
} }
@ -447,8 +460,6 @@ function check_plugin_versions($info) {
} }
/** /**
* @brief Parse theme comment in search of theme infos. * @brief Parse theme comment in search of theme infos.
* *
@ -532,7 +543,7 @@ function get_theme_info($theme){
* *
* The screenshot is expected as view/theme/$theme/img/screenshot.[png|jpg]. * The screenshot is expected as view/theme/$theme/img/screenshot.[png|jpg].
* *
* @param sring $theme The name of the theme * @param string $theme The name of the theme
* @return string * @return string
*/ */
function get_theme_screenshot($theme) { function get_theme_screenshot($theme) {
@ -626,15 +637,16 @@ function format_css_if_exists($source) {
} }
} }
/* /**
* This basically calculates the baseurl. We have other functions to do that, but * This basically calculates the baseurl. We have other functions to do that, but
* there was an issue with script paths and mixed-content whose details are arcane * there was an issue with script paths and mixed-content whose details are arcane
* and perhaps lost in the message archives. The short answer is that we're ignoring * and perhaps lost in the message archives. The short answer is that we're ignoring
* the URL which we are "supposed" to use, and generating script paths relative to * the URL which we are "supposed" to use, and generating script paths relative to
* the URL which we are currently using; in order to ensure they are found and aren't * the URL which we are currently using; in order to ensure they are found and aren't
* blocked due to mixed content issues. * blocked due to mixed content issues.
*
* @return string
*/ */
function script_path() { function script_path() {
if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS']) if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS'])
$scheme = 'https'; $scheme = 'https';
@ -659,6 +671,7 @@ function script_path() {
else { else {
return z_root(); return z_root();
} }
return $scheme . '://' . $hostname; return $scheme . '://' . $hostname;
} }
@ -675,10 +688,13 @@ function head_remove_js($src, $priority = 0) {
unset(App::$js_sources[$priority][$index]); unset(App::$js_sources[$priority][$index]);
} }
// We should probably try to register main.js with a high priority, but currently we handle it /**
// separately and put it at the end of the html head block in case any other javascript is * We should probably try to register main.js with a high priority, but currently
// added outside the head_add_js construct. * we handle it separately and put it at the end of the html head block in case
* any other javascript is added outside the head_add_js construct.
*
* @return string
*/
function head_get_js() { function head_get_js() {
$str = ''; $str = '';
@ -694,6 +710,7 @@ function head_get_js() {
} }
} }
} }
return $str; return $str;
} }
@ -703,6 +720,7 @@ function head_get_main_js() {
if(count($sources)) if(count($sources))
foreach($sources as $source) foreach($sources as $source)
$str .= format_js_if_exists($source,true); $str .= format_js_if_exists($source,true);
return $str; return $str;
} }
@ -716,7 +734,7 @@ function format_js_if_exists($source) {
if(substr($source,0,2) === '//') { if(substr($source,0,2) === '//') {
$path_prefix = ''; $path_prefix = '';
} }
} }
else { else {
// It's a file from the theme // It's a file from the theme
$path = '/' . theme_include($source); $path = '/' . theme_include($source);
@ -781,12 +799,16 @@ function get_markup_template($s, $root = '') {
return $template; return $template;
} }
/**
* @brief
*
* @param string $folder
* @return boolean|string
*/
function folder_exists($folder) {
// Get canonicalized absolute pathname
$path = realpath($folder);
function folder_exists($folder) // If it exist, check if it's a directory
{ return (($path !== false) && is_dir($path)) ? $path : false;
// Get canonicalized absolute pathname
$path = realpath($folder);
// If it exist, check if it's a directory
return (($path !== false) && is_dir($path)) ? $path : false;
} }

View file

@ -21,6 +21,7 @@ function is_matrix_url($url) {
} }
$remembered[$m['host']] = false; $remembered[$m['host']] = false;
} }
return false; return false;
} }
@ -32,14 +33,8 @@ function is_matrix_url($url) {
* @param boolean $address * @param boolean $address
* $address to use instead of session environment * $address to use instead of session environment
* @return string * @return string
*
* @hooks 'zid'
* string url - url to accept zid
* string zid - urlencoded zid
* string result - the return string we calculated, change it if you want to return something else
*/ */
function zid($s, $address = '') {
function zid($s,$address = '') {
if (! strlen($s) || strpos($s,'zid=')) if (! strlen($s) || strpos($s,'zid='))
return $s; return $s;
@ -74,7 +69,18 @@ function zid($s,$address = '') {
if($fragment) if($fragment)
$zurl .= '#' . $fragment; $zurl .= '#' . $fragment;
$arr = array('url' => $s, 'zid' => urlencode($myaddr), 'result' => $zurl); $arr = [
'url' => $s,
'zid' => urlencode($myaddr),
'result' => $zurl
];
/**
* @hooks zid
* Called when adding the observer's zid to a URL.
* * \e string \b url - url to accept zid
* * \e string \b zid - urlencoded zid
* * \e string \b result - the return string we calculated, change it if you want to return something else
*/
call_hooks('zid', $arr); call_hooks('zid', $arr);
return $arr['result']; return $arr['result'];
@ -125,25 +131,26 @@ function strip_auth_query_params() {
* because the latter is used for general purpose conversions and the former is used only when preparing text for * because the latter is used for general purpose conversions and the former is used only when preparing text for
* immediate display. * immediate display.
* *
* Issues: Currently the order of HTML parameters in the text is somewhat rigid and inflexible. * @TODO Issues: Currently the order of HTML parameters in the text is somewhat rigid and inflexible.
* We assume it looks like \<a class="zrl" href="xxxxxxxxxx"\> and will not work if zrl and href appear in a different order. * We assume it looks like \<a class="zrl" href="xxxxxxxxxx"\> and will not work if zrl and href appear in a different order.
* *
* @param array $match * @param array $match
* @return string * @return string
*/ */
function zidify_callback($match) { function zidify_callback($match) {
$is_zid = ((feature_enabled(local_channel(),'sendzid')) || (strpos($match[1],'zrl')) ? true : false); $is_zid = ((feature_enabled(local_channel(), 'sendzid')) || (strpos($match[1], 'zrl')) ? true : false);
$replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"'; $replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"';
$x = str_replace($match[0],$replace,$match[0]);
$x = str_replace($match[0], $replace, $match[0]);
return $x; return $x;
} }
function zidify_img_callback($match) { function zidify_img_callback($match) {
$is_zid = ((feature_enabled(local_channel(),'sendzid')) || (strpos($match[1],'zrl')) ? true : false); $is_zid = ((feature_enabled(local_channel(), 'sendzid')) || (strpos($match[1], 'zrl')) ? true : false);
$replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"'; $replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"';
$x = str_replace($match[0],$replace,$match[0]); $x = str_replace($match[0], $replace, $match[0]);
return $x; return $x;
} }
@ -157,12 +164,11 @@ function zidify_links($s) {
} }
function zidify_text_callback($match) { function zidify_text_callback($match) {
$is_zid = is_matrix_url($match[2]); $is_zid = is_matrix_url($match[2]);
$replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"'; $replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"';
$x = str_replace($match[0],$replace,$match[0]);
$x = str_replace($match[0], $replace, $match[0]);
return $x; return $x;
} }
@ -171,7 +177,7 @@ function zidify_text_img_callback($match) {
$is_zid = is_matrix_url($match[2]); $is_zid = is_matrix_url($match[2]);
$replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"'; $replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"';
$x = str_replace($match[0],$replace,$match[0]); $x = str_replace($match[0], $replace, $match[0]);
return $x; return $x;
} }
@ -182,8 +188,6 @@ function zidify_text($s) {
$s = preg_replace_callback('/\<img(.*?)src\=\"(.*?)\"/ism','zidify_text_img_callback',$s); $s = preg_replace_callback('/\<img(.*?)src\=\"(.*?)\"/ism','zidify_text_img_callback',$s);
return $s; return $s;
} }
@ -223,7 +227,6 @@ function red_zrl_callback($matches) {
* @param array $matches * @param array $matches
* @return string * @return string
*/ */
function red_escape_zrl_callback($matches) { function red_escape_zrl_callback($matches) {
// Uncertain why the url/zrl forms weren't picked up by the non-greedy regex. // Uncertain why the url/zrl forms weren't picked up by the non-greedy regex.
@ -259,11 +262,17 @@ function red_zrlify_img_callback($matches) {
return $matches[0]; return $matches[0];
} }
/**
* @brief OpenWebAuth authentication.
*
* @param string $token
*/
function owt_init($token) { function owt_init($token) {
\Zotlabs\Zot\Verify::purge('owt','3 MINUTE'); \Zotlabs\Zot\Verify::purge('owt', '3 MINUTE');
$ob_hash = \Zotlabs\Zot\Verify::get_meta('owt',0,$token); $ob_hash = \Zotlabs\Zot\Verify::get_meta('owt', 0, $token);
if($ob_hash === false) { if($ob_hash === false) {
return; return;
@ -287,7 +296,7 @@ function owt_init($token) {
} }
if(! $r) { if(! $r) {
logger('owt: unable to finger ' . $ob_hash); logger('owt: unable to finger ' . $ob_hash);
return; return;
} }
$hubloc = $r[0]; $hubloc = $r[0];
@ -321,14 +330,25 @@ function owt_init($token) {
$_SESSION['DNT'] = 1; $_SESSION['DNT'] = 1;
} }
$arr = array('xchan' => $hubloc, 'url' => \App::$query_string, 'session' => $_SESSION); $arr = [
call_hooks('magic_auth_success',$arr); 'xchan' => $hubloc,
'url' => \App::$query_string,
'session' => $_SESSION
];
/**
* @hooks magic_auth_success
* Called when a magic-auth was successful.
* * \e array \b xchan
* * \e string \b url
* * \e array \b session
*/
call_hooks('magic_auth_success', $arr);
\App::set_observer($hubloc); \App::set_observer($hubloc);
require_once('include/security.php'); require_once('include/security.php');
\App::set_groups(init_groups_visitor($_SESSION['visitor_id'])); \App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
if(! get_config('system','hide_owa_greeting')) if(! get_config('system', 'hide_owa_greeting'))
info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),\App::get_hostname(), $hubloc['xchan_name'])); info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),\App::get_hostname(), $hubloc['xchan_name']));
logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']); logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
} }

File diff suppressed because it is too large Load diff