aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/acl_selectors.php4
-rw-r--r--include/api_auth.php3
-rw-r--r--include/api_zot.php11
-rw-r--r--include/attach.php313
-rw-r--r--include/bbcode.php21
-rw-r--r--include/channel.php522
-rw-r--r--include/connections.php2
-rw-r--r--include/contact_widgets.php87
-rw-r--r--include/conversation.php86
-rw-r--r--include/datetime.php87
-rw-r--r--include/event.php139
-rw-r--r--include/features.php19
-rw-r--r--include/feedutils.php191
-rw-r--r--include/follow.php3
-rw-r--r--include/group.php8
-rw-r--r--include/help.php28
-rw-r--r--include/html2bbcode.php12
-rw-r--r--include/import.php72
-rwxr-xr-xinclude/items.php786
-rw-r--r--include/language.php23
-rw-r--r--include/markdown.php82
-rw-r--r--include/message.php7
-rw-r--r--include/nav.php44
-rw-r--r--include/network.php235
-rw-r--r--include/photo/photo_driver.php138
-rw-r--r--include/photos.php285
-rwxr-xr-xinclude/plugin.php70
-rw-r--r--include/queue_fn.php9
-rw-r--r--include/security.php1
-rw-r--r--include/socgraph.php6
-rw-r--r--include/taxonomy.php102
-rw-r--r--include/text.php42
-rw-r--r--include/zid.php90
-rw-r--r--include/zot.php528
34 files changed, 2655 insertions, 1401 deletions
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 09c24f82c..4e203074b 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -110,7 +110,7 @@ function fixacl(&$item) {
*
* @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 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 $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.
@@ -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)) {
$just_me = true;
$custom = false;
- }
+ }
$r = q("SELECT id, profile_guid, profile_name from profile where is_default = 0 and uid = %d order by profile_name",
intval(local_channel())
diff --git a/include/api_auth.php b/include/api_auth.php
index 0818fa54b..5c0bcb317 100644
--- a/include/api_auth.php
+++ b/include/api_auth.php
@@ -52,6 +52,7 @@ function api_login(&$a){
/* Signature authentication */
if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+
if($head !== 'HTTP_AUTHORIZATION') {
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
continue;
@@ -59,7 +60,7 @@ function api_login(&$a){
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) {
- $keyId = $sigblock['keyId'];
+ $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) {
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($keyId)
diff --git a/include/api_zot.php b/include/api_zot.php
index aaa9ee497..54f905b4c 100644
--- a/include/api_zot.php
+++ b/include/api_zot.php
@@ -150,7 +150,11 @@
$start = ((array_key_exists('start',$_REQUEST)) ? intval($_REQUEST['start']) : 0);
$records = ((array_key_exists('records',$_REQUEST)) ? intval($_REQUEST['records']) : 0);
- $x = attach_list_files(api_user(),get_observer_hash(),$hash,$filename,$filetype,'created asc',$start,$records);
+ $since = ((array_key_exists('since',$_REQUEST)) ? datetime_convert(date_default_timezone_get(),'UTC',$_REQUEST['since']) : NULL_DATE);
+ $until = ((array_key_exists('until',$_REQUEST)) ? datetime_convert(date_default_timezone_get(),'UTC',$_REQUEST['until']) : datetime_convert());
+
+ $x = attach_list_files(api_user(),get_observer_hash(),$hash,$filename,$filetype,'created asc',$start,$records, $since, $until);
+
if($start || $records) {
$x['start'] = $start;
$x['records'] = count($x['results']);
@@ -226,7 +230,10 @@
if(! $_REQUEST['file_id'])
return false;
- $ret = attach_export_data(api_user(),$_REQUEST['file_id']);
+ $channel = channelx_by_n(api_user());
+
+ $ret = attach_export_data($channel,$_REQUEST['file_id']);
+
if($ret) {
json_return_and_die($ret);
}
diff --git a/include/attach.php b/include/attach.php
index e1db67af4..39269eb03 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -21,7 +21,7 @@ require_once('include/group.php');
* This function takes a file name and guess the mimetype from the
* filename extension.
*
- * @param $filename a string filename
+ * @param string $filename a string filename
* @return string The mimetype according to a file ending.
*/
function z_mime_content_type($filename) {
@@ -31,7 +31,6 @@ function z_mime_content_type($filename) {
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
- 'php' => 'text/html',
'css' => 'text/css',
'md' => 'text/markdown',
'bb' => 'text/bbcode',
@@ -41,8 +40,17 @@ function z_mime_content_type($filename) {
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
'epub' => 'application/epub+zip',
+ 'c' => 'text/plain',
+ 'h' => 'text/plain',
+ 'sh' => 'text/plain',
+ 'py' => 'text/plain',
+ 'php' => 'text/plain',
+ 'rb' => 'text/plain',
+ 'pdl' => 'text/plain',
+
// images
+
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
@@ -73,9 +81,7 @@ function z_mime_content_type($filename) {
'flac' => 'audio/flac',
'opus' => 'audio/ogg',
'webm' => 'video/webm',
-// 'webm' => 'audio/webm',
'mp4' => 'video/mp4',
-// 'mp4' => 'audio/mp4',
'mkv' => 'video/x-matroska',
// adobe
@@ -183,7 +189,7 @@ function attach_count_files($channel_id, $observer, $hash = '', $filename = '',
* * \e array|boolean \b results array with results, or false
* * \e string \b message with error messages if any
*/
-function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $filetype = '', $orderby = 'created desc', $start = 0, $entries = 0) {
+function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $filetype = '', $orderby = 'created desc', $start = 0, $entries = 0, $since = '', $until = '') {
$ret = array('success' => false);
@@ -192,6 +198,7 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $
return $ret;
}
+
require_once('include/security.php');
$sql_extra = permissions_sql($channel_id);
@@ -207,14 +214,22 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $
if($entries)
$limit = " limit " . intval($start) . ", " . intval($entries) . " ";
- // Retrieve all columns except 'data'
+ if(! $since)
+ $since = NULL_DATE;
+
+ if(! $until)
+ $until = datetime_convert();
+
+ $sql_extra .= " and created >= '" . dbesc($since) . "' and created <= '" . dbesc($until) . "' ";
+
+ // Retrieve all columns except 'content'
$r = q("select id, aid, uid, hash, filename, filetype, filesize, revision, folder, os_path, display_path, os_storage, is_dir, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d $sql_extra ORDER BY $orderby $limit",
intval($channel_id)
);
$ret['success'] = ((is_array($r)) ? true : false);
- $ret['results'] = ((is_array($r)) ? $r : false);
+ $ret['results'] = ((is_array($r)) ? $r : []);
return $ret;
}
@@ -270,6 +285,8 @@ function attach_by_hash($hash, $observer_hash, $rev = 0) {
return $ret;
}
+ $r[0]['content'] = dbunescbin($r[0]['content']);
+
if($r[0]['folder']) {
$x = attach_can_view_folder($r[0]['uid'],$observer_hash,$r[0]['folder']);
if(! $x) {
@@ -291,6 +308,11 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
$hash = $folder_hash;
$result = false;
+ if(! $folder_hash) {
+ return perm_is_allowed($uid,$ob_hash,'view_storage');
+ }
+
+
do {
$r = q("select folder from attach where hash = '%s' and uid = %d $sql_extra",
dbesc($hash),
@@ -412,6 +434,10 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
require_once('include/photos.php');
+ /**
+ * @hooks photo_upload_begin
+ * Called when attempting to upload a photo.
+ */
call_hooks('photo_upload_begin', $arr);
$ret = array('success' => false);
@@ -486,14 +512,36 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$x = attach_mkdir($channel,$observer_hash,$arr);
if($x['message'])
logger('import_directory: ' . $x['message']);
+
return;
}
}
elseif($options !== 'update') {
- $f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => '');
-
- call_hooks('photo_upload_file',$f);
- call_hooks('attach_upload_file',$f);
+ $f = [
+ 'src' => '',
+ 'filename' => '',
+ 'filesize' => 0,
+ 'type' => ''
+ ];
+
+ /**
+ * @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')) {
$src = $f['src'];
@@ -502,6 +550,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$type = $f['type'];
} else {
if(! x($_FILES,'userfile')) {
+ logger('No source file');
$ret['message'] = t('No source file.');
return $ret;
}
@@ -542,6 +591,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($channel_id)
);
if(! $x) {
+ logger('update file source not found');
$ret['message'] = t('Cannot locate file to revise/update');
return $ret;
}
@@ -562,6 +612,12 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$def_extension = '.png';
}
+ // If we know it's a photo, over-ride the type in case the source system could not determine what it was
+
+ if($is_photo) {
+ $type = $gis['mime'];
+ }
+
$pathname = '';
if($is_photo) {
@@ -677,10 +733,17 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$maxfilesize = get_config('system','maxfilesize');
if(($maxfilesize) && ($filesize > $maxfilesize)) {
+ logger('quota_exceeded');
$ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize);
if($remove_when_processed)
@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;
}
@@ -691,11 +754,17 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($channel['channel_account_id'])
);
if(($r) && (($r[0]['total'] + $filesize) > ($limit - $existing_size))) {
+ logger('service_class limit exceeded');
$ret['message'] = upgrade_message(true) . sprintf(t("You have reached your limit of %1$.0f Mbytes attachment storage."), $limit / 1024000);
if($remove_when_processed)
@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;
}
}
@@ -718,8 +787,15 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$os_path = $os_relpath;
$display_path = ltrim($pathname . '/' . $filename,'/');
- if($src)
- @file_put_contents($os_basepath . $os_relpath,@file_get_contents($src));
+ if($src) {
+ $istream = @fopen($src,'rb');
+ $ostream = @fopen($os_basepath . $os_relpath,'wb');
+ if($istream && $ostream) {
+ pipe_streams($istream,$ostream,65535);
+ fclose($istream);
+ fclose($ostream);
+ }
+ }
if(array_key_exists('created', $arr))
$created = $arr['created'];
@@ -773,7 +849,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
);
}
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",
dbesc((array_key_exists('filename',$arr)) ? $arr['filename'] : $x[0]['filename']),
dbesc((array_key_exists('filetype',$arr)) ? $arr['filetype'] : $x[0]['filetype']),
@@ -862,7 +938,13 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if(! $r) {
$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;
}
@@ -875,17 +957,30 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if(! $r) {
$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;
}
$ret['success'] = true;
$ret['data'] = $r[0];
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);
}
+ \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $hash ]);
+
+
if($dosync) {
$sync = attach_export_data($channel,$hash);
@@ -894,9 +989,9 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
}
if($notify) {
- //$cloudPath = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['0']['display_path'];
- //$object = get_file_activity_object($channel['channel_id'], $r['0']['hash'], $cloudPath);
- //file_activity($channel['channel_id'], $object, $r['0']['allow_cid'], $r['0']['allow_gid'], $r['0']['deny_cid'], $r['0']['deny_gid'], 'post', $notify);
+ $cloudPath = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['0']['display_path'];
+ $object = get_file_activity_object($channel['channel_id'], $r['0']['hash'], $cloudPath);
+ file_activity($channel['channel_id'], $object, $r['0']['allow_cid'], $r['0']['allow_gid'], $r['0']['deny_cid'], $r['0']['deny_gid'], 'post', $notify);
}
return $ret;
@@ -986,7 +1081,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
$os_basepath = 'store/' . $channel['channel_address'];
- logger('attach_mkdir: basepath: ' . $os_basepath);
+ logger('basepath: ' . $os_basepath);
if(! is_dir($os_basepath))
os_mkdir($os_basepath,STORAGE_DEFAULT_PERMISSIONS, true);
@@ -1055,7 +1150,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
return $ret;
}
- $dpath = $r[0]['filename'] . (($dpath) ? '/' . $dpath : '');
+ $dpath = $r[0]['filename'] . (($dpath) ? '/' . $dpath : '');
if($lfile)
$lpath = $r[0]['hash'] . (($lpath) ? '/' . $lpath : '');
@@ -1154,7 +1249,7 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
$basepath = 'store/' . $channel['channel_address'];
- logger('attach_mkdirp: basepath: ' . $basepath);
+ logger('basepath: ' . $basepath);
if(! is_dir($basepath))
os_mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS, true);
@@ -1180,6 +1275,7 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
foreach($paths as $p) {
if(! $p)
continue;
+
$arx = array(
'filename' => $p,
'folder' => $current_parent,
@@ -1308,7 +1404,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
);
if(! $r) {
- attach_drop_photo($channel_id,$resource);
+ attach_drop_photo($channel_id,$resource);
return;
}
@@ -1367,7 +1463,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
intval($channel_id)
);
- file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', $notify=1);
+ file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', true);
return;
}
@@ -1501,6 +1597,13 @@ function find_folder_hash_by_attach_hash($channel_id, $attachHash, $recurse = fa
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) {
if(! $path)
@@ -1530,7 +1633,6 @@ function find_folder_hash_by_path($channel_id, $path) {
return '';
return $parent_hash;
-
}
/**
@@ -1557,14 +1659,17 @@ function find_filename_by_hash($channel_id, $attachHash) {
}
/**
+ * @brief Pipes $in to $out in 16KB chunks.
*
- * @param $in
- * @param $out
+ * @param resource $in File pointer of input
+ * @param resource $out File pointer of output
+ * @param int $bufsize size of chunk, default 16384
+ * @return number with the size
*/
-function pipe_streams($in, $out) {
+function pipe_streams($in, $out, $bufsize = 16384) {
$size = 0;
while (!feof($in))
- $size += fwrite($out, fread($in, 16384));
+ $size += fwrite($out, fread($in, $bufsize));
return $size;
}
@@ -1726,11 +1831,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 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) {
@@ -1958,6 +2064,7 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
if($hash_ptr === $resource_id) {
$attach_ptr = $r[0];
}
+ $r[0]['content'] = dbunescbin($r[0]['content']);
$hash_ptr = $r[0]['folder'];
$paths[] = $r[0];
@@ -1970,6 +2077,9 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
if($attach_ptr['is_photo']) {
+
+ // This query could potentially result in a few megabytes of data use.
+
$r = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale asc",
dbesc($resource_id),
intval($channel['channel_id'])
@@ -1981,6 +2091,17 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
$ret['photo'] = $r;
}
+// This query can be used instead in memory starved environments. There will be a corresponding
+// performance hit during sync because the data will need to be fetched over the network.
+// $r = q("select aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,profile,is_nsfw,os_storage,display_path,photo_flags,allow_cid,allow_gid,deny_cid,deny_gid from photo where resource_id = '%s' and uid = %d order by imgscale asc",
+// dbesc($resource_id),
+// intval($channel['channel_id'])
+// );
+
+// if($r) {
+// $ret['photo'] = $r;
+// }
+
$r = q("select * from item where resource_id = '%s' and resource_type = 'photo' and uid = %d ",
dbesc($resource_id),
intval($channel['channel_id'])
@@ -2143,7 +2264,6 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat
* the attach.hash of the new parent folder, which must already exist. If $new_folder_hash is blank or empty,
* the file is relocated to the root of the channel's storage area.
*
- * @fixme: this operation is currently not synced to clones !!
*
* @param int $channel_id
* @param int $resource_id
@@ -2153,7 +2273,7 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat
function attach_move($channel_id, $resource_id, $new_folder_hash) {
$c = channelx_by_n($channel_id);
- if(! $c)
+ if(! ($c && $resource_id))
return false;
$r = q("select * from attach where hash = '%s' and uid = %d limit 1",
@@ -2165,13 +2285,32 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$oldstorepath = dbunescbin($r[0]['content']);
+ if($r[0]['is_dir']) {
+ $move_success = true;
+ $x = q("select hash from attach where folder = '%s' and uid = %d",
+ dbesc($r[0]['hash']),
+ intval($channel_id)
+ );
+ if($x) {
+ foreach($x as $xv) {
+ $rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']);
+ if(! $rs) {
+ $move_success = false;
+ break;
+ }
+ }
+ }
+ return $move_success;
+ }
+
+
if($new_folder_hash) {
- $n = q("select * from attach where hash = '%s' and uid = %d limit 1",
+ $n = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1",
dbesc($new_folder_hash),
intval($channel_id)
);
if(! $n)
- return;
+ return false;
$newdirname = $n[0]['filename'];
$newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id;
@@ -2257,7 +2396,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
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",
dbesc($newdirname),
dbesc($filename),
@@ -2278,6 +2417,11 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
}
+/**
+ * Used to generate a select input box of all your folders
+ */
+
+
function attach_folder_select_list($channel_id) {
$r = q("select * from attach where is_dir = 1 and uid = %d",
@@ -2328,6 +2472,10 @@ function attach_folder_rpaths($all_folders,$that_folder) {
return (($error) ? false : [ $current_hash , $path ]);
}
+/**
+ * @brief Given a channel_id and attach_hash, return an array with the full relative path and os_path
+ */
+
function attach_syspaths($channel_id,$attach_hash) {
@@ -2349,10 +2497,19 @@ function attach_syspaths($channel_id,$attach_hash) {
while($attach_hash);
return [ 'os_path' => $os_path, 'path' => $path ];
-
-
}
+/**
+ * in earlier releases we did not fill in os_path and display_path in the attach DB structure.
+ * (It was not needed or used). Going forward we intend to make use of these fields.
+ * A cron task checks for empty values (as older attachments may have arrived at our site
+ * in a clone operation) and executes attach_syspaths() to generate these field values and correct
+ * the attach table entry. The operation is limited to 100 DB entries at a time so as not to
+ * overload the system in any cron run. Eventually it will catch up with old attach structures
+ * and switch into maintenance mode to correct any that might arrive in clone packets from older
+ * sites.
+ */
+
function attach_upgrade() {
@@ -2379,6 +2536,12 @@ function attach_upgrade() {
}
+/**
+ * Chunked uploader for integration with the blueimp jquery-uploader
+ * This is currently used.
+ */
+
+
function save_chunk($channel,$start,$end,$len) {
$result = [];
@@ -2386,7 +2549,7 @@ function save_chunk($channel,$start,$end,$len) {
$tmp_path = $_FILES['files']['tmp_name'];
$new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true);
-
+
$new_path = $new_base . '/' . $_FILES['files']['name'];
if(! file_exists($new_path)) {
@@ -2403,7 +2566,7 @@ function save_chunk($channel,$start,$end,$len) {
}
if(($len - 1) == $end) {
unlink($tmp_path);
- $result['name'] = $_FILES['files']['tmp_name'];
+ $result['name'] = $_FILES['files']['name'];
$result['type'] = $_FILES['files']['type'];
$result['tmp_name'] = $new_path;
$result['error'] = 0;
@@ -2417,65 +2580,3 @@ function save_chunk($channel,$start,$end,$len) {
}
-/*
- * chunkloader
- * Submit handler for chunked uploads
- *
- */
-
-function chunkloader($channel,$arr) {
-
- logger('request: ' . print_r($arr,true), LOGGER_DEBUG);
- logger('files: ' . print_r($_FILES,true), LOGGER_DEBUG);
-
-
- $result = [];
-
-
- $tmp_path = $_FILES['file']['tmp_name'];
- $new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
- os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true);
-
- $new_path = $new_base . '/' . $arr['resumableFilename'];
-
- rename($tmp_path,$new_path . '.' . intval($arr['resumableChunkNumber']));
-
- $missing_parts = false;
- for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) {
- if(! file_exists($new_path . '.' . $x)) {
- $missing_parts = true;
- break;
- }
- }
-
- if($missing_parts) {
- $result['partial'] = true;
- return $result;
- }
-
- if(intval($arr['resumableTotalChunks']) === 1) {
- rename($new_path . '.' . '1', $new_path);
- }
- else {
- for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) {
- $istream = fopen($new_path . '.' . $x,'rb');
- $ostream = fopen($new_path,'ab');
- if($istream && $ostream) {
- pipe_streams($istream,$ostream);
- fclose($istream);
- fclose($ostream);
- }
- unlink($new_path . '.' . $x);
- }
- }
-
- $result['name'] = $arr['resumableFilename'];
- $result['type'] = $arr['resumableType'];
- $result['tmp_name'] = $new_path;
- $result['error'] = 0;
- $result['size'] = $arr['resumableTotalSize'];
- $result['complete'] = true;
- return $result;
-
-}
-
diff --git a/include/bbcode.php b/include/bbcode.php
index 050ab2d29..775a91f9a 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -246,8 +246,8 @@ function bb_parse_element($match) {
$j = json_decode(base64url_decode($match[1]),true);
if ($j && local_channel()) {
- $text = sprintf( t('Install %s element: '), translate_design_element($j['type'])) . $j['pagetitle'];
- $o = EOL . '<a href="#" onclick="importElement(\'' . $match[1] . '\'); return false;" >' . $text . '</a>' . EOL;
+ $text = sprintf( t('Install %1$s element %2$s'), translate_design_element($j['type']), $j['pagetitle']);
+ $o = EOL . '<button class="btn btn-primary" onclick="importElement(\'' . $match[1] . '\'); return false;" >' . $text . '</button>' . EOL;
}
else {
$text = sprintf( t('This post contains an installable %s element, however you lack permissions to install it on this site.' ), translate_design_element($j['type'])) . $j['pagetitle'];
@@ -329,6 +329,8 @@ function bb_ShareAttributes($match) {
if(strpos($link,'/cards/'))
$type = t('card');
+ elseif(strpos($link,'/articles/'))
+ $type = t('article');
else
$type = t('post');
@@ -705,10 +707,12 @@ function parseIdentityAwareHTML($Text) {
return $Text;
}
- // BBcode 2 HTML was written by WAY2WEB.net
- // extended to work with Mistpark/Friendica/Redmatrix/Hubzilla - Mike Macgirvin
-function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) {
+function bbcode($Text, $options = []) {
+
+ $preserve_nl = ((array_key_exists('preserve_nl',$options)) ? $options['preserve_nl'] : false);
+ $tryoembed = ((array_key_exists('tryoembed',$options)) ? $options['tryoembed'] : true);
+ $cache = ((array_key_exists('cache',$options)) ? $options['cache'] : false);
call_hooks('bbcode_filter', $Text);
@@ -937,27 +941,34 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
// Check for h1
if (strpos($Text,'[h1]') !== false) {
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text);
+ $Text = str_replace('</h1><br />', '</h1>', $Text);
}
// Check for h2
if (strpos($Text,'[h2]') !== false) {
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text);
+ $Text = str_replace('</h2><br />', '</h2>', $Text);
}
// Check for h3
if (strpos($Text,'[h3]') !== false) {
$Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'<h3>$1</h3>',$Text);
+ $Text = str_replace('</h3><br />', '</h3>', $Text);
}
// Check for h4
if (strpos($Text,'[h4]') !== false) {
$Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'<h4>$1</h4>',$Text);
+ $Text = str_replace('</h4><br />', '</h4>', $Text);
}
// Check for h5
if (strpos($Text,'[h5]') !== false) {
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text);
+ $Text = str_replace('</h5><br />', '</h5>', $Text);
}
// Check for h6
if (strpos($Text,'[h6]') !== false) {
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
+ $Text = str_replace('</h6><br />', '</h6>', $Text);
}
+
// Check for table of content without params
while(strpos($Text,'[toc]') !== false) {
$toc_id = 'toc-' . random_string(10);
diff --git a/include/channel.php b/include/channel.php
index d7116ce28..b9adc588b 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -1,6 +1,7 @@
<?php
/**
* @file include/channel.php
+ * @brief Channel related functions.
*/
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
* sets, multi-byte length, etc.
*
- * @hooks validate_channelname
- * * \e array \b 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) {
@@ -72,6 +71,12 @@ function validate_channelname($name) {
return t('Name too long');
$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);
if (x($arr, 'message'))
@@ -96,14 +101,14 @@ function create_sys_channel() {
set_config('system', 'prvkey', $hostkey['prvkey']);
}
- create_identity(array(
- 'account_id' => 'xxx', // This will create an identity with an (integer) account_id of 0, but account_id is required
- 'nickname' => 'sys',
- 'name' => 'System',
- 'pageflags' => 0,
- 'publish' => 0,
- 'system' => 1
- ));
+ create_identity([
+ 'account_id' => 'xxx', // Typecast trickery: account_id is required. This will create an identity with an (integer) account_id of 0
+ 'nickname' => 'sys',
+ 'name' => 'System',
+ 'pageflags' => 0,
+ 'publish' => 0,
+ 'system' => 1
+ ]);
}
@@ -259,7 +264,6 @@ function create_identity($arr) {
'channel_system' => intval($system),
'channel_expire_days' => intval($expire),
'channel_timezone' => App::$timezone
-
]
);
@@ -280,9 +284,19 @@ function create_identity($arr) {
$photo_type = null;
- $z = [ 'account' => $a[0], 'channel' => $r[0], 'photo_url' => '' ];
- call_hooks('create_channel_photo',$z);
-
+ $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']) {
$photo_type = import_channel_photo_from_url($z['photo_url'],$arr['account_id'],$r[0]['channel_id']);
}
@@ -311,7 +325,7 @@ function create_identity($arr) {
'hubloc_guid_sig' => $sig,
'hubloc_hash' => $hash,
'hubloc_addr' => channel_reddress($ret['channel']),
- 'hubloc_primary' => $primary,
+ 'hubloc_primary' => intval($primary),
'hubloc_url' => z_root(),
'hubloc_url_sig' => base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey'])),
'hubloc_host' => App::get_hostname(),
@@ -322,7 +336,7 @@ function create_identity($arr) {
]
);
if(! $r)
- logger('create_identity: Unable to store hub location');
+ logger('Unable to store hub location');
$newuid = $ret['channel']['channel_id'];
@@ -454,12 +468,18 @@ function create_identity($arr) {
require_once('include/follow.php');
if(! is_array($accts))
$accts = array($accts);
+
foreach($accts as $acct) {
if(trim($acct))
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);
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'];
if($new_address === 'sys') {
- $ret['message'] = t('Reserved nickname. Please choose another.');
- return $ret;
- }
+ $ret['message'] = t('Reserved nickname. Please choose another.');
+ return $ret;
+ }
- if(check_webbie(array($new_address)) !== $new_address) {
- $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
- return $ret;
- }
+ if(check_webbie(array($new_address)) !== $new_address) {
+ $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
+ return $ret;
+ }
$r = q("update channel set channel_address = '%s' where channel_id = %d",
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']));
@@ -653,10 +673,6 @@ function channel_change_address($channel,$new_address) {
}
-
-
-
-
/**
* @brief Set default channel to be used on login.
*
@@ -664,9 +680,9 @@ function channel_change_address($channel,$new_address) {
* login account
* @param int $channel_id
* channel id to set as default for this account
- * @param boolean $force
- * if true, set this default unconditionally
- * if $force is false only do this if there is no existing default
+ * @param boolean $force (optional) default true
+ * - if true, set this default unconditionally
+ * - if $force is false only do this if there is no existing default
*/
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",
@@ -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.
*
- * @hooks get_default_export_sections
- * * \e array \b sections
* @return array with default section names to export
*/
function get_default_export_sections() {
@@ -703,6 +717,11 @@ function get_default_export_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);
return $cb['sections'];
@@ -714,15 +733,11 @@ function get_default_export_sections() {
* which would be necessary to create a nomadic identity clone. This includes
* 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
* Channel_id to export
* @param array $sections (optional)
* Which sections to include in the export, default see get_default_export_sections()
- * @returns array
+ * @return array
* See function for details
*/
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 */
/** 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];
- call_hooks('identity_basic_export',$addon);
+ $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'];
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)
return array();
if($month && $month <= 12) {
- $target_month = sprintf('%02d',$month);
- $target_month_plus = sprintf('%02d',$month+1);
+ $target_month = sprintf('%02d', $month);
+ $target_month_plus = sprintf('%02d', $month+1);
}
else
$target_month = '01';
@@ -1017,13 +1052,13 @@ function identity_export_year($channel_id,$year,$month = 0) {
if($ch) {
$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)
- $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
- $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($channel_id),
dbesc($mindate),
@@ -1033,9 +1068,9 @@ function identity_export_year($channel_id,$year,$month = 0) {
if($r) {
$ret['item'] = array();
xchan_query($r);
- $r = fetch_post_tags($r,true);
+ $r = fetch_post_tags($r, true);
foreach($r as $rr)
- $ret['item'][] = encode_item($rr,true);
+ $ret['item'][] = encode_item($rr, true);
}
return $ret;
@@ -1274,6 +1309,7 @@ function profile_edit_menu($uid) {
foreach($r as $rr) {
if(!($multi_profiles || $rr['is_default']))
continue;
+
$ret['menu']['entries'][] = array(
'photo' => $rr['thumb'],
'id' => $rr['id'],
@@ -1298,8 +1334,8 @@ function profile_edit_menu($uid) {
*
* @param array $profile
* @param int $block
- * @param boolean $show_connect
- * @param mixed $zcard
+ * @param boolean $show_connect (optional) default true
+ * @param mixed $zcard (optional) default false
*
* @return HTML string suitable for sidebar inclusion
* 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']);
+ /**
+ * @hooks profile_sidebar_enter
+ * Called before generating the 'channel sidebar' or mini-profile.
+ */
call_hooks('profile_sidebar_enter', $profile);
if($show_connect) {
@@ -1409,22 +1449,30 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
'$reddress' => $reddress,
'$rating' => '',
'$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);
return $arr['entry'];
-
}
function gender_icon($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.
if(strpos(strtolower($gender),strtolower(t('Female'))) !== false)
@@ -1442,7 +1490,7 @@ function gender_icon($gender) {
}
-function advanced_profile(&$a) {
+function advanced_profile() {
require_once('include/text.php');
if(! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'view_profile'))
return '';
@@ -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
* don't have it already.
* 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() {
$tmp_str = get_my_address();
if(validate_email($tmp_str)) {
- $arr = array('zid' => $tmp_str, 'url' => App::$cmd);
- call_hooks('zid_init',$arr);
+ $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()) {
$r = q("select * from hubloc where hubloc_addr = '%s' order by hubloc_connected desc limit 1",
dbesc($tmp_str)
@@ -1641,7 +1694,8 @@ function zid_init() {
}
if($r && remote_channel() && remote_channel() === $r[0]['hubloc_hash'])
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
$query = App::$query_string;
$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);
}
else
- logger('zid_init: no hubloc found.');
+ logger('No hubloc found.');
}
}
}
@@ -1673,14 +1727,16 @@ function zat_init() {
}
-
-
-// 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
-// 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
-// settings except their own while on this site.
-
+/**
+ * @brief 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 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
+ * settings except their own while on this site.
+ *
+ * @return int
+ */
function get_theme_uid() {
$uid = (($_REQUEST['puid']) ? intval($_REQUEST['puid']) : 0);
if(local_channel()) {
@@ -1700,9 +1756,9 @@ function get_theme_uid() {
* @brief Retrieves the path of the default_profile_photo for this system
* with the specified size.
*
-* @param int $size
-* one of (300, 80, 48)
-* @returns string with path to profile photo
+* @param int $size (optional) default 300
+* one of (300, 80, 48)
+* @return string with path to profile photo
*/
function get_default_profile_photo($size = 300) {
$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.
*
- * @param string $s;
+ * @param string $s
* xchan_hash of the identity in question
- * @returns boolean true or false
+ * @return boolean true or false
*/
function is_foreigner($s) {
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.
*
- * @param string $s;
+ * @param string $s
* xchan_hash of the identity in question
- * @returns boolean true or false
+ * @return boolean true or false
*/
function is_member($s) {
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) {
$ret = array('result' => false);
@@ -1748,6 +1811,7 @@ function get_online_status($nick) {
$hide = get_pconfig($r[0]['channel_id'],'system','hide_online_status');
if($hide)
return $ret;
+
$x = q("select cp_status from chatpresence where cp_xchan = '%s' and cp_room = 0 limit 1",
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) {
$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() {
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 ",
@@ -1798,6 +1867,7 @@ function identity_selector() {
'$channels' => $r,
'$selected' => local_channel()
));
+
return $o;
}
}
@@ -1809,14 +1879,17 @@ function identity_selector() {
function is_public_profile() {
if(! local_channel())
return false;
+
if(intval(get_config('system','block_public')))
return false;
+
$channel = App::get_channel();
if($channel) {
$perm = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile');
if($perm == PERMS_PUBLIC)
return true;
}
+
return false;
}
@@ -1861,7 +1934,7 @@ function get_profile_fields_advanced($filter = 0) {
*
* @param int $channel_id
* 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
* with the activity requiring notifications_off();
*/
@@ -1909,12 +1982,17 @@ function get_channel_default_perms($uid) {
}
-function profiles_build_sync($channel_id) {
+function profiles_build_sync($channel_id,$send = true) {
$r = q("select * from profile where uid = %d",
intval($channel_id)
);
if($r) {
- build_sync_packet($channel_id,array('profile' => $r));
+ if($send) {
+ build_sync_packet($channel_id,array('profile' => $r));
+ }
+ else {
+ return $r;
+ }
}
}
@@ -1993,13 +2071,14 @@ function get_cover_photo($channel_id,$format = 'bbcode', $res = PHOTO_RES_COVER_
return $output;
}
+
/**
- * @brief
+ * @brief Return parsed HTML zcard template.
*
* @param array $channel
- * @param string $observer_hash
- * @param array $args
- * @return string
+ * @param string $observer_hash (optional)
+ * @param array $args (optional)
+ * @return string parsed HTML from \e zcard template
*/
function get_zcard($channel, $observer_hash = '', $args = array()) {
@@ -2067,6 +2146,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()) {
logger('get_zcard_embed');
@@ -2133,10 +2220,12 @@ function get_zcard_embed($channel, $observer_hash = '', $args = array()) {
}
/**
- * @brief
+ * @brief Get a channel array from a channel nickname.
*
- * @param string $nick
- * @return mixed
+ * @param string $nick - A channel_address nickname
+ * @return array|boolean
+ * - array with channel entry
+ * - false if no channel with $nick was found
*/
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",
@@ -2147,10 +2236,10 @@ function channelx_by_nick($nick) {
}
/**
- * @brief
+ * @brief Get a channel array by a channel_hash.
*
* @param string $hash
- * @return mixed
+ * @return array|boolean false if channel ID not found, otherwise the channel array
*/
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",
@@ -2161,13 +2250,13 @@ function channelx_by_hash($hash) {
}
/**
- * @brief
+ * @brief Get a channel array by a channel ID.
*
- * @param int $id
- * @return mixed
+ * @param int $id A channel ID
+ * @return array|boolean false if channel ID not found, otherwise the channel array
*/
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)
);
@@ -2177,7 +2266,7 @@ function channelx_by_n($id) {
/**
* @brief
*
- * @param string $channel
+ * @param array $channel
* @return string
*/
function channel_reddress($channel) {
@@ -2188,67 +2277,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) {
- $x = get_pconfig($channel_id, 'system','manual_conversation_update');
+ $x = get_pconfig($channel_id, 'system', 'manual_conversation_update');
if($x === false)
- $x = get_config('system','manual_conversation_update', 1);
+ $x = get_config('system', 'manual_conversation_update', 1);
return intval($x);
}
+/**
+ * @brief Return parsed HTML remote_login template.
+ *
+ * @return string with parsed HTML from \e remote_login template
+ */
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(
- '$title' => t('Remote Authentication'),
- '$desc' => t('Enter your channel address (e.g. channel@example.com)'),
- '$submit' => t('Authenticate')
- ));
- return $o;
-
+ return $o;
}
function channel_store_lowlevel($arr) {
- $store = [
- '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_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''),
- 'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''),
- '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_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''),
- 'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'),
- 'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''),
- 'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''),
- 'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''),
- 'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''),
- 'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''),
- '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_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_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_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_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_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_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_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '0'),
- 'channel_system' => ((array_key_exists('channel_system',$arr)) ? $arr['channel_system'] : '0'),
-
+ $store = [
+ '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_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''),
+ 'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''),
+ '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_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''),
+ 'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'),
+ 'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''),
+ 'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''),
+ 'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''),
+ 'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''),
+ 'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''),
+ '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_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_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_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_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_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_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_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '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_password' => ((array_key_exists('channel_password',$arr)) ? $arr['channel_password'] : ''),
'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) {
@@ -2304,16 +2403,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
-// authorisation to do this.
-
-function account_remove($account_id,$local = true,$unset_session = true) {
+/**
+ * Included here for completeness, but this is a very dangerous operation.
+ * It is the caller's responsibility to confirm the requestor's intent and
+ * authorisation to do this.
+ *
+ * @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);
if(! intval($account_id)) {
- logger('account_remove: no account.');
+ logger('No account.');
return false;
}
@@ -2334,7 +2439,7 @@ function account_remove($account_id,$local = true,$unset_session = true) {
$account_email=$r[0]['account_email'];
if(! $r) {
- logger('account_remove: No account with id: ' . $account_id);
+ logger('No account with id: ' . $account_id);
return false;
}
@@ -2351,7 +2456,6 @@ function account_remove($account_id,$local = true,$unset_session = true) {
intval($account_id)
);
-
if ($unset_session) {
App::$session->nuke();
notice( sprintf(t('Account \'%s\' deleted'),$account_email) . EOL);
@@ -2364,8 +2468,6 @@ function account_remove($account_id,$local = true,$unset_session = true) {
/**
* @brief Removes a channel.
*
- * @hooks channel_remove
- * * \e array \b entry from channel tabel for $channel_id
* @param int $channel_id
* @param boolean $local default true
* @param boolean $unset_session default false
@@ -2386,6 +2488,11 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
$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]);
if(! $local) {
@@ -2425,19 +2532,43 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
}
}
+ q("DELETE FROM app WHERE app_channel = %d", intval($channel_id));
+ q("DELETE FROM atoken WHERE atoken_uid = %d", intval($channel_id));
+ q("DELETE FROM chatroom WHERE cr_uid = %d", intval($channel_id));
+ q("DELETE FROM conv WHERE uid = %d", intval($channel_id));
q("DELETE FROM groups WHERE uid = %d", intval($channel_id));
q("DELETE FROM group_member WHERE uid = %d", intval($channel_id));
q("DELETE FROM event WHERE uid = %d", intval($channel_id));
- q("DELETE FROM item WHERE uid = %d", intval($channel_id));
q("DELETE FROM mail WHERE channel_id = %d", intval($channel_id));
+ q("DELETE FROM menu WHERE menu_channel_id = %d", intval($channel_id));
+ q("DELETE FROM menu_item WHERE mitem_channel_id = %d", intval($channel_id));
+
q("DELETE FROM notify WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM obj WHERE obj_channel = %d", intval($channel_id));
+
+
q("DELETE FROM photo WHERE uid = %d", intval($channel_id));
q("DELETE FROM attach WHERE uid = %d", intval($channel_id));
q("DELETE FROM profile WHERE uid = %d", intval($channel_id));
- q("DELETE FROM pconfig WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM src WHERE src_channel_id = %d", intval($channel_id));
+
+ $r = q("select resource_id FROM attach WHERE uid = %d", intval($channel_id));
+ if($r) {
+ foreach($r as $rv) {
+ attach_delete($channel_id,$rv['resource_id']);
+ }
+ }
+
+
+
+ $r = q("select id from item where uid = %d", intval($channel_id));
+ if($r) {
+ foreach($r as $rv) {
+ drop_item($rv['id'],false);
+ }
+ }
- /// @FIXME At this stage we need to remove the file resources located under /store/$nickname
q("delete from abook where abook_xchan = '%s' and abook_self = 1 ",
dbesc($channel['channel_hash'])
@@ -2457,6 +2588,7 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
$rr = q("update account set account_default_channel = %d where account_id = %d",
intval($r[0]['channel_id']),
intval(App::$account['account_id']));
+
logger("Default channel deleted, changing default to channel_id " . $r[0]['channel_id']);
}
else {
@@ -2490,19 +2622,11 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
}
//remove from file system
- $r = q("select channel_address from channel where channel_id = %d limit 1",
- intval($channel_id)
- );
- if($r) {
- $channel_address = $r[0]['channel_address'] ;
- }
- if($channel_address) {
- $f = 'store/' . $channel_address.'/';
- logger('delete '. $f);
- if(is_dir($f)) {
- @rrmdir($f);
- }
+
+ $f = 'store/' . $channel['channel_address'];
+ if(is_dir($f)) {
+ @rrmdir($f);
}
Zotlabs\Daemon\Master::Summon(array('Directory',$channel_id));
@@ -2513,6 +2637,20 @@ function channel_remove($channel_id, $local = true, $unset_session = false) {
}
}
+// execute this at least a week after removing a channel
+
+function channel_remove_final($channel_id) {
+
+ q("delete from abook where abook_channel = %d", intval($channel_id));
+ q("delete from abconfig where chan = %d", intval($channel_id));
+ q("delete from pconfig where uid = %d", intval($channel_id));
+
+
+}
+
+
+
+
/**
* @brief This checks if a channel is allowed to publish executable code.
*
@@ -2531,20 +2669,30 @@ function channel_codeallowed($channel_id) {
return true;
return false;
-
}
function anon_identity_init($reqvars) {
- $x = [ 'request_vars' => $reqvars, 'xchan' => null, 'success' => 'unset' ];
- call_hooks('anon_identity_init',$x);
+ $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'])
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))
- return false;
-
+ return false;
+
$anon_name = strip_tags(trim($reqvars['anonname']));
$anon_email = strip_tags(trim($reqvars['anonmail']));
@@ -2571,7 +2719,7 @@ function anon_identity_init($reqvars) {
);
if(! $x) {
- xchan_store_lowlevel([
+ xchan_store_lowlevel([
'xchan_guid' => $anon_email,
'xchan_hash' => $hash,
'xchan_name' => $anon_name,
@@ -2579,7 +2727,7 @@ function anon_identity_init($reqvars) {
'xchan_network' => 'unknown',
'xchan_name_date' => datetime_convert()
]);
-
+
$x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1",
dbesc($anon_email),
@@ -2597,10 +2745,26 @@ function anon_identity_init($reqvars) {
dbesc($anon_email),
dbesc($hash)
);
-
}
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) {
+ $chan = $pchan;
+ $chan['channel_address'] = $pchan['pchan_guid'];
+ $chan['channel_hash'] = $pchan['pchan_hash'];
+ $chan['channel_pubkey'] = $pchan['pchan_pubkey'];
+ $chan['channel_prvkey'] = $pchan['pchan_prvkey'];
+ $chan['channel_name'] = $pchan['xchan_name'];
+
+ return $chan;
+}
+
diff --git a/include/connections.php b/include/connections.php
index 60bce018e..e9d7daa2d 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -369,7 +369,7 @@ function contact_remove($channel_id, $abook_id) {
return false;
- $r = q("select * from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d",
+ $r = q("select id from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d",
dbesc($abook['abook_xchan']),
dbesc($abook['abook_xchan']),
intval($channel_id)
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index 9cc9f0baf..a105bca19 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -72,21 +72,66 @@ function categories_widget($baseurl,$selected = '') {
$item_normal = item_normal();
$terms = array();
+ $r = q("select distinct(term.term) from term join item on term.oid = item.id
+ where item.uid = %d
+ and term.uid = item.uid
+ and term.ttype = %d
+ and term.otype = %d
+ and item.owner_xchan = '%s'
+ and item.item_wall = 1
+ and item.verb != '%s'
+ $item_normal
+ $sql_extra
+ order by term.term asc",
+ intval(App::$profile['profile_uid']),
+ intval(TERM_CATEGORY),
+ intval(TERM_OBJ_POST),
+ dbesc(App::$profile['channel_hash']),
+ dbesc(ACTIVITY_UPDATE)
+ );
+ if($r && count($r)) {
+ foreach($r as $rr)
+ $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : ''));
+
+ return replace_macros(get_markup_template('categories_widget.tpl'),array(
+ '$title' => t('Categories'),
+ '$desc' => '',
+ '$sel_all' => (($selected == '') ? 'selected' : ''),
+ '$all' => t('Everything'),
+ '$terms' => $terms,
+ '$base' => $baseurl,
+
+ ));
+ }
+ return '';
+}
+
+function cardcategories_widget($baseurl,$selected = '') {
+
+ if(! feature_enabled(App::$profile['profile_uid'],'categories'))
+ return '';
+
+ $sql_extra = item_permissions_sql(App::$profile['profile_uid']);
+
+ $item_normal = "and item.item_hidden = 0 and item.item_type = 6 and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ $terms = array();
$r = q("select distinct(term.term)
- from term join item on term.oid = item.id
- where item.uid = %d
- and term.uid = item.uid
- and term.ttype = %d
+ from term join item on term.oid = item.id
+ where item.uid = %d
+ and term.uid = item.uid
+ and term.ttype = %d
and term.otype = %d
- and item.owner_xchan = '%s'
- and item.item_wall = 1
+ and item.owner_xchan = '%s'
$item_normal
$sql_extra
- order by term.term asc",
+ order by term.term asc",
intval(App::$profile['profile_uid']),
- intval(TERM_CATEGORY),
+ intval(TERM_CATEGORY),
intval(TERM_OBJ_POST),
- dbesc(App::$profile['channel_hash'])
+ dbesc(App::$profile['channel_hash'])
);
if($r && count($r)) {
foreach($r as $rr)
@@ -105,32 +150,33 @@ function categories_widget($baseurl,$selected = '') {
return '';
}
-function cardcategories_widget($baseurl,$selected = '') {
+
+function articlecategories_widget($baseurl,$selected = '') {
if(! feature_enabled(App::$profile['profile_uid'],'categories'))
return '';
$sql_extra = item_permissions_sql(App::$profile['profile_uid']);
- $item_normal = "and item.item_hidden = 0 and item.item_type = 6 and item.item_deleted = 0
+ $item_normal = "and item.item_hidden = 0 and item.item_type = 7 and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
and item.item_blocked = 0 ";
$terms = array();
$r = q("select distinct(term.term)
- from term join item on term.oid = item.id
- where item.uid = %d
- and term.uid = item.uid
- and term.ttype = %d
+ from term join item on term.oid = item.id
+ where item.uid = %d
+ and term.uid = item.uid
+ and term.ttype = %d
and term.otype = %d
- and item.owner_xchan = '%s'
+ and item.owner_xchan = '%s'
$item_normal
$sql_extra
- order by term.term asc",
+ order by term.term asc",
intval(App::$profile['profile_uid']),
- intval(TERM_CATEGORY),
+ intval(TERM_CATEGORY),
intval(TERM_OBJ_POST),
- dbesc(App::$profile['channel_hash'])
+ dbesc(App::$profile['channel_hash'])
);
if($r && count($r)) {
foreach($r as $rr)
@@ -151,6 +197,9 @@ function cardcategories_widget($baseurl,$selected = '') {
+
+
+
function common_friends_visitor_widget($profile_uid,$cnt = 25) {
if(local_channel() == $profile_uid)
diff --git a/include/conversation.php b/include/conversation.php
index f395b2cbe..77694deb3 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -162,6 +162,18 @@ function localize_item(&$item){
elseif(activity_match($item['verb'],ACTIVITY_DISLIKE)) {
$bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
}
+
+ // short version, in notification strings the author will be displayed separately
+
+ if(activity_match($item['verb'],ACTIVITY_LIKE)) {
+ $shortbodyverb = t('likes %1$s\'s %2$s');
+ }
+ elseif(activity_match($item['verb'],ACTIVITY_DISLIKE)) {
+ $shortbodyverb = t('doesn\'t like %1$s\'s %2$s');
+ }
+
+ $item['shortlocalize'] = sprintf($shortbodyverb, $objauthor, $plink);
+
$item['body'] = $item['localize'] = sprintf($bodyverb, $author, $objauthor, $plink);
if($Bphoto != "")
$item['body'] .= "\n\n\n" . '[zrl=' . chanlink_url($author_link) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]';
@@ -470,10 +482,10 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$previewing = (($preview) ? ' preview ' : '');
$preview_lbl = t('This is an unsaved preview');
- if ($mode === 'network') {
+ if (in_array($mode, [ 'network', 'pubstream'])) {
$profile_owner = local_channel();
- $page_writeable = true;
+ $page_writeable = ((local_channel()) ? true : false);
if (!$update) {
// The special div is needed for liveUpdate to kick in for this page.
@@ -501,6 +513,12 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
}
}
+ elseif ($mode === 'hq') {
+ $profile_owner = local_channel();
+ $page_writeable = true;
+ $live_update_div = '<div id="live-hq"></div>' . "\r\n";
+ }
+
elseif ($mode === 'channel') {
$profile_owner = App::$profile['profile_uid'];
$page_writeable = ($profile_owner == local_channel());
@@ -527,6 +545,15 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$jsreload = $_SESSION['return_url'];
}
+ elseif ($mode === 'articles') {
+ $profile_owner = App::$profile['profile_uid'];
+ $page_writeable = ($profile_owner == local_channel());
+ $live_update_div = '<div id="live-articles"></div>' . "\r\n"
+ . "<script> var profile_uid = " . App::$profile['profile_uid']
+ . "; var netargs = '?f='; var profile_page = " . App::$pager['page'] . "; </script>\r\n";
+ $jsreload = $_SESSION['return_url'];
+ }
+
elseif ($mode === 'display') {
$profile_owner = local_channel();
@@ -561,19 +588,16 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
if (! feature_enabled($profile_owner,'multi_delete'))
$page_dropping = false;
- $uploading = true;
+ $uploading = false;
- if($profile_owner > 0) {
- $owner_channel = channelx_by_n($profile_owner);
- if($owner_channel['channel_allow_cid'] || $owner_channel['channel_allow_gid']
- || $owner_channel['channel_deny_cid'] || $owner_channel['channel_deny_gid']) {
- $uploading = false;
+ if(local_channel()) {
+ $cur_channel = App::get_channel();
+ if($cur_channel['channel_allow_cid'] === '' && $cur_channel['channel_allow_gid'] === ''
+ && $cur_channel['channel_deny_cid'] === '' && $cur_channel['channel_deny_gid'] === ''
+ && intval(\Zotlabs\Access\PermissionLimits::Get(local_channel(),'view_storage')) === PERMS_PUBLIC) {
+ $uploading = true;
}
}
- else {
- $uploading = false;
- }
-
$channel = App::get_channel();
$observer = App::get_observer();
@@ -610,13 +634,14 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
// "New Item View" on network page or search page results
// - just loop through the items and format them minimally for display
-
- //$tpl = get_markup_template('search_item.tpl');
$tpl = 'search_item.tpl';
foreach($items as $item) {
- $x = [ 'mode' => $mode, 'item' => $item ];
+ $x = [
+ 'mode' => $mode,
+ 'item' => $item
+ ];
call_hooks('stream_item',$x);
if($x['item']['blocked'])
@@ -637,14 +662,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE)))
&& ($item['id'] != $item['parent']))
continue;
-// $nickname = $item['nickname'];
}
-// else
-// $nickname = App::$user['nickname'];
-
-// $profile_name = ((strlen($item['author-name'])) ? $item['author-name'] : $item['name']);
-// if($item['author-link'] && (! $item['author-name']))
-// $profile_name = $item['author-link'];
$sp = false;
$profile_link = best_link_url($item,$sp);
@@ -653,8 +671,6 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
else
$profile_link = zid($profile_link);
-// $normalised = normalise_link((strlen($item['author-link'])) ? $item['author-link'] : $item['url']);
-
$profile_name = $item['author']['xchan_name'];
$profile_link = $item['author']['xchan_url'];
$profile_avatar = $item['author']['xchan_photo_m'];
@@ -705,7 +721,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$conv_link_mid = (($mode == 'moderate') ? $item['parent_mid'] : $item['mid']);
- $conv_link = (($item['item_type'] == ITEM_TYPE_CARD) ? $item['plink'] : z_root() . '/display/' . gen_link_id($conv_link_mid));
+ $conv_link = ((in_array($item['item_type'],[ ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE] )) ? $item['plink'] : z_root() . '/display/' . gen_link_id($conv_link_mid));
$tmp_item = array(
@@ -739,8 +755,8 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'forged' => $forged,
'txt_cats' => t('Categories:'),
'txt_folders' => t('Filed under:'),
- 'has_cats' => ((count($body['categories'])) ? 'true' : ''),
- 'has_folders' => ((count($body['folders'])) ? 'true' : ''),
+ 'has_cats' => (($body['categories']) ? 'true' : ''),
+ 'has_folders' => (($body['folders']) ? 'true' : ''),
'text' => strip_tags($body['html']),
'ago' => relative_date($item['created']),
'app' => $item['app'],
@@ -750,6 +766,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
'location' => $location,
+ 'divider' => false,
'indent' => '',
'owner_name' => $owner_name,
'owner_url' => $owner_url,
@@ -1456,7 +1473,7 @@ function sort_item_children($items) {
$result = $items;
usort($result,'sort_thr_created_rev');
foreach($result as $k => $i) {
- if(count($result[$k]['children'])) {
+ if($result[$k]['children']) {
$result[$k]['children'] = sort_item_children($result[$k]['children']);
}
}
@@ -1466,7 +1483,7 @@ function sort_item_children($items) {
function add_children_to_list($children, &$arr) {
foreach($children as $y) {
$arr[] = $y;
- if(count($y['children']))
+ if($y['children'])
add_children_to_list($y['children'], $arr);
}
}
@@ -1878,6 +1895,17 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
'icon' => 'list'
);
}
+
+ if(feature_enabled($uid,'articles')) {
+ $tabs[] = array(
+ 'label' => t('articles'),
+ 'url' => z_root() . '/articles/' . $nickname,
+ 'sel' => ((argv(0) == 'articles') ? 'active' : ''),
+ 'title' => t('View Articles'),
+ 'id' => 'articles-tab',
+ 'icon' => 'file-text-o'
+ );
+ }
if($has_webpages && feature_enabled($uid,'webpages')) {
$tabs[] = array(
diff --git a/include/datetime.php b/include/datetime.php
index 85e87848b..0fcd957be 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -8,6 +8,8 @@
/**
* @brief Two-level sort for timezones.
*
+ * Can be used in usort() to sort timezones.
+ *
* @param string $a
* @param string $b
* @return number
@@ -27,13 +29,14 @@ function timezone_cmp($a, $b) {
function is_null_date($s) {
if($s === '0000-00-00 00:00:00' || $s === '0001-01-01 00:00:00')
return true;
+
return false;
}
-
/**
* @brief Return timezones grouped (primarily) by continent.
*
+ * @see timezone_cmp()
* @return array
*/
function get_timezones( ){
@@ -54,7 +57,7 @@ function get_timezones( ){
$city = $ex[0];
$continent = t('Miscellaneous');
}
- $city = str_replace('_', ' ', t($city));
+ $city = str_replace('_', ' ', t($city));
if (!x($continents, $ex[0])) $continents[$ex[0]] = array();
$continents[$continent][$value] = $city;
@@ -109,7 +112,7 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
try {
$d = new DateTime($s, $from_obj);
} catch(Exception $e) {
- logger('datetime_convert: exception: ' . $e->getMessage());
+ logger('exception: ' . $e->getMessage());
$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.
*
* @param string $dob Date of Birth
- * @return string
+ * @return string Parsed HTML with selector
*/
function dob($dob) {
@@ -161,59 +164,62 @@ function dob($dob) {
}
/**
- * returns a date selector
- * @param $format
- * format string, e.g. 'ymd' or 'mdy'. Not currently supported
- * @param $min
- * unix timestamp of minimum date
- * @param $max
- * unix timestap of maximum date
- * @param $default
- * unix timestamp of default date
- * @param $id
- * id and name of datetimepicker (defaults to "datetimepicker")
+ * @brief Returns a date selector.
+ *
+ * @see datetimesel()
+ * @param string $format
+ * format string, e.g. 'ymd' or 'mdy'. Not currently supported
+ * @param DateTime $min
+ * unix timestamp of minimum date
+ * @param DateTime $max
+ * unix timestap of maximum date
+ * @param DateTime $default
+ * unix timestamp of default date
+ * @param string $id
+ * id and name of datetimepicker (defaults to "datetimepicker")
*/
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
- * @param $format
- * format string, e.g. 'ymd' or 'mdy'. Not currently supported
- * @param $h
- * already selected hour
- * @param $m
+ * @brief Returns a time selector.
+ *
+ * @param string $format
+ * format string, e.g. 'ymd' or 'mdy'. Not currently supported
+ * @param string $h
+ * already selected hour
+ * @param string $m
* already selected minute
- * @param $id
+ * @param string $id
* id and name of datetimepicker (defaults to "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.
*
* @param string $format
- * format string, e.g. 'ymd' or 'mdy'. Not currently supported
- * @param $min
- * unix timestamp of minimum date
- * @param $max
- * unix timestap of maximum date
- * @param $default
- * unix timestamp of default date
+ * format string, e.g. 'ymd' or 'mdy'. Not currently supported
+ * @param DateTime $min
+ * unix timestamp of minimum date
+ * @param DateTime $max
+ * unix timestap of maximum date
+ * @param DateTime $default
+ * unix timestamp of default date
* @param string $label
* @param string $id
- * id and name of datetimepicker (defaults to "datetimepicker")
+ * id and name of datetimepicker (defaults to "datetimepicker")
* @param boolean $pickdate
- * true to show date picker (default)
+ * true to show date picker (default)
* @param boolean $picktime
- * true to show time picker (default)
- * @param $minfrom
- * set minimum date from picker with id $minfrom (none by default)
- * @param $maxfrom
- * set maximum date from picker with id $maxfrom (none by default)
+ * true to show time picker (default)
+ * @param DateTime $minfrom
+ * set minimum date from picker with id $minfrom (none by default)
+ * @param DateTime $maxfrom
+ * set maximum date from picker with id $maxfrom (none by default)
* @param boolean $required default false
* @param int $first_day (optional) default 0
* @return string Parsed HTML output.
@@ -343,9 +349,6 @@ function plural_dates($k,$n) {
}
}
-
-
-
/**
* @brief Returns timezone correct age in years.
*
@@ -418,7 +421,7 @@ function get_dim($y, $m) {
*
* @param int $y Year
* @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) {
$d = sprintf('%04d-%02d-01 00:00', intval($y), intval($m));
diff --git a/include/event.php b/include/event.php
index b56a5fb3e..282c1a9d7 100644
--- a/include/event.php
+++ b/include/event.php
@@ -1,15 +1,16 @@
<?php
-use Sabre\VObject;
-
/**
* @file include/event.php
+ * @brief Event related functions.
*/
+use Sabre\VObject;
+
/**
- * @brief Returns an event as HTML
+ * @brief Returns an event as HTML.
*
* @param array $ev
- * @return string
+ * @return string HTML formatted event
*/
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
- //todo: move this to template
+ /// @TODO move this to template
$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="'
. 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 ))
- : day_translate(datetime_convert('UTC', 'UTC',
+ : day_translate(datetime_convert('UTC', 'UTC',
$ev['dtstart'] , $bd_format)))
. '</span></div>' . "\r\n";
if(! $ev['nofinish'])
$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' ))
- . '" >'
- . (($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 ))
- : day_translate(datetime_convert('UTC', 'UTC',
+ : day_translate(datetime_convert('UTC', 'UTC',
$ev['dtend'] , $bd_format )))
. '</span></div>' . "\r\n";
$o .= '<div class="event-description">' . zidify_links(smilies(bbcode($ev['description']))) . '</div>' . "\r\n";
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'])))
. '</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\nLAST-MODIFIED:" . 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' : ''));
- if($ev['dtend'] && ! $ev['nofinish'])
+ if($ev['dtend'] && ! $ev['nofinish'])
$o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($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\nUID:" . $ev['event_hash'] ;
$o .= "\r\nEND:VEVENT\r\n";
-
+
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\nLAST-MODIFIED:" . 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' : ''));
- if($ev['dtend'] && ! $ev['nofinish'])
+ if($ev['dtend'] && ! $ev['nofinish'])
$o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($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');
}
if(intval($ev['event_percent']))
- $o .= "\r\nPERCENT-COMPLETE:" . $ev['event_percent'];
- if(intval($ev['event_sequence']))
+ $o .= "\r\nPERCENT-COMPLETE:" . $ev['event_percent'];
+ if(intval($ev['event_sequence']))
$o .= "\r\nSEQUENCE:" . $ev['event_sequence'];
if($ev['location']) {
$o .= "\r\nLOCATION:" . format_ical_text($ev['location']);
@@ -196,12 +197,13 @@ function format_ical_text($s) {
$s = html2plain(bbcode($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) {
$s = base64_encode($s);
+
return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
}
@@ -225,7 +227,7 @@ function format_event_bbcode($ev) {
if(($ev['dtend']) && (! $ev['nofinish']))
$o .= '[event-finish]' . $ev['dtend'] . '[/event-finish]';
-
+
if($ev['location'])
$o .= '[event-location]' . $ev['location'] . '[/event-location]';
@@ -253,7 +255,6 @@ function bbtoevent($s) {
$ev = array();
-
$match = '';
if(preg_match("/\[event\](.*?)\[\/event\]/is",$s,$match)) {
// only parse one object per event tag
@@ -306,7 +307,7 @@ function bbtoevent($s) {
*
* @see ev_compare()
* @param array $arr
- * @return sorted array
+ * @return array Date sorted array of events
*/
function sort_by_date($arr) {
if (is_array($arr))
@@ -318,6 +319,8 @@ function sort_by_date($arr) {
/**
* @brief Compare function for events.
*
+ * This function can be used in usort() to sort events by date.
+ *
* @see sort_by_date()
* @param array $a
* @param array $b
@@ -375,8 +378,19 @@ function event_store_event($arr) {
}
}
- $hook_info = [ 'event' => $arr, 'existing_event' => $existing_event, 'cancel' => false ];
- call_hooks('event_store_event',$hook_info);
+ $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'])
return false;
@@ -386,7 +400,7 @@ function event_store_event($arr) {
if($existing_event) {
if($existing_event['edited'] >= $arr['edited']) {
- // Nothing has changed.
+ // Nothing has changed.
return $existing_event;
}
@@ -444,7 +458,6 @@ function event_store_event($arr) {
// New event. Store it.
-
if(array_key_exists('external_id',$arr))
$hash = $arr['external_id'];
elseif(array_key_exists('event_hash',$arr))
@@ -531,7 +544,7 @@ function event_addtocal($item_id, $uid) {
}
if($ev->private)
- $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
+ $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
else {
$acl = new Zotlabs\Access\AccessList($channel);
$x = $acl->get();
@@ -596,14 +609,12 @@ function ical_to_ev($s) {
date_default_timezone_set($saved_timezone);
return $ev;
-
}
function parse_vobject($ical, $type) {
-
$ev = [];
if(! isset($ical->DTSTART)) {
@@ -698,10 +709,8 @@ function parse_vobject($ical, $type) {
-
-
function parse_ical_file($f,$uid) {
-require_once('vendor/autoload.php');
+ require_once('vendor/autoload.php');
$s = @file_get_contents($f);
@@ -731,6 +740,7 @@ require_once('vendor/autoload.php');
if($ical)
return true;
+
return false;
}
@@ -779,7 +789,6 @@ function event_import_ical($ical, $uid) {
$ev['created'] = datetime_convert('UTC','UTC',$created->format(\DateTime::W3C));
}
-
if(isset($ical->{'LAST-MODIFIED'})) {
$edited = $ical->{'LAST-MODIFIED'}->getDateTime();
$ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C));
@@ -814,7 +823,7 @@ function event_import_ical($ical, $uid) {
else
$ev['external_id'] = $evuid;
}
-
+
if($ev['summary'] && $ev['dtstart']) {
$ev['event_xchan'] = $channel['channel_hash'];
$ev['uid'] = $channel['channel_id'];
@@ -822,7 +831,7 @@ function event_import_ical($ical, $uid) {
$ev['private'] = 1;
$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);
if($event) {
$item_id = event_store_item($ev,$event);
@@ -831,7 +840,6 @@ function event_import_ical($ical, $uid) {
}
return false;
-
}
function event_ical_get_sourcetext($s) {
@@ -931,7 +939,7 @@ function event_import_ical_task($ical, $uid) {
if(isset($ical->SEQUENCE)) {
$ev['event_sequence'] = (string) $ical->SEQUENCE;
// 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']))
return false;
}
@@ -958,7 +966,7 @@ function event_import_ical_task($ical, $uid) {
$ev['private'] = 1;
$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);
if($event) {
$item_id = event_store_item($ev,$event);
@@ -967,14 +975,10 @@ function event_import_ical_task($ical, $uid) {
}
return false;
-
}
-
-
-
function event_store_item($arr, $event) {
require_once('include/datetime.php');
@@ -995,7 +999,6 @@ function event_store_item($arr, $event) {
}
-
$item_arr = array();
$prefix = '';
// $birthday = false;
@@ -1008,9 +1011,9 @@ function event_store_item($arr, $event) {
$prefix = t('This event has been added to your calendar.');
// $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
- // 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
// 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);
- // @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 = '';
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'];
+ /**
+ * @hooks event_updated
+ * Called when an event record is modified.
+ */
call_hooks('event_updated', $event['id']);
return $item_id;
@@ -1103,7 +1111,7 @@ function event_store_item($arr, $event) {
$item_wall = 0;
$item_origin = 0;
- $item_thread_top = 0;
+ $item_thread_top = 0;
if($item) {
$item_arr['id'] = $item['id'];
@@ -1196,6 +1204,10 @@ function event_store_item($arr, $event) {
$item_id = $res['item_id'];
+ /**
+ * @hooks event_created
+ * Called when an event record is created.
+ */
call_hooks('event_created', $event['id']);
return $item_id;
@@ -1216,25 +1228,24 @@ function todo_stat() {
function tasks_fetch($arr) {
- if(! local_channel())
- return;
+ if(! local_channel())
+ return;
- $ret = array();
- $sql_extra = " and event_status != 'COMPLETED' ";
- if($arr && $arr['all'] == 1)
- $sql_extra = '';
+ $ret = array();
+ $sql_extra = " and event_status != 'COMPLETED' ";
+ if($arr && $arr['all'] == 1)
+ $sql_extra = '';
- $r = q("select * from event where etype = 'task' and uid = %d $sql_extra order by created desc",
- intval(local_channel())
- );
+ $r = q("select * from event where etype = 'task' and uid = %d $sql_extra order by created desc",
+ intval(local_channel())
+ );
- $ret['success'] = (($r) ? true : false);
- if($r) {
- $ret['tasks'] = $r;
- }
+ $ret['success'] = (($r) ? true : false);
+ if($r) {
+ $ret['tasks'] = $r;
+ }
return $ret;
-
}
function cdav_principal($uri) {
diff --git a/include/features.php b/include/features.php
index f84c9cb05..8601ff79e 100644
--- a/include/features.php
+++ b/include/features.php
@@ -126,6 +126,16 @@ function get_features($filtered = true) {
feature_level('cards',1),
],
+/* reserved, work in progress
+ [
+ 'articles',
+ t('Articles'),
+ t('Create interactive articles'),
+ false,
+ get_config('feature_lock','articles'),
+ feature_level('articles',1),
+ ],
+*/
[
'nav_channel_select',
t('Navigation Channel Select'),
@@ -364,6 +374,15 @@ function get_features($filtered = true) {
t('Post/Comment Tools'),
[
+ 'markdown',
+ t('Markdown'),
+ t('Use markdown for editing posts'),
+ false,
+ get_config('feature_lock','markdown'),
+ feature_level('markdown',2),
+ ],
+
+ [
'commtag',
t('Community Tagging'),
t('Ability to tag existing posts'),
diff --git a/include/feedutils.php b/include/feedutils.php
index 217da8188..4638ef66a 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -1,5 +1,8 @@
<?php
-
+/**
+ * @file include/feedutils.php
+ * @brief Some functions to work with XML feeds.
+ */
/**
* @brief Return an Atom feed for channel.
@@ -57,21 +60,39 @@ function get_public_feed($channel, $params) {
* @param array $params
* @return string with an atom feed
*/
-
function get_feed_for($channel, $observer_hash, $params) {
if(! $channel)
http_status_exit(401);
+
+ // logger('params: ' . print_r($params,true));
+
+
+ $interactive = ((is_array($params) && array_key_exists('interactive',$params)) ? intval($params['interactive']) : 0);
+
+
if($params['pages']) {
- if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_pages'))
- http_status_exit(403);
- } else {
- if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_stream'))
- http_status_exit(403);
+ if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_pages')) {
+ if($interactive) {
+ return '';
+ }
+ else {
+ http_status_exit(403);
+ }
+ }
+ }
+ else {
+ if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_stream')) {
+ if($interactive) {
+ return '';
+ }
+ else {
+ http_status_exit(403);
+ }
+ }
}
- // logger('params: ' . print_r($params,true));
$feed_template = get_markup_template('atom_feed.tpl');
@@ -105,12 +126,28 @@ function get_feed_for($channel, $observer_hash, $params) {
));
- $x = [ 'xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params ];
- call_hooks('atom_feed_top',$x);
+ $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'];
- // 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);
$items = items_fetch(
@@ -135,11 +172,14 @@ function get_feed_for($channel, $observer_hash, $params) {
if($item['item_private'])
continue;
- /** @BUG $owner is undefined in this call */
$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);
$atom .= '</feed>' . "\r\n";
@@ -344,6 +384,7 @@ function get_atom_elements($feed, $item, &$author) {
}
}
+
// check for a yahoo media element (github etc.)
if(! $author['author_photo']) {
@@ -356,7 +397,6 @@ function get_atom_elements($feed, $item, &$author) {
// No photo/profile-link on the item - look at the feed level
-
if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
$rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
@@ -396,7 +436,7 @@ function get_atom_elements($feed, $item, &$author) {
// new style
$ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['attribs']['']['ref']));
if(! $ostatus_conversation) {
- // old style
+ // old style
$ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['data']));
}
if($ostatus_conversation) {
@@ -406,7 +446,7 @@ function get_atom_elements($feed, $item, &$author) {
}
$ostatus_protocol = (($ostatus_conversation) ? true : false);
-
+
$mastodon = (($item->get_item_tags('http://mastodon.social/schema/1.0','scope')) ? true : false);
if($mastodon) {
$ostatus_protocol = true;
@@ -645,7 +685,7 @@ function get_atom_elements($feed, $item, &$author) {
$res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title );
}
}
-
+
$rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
@@ -723,7 +763,6 @@ function get_atom_elements($feed, $item, &$author) {
$res['target'] = $obj;
}
-
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 ] )) {
@@ -737,7 +776,13 @@ function get_atom_elements($feed, $item, &$author) {
'author' => $author,
'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);
logger('author: ' .print_r($arr['author'], true), LOGGER_DATA);
@@ -782,7 +827,7 @@ function feed_get_reshare(&$res,$item) {
$share['avatar'] = z_root() . '/' . get_default_profile_photo(80);
if(! $share['profile'])
$share['profile'] = z_root();
-
+
$child = $rawobj[0]['child'];
@@ -809,7 +854,7 @@ function feed_get_reshare(&$res,$item) {
$body = html2bbcode($body);
}
}
-
+
$attach = $share['links'];
if($attach) {
@@ -845,16 +890,16 @@ function feed_get_reshare(&$res,$item) {
}
}
}
-
+
if((! $body) && ($share['alternate'])) {
$body = $share['alternate'];
- }
+ }
- $res['body'] = "[share author='" . urlencode($share['author']) .
+ $res['body'] = "[share author='" . urlencode($share['author']) .
"' profile='" . $share['profile'] .
"' avatar='" . $share['avatar'] .
"' link='" . $share['alternate'] .
- "' posted='" . $share['created'] .
+ "' posted='" . $share['created'] .
"' message_id='" . $share['message_id'] . "']";
$res['body'] .= $body;
@@ -864,7 +909,6 @@ function feed_get_reshare(&$res,$item) {
}
-
/**
* @brief Encodes SimplePie_Item link arrays.
*
@@ -940,7 +984,7 @@ function process_feed_tombstones($feed,$importer,$contact,$pass) {
*
* @param string $xml
* 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
* relationship. It is this person's stuff that is going to be updated.
* @param[in,out] array $contact
@@ -1103,7 +1147,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Update content if 'updated' changes
if($r) {
- if(activity_match($datarray['verb'],ACTIVITY_DELETE)
+ if(activity_match($datarray['verb'],ACTIVITY_DELETE)
&& $datarray['author_xchan'] === $r[0]['author_xchan']) {
if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
@@ -1147,6 +1191,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$datarray['parent_mid'] = $pmid;
}
}
+
if(($item_parent_mid) && (! $pmid)) {
logger('find_parent: matched in-reply-to: ' . $parent_mid, LOGGER_DEBUG);
$pmid = $item_parent_mid[0]['parent_mid'];
@@ -1172,7 +1217,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
dbesc($parent_mid),
intval($importer['channel_id'])
);
-
+
if($x) {
$item_parent_mid = $x;
$pmid = $x[0]['parent_mid'];
@@ -1205,7 +1250,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
);
if($r) {
$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())) {
logger('comments disabled for post ' . $parent_item['mid']);
continue;
@@ -1215,7 +1260,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$allowed = false;
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');
else
$allowed = true;
@@ -1230,16 +1275,17 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// 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
- 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'])) {
$send_downstream = true;
}
}
else {
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.');
continue;
}
@@ -1249,17 +1295,17 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// 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.
-
+
if(! post_is_importable($datarray, $contact))
continue;
+
$datarray['parent_mid'] = $datarray['mid'];
set_iconfig($datarray,'system','parent_mid',$parent_mid,true);
}
-
// allow likes of comments
- if($item_parent_mid && activity_match($datarray['verb'],ACTVITY_LIKE)) {
+ if($item_parent_mid && activity_match($datarray['verb'],ACTIVITY_LIKE)) {
$datarray['thr_parent'] = $item_parent_mid[0]['parent_mid'];
}
@@ -1306,7 +1352,6 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
}
-
// if we have everything but a photo, provide the default profile photo
if($author['author_name'] && $author['author_link'] && (! $author['author_photo']))
@@ -1364,7 +1409,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Update content if 'updated' changes
if($r) {
- if(activity_match($datarray['verb'],ACTIVITY_DELETE)
+ if(activity_match($datarray['verb'],ACTIVITY_DELETE)
&& $datarray['author_xchan'] === $r[0]['author_xchan']) {
if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
@@ -1426,12 +1471,12 @@ function feed_conversation_fetch($importer,$contact,$parent_link) {
// GNU-Social flavoured feeds
if(strpos($parent_link,'/notice/')) {
$link = str_replace('/notice/','/api/statuses/show/',$parent_link) . '.atom';
- }
+ }
// Mastodon flavoured feeds
if(strpos($parent_link,'/users/') && strpos($parent_link,'/updates/')) {
$link = $parent_link . '.atom';
- }
+ }
if(! $link)
return false;
@@ -1446,21 +1491,21 @@ function feed_conversation_fetch($importer,$contact,$parent_link) {
$data = $fetch['body'];
// 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
- // tag to trick it into believing it's a compliant 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.
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>';
- }
-
+ }
+
consume_feed($data,$importer,$contact,1);
consume_feed($data,$importer,$contact,2);
return true;
-
}
+
/**
* @brief Normalise an id.
*
@@ -1479,7 +1524,7 @@ function normalise_id($id) {
*
* @param string $xml
* 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
* relationship. It is this person's stuff that is going to be updated.
*/
@@ -1617,6 +1662,7 @@ function feed_meta($xml) {
return $ret;
}
+
/**
* @brief Not yet implemented function to update feed item.
*
@@ -1627,6 +1673,7 @@ function update_feed_item($uid, $datarray) {
item_store_update($datarray);
}
+
/**
* @brief Fetch the content of a feed and further consume it.
*
@@ -1659,11 +1706,10 @@ function handle_feed($uid, $abook_id, $url) {
}
}
+
/**
* @brief Return a XML tag with author information.
*
- * @hooks \b atom_author Possibility to add further tags to returned XML string
- * * \e string The created XML tag as a string without closing tag
* @param string $tag The XML tag to create
* @param string $nick preferred username
* @param string $name displayed name of the author
@@ -1672,7 +1718,7 @@ function handle_feed($uid, $abook_id, $url) {
* @param int $w image width
* @param string $type profile photo mime type
* @param string $photo Fully qualified URL to a profile/avator photo
- * @return string
+ * @return string XML tag
*/
function atom_author($tag, $nick, $name, $uri, $h, $w, $type, $photo) {
$o = '';
@@ -1695,6 +1741,11 @@ function atom_author($tag, $nick, $name, $uri, $h, $w, $type, $photo) {
$o .= ' <poco:preferredUsername>' . $nick . '</poco:preferredUsername>' . "\r\n";
$o .= ' <poco:displayName>' . $name . '</poco:displayName>' . "\r\n";
+ /**
+ * @hooks atom_author
+ * Possibility to add further tags to returned XML string
+ * * \e string - The created XML tag as a string without closing tag
+ */
call_hooks('atom_author', $o);
$o .= "</$tag>\r\n";
@@ -1703,17 +1754,23 @@ function atom_author($tag, $nick, $name, $uri, $h, $w, $type, $photo) {
}
-function atom_render_author($tag,$xchan) {
+/**
+ * @brief Return an atom tag with author information from an xchan.
+ *
+ * @param string $tag
+ * @param array $xchan
+ * @return string
+ */
+function atom_render_author($tag, $xchan) {
-
- $nick = xmlify(substr($xchan['xchan_addr'],0,strpos($xchan['xchan_addr'],'@')));
+ $nick = xmlify(substr($xchan['xchan_addr'], 0, strpos($xchan['xchan_addr'], '@')));
$id = xmlify($xchan['xchan_url']);
$name = xmlify($xchan['xchan_name']);
$photo = xmlify($xchan['xchan_photo_l']);
$type = xmlify($xchan['xchan_photo_mimetype']);
$w = $h = 300;
- $o .= "<$tag>\r\n";
+ $o = "<$tag>\r\n";
$o .= " <as:object-type>http://activitystrea.ms/schema/1.0/person</as:object-type>\r\n";
$o .= " <id>$id</id>\r\n";
$o .= " <name>$nick</name>\r\n";
@@ -1724,13 +1781,16 @@ function atom_render_author($tag,$xchan) {
$o .= ' <poco:preferredUsername>' . $nick . '</poco:preferredUsername>' . "\r\n";
$o .= ' <poco:displayName>' . $name . '</poco:displayName>' . "\r\n";
+ /**
+ * @hooks atom_render_author
+ * Possibility to add further tags to returned XML string.
+ * * \e string The created XML tag as a string without closing tag
+ */
call_hooks('atom_render_author', $o);
$o .= "</$tag>\r\n";
return $o;
-
-
}
function compat_photos_list($s) {
@@ -1740,7 +1800,7 @@ function compat_photos_list($s) {
$found = preg_match_all('/\[[zi]mg(.*?)\](.*?)\[/ism',$s,$matches,PREG_SET_ORDER);
if($found) {
- foreach($matches as $match) {
+ foreach($matches as $match) {
$ret[] = [
'href' => $match[2],
'length' => 0,
@@ -1754,7 +1814,6 @@ function compat_photos_list($s) {
}
-
/**
* @brief Create an item for the Atom feed.
*
@@ -1766,11 +1825,11 @@ function compat_photos_list($s) {
* @param array $owner
* @param string $comment default false
* @param number $cid default 0
+ * @param boolean $compat default false
* @return void|string
*/
function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $compat = false) {
-
if(! $item['parent'])
return;
@@ -1922,9 +1981,17 @@ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $
'abook_id' => $cid,
'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);
return $x['entry'];
}
-
diff --git a/include/follow.php b/include/follow.php
index 56d8294c5..0843802c5 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -226,6 +226,8 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
}
+ $profile_assign = get_pconfig($uid,'system','profile_assign','');
+
$r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
where abook_xchan = '%s' and abook_channel = %d limit 1",
@@ -265,6 +267,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
'abook_channel' => intval($uid),
'abook_closeness' => intval($closeness),
'abook_xchan' => $xchan_hash,
+ 'abook_profile' => $profile_assign,
'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
diff --git a/include/group.php b/include/group.php
index e0c20b536..03ebf7ee5 100644
--- a/include/group.php
+++ b/include/group.php
@@ -18,10 +18,6 @@ function group_add($uid,$name,$public = 0) {
intval($r)
);
if(($z) && $z[0]['deleted']) {
- /*$r = q("UPDATE groups SET deleted = 0 WHERE uid = %d AND gname = '%s'",
- intval($uid),
- dbesc($name)
- );*/
q('UPDATE groups SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
notice( t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL);
}
@@ -81,11 +77,11 @@ function group_rmv($uid,$name) {
$user_info['channel_default_group'] = '';
$change = true;
}
- if(strpos($user_info['channel_allow_gid'], '<' . $group_id . '>') !== false) {
+ if(strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
$change = true;
}
- if(strpos($user_info['channel_deny_gid'], '<' . $group_id . '>') !== false) {
+ if(strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
$change = true;
}
diff --git a/include/help.php b/include/help.php
index 02c3cb8e4..0dc37e517 100644
--- a/include/help.php
+++ b/include/help.php
@@ -28,7 +28,7 @@ function get_help_content($tocpath = false) {
}
if($path) {
-
+
$title = basename($path);
if(! $tocpath)
\App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title)));
@@ -38,10 +38,10 @@ function get_help_content($tocpath = false) {
// available and so default back to the English TOC at /doc/toc.{html,bb,md}
// TODO: This is incompatible with the hierarchical TOC construction
// defined in /Zotlabs/Widget/Helpindex.php.
- if($tocpath !== false &&
- load_doc_file('doc/' . $path . '.md') === '' &&
- load_doc_file('doc/' . $path . '.bb') === '' &&
- load_doc_file('doc/' . $path . '.html') === ''
+ if($tocpath !== false &&
+ load_doc_file('doc/' . $path . '.md') === '' &&
+ load_doc_file('doc/' . $path . '.bb') === '' &&
+ load_doc_file('doc/' . $path . '.html') === ''
) {
$path = $title;
}
@@ -120,22 +120,28 @@ function preg_callback_help_include($matches) {
}
+/**
+ * @brief
+ *
+ * @return boolean|array
+ */
function determine_help_language() {
- require_once('Text/LanguageDetect.php');
$lang_detect = new Text_LanguageDetect();
// Set this mode to recognize language by the short code like "en", "ru", etc.
$lang_detect->setNameMode(2);
- // If the language was specified in the URL, override the language preference
+ // If the language was specified in the URL, override the language preference
// of the browser. Default to English if both of these are absent.
if($lang_detect->languageExists(argv(1))) {
$lang = argv(1);
$from_url = true;
} else {
$lang = \App::$language;
- if(! isset($lang))
+ if(! isset($lang))
$lang = 'en';
+
$from_url = false;
}
+
return array('language' => $lang, 'from_url' => $from_url);
}
@@ -145,14 +151,14 @@ function load_doc_file($s) {
$x = determine_help_language();
$lang = $x['language'];
$url_idx = ($x['from_url'] ? 1 : 0);
- // The English translation is at the root of /doc/. Other languages are in
+ // The English translation is at the root of /doc/. Other languages are in
// subfolders named by the language code such as "de", "es", etc.
if($lang !== 'en') {
- $path .= '/' . $lang;
+ $path .= '/' . $lang;
}
$b = basename($s);
-
+
for($i=1+$url_idx; $i<argc()-1; $i++) {
$path .= '/' . argv($i);
}
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index d7fbd8660..f67231847 100644
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -196,12 +196,12 @@ function html2bbcode($message)
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
//node2bbcode($doc, 'td', array(), "[td]", "[/td]");
- node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
- node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
- node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
- node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
- node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
- node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
+ node2bbcode($doc, 'h1', array(), "\n\n[h1]", "[/h1]\n");
+ node2bbcode($doc, 'h2', array(), "\n\n[h2]", "[/h2]\n");
+ node2bbcode($doc, 'h3', array(), "\n\n[h3]", "[/h3]\n");
+ node2bbcode($doc, 'h4', array(), "\n\n[h4]", "[/h4]\n");
+ node2bbcode($doc, 'h5', array(), "\n\n[h5]", "[/h5]\n");
+ node2bbcode($doc, 'h6', array(), "\n\n[h6]", "[/h6]\n");
node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]');
diff --git a/include/import.php b/include/import.php
index f32f655da..a6d738e52 100644
--- a/include/import.php
+++ b/include/import.php
@@ -163,13 +163,17 @@ function import_profiles($channel, $profiles) {
convert_oldfields($profile,'work','employment');
/**
- * @TODO we are going to reset all profile photos to the original
- * somebody will have to fix this later and put all the applicable
- * photos into the export.
+ * @TODO put all the applicable photos into the export.
*/
- $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
- $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
+ if((strpos($profile['thumb'],'/photo/profile/l/') !== false) || intval($profile['is_default'])) {
+ $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
+ $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
+ }
+ else {
+ $profile['photo'] = z_root() . '/photo/' . basename($profile['photo']);
+ $profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']);
+ }
create_table_from_array('profile', $profile);
}
@@ -1082,6 +1086,7 @@ function sync_files($channel, $files) {
logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
if($x['success']) {
+ $orig_attach = $x[0];
$attach_exists = true;
$attach_id = $x[0]['id'];
}
@@ -1146,12 +1151,18 @@ function sync_files($channel, $files) {
// If the hash ever contains any escapable chars this could cause
// problems. Currently it does not.
- /// @TODO implement os_path
if(!isset($att['os_path']))
$att['os_path'] = '';
if($attach_exists) {
logger('sync_files attach exists: ' . print_r($att,true), LOGGER_DEBUG);
+
+ // process/sync a remote rename/move operation
+
+ if($orig_attach['content'] !== $newfname) {
+ rename($orig_attach['content'],$newfname);
+ }
+
if(! dbesc_array($att))
continue;
@@ -1200,7 +1211,14 @@ function sync_files($channel, $files) {
continue;
}
$redirects = 0;
- $x = z_post_url($fetch_url,$parr,$redirects,array('filep' => $fp));
+
+
+ $headers = [];
+ $headers['Accept'] = 'application/x-zot+json' ;
+ $headers['Sigtoken'] = random_string();
+ $headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
+
+ $x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
fclose($fp);
if($x['success']) {
@@ -1250,10 +1268,43 @@ function sync_files($channel, $files) {
);
}
- if($p['imgscale'] === 0 && $p['os_storage'])
+ if(intval($p['imgscale']) === 0 && $p['os_storage'])
$p['content'] = $store_path;
else
- $p['content'] = base64_decode($p['content']);
+ $p['content'] = (($p['content'])? base64_decode($p['content']) : '');
+
+ if(intval($p['imgscale']) && (! $p['content'])) {
+
+ $time = datetime_convert();
+
+ $parr = array('hash' => $channel['channel_hash'],
+ 'time' => $time,
+ 'resource' => $att['hash'],
+ 'revision' => 0,
+ 'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])),
+ 'resolution' => $p['imgscale']
+ );
+
+ $stored_image = $newfname . '-' . intval($p['imgscale']);
+
+ $fp = fopen($stored_image,'w');
+ if(! $fp) {
+ logger('failed to open storage file.',LOGGER_NORMAL,LOG_ERR);
+ continue;
+ }
+ $redirects = 0;
+
+
+ $headers = [];
+ $headers['Accept'] = 'application/x-zot+json' ;
+ $headers['Sigtoken'] = random_string();
+ $headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
+
+ $x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
+ fclose($fp);
+ $p['content'] = file_get_contents($stored_image);
+ unlink($stored_image);
+ }
if(!isset($p['display_path']))
$p['display_path'] = '';
@@ -1282,6 +1333,9 @@ function sync_files($channel, $files) {
}
}
}
+
+ \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $att['hash'] ]);
+
if($f['item']) {
sync_items($channel,$f['item'],
['channel_address' => $original_channel,'url' => $oldbase]
diff --git a/include/items.php b/include/items.php
index dd8b394d3..d0b9cffc9 100755
--- a/include/items.php
+++ b/include/items.php
@@ -1,6 +1,7 @@
<?php
/**
* @file include/items.php
+ * @brief Items related functions.
*/
use Zotlabs\Lib as Zlib;
@@ -173,19 +174,19 @@ function comments_are_now_closed($item) {
function item_normal() {
return " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 ";
+ and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
}
function item_normal_search() {
return " and item.item_hidden = 0 and item.item_type in (0,3,6) and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 ";
+ and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
}
function item_normal_update() {
return " and item.item_hidden = 0 and item.item_type = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
- and item.item_blocked = 0 ";
+ and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
}
@@ -201,14 +202,14 @@ function is_item_normal($item) {
if(intval($item['item_hidden']) || intval($item['item_type']) || intval($item['item_deleted'])
|| intval($item['item_unpublished']) || intval($item['item_delayed']) || intval($item['item_pending_remove'])
- || intval($item['item_blocked']))
+ || intval($item['item_blocked']) || ($item['obj_type'] == ACTIVITY_OBJ_FILE))
return false;
return true;
}
/**
- * @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
* sufficient privileges to comment. This will normally be called on a remote site where perm_is_allowed()
@@ -224,10 +225,21 @@ function is_item_normal($item) {
*/
function can_comment_on_post($observer_xchan, $item) {
-// logger('can_comment_on_post: comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
-
- $x = [ 'observer_hash' => $observer_xchan, 'item' => $item, 'allowed' => 'unset' ];
- call_hooks('can_comment_on_post',$x);
+// logger('Comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
+
+ $x = [
+ 'observer_hash' => $observer_xchan,
+ 'item' => $item,
+ 'allowed' => 'unset'
+ ];
+ /**
+ * @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')
return $x['allowed'];
@@ -386,10 +398,14 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$_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')) {
- logger('post_activity_item: post cancelled by plugin.');
+ if(x($arr, 'cancel')) {
+ logger('Post cancelled by plugin.');
return $ret;
}
@@ -400,6 +416,12 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$ret['success'] = true;
$ret['item_id'] = $post_id;
$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']);
}
@@ -407,8 +429,8 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id));
}
-
$ret['success'] = true;
+
return $ret;
}
@@ -430,7 +452,6 @@ function validate_item_elements($message,$arr) {
$result['success'] = true;
return $result;
-
}
@@ -469,7 +490,7 @@ function limit_body_size($body) {
if( ($textlen + $img_start) > $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);
$textlen = $maxlen;
}
@@ -799,8 +820,17 @@ function get_item_elements($x,$allow_code = false) {
function import_author_xchan($x) {
- $arr = array('xchan' => $x, 'xchan_hash' => '');
- call_hooks('import_author_xchan',$arr);
+ $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'])
return $arr['xchan_hash'];
@@ -823,7 +853,6 @@ function import_author_xchan($x) {
}
return($y);
-
}
/**
@@ -835,7 +864,6 @@ function import_author_xchan($x) {
* * \e string \b guid
* @return boolean|string
*/
-
function import_author_rss($x) {
if(! $x['url'])
return false;
@@ -844,7 +872,7 @@ function import_author_rss($x) {
dbesc($x['url'])
);
if($r) {
- logger('import_author_rss: in cache' , LOGGER_DEBUG);
+ logger('In cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash'];
}
$name = trim($x['name']);
@@ -883,7 +911,15 @@ function import_author_rss($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);
if($arr['result'])
return $arr['result'];
@@ -895,7 +931,7 @@ function import_author_unknown($x) {
dbesc($x['url'])
);
if($r) {
- logger('import_author_unknown: in cache' , LOGGER_DEBUG);
+ logger('In cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash'];
}
@@ -1469,8 +1505,11 @@ function get_profile_elements($x) {
}
-
-
+/**
+ * @brief Signs an item body.
+ *
+ * @param[in,out] array $item
+ */
function item_sign(&$item) {
if(array_key_exists('sig',$item) && $item['sig'])
@@ -1483,14 +1522,13 @@ function item_sign(&$item) {
if(! $r)
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;
-
}
/**
- * @brief
+ * @brief Stores an item type record.
*
* @param array $arr
* @param boolean $allow_exec (optional) default false
@@ -1502,8 +1540,17 @@ function item_sign(&$item) {
*/
function item_store($arr, $allow_exec = false, $deliver = true) {
- $d = array('item' => $arr, 'allow_exec' => $allow_exec);
- call_hooks('item_store', $d );
+ $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'];
$allow_exec = $d['allow_exec'];
@@ -1548,7 +1595,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
return $ret;
}
-
$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']) : '');
@@ -1566,7 +1612,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 );
-
$arr['lang'] = detect_language($arr['body']);
// apply the input filter here
@@ -1581,10 +1626,23 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$allowed_languages = get_pconfig($arr['uid'],'system','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);
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';
return $ret;
}
@@ -1776,18 +1834,26 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
intval($arr['revision'])
);
if($r) {
- logger('item_store: duplicate item ignored. ' . print_r($arr,true));
+ logger('duplicate item ignored. ' . print_r($arr,true));
$ret['message'] = 'duplicate post.';
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')) {
- logger('item_store: post cancelled by plugin.');
+ if(x($arr, 'cancel')) {
+ logger('Post cancelled by plugin.');
$ret['message'] = 'cancelled.';
return $ret;
}
@@ -1894,7 +1960,11 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$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
// which we don't wish to bring to the surface. As the queue only holds deliveries for 3 days, it's
@@ -1931,11 +2001,28 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
}
-
-function item_store_update($arr,$allow_exec = false, $deliver = true) {
-
- $d = array('item' => $arr, 'allow_exec' => $allow_exec);
- call_hooks('item_store_update', $d );
+/**
+ * @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) {
+
+ $d = [
+ 'item' => $arr,
+ 'allow_exec' => $allow_exec
+ ];
+ /**
+ * @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'];
$allow_exec = $d['allow_exec'];
@@ -1947,12 +2034,12 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
}
if(! intval($arr['uid'])) {
- logger('item_store_update: no uid');
+ logger('no uid');
$ret['message'] = 'no uid.';
return $ret;
}
if(! intval($arr['id'])) {
- logger('item_store_update: no id');
+ logger('no id');
$ret['message'] = 'no id.';
return $ret;
}
@@ -1965,7 +2052,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
intval($uid)
);
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';
return $ret;
}
@@ -1997,7 +2084,20 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$allowed_languages = get_pconfig($arr['uid'],'system','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);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
@@ -2097,18 +2197,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_blocked'] = ((array_key_exists('item_blocked',$arr)) ? intval($arr['item_blocked']) : $orig[0]['item_blocked'] );
-
-
$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['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'] );
- 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')) {
- logger('item_store_update: post cancelled by plugin.');
+ if(x($arr, 'cancel')) {
+ logger('Post cancelled by plugin.');
$ret['message'] = 'cancelled.';
return $ret;
}
@@ -2145,9 +2247,9 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$r = dbq("update item set " . $str . " where id = " . $orig_post_id );
if($r)
- logger('item_store_update: updated item ' . $orig_post_id, LOGGER_DEBUG);
+ logger('Updated item ' . $orig_post_id, LOGGER_DEBUG);
else {
- logger('item_store_update: could not update item');
+ logger('Could not update item');
$ret['message'] = 'DB update failed.';
return $ret;
}
@@ -2194,7 +2296,11 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$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) {
send_status_notifications($orig_post_id,$arr);
@@ -2427,7 +2533,7 @@ function tag_deliver($uid, $item_id) {
}
}
else
- logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']);
+ logger('Tag permission denied for ' . $u[0]['channel_address']);
}
/*
@@ -2463,139 +2569,163 @@ function tag_deliver($uid, $item_id) {
$terms = array_merge(get_terms_oftype($item['term'],TERM_MENTION),get_terms_oftype($item['term'],TERM_FORUM));
if($terms)
- logger('tag_deliver: post mentions: ' . print_r($terms,true), LOGGER_DATA);
+ logger('Post mentions: ' . print_r($terms,true), LOGGER_DATA);
+
+
+ $max_forums = get_config('system','max_tagged_forums',2);
+ $matched_forums = 0;
+
$link = normalise_link($u[0]['xchan_url']);
+
if($terms) {
foreach($terms as $term) {
- if(link_compare($term['url'],$link)) {
- $mention = true;
- break;
+ if(! link_compare($term['url'],$link)) {
+ continue;
}
- }
- }
- if($mention) {
- logger('tag_deliver: mention found for ' . $u[0]['channel_name']);
+ $mention = true;
- $r = q("update item set item_mentionsme = 1 where id = %d",
- intval($item_id)
- );
+ logger('Mention found for ' . $u[0]['channel_name']);
- // At this point we've determined that the person receiving this post was mentioned in it or it is a union.
- // Now let's check if this mention was inside a reshare so we don't spam a forum
- // If it's private we may have to unobscure it momentarily so that we can parse it.
+ $r = q("update item set item_mentionsme = 1 where id = %d",
+ intval($item_id)
+ );
- $body = $item['body'];
+ // At this point we've determined that the person receiving this post was mentioned in it or it is a union.
+ // Now let's check if this mention was inside a reshare so we don't spam a forum
+ // If it's private we may have to unobscure it momentarily so that we can parse it.
- $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
+ $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']);
- $tagged = false;
- $plustagged = false;
- $matches = array();
+ $tagged = false;
+ $plustagged = false;
+ $matches = array();
- $pattern = '/[\!@]\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'],'/') . '\[\/zrl\]/';
- if(preg_match($pattern,$body,$matches))
- $tagged = true;
+ $pattern = '/[\!@]\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'],'/') . '\[\/zrl\]/';
+ if(preg_match($pattern,$body,$matches))
+ $tagged = true;
- // original red forum tagging sequence @forumname+
- // standard forum tagging sequence !forumname
+ // original red forum tagging sequence @forumname+
+ // standard forum tagging sequence !forumname
- $pluspattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
+ $pluspattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
- $forumpattern = '/\!\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\[\/zrl\]/';
+ $forumpattern = '/\!\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\[\/zrl\]/';
- $found = false;
+ $found = false;
- $max_forums = get_config('system','max_tagged_forums');
- if(! $max_forums)
- $max_forums = 2;
- $matched_forums = 0;
- $matches = array();
+ $matches = array();
- if(preg_match_all($pluspattern,$body,$matches,PREG_SET_ORDER)) {
- foreach($matches as $match) {
- $matched_forums ++;
- if($term['url'] === $match[1] && $term['term'] === $match[2]) {
- if($matched_forums <= $max_forums) {
- $plustagged = true;
- $found = true;
- break;
+ if(preg_match_all($pluspattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_MENTION) {
+ if($matched_forums <= $max_forums) {
+ $plustagged = true;
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
- logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
}
- }
- if(preg_match_all($forumpattern,$body,$matches,PREG_SET_ORDER)) {
- foreach($matches as $match) {
- $matched_forums ++;
- if($term['url'] === $match[1] && $term['term'] === $match[2]) {
- if($matched_forums <= $max_forums) {
- $plustagged = true;
- $found = true;
- break;
+ if(preg_match_all($forumpattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_FORUM) {
+ if($matched_forums <= $max_forums) {
+ $plustagged = true;
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
- logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
}
- }
- if(! ($tagged || $plustagged)) {
- logger('tag_deliver: mention was in a reshare or exceeded max_tagged_forums - ignoring');
- return;
- }
+ if(! ($tagged || $plustagged)) {
+ logger('Mention was in a reshare or exceeded max_tagged_forums - ignoring');
+ continue;
+ }
- $arr = array('channel_id' => $uid, 'item' => $item, 'body' => $body);
- call_hooks('tagged',$arr);
+ $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.
- */
+ Zlib\Enotify::submit(array(
+ 'to_xchan' => $u[0]['channel_hash'],
+ 'from_xchan' => $item['author_xchan'],
+ 'type' => NOTIFY_TAGSELF,
+ 'item' => $item,
+ 'link' => $i[0]['llink'],
+ 'verb' => ACTIVITY_TAG,
+ 'otype' => 'item'
+ ));
- Zlib\Enotify::submit(array(
- 'to_xchan' => $u[0]['channel_hash'],
- 'from_xchan' => $item['author_xchan'],
- 'type' => NOTIFY_TAGSELF,
- 'item' => $item,
- 'link' => $i[0]['llink'],
- 'verb' => ACTIVITY_TAG,
- 'otype' => 'item'
- ));
+ // Just a normal tag?
- // Just a normal tag?
+ if(! $plustagged) {
+ logger('Not a plus tag', LOGGER_DEBUG);
+ continue;
+ }
- if(! $plustagged) {
- logger('tag_deliver: not a plus tag', LOGGER_DEBUG);
- return;
- }
+ // plustagged - keep going, next check permissions
- // plustagged - keep going, next check permissions
+ if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) {
+ logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']);
+ continue;
+ }
- if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) {
- logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']);
- return;
- }
- }
- if((! $mention) && (! $union)) {
- logger('tag_deliver: no mention for ' . $u[0]['channel_name'] . ' and no union.');
- return;
+ if(! $mention) {
+ logger('No mention for ' . $u[0]['channel_name']);
+ continue;
+ }
+
+ // tgroup delivery - setup a second delivery chain
+ // prevent delivery looping - only proceed
+ // if the message originated elsewhere and is a top-level post
+
+
+ if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) {
+ logger('Item was local or a comment. rejected.');
+ continue;
+ }
+
+ logger('Creating second delivery chain.');
+ start_delivery_chain($u[0],$item,$item_id,null);
+
+ }
}
- // tgroup delivery - setup a second delivery chain
- // prevent delivery looping - only proceed
- // if the message originated elsewhere and is a top-level post
+ if($union) {
+ if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) {
+ logger('Item was local or a comment. rejected.');
+ return;
+ }
+ logger('Creating second delivery chain.');
+ start_delivery_chain($u[0],$item,$item_id,null);
- 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.');
- return;
}
- logger('tag_deliver: creating second delivery chain.');
- start_delivery_chain($u[0],$item,$item_id,null);
}
/**
@@ -2605,8 +2735,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
* 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.
+ *
+ * @param number $uid A chnnel_id
+ * @param array $item
+ * @return boolean
*/
-function tgroup_check($uid,$item) {
+function tgroup_check($uid, $item) {
$mention = false;
@@ -2639,78 +2773,73 @@ function tgroup_check($uid,$item) {
if($terms)
logger('tgroup_check: post mentions: ' . print_r($terms,true), LOGGER_DATA);
+ $max_forums = get_config('system','max_tagged_forums',2);
+ $matched_forums = 0;
+
$link = normalise_link($u[0]['xchan_url']);
if($terms) {
foreach($terms as $term) {
- if(link_compare($term['url'],$link)) {
- $mention = true;
- break;
+ if(! link_compare($term['url'],$link)) {
+ continue;
}
- }
- }
- if($mention) {
- logger('tgroup_check: mention found for ' . $u[0]['channel_name']);
- }
- else
- return false;
+ $mention = true;
+ logger('tgroup_check: mention found for ' . $u[0]['channel_name']);
- // At this point we've determined that the person receiving this post was mentioned in it.
- // Now let's check if this mention was inside a reshare so we don't spam a forum
- // note: $term has been set to the matching term
+ // At this point we've determined that the person receiving this post was mentioned in it.
+ // Now let's check if this mention was inside a reshare so we don't spam a forum
+ // note: $term has been set to the matching term
- $body = $item['body'];
+ $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']);
- $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
+ $pluspattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
- $pluspattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/';
+ $forumpattern = '/\!\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\[\/zrl\]/';
- $forumpattern = '/\!\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\[\/zrl\]/';
+ $found = false;
+ $matches = array();
- $found = false;
-
- $max_forums = get_config('system','max_tagged_forums');
- if(! $max_forums)
- $max_forums = 2;
- $matched_forums = 0;
- $matches = array();
-
- if(preg_match_all($pluspattern,$body,$matches,PREG_SET_ORDER)) {
- foreach($matches as $match) {
- $matched_forums ++;
- if($term['url'] === $match[1] && $term['term'] === $match[2]) {
- if($matched_forums <= $max_forums) {
- $found = true;
- break;
+ if(preg_match_all($pluspattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_MENTION) {
+ if($matched_forums <= $max_forums) {
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
+ }
}
- logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
- }
- }
- if(preg_match_all($forumpattern,$body,$matches,PREG_SET_ORDER)) {
- foreach($matches as $match) {
- $matched_forums ++;
- if($term['url'] === $match[1] && $term['term'] === $match[2]) {
- if($matched_forums <= $max_forums) {
- $found = true;
- break;
+ if(preg_match_all($forumpattern,$body,$matches,PREG_SET_ORDER)) {
+ foreach($matches as $match) {
+ $matched_forums ++;
+ if($term['url'] === $match[1] && $term['term'] === $match[2] && intval($term['ttype']) === TERM_FORUM) {
+ if($matched_forums <= $max_forums) {
+ $found = true;
+ break;
+ }
+ logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
+ }
}
- logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring');
}
+
+ if(! $found) {
+ logger('tgroup_check: mention was in a reshare or exceeded max_tagged_forums - ignoring');
+ continue;
+ }
+
+ return true;
}
}
- if(! $found) {
- logger('tgroup_check: mention was in a reshare or exceeded max_tagged_forums - ignoring');
- return false;
- }
+ return false;
- return true;
}
/**
@@ -2731,8 +2860,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
if($sourced) {
$r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1",
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) {
$t = trim($r[0]['src_tag']);
if($t) {
@@ -2741,15 +2870,15 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
foreach($tags as $tt) {
$tt = trim($tt);
if($tt) {
- q("insert into term (uid,oid,otype,ttype,term,url)
- values(%d,%d,%d,%d,'%s','%s') ",
- intval($channel['channel_id']),
- intval($item_id),
- intval(TERM_OBJ_POST),
- intval(TERM_CATEGORY),
- dbesc($tt),
+ q("insert into term (uid,oid,otype,ttype,term,url)
+ values(%d,%d,%d,%d,'%s','%s') ",
+ intval($channel['channel_id']),
+ intval($item_id),
+ intval(TERM_OBJ_POST),
+ intval(TERM_CATEGORY),
+ dbesc($tt),
dbesc(z_root() . '/channel/' . $channel['channel_address'] . '?f=&cat=' . urlencode($tt))
- );
+ );
}
}
}
@@ -3014,7 +3143,6 @@ function mail_store($arr) {
$arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 );
$arr['mail_raw'] = ((x($arr,'mail_raw')) ? intval($arr['mail_raw']) : 0 );
-
if($arr['parent_mid']) {
$parent_item = q("select * from mail where mid = '%s' and channel_id = %d limit 1",
@@ -3022,7 +3150,7 @@ function mail_store($arr) {
intval($arr['channel_id'])
);
if(($parent_item) && (! $arr['conv_guid'])) {
- $arr['conv_guid'] = $parent_item[0]['conv_guid'];
+ $arr['conv_guid'] = $parent_item[0]['conv_guid'];
}
}
else {
@@ -3048,19 +3176,23 @@ function mail_store($arr) {
);
if($r) {
- logger('mail_store: duplicate item ignored. ' . print_r($arr,true));
+ logger('Duplicate item ignored. ' . print_r($arr,true));
return 0;
}
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;
}
- 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')) {
- logger('mail_store: post cancelled by plugin.');
+ logger('Post cancelled by plugin.');
return 0;
}
@@ -3077,15 +3209,15 @@ function mail_store($arr) {
if($r) {
$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
}
else {
- logger('mail_store: could not locate created item');
+ logger('Could not locate created item');
return 0;
}
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 ",
$arr['mid'],
intval($arr['channel_id']),
@@ -3114,7 +3246,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;
}
@@ -3135,7 +3271,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
$img_st_close++; // make it point to AFTER the closing bracket
$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/')) {
// Only embed locally hosted photos
@@ -3179,7 +3315,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
// 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)) {
- logger('fix_private_photos: scaling photo', LOGGER_DEBUG);
+ logger('Scaling photo', LOGGER_DEBUG);
$width = intval($match[1]);
$height = intval($match[2]);
@@ -3192,9 +3328,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);
- logger('fix_private_photos: replaced: ' . $image, LOGGER_DATA);
+ logger('Replaced: ' . $image, LOGGER_DATA);
}
}
}
@@ -3451,8 +3587,16 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
);
}
- $arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage);
- call_hooks('drop_item', $arr );
+ $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']);
@@ -3602,8 +3746,14 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
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 " : "" );
$item_normal = item_normal();
@@ -3612,7 +3762,6 @@ function first_post_date($uid,$wall = false) {
where uid = %d and id = parent $item_normal $wall_sql
order by created asc limit 1",
intval($uid)
-
);
if($r) {
// logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA);
@@ -3628,8 +3777,8 @@ function first_post_date($uid,$wall = false) {
* current flat list of all representative dates.
*
* @param int $uid
- * @param unknown $wall
- * @param unknown $mindate
+ * @param boolean $wall
+ * @param string $mindate
* @return array
*/
function list_post_dates($uid, $wall, $mindate) {
@@ -3700,8 +3849,14 @@ function posted_dates($uid,$wall) {
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();
if($items) {
@@ -3720,7 +3875,6 @@ function fetch_post_tags($items,$link = false) {
}
$tag_finder_str = implode(', ', $tag_finder);
-
if(strlen($tag_finder_str)) {
$tags = q("select * from term where oid in ( %s ) and otype = %d",
dbesc($tag_finder_str),
@@ -3729,7 +3883,6 @@ function fetch_post_tags($items,$link = false) {
$imeta = q("select * from iconfig where iid in ( %s )",
dbesc($tag_finder_str)
);
-
}
for($x = 0; $x < count($items); $x ++) {
@@ -3779,8 +3932,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();
$mindate = null;
@@ -3903,8 +4063,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$item_uids = ' true ';
$item_normal = item_normal();
-
- if ($arr['uid']) $uid= $arr['uid'];
+ if($arr['uid']) {
+ $uid = $arr['uid'];
+ }
if($channel) {
$uid = $channel['channel_id'];
@@ -3979,7 +4140,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
if($channel && intval($arr['compat']) === 1) {
- $sql_extra = " AND author_xchan = '" . $channel['channel_hash'] . "' and item_private = 0 ";
+ $sql_extra = " AND author_xchan = '" . $channel['channel_hash'] . "' and item_private = 0 $item_normal ";
}
if ($arr['datequery']) {
@@ -3990,24 +4151,23 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
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)
- $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(strlen($arr['file'])) {
- $sql_extra .= term_query('item',$arr['files'],TERM_FILE);
- }
+ if(strlen($arr['file'])) {
+ $sql_extra .= term_query('item',$arr['files'],TERM_FILE);
+ }
- 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($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))) {
// only setup pagination on initial page view
@@ -4042,9 +4202,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 " : '');
- if($client_mode & CLIENT_MODE_LOAD)
- $simple_update = '';
+ $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : '');
+ if($client_mode & CLIENT_MODE_LOAD)
+ $simple_update = '';
//$start = dba_timer();
@@ -4067,7 +4227,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$items = q("SELECT item.*, item.id AS item_id FROM item
WHERE $item_uids $item_restrict
$simple_update
- $sql_extra $sql_nets
+ $sql_extra $sql_nets $sql_extra3
ORDER BY item.received DESC $pager_sql"
);
@@ -4087,27 +4247,26 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) {
- // Fetch a page full of parent items for this page
-
- $r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE $item_uids $item_restrict
- AND item.parent = item.id
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets
- ORDER BY item.$ordering DESC $pager_sql "
- );
-
- }
- else {
- // update
- $r = q("SELECT item.parent AS item_id FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE $item_uids $item_restrict $simple_update
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets "
- );
- }
+ // Fetch a page full of parent items for this page
+
+ $r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE $item_uids $item_restrict
+ AND item.parent = item.id
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets
+ ORDER BY item.$ordering DESC $pager_sql "
+ );
+ }
+ else {
+ // update
+ $r = q("SELECT item.parent AS item_id FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE $item_uids $item_restrict $simple_update
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets "
+ );
+ }
//$first = dba_timer();
@@ -4163,16 +4322,17 @@ function webpage_to_namespace($webpage) {
$page_type = 'PDL';
elseif($webpage == ITEM_TYPE_CARD)
$page_type = 'CARD';
+ elseif($webpage == ITEM_TYPE_ARTICLE)
+ $page_type = 'ARTICLE';
elseif($webpage == ITEM_TYPE_DOC)
$page_type = 'docfile';
else
$page_type = 'unknown';
- return $page_type;
+ return $page_type;
}
-
function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
if(! $post_id)
@@ -4296,7 +4456,6 @@ function comment_local_origin($item) {
-
function send_profile_photo_activity($channel,$photo,$profile) {
// for now only create activities for the default profile
@@ -4345,8 +4504,6 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['author_xchan'] = $channel['channel_hash'];
post_activity_item($arr);
-
-
}
@@ -4549,7 +4706,6 @@ function item_create_edit_activity($post) {
));
-
$x = post_activity_item($new_item);
$post_id = $x['id'];
@@ -4565,5 +4721,63 @@ function item_create_edit_activity($post) {
}
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_activity', $post_id));
+}
+/**
+ * @brief copies an entire conversation from the pubstream to this channel's stream
+ * which will allow you to interact with it.
+ */
+
+
+
+function copy_of_pubitem($channel,$mid) {
+
+ $result = null;
+ $syschan = get_sys_channel();
+
+ // logger('copy_of_pubitem: ' . $channel['channel_id'] . ' mid: ' . $mid);
+
+ $r = q("select * from item where mid = '%s' and uid = %d limit 1",
+ dbesc($mid),
+ intval($channel['channel_id'])
+ );
+
+ if($r) {
+ logger('exists');
+ $item = fetch_post_tags($r,true);
+ return $item[0];
+ }
+
+
+ $r = q("select * from item where parent_mid = (select parent_mid from item where mid = '%s' and uid = %d ) order by id ",
+ dbesc($mid),
+ intval($syschan['channel_id'])
+ );
+
+ if($r) {
+ $items = fetch_post_tags($r,true);
+ foreach($items as $rv) {
+ $d = q("select id from item where mid = '%s' and uid = %d limit 1",
+ dbesc($rv['mid']),
+ intval($channel['channel_id'])
+ );
+ if($d) {
+ continue;
+ }
+
+ unset($rv['id']);
+ unset($rv['parent']);
+ $rv['aid'] = $channel['channel_account_id'];
+ $rv['uid'] = $channel['channel_id'];
+ $rv['item_wall'] = 0;
+ $rv['item_origin'] = 0;
+
+ $x = item_store($rv);
+ if($x['item_id'] && $x['item']['mid'] === $mid) {
+ $result = $x['item'];
+ }
+
+ }
+ }
+ return $result;
}
diff --git a/include/language.php b/include/language.php
index efe9397fb..f6f266685 100644
--- a/include/language.php
+++ b/include/language.php
@@ -8,6 +8,7 @@
* language related tasks.
*/
+use CommerceGuys\Intl\Language\LanguageRepository;
/**
* @brief Get the browser's submitted preferred languages.
@@ -17,7 +18,7 @@
*
* Get the language setting directly from system variables, bypassing get_config()
* as database may not yet be configured.
- *
+ *
* If possible, we use the value from the browser.
*
* @return array with ordered list of preferred languages from browser
@@ -28,7 +29,7 @@ function get_browser_language() {
if (x($_SERVER, 'HTTP_ACCEPT_LANGUAGE')) {
// break up string into pieces (languages and q factors)
- preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
+ preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])) {
@@ -40,7 +41,7 @@ function get_browser_language() {
if ($val === '') $langs[$lang] = 1;
}
- // sort list based on value
+ // sort list based on value
arsort($langs, SORT_NUMERIC);
}
}
@@ -52,7 +53,7 @@ function get_browser_language() {
* @brief Returns the best language for which also a translation exists.
*
* This function takes the results from get_browser_language() and compares it
- * with the available translations and returns the best fitting language for
+ * with the available translations and returns the best fitting language for
* which there exists a translation.
*
* If there is no match fall back to config['system']['language']
@@ -243,11 +244,9 @@ function string_plural_select_default($n) {
*
* @see http://pear.php.net/package/Text_LanguageDetect
* @param string $s A string to examine
- * @return Language code in 2-letter ISO 639-1 (en, de, fr) format
+ * @return string Language code in 2-letter ISO 639-1 (en, de, fr) format
*/
function detect_language($s) {
- require_once('Text/LanguageDetect.php');
-
$min_length = get_config('system', 'language_detect_min_length');
if ($min_length === false)
$min_length = LANGUAGE_DETECT_MIN_LENGTH;
@@ -257,7 +256,7 @@ function detect_language($s) {
$min_confidence = LANGUAGE_DETECT_MIN_CONFIDENCE;
// embedded apps have long base64 strings which will trip up the detector.
- $naked_body = preg_replace('/\[app\](.*?)\[\/app\]/','',$s);
+ $naked_body = preg_replace('/\[app\](.*?)\[\/app\]/', '', $s);
// strip off bbcode
$naked_body = preg_replace('/\[(.+?)\]/', '', $naked_body);
if (mb_strlen($naked_body) < intval($min_length)) {
@@ -300,11 +299,7 @@ function detect_language($s) {
* @param string $s Language code to look up
* @param string $l (optional) In which language to return the name
* @return string with the language name, or $s if unrecognized
- *
- * @todo include CommerceGuys\Intl through composer like SabreDAV.
*/
-require_once(__DIR__ . '/../library/intl/vendor/autoload.php');
-use CommerceGuys\Intl\Language\LanguageRepository;
function get_language_name($s, $l = null) {
// get() expects the second part to be in upper case
if (strpos($s, '-') !== false) $s = substr($s, 0, 2) . strtoupper(substr($s, 2));
@@ -322,6 +317,8 @@ function get_language_name($s, $l = null) {
$language = $languageRepository->get($s, $l);
} catch (CommerceGuys\Intl\Exception\UnknownLanguageException $e) {
return $s; // Give up
+ } catch (CommerceGuys\Intl\Exception\UnknownLocaleException $e) {
+ return $s; // Give up
}
}
@@ -379,7 +376,7 @@ function lang_selector() {
$o = replace_macros($tpl, array(
'$title' => t('Select an alternate language'),
'$langs' => array($lang_options, $selected),
-
+
));
return $o;
diff --git a/include/markdown.php b/include/markdown.php
index 15e19bde1..e4a35e3c3 100644
--- a/include/markdown.php
+++ b/include/markdown.php
@@ -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
* 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,
* 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
- * @return string
+ * @param array $options default empty
+ * @return string The message converted to bbcode
*/
-
function markdown_to_bb($s, $use_zrl = false, $options = []) {
-
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 '';
}
-
$s = str_replace("&#xD;","\r",$s);
$s = str_replace("&#xD;\n&gt;","",$s);
@@ -43,20 +41,32 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
// if empty link text replace with the url
$s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s);
- $x = [ 'text' => $s , 'zrl' => $use_zrl, 'options' => $options ];
-
- call_hooks('markdown_to_bb_init',$x);
+ $x = [
+ 'text' => $s,
+ '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'];
- // Escaping the hash tags - doesn't always seem to work
- // $s = preg_replace('/\#([^\s\#])/','\\#$1',$s);
- // This seems to work
+ // Escaping the hash tags
$s = preg_replace('/\#([^\s\#])/','&#35;$1',$s);
$s = MarkdownExtra::defaultTransform($s);
- $s = str_replace("\r","",$s);
+ if($options && $options['preserve_lf']) {
+ $s = str_replace(["\r","\n"],["",'<br>'],$s);
+ }
+ else {
+ $s = str_replace("\r","",$s);
+ }
$s = str_replace('&#35;','#',$s);
@@ -77,13 +87,22 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
// Don't show link to full picture (until it is fixed)
$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;
}
-
+/**
+ * @brief
+ *
+ * @param array $match
+ * @return string
+ */
function bb_to_markdown_share($match) {
$matches = array();
@@ -150,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 = []) {
/*
* 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);
-
$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.
@@ -170,12 +194,17 @@ function bb_to_markdown($Text, $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'];
// Convert it to HTML - don't try oembed
- $Text = bbcode($Text, $preserve_nl, false);
+ $Text = bbcode($Text, [ 'tryoembed' => false ]);
// Markdownify does not preserve previously escaped html entities such as <> and &.
$Text = str_replace(array('&lt;','&gt;','&amp;'),array('&_lt_;','&_gt_;','&_amp_;'),$Text);
@@ -199,14 +228,16 @@ function bb_to_markdown($Text, $options = []) {
$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);
return $Text;
-
}
-
/**
* @brief Convert a HTML text into Markdown.
*
@@ -214,8 +245,6 @@ function bb_to_markdown($Text, $options = []) {
*
* If the HTML text can not get parsed it will return an empty string.
*
- * @see HTMLToMarkdown
- *
* @param string $html The HTML code to convert
* @return string Markdown representation of the given HTML text, empty on error
*/
@@ -229,8 +258,5 @@ function html2markdown($html) {
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;
}
diff --git a/include/message.php b/include/message.php
index 477c7172c..4a673b961 100644
--- a/include/message.php
+++ b/include/message.php
@@ -215,7 +215,7 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep
return $ret;
}
- if(count($images)) {
+ if($images) {
foreach($images as $image) {
if(! stristr($image,z_root() . '/photo/'))
continue;
@@ -335,12 +335,9 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) {
case 'combined':
default:
-
- $parents = q("SELECT parent_mid FROM mail WHERE mid = parent_mid AND channel_id = %d ORDER BY created DESC",
+ $parents = q("SELECT mail.parent_mid FROM mail LEFT JOIN conv ON mail.conv_guid = conv.guid WHERE mail.mid = mail.parent_mid AND mail.channel_id = %d ORDER BY conv.updated DESC $limit",
dbesc($local_channel)
);
- //FIXME: We need the latest mail of a thread here. This query throws errors in postgres. We now look for the latest in php until somebody can fix this...
- //$sql = "SELECT * FROM ( SELECT * FROM mail WHERE channel_id = $local_channel ORDER BY created DESC $limit ) AS temp_table GROUP BY parent_mid ORDER BY created DESC";
break;
}
diff --git a/include/nav.php b/include/nav.php
index 6b98a807d..8566cc58c 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -73,6 +73,11 @@ EOT;
// nav links: array of array('href', 'text', 'extra css classes', 'title')
$nav = [];
+ $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
+
+ if(! $disable_discover_tab)
+ $nav['pubs'] = true;
+
/**
* Display login or logout
*/
@@ -171,13 +176,15 @@ EOT;
}
-
- $homelink = get_my_url();
- if(! $homelink) {
+ $my_url = get_my_url();
+ if(! $my_url) {
$observer = App::get_observer();
- $homelink = (($observer) ? $observer['xchan_url'] : '');
+ $my_url = (($observer) ? $observer['xchan_url'] : '');
}
+ $homelink_arr = parse_url($my_url);
+ $homelink = $homelink_arr['scheme'] . '://' . $homelink_arr['host'];
+
if(! $is_owner) {
$nav['rusermenu'] = array(
$homelink,
@@ -253,7 +260,7 @@ EOT;
}
$syslist = array();
- $list = Zlib\Apps::app_list(local_channel(), false, 'nav_featured_app');
+ $list = Zlib\Apps::app_list(local_channel(), false, ['nav_featured_app', 'nav_pinned_app']);
if($list) {
foreach($list as $li) {
$syslist[] = Zlib\Apps::app_encode($li);
@@ -274,16 +281,20 @@ EOT;
$app['active'] = true;
if($is_owner) {
- $nav_apps[] = Zlib\Apps::app_render($app,'nav');
- if(strpos($app['categories'],'navbar_' . $template)) {
+ if(strpos($app['categories'],'nav_pinned_app') !== false) {
$navbar_apps[] = Zlib\Apps::app_render($app,'navbar');
}
+ else {
+ $nav_apps[] = Zlib\Apps::app_render($app,'nav');
+ }
}
elseif(! $is_owner && strpos($app['requires'], 'local_channel') === false) {
- $nav_apps[] = Zlib\Apps::app_render($app,'nav');
- if(strpos($app['categories'],'navbar_' . $template)) {
+ if(strpos($app['categories'],'nav_pinned_app') !== false) {
$navbar_apps[] = Zlib\Apps::app_render($app,'navbar');
}
+ else {
+ $nav_apps[] = Zlib\Apps::app_render($app,'nav');
+ }
}
}
@@ -304,7 +315,7 @@ EOT;
'$sitelocation' => $sitelocation,
'$nav' => $x['nav'],
'$banner' => $banner,
- '$emptynotifications' => t('Loading...'),
+ '$emptynotifications' => t('Loading'),
'$userinfo' => $x['usermenu'],
'$localuser' => local_channel(),
'$is_owner' => $is_owner,
@@ -314,7 +325,7 @@ EOT;
'$pleasewait' => t('Please wait...'),
'$nav_apps' => $nav_apps,
'$navbar_apps' => $navbar_apps,
- '$channel_menu' => get_config('system','channel_menu'),
+ '$channel_menu' => get_pconfig(App::$profile_uid,'system','channel_menu',get_config('system','channel_menu')),
'$channel_thumb' => ((App::$profile) ? App::$profile['thumb'] : ''),
'$channel_apps' => $channel_apps,
'$addapps' => t('Add Apps'),
@@ -487,6 +498,17 @@ function channel_apps($is_owner = false, $nickname = null) {
];
}
+ if($p['view_pages'] && feature_enabled($uid,'articles')) {
+ $tabs[] = [
+ 'label' => t('Articles'),
+ 'url' => z_root() . '/articles/' . $nickname ,
+ 'sel' => ((argv(0) == 'articles') ? 'active' : ''),
+ 'title' => t('View Articles'),
+ 'id' => 'articles-tab',
+ 'icon' => 'file-text-o'
+ ];
+ }
+
if($has_webpages && feature_enabled($uid,'webpages')) {
$tabs[] = [
diff --git a/include/network.php b/include/network.php
index 7e2dbf4cf..79a8c6578 100644
--- a/include/network.php
+++ b/include/network.php
@@ -1,6 +1,7 @@
<?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
* 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 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('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']);
}
-
if(x($opts,'cookiejar'))
@curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
if(x($opts,'cookiefile'))
@curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
-
-
if(x($opts,'cookie'))
@curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
@@ -423,7 +421,7 @@ function http_status($val, $msg = '') {
* integer HTTP status result value
* @param string $msg
* optional message
- * @return does not return, process is terminated
+ * @return void does not return, process is terminated
*/
function http_status_exit($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 int $recursion_depth[in,out]
+ * @param[in,out] int $recursion_depth
* @return NULL|string|array
*/
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
* if it's real (or check if is a valid IP address).
*
* @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
*/
function validate_url(&$url) {
@@ -593,6 +591,7 @@ function allowed_url($url) {
}
}
}
+
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(! strstr($s,'<?xml'))
return false;
@@ -683,14 +682,21 @@ function parse_xml_string($s,$strict = true) {
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) {
// Picture addresses can contain special characters
$s = htmlspecialchars_decode($s, ENT_COMPAT);
$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) {
require_once('include/photo/photo_driver.php');
@@ -716,19 +722,22 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
$scaled = str_replace($scale_replace[0], $scale_replace[1], $mtch[3]);
else
$scaled = $mtch[3];
- $i = z_fetch_url($scaled,true);
+ if(! strpbrk(substr($scaled, 0, 1), 'zhfmt'))
+ continue;
+
+ $i = z_fetch_url($scaled, true);
- $cache = get_config('system','itemcache');
+ $cache = get_config('system', 'itemcache');
if (($cache != '') and is_dir($cache)) {
- $cachefile = $cache."/".hash("md5", $scaled);
+ $cachefile = $cache . '/' . hash('md5', $scaled);
file_put_contents($cachefile, $i['body']);
}
// guess mimetype from headers or filename
- $type = guess_image_type($mtch[3],$i['header']);
- if(strpos($type,'image') === false)
+ $type = guess_image_type($mtch[3], $i['header']);
+ if(strpos($type, 'image') === false)
continue;
if($i['success']) {
@@ -743,13 +752,14 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
if($orig_width > 1024 || $orig_height > 1024) {
$tag = (($match[1] == 'z') ? 'zmg' : 'img');
+ $linktag = (($match[1] == 'z') ? 'zrl' : 'url');
$ph->scaleImage(1024);
$new_width = $ph->getWidth();
$new_height = $ph->getHeight();
logger('data: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG);
$s = str_replace($mtch[0],'[' . $tag . '=' . $new_width . 'x' . $new_height. ']' . $scaled . '[/' . $tag . ']'
. "\n" . (($include_link)
- ? '[zrl=' . $mtch[2] . ']' . t('view full size') . '[/zrl]' . "\n"
+ ? '[' . $linktag . '=' . $mtch[3] . ']' . t('view full size') . '[/' . $linktag . ']' . "\n"
: ''),$s);
logger('new string: ' . $s, LOGGER_DEBUG);
}
@@ -760,7 +770,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
// replace the special char encoding
- $s = htmlspecialchars($s,ENT_COMPAT,'UTF-8');
+ $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
return $s;
}
@@ -1137,7 +1147,14 @@ function discover_by_url($url, $arr = null) {
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 = [];
@@ -1145,7 +1162,7 @@ function discover_by_webbie($webbie,$protocol = '') {
// $webbie = strtolower($webbie);
- $x = webfinger_rfc7033($webbie,true);
+ $x = webfinger_rfc7033($webbie, true);
if($x && array_key_exists('links',$x) && $x['links']) {
foreach($x['links'] as $link) {
if(array_key_exists('rel',$link)) {
@@ -1154,7 +1171,7 @@ function discover_by_webbie($webbie,$protocol = '') {
// here.
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']) {
$i = import_xchan($x['zot']);
return true;
@@ -1174,16 +1191,35 @@ function discover_by_webbie($webbie,$protocol = '') {
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);
if($arr['success'])
return true;
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,'@')) {
$lhs = substr($webbie,0,strpos($webbie,'@'));
@@ -1195,6 +1231,7 @@ function webfinger_rfc7033($webbie,$zot = false) {
if($m) {
if($m['scheme'] !== 'https')
return false;
+
$rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
$resource = urlencode($webbie);
}
@@ -1207,20 +1244,19 @@ function webfinger_rfc7033($webbie,$zot = false) {
// 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,
// 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
- // accomplished by setting it to nothing.
+ // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is
+ // accomplished by setting it to nothing.
$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:' ] ]);
if($s['success']) {
- $j = json_decode($s['body'],true);
+ $j = json_decode($s['body'], true);
return($j);
}
return false;
-
}
function old_webfinger($webbie) {
@@ -1429,11 +1465,27 @@ function scrape_feed($url) {
-function do_delivery($deliveries) {
+
+
+function do_delivery($deliveries, $force = false) {
+
+ // $force is set if a site that wasn't responding suddenly returns to life.
+ // Try and shove through everything going to that site while it's responding.
if(! (is_array($deliveries) && count($deliveries)))
return;
+
+ $x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
+ if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300)) && (! $force)) {
+ logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
+ foreach($deliveries as $d) {
+ update_queue_item($d);
+ }
+ return;
+ }
+
+
$interval = ((get_config('system','delivery_interval') !== false)
? intval(get_config('system','delivery_interval')) : 2 );
@@ -1584,7 +1636,13 @@ function check_siteallowed($url) {
$retvalue = true;
$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))
return $arr['allowed'];
@@ -1623,7 +1681,13 @@ function check_channelallowed($hash) {
$retvalue = true;
$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))
return $arr['allowed'];
@@ -1712,6 +1776,10 @@ function network_to_name($s) {
NETWORK_MYSPACE => t('MySpace'),
);
+ /**
+ * @hooks network_to_name
+ * @deprecated
+ */
call_hooks('network_to_name', $nets);
$search = array_keys($nets);
@@ -1723,7 +1791,7 @@ function network_to_name($s) {
/**
* @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 fromEmail email of the sender
* * \e string \b replyTo replyTo address to direct responses
@@ -1754,6 +1822,10 @@ function z_mail($params) {
$params['sent'] = false;
$params['result'] = false;
+ /**
+ * @hooks email_send
+ * * \e params @see z_mail()
+ */
call_hooks('email_send', $params);
if($params['sent']) {
@@ -1901,60 +1973,78 @@ function service_plink($contact, $guid) {
$plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid;
$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);
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) {
- // Values will be stored in this array
+ // Values will be stored in this array
+ $AcceptTypes = [];
if($acceptedTypes === false)
$acceptedTypes = $_SERVER['HTTP_ACCEPT'];
- $AcceptTypes = Array ();
-
- // Accept header is case insensitive, and whitespace isn’t 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 isn’t supported!
- $AcceptTypes[$a] = $q;
- }
- arsort($AcceptTypes);
-
- // if no parameter was passed, just return parsed data
- if (!$mimeTypes) return $AcceptTypes;
-
- $mimeTypes = array_map('strtolower', (array)$mimeTypes);
-
- // let’s check our supported types:
- foreach ($AcceptTypes as $mime => $q) {
- if ($q && in_array($mime, $mimeTypes)) return $mime;
- }
- // no mime-type found
- return null;
-}
+ // Accept header is case insensitive, and whitespace isn’t 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 isn’t supported!
+ $AcceptTypes[$a] = $q;
+ }
+ arsort($AcceptTypes);
+ // if no parameter was passed, just return parsed data
+ if (!$mimeTypes) return $AcceptTypes;
-function jsonld_document_loader($url) {
+ $mimeTypes = array_map('strtolower', (array)$mimeTypes);
- // perform caching for jsonld normaliser
+ // let’s check our supported types:
+ foreach ($AcceptTypes as $mime => $q) {
+ 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) {
require_once('library/jsonld/jsonld.php');
$cachepath = 'store/[data]/ldcache';
if(! is_dir($cachepath))
- os_mkdir($cachepath,STORAGE_DEFAULT_PERMISSIONS,true);
+ os_mkdir($cachepath, STORAGE_DEFAULT_PERMISSIONS, true);
$filename = $cachepath . '/' . urlencode($url);
if(file_exists($filename) && filemtime($filename) > time() - (12 * 60 * 60)) {
@@ -1963,7 +2053,7 @@ function jsonld_document_loader($url) {
$r = jsonld_default_document_loader($url);
if($r) {
- file_put_contents($filename,json_encode($r));
+ file_put_contents($filename, json_encode($r));
return $r;
}
@@ -1973,5 +2063,4 @@ function jsonld_document_loader($url) {
}
return [];
-
} \ No newline at end of file
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 5eb1f9113..6af753195 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -129,7 +129,14 @@ abstract class photo_driver {
return $this->types[$this->getType()];
}
- public function scaleImage($max) {
+ /**
+ * @brief scale image
+ * int $max maximum pixel size in either dimension
+ * boolean $float_height - if true allow height to float to any length on tall images,
+ * constraining only the width
+ */
+
+ public function scaleImage($max, $float_height = true) {
if(!$this->is_valid())
return FALSE;
@@ -146,7 +153,7 @@ abstract class photo_driver {
// very tall image (greater than 16:9)
// constrain the width - let the height float.
- if((($height * 9) / 16) > $width) {
+ if(((($height * 9) / 16) > $width) && ($float_height)) {
$dest_width = $max;
$dest_height = intval(( $height * $max ) / $width);
}
@@ -173,7 +180,7 @@ abstract class photo_driver {
// very tall image (greater than 16:9)
// but width is OK - don't do anything
- if((($height * 9) / 16) > $width) {
+ if(((($height * 9) / 16) > $width) && ($float_height)) {
$dest_width = $width;
$dest_height = $height;
}
@@ -241,74 +248,94 @@ abstract class photo_driver {
}
+ /**
+ * @brief reads exif data from filename
+ */
+ public function exif($filename) {
- public function orient($filename) {
- /**
- * This function is a bit unusual, because it is operating on a file, but you must
- * first create an image from that file to initialise the type and check validity
- * of the image.
- */
-
- if(! $this->is_valid())
- return false;
-
- if((! function_exists('exif_read_data')) || ($this->getType() !== 'image/jpeg'))
+ if((! function_exists('exif_read_data'))
+ || (! in_array($this->getType(), [ 'image/jpeg' , 'image/tiff'] ))) {
return false;
+ }
- $exif = @exif_read_data($filename,null,true);
-
- if($exif) {
- $ort = $exif['IFD0']['Orientation'];
-
- switch($ort)
- {
- case 1: // nothing
- break;
+ /*
+ * PHP 7.2 allows you to use a stream resource, which should reduce/avoid
+ * memory exhaustion on large images.
+ */
- case 2: // horizontal flip
- $this->flip();
- break;
+ if(version_compare(PHP_VERSION,'7.2.0') >= 0) {
+ $f = @fopen($filename,'rb');
+ }
+ else {
+ $f = $filename;
+ }
- case 3: // 180 rotate left
- $this->rotate(180);
- break;
+ if($f) {
+ return @exif_read_data($f);
+ }
- case 4: // vertical flip
- $this->flip(false, true);
- break;
+ return false;
+ }
- case 5: // vertical flip + 90 rotate right
- $this->flip(false, true);
- $this->rotate(-90);
- break;
+ /**
+ * @brief orients current image based on exif orientation information
+ */
- case 6: // 90 rotate right
- $this->rotate(-90);
- break;
+ public function orient($exif) {
- case 7: // horizontal flip + 90 rotate right
- $this->flip();
- $this->rotate(-90);
- break;
+ if(! ($this->is_valid() && $exif)) {
+ return false;
+ }
- case 8: // 90 rotate left
- $this->rotate(90);
- break;
- }
+ $ort = $exif['IFD0']['Orientation'];
- return $exif;
+ if(! $ort) {
+ return false;
+ }
+ switch($ort) {
+ case 1: // nothing
+ break;
+ case 2: // horizontal flip
+ $this->flip();
+ break;
+ case 3: // 180 rotate left
+ $this->rotate(180);
+ break;
+ case 4: // vertical flip
+ $this->flip(false, true);
+ break;
+ case 5: // vertical flip + 90 rotate right
+ $this->flip(false, true);
+ $this->rotate(-90);
+ break;
+ case 6: // 90 rotate right
+ $this->rotate(-90);
+ break;
+ case 7: // horizontal flip + 90 rotate right
+ $this->flip();
+ $this->rotate(-90);
+ break;
+ case 8: // 90 rotate left
+ $this->rotate(90);
+ break;
+ default:
+ break;
}
-
- return false;
+ return true;
}
public function save($arr) {
+ if(! $this->is_valid()) {
+ logger('attempt to store invalid photo.');
+ return false;
+ }
+
$p = array();
$p['aid'] = ((intval($arr['aid'])) ? intval($arr['aid']) : 0);
@@ -331,6 +358,8 @@ abstract class photo_driver {
$p['os_path'] = $arr['os_path'];
$p['os_syspath'] = ((array_key_exists('os_syspath',$arr)) ? $arr['os_syspath'] : '');
$p['display_path'] = (($arr['display_path']) ? $arr['display_path'] : '');
+ $p['width'] = (($arr['width']) ? $arr['width'] : $this->getWidth());
+ $p['height'] = (($arr['height']) ? $arr['height'] : $this->getHeight());
if(! intval($p['imgscale']))
logger('save: ' . print_r($arr,true), LOGGER_DATA);
@@ -378,8 +407,8 @@ abstract class photo_driver {
dbesc(basename($p['filename'])),
dbesc($this->getType()),
dbesc($p['album']),
- intval($this->getHeight()),
- intval($this->getWidth()),
+ intval($p['height']),
+ intval($p['width']),
(intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())),
intval($p['os_storage']),
intval(strlen($this->imageString())),
@@ -409,8 +438,8 @@ abstract class photo_driver {
dbesc(basename($p['filename'])),
dbesc($this->getType()),
dbesc($p['album']),
- intval($this->getHeight()),
- intval($this->getWidth()),
+ intval($p['height']),
+ intval($p['width']),
(intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())),
intval($p['os_storage']),
intval(strlen($this->imageString())),
@@ -426,6 +455,7 @@ abstract class photo_driver {
dbesc($p['deny_gid'])
);
}
+ logger('photo save ' . $p['imgscale'] . ' returned ' . intval($r));
return $r;
}
diff --git a/include/photos.php b/include/photos.php
index 503a725cd..b1391f284 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -10,14 +10,13 @@ require_once('include/photo/photo_driver.php');
require_once('include/text.php');
/**
- * @brief
+ * @brief Upload a photo.
*
* @param array $channel
* @param array $observer
* @param array $args
* @return array
*/
-
function photo_upload($channel, $observer, $args) {
$ret = array('success' => false);
@@ -63,27 +62,52 @@ function photo_upload($channel, $observer, $args) {
$ac = $acl->get();
+ $width = $height = 0;
+
+ if($args['getimagesize']) {
+ $width = $args['getimagesize'][0];
+ $height = $args['getimagesize'][1];
+ }
+
+
$os_storage = 0;
+ $max_thumb = get_config('system','max_thumbnail',1600);
+
if($args['os_syspath'] && $args['getimagesize']) {
- if($args['getimagesize'][0] > 1600 || $args['getimagesize'][1] > 1600) {
+ if($args['getimagesize'][0] > $max_thumb || $args['getimagesize'][1] > $max_thumb) {
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path)) {
$tmp_name = $args['os_syspath'] . '-001';
- $newsize = photo_calculate_1600_scale($args['getimagesize']);
- exec($imagick_path . ' ' . $args['os_syspath'] . ' -resize ' . $newsize . '^ ' . $tmp_name);
+ $newsize = photo_calculate_scale(array_merge($args['getimagesize'],['max' => $max_thumb]));
+ $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $args['os_syspath']) . ' -thumbnail ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
+ // logger('imagick thumbnail command: ' . $cmd);
+ for($x = 0; $x < 4; $x ++) {
+ exec($cmd);
+ if(! file_exists($tmp_name)) {
+ logger('imagick scale failed. Retrying.');
+ continue;
+ }
+ }
+ if(! file_exists($tmp_name)) {
+ logger('imagick scale failed. Abort.');
+ return $ret;
+ }
+
$imagedata = @file_get_contents($tmp_name);
+ $filesize = @filesize($args['os_syspath']);
@unlink($tmp_name);
}
else {
$imagedata = @file_get_contents($args['os_syspath']);
+ $filesize = strlen($imagedata);
}
}
else {
$imagedata = @file_get_contents($args['os_syspath']);
+ $filesize = strlen($imagedata);
}
$filename = $args['filename'];
- $filesize = strlen($imagedata);
// this is going to be deleted if it exists
$src = '/tmp/deletemenow';
$type = $args['getimagesize']['mime'];
@@ -118,25 +142,33 @@ function photo_upload($channel, $observer, $args) {
if (! $type)
$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');
if (($maximagesize) && ($filesize > $maximagesize)) {
$ret['message'] = sprintf ( t('Image exceeds website size limit of %lu bytes'), $maximagesize);
@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;
}
if (! $filesize) {
$ret['message'] = t('Image file is empty.');
@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;
}
- logger('photo_upload: loading the contents of ' . $src , LOGGER_DEBUG);
+ logger('Loading the contents of ' . $src , LOGGER_DEBUG);
$imagedata = @file_get_contents($src);
}
@@ -149,7 +181,11 @@ function photo_upload($channel, $observer, $args) {
if (($r) && ($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) {
$ret['message'] = upgrade_message();
@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;
}
@@ -157,13 +193,23 @@ function photo_upload($channel, $observer, $args) {
if (! $ph->is_valid()) {
$ret['message'] = t('Unable to process image');
- logger('photo_upload: unable to process image');
+ logger('unable to process image');
@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;
}
- $exif = $ph->orient(($args['os_syspath']) ? $args['os_syspath'] : $src);
+ // obtain exif data from the source file if present
+
+ $exif = $ph->exif(($args['os_syspath']) ? $args['os_syspath'] : $src);
+
+ if($exif) {
+ $ph->orient($exif);
+ }
@unlink($src);
@@ -173,8 +219,10 @@ function photo_upload($channel, $observer, $args) {
if ($max_length > 0)
$ph->scaleImage($max_length);
- $width = $ph->getWidth();
- $height = $ph->getHeight();
+ if(! $width)
+ $width = $ph->getWidth();
+ if(! $height)
+ $height = $ph->getHeight();
$smallest = 0;
@@ -188,6 +236,7 @@ function photo_upload($channel, $observer, $args) {
$p = array('aid' => $account_id, 'uid' => $channel_id, 'xchan' => $visitor, 'resource_id' => $photo_hash,
'filename' => $filename, 'album' => $album, 'imgscale' => 0, 'photo_usage' => PHOTO_NORMAL,
+ 'width' => $width, 'height' => $height,
'allow_cid' => $ac['allow_cid'], 'allow_gid' => $ac['allow_gid'],
'deny_cid' => $ac['deny_cid'], 'deny_gid' => $ac['deny_gid'],
'os_storage' => $os_storage, 'os_syspath' => $args['os_syspath'],
@@ -209,14 +258,16 @@ function photo_upload($channel, $observer, $args) {
'rel' => 'alternate',
'type' => 'text/html',
'href' => z_root() . '/photo/' . $photo_hash . '-0.' . $ph->getExt(),
- 'width' => $ph->getWidth(),
- 'height' => $ph->getHeight()
+ 'width' => $width,
+ 'height' => $height
);
if(! $r0)
$errors = true;
unset($p['os_storage']);
unset($p['os_syspath']);
+ unset($p['width']);
+ unset($p['height']);
if(($width > 1024 || $height > 1024) && (! $errors))
$ph->scaleImage(1024);
@@ -269,8 +320,12 @@ function photo_upload($channel, $observer, $args) {
intval($channel_id)
);
$ret['message'] = t('Photo storage failed.');
- logger('photo_upload: photo store failed.');
- call_hooks('photo_upload_end',$ret);
+ logger('Photo store failed.');
+ /**
+ * @hooks photo_upload_end
+ * Called when a photo upload has been processed.
+ */
+ call_hooks('photo_upload_end', $ret);
return $ret;
}
@@ -296,8 +351,6 @@ function photo_upload($channel, $observer, $args) {
$width = $link[1]['width'];
$height = $link[1]['height'];
$tag = (($r1) ? '[zmg=' . $width . 'x' . $height . ']' : '[zmg]');
-
-
}
else {
$scale = 2;
@@ -355,7 +408,6 @@ function photo_upload($channel, $observer, $args) {
$item['target'] = json_encode($target);
$force = true;
-
}
$r = q("select id, edited from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']),
@@ -423,7 +475,6 @@ function photo_upload($channel, $observer, $args) {
$arr['item_private'] = 1;
-
$result = item_store($arr,false,$deliver);
$item_id = $result['item_id'];
@@ -437,15 +488,19 @@ function photo_upload($channel, $observer, $args) {
$ret['resource_id'] = $photo_hash;
$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;
}
-function photo_calculate_1600_scale($arr) {
+function photo_calculate_scale($arr) {
- $max = 1600;
+ $max = $arr['max'];
$width = $arr[0];
$height = $arr[1];
@@ -502,10 +557,8 @@ function photo_calculate_1600_scale($arr) {
}
return $dest_width . 'x' . $dest_height;
-
}
-
/**
* @brief Returns a list with all photo albums observer is allowed to see.
*
@@ -520,7 +573,6 @@ function photo_calculate_1600_scale($arr) {
* * \e boolean \b success
* * \e array \b albums
*/
-
function photos_albums_list($channel, $observer, $sort_key = 'display_path', $direction = 'asc') {
$channel_id = $channel['channel_id'];
@@ -613,14 +665,13 @@ function photos_album_widget($channelx,$observer,$sortkey = 'display_path',$dire
}
/**
- * @brief
+ * @brief Return an array of photos.
*
* @param array $channel
* @param array $observer
- * @param string $album default empty
+ * @param string $album (optional) default empty
* @return boolean|array
*/
-
function photos_list_photos($channel, $observer, $album = '') {
$channel_id = $channel['channel_id'];
@@ -657,21 +708,20 @@ function photos_list_photos($channel, $observer, $album = '') {
* @brief Check if given photo album exists in channel.
*
* @param int $channel_id id of the channel
+ * @param string $observer_hash
* @param string $album name of the album
* @return boolean
*/
-
-
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",
dbesc($album),
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)
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",
@@ -693,7 +743,6 @@ function photos_album_exists($channel_id, $observer_hash, $album) {
* @param string $newname The new name of the album
* @return bool|array
*/
-
function photos_album_rename($channel_id, $oldname, $newname) {
return q("UPDATE photo SET album = '%s' WHERE album = '%s' AND uid = %d",
dbesc($newname),
@@ -702,17 +751,14 @@ function photos_album_rename($channel_id, $oldname, $newname) {
);
}
-
-
/**
* @brief
*
* @param int $channel_id
* @param string $album
- * @param string $remote_xchan
+ * @param string $remote_xchan (optional) default empty
* @return string|boolean
*/
-
function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') {
if($remote_xchan) {
@@ -746,15 +792,13 @@ function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') {
* @param array $channel
* @param string $creator_hash
* @param array $photo
- * @param boolean $visible default false
+ * @param boolean $visible (optional) default false
* @return int item_id
*/
-
function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
// Create item container
-
$item_hidden = (($visible) ? 0 : 1 );
$mid = item_message_id();
@@ -794,36 +838,36 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
function getGps($exifCoord, $hemi) {
- $degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
- $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;
- $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;
+ $degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
+ $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 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) {
- $hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
- $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;
- $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;
+ $hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
+ $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 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) {
- $parts = explode('/', $coordPart);
+ $parts = explode('/', $coordPart);
- if (count($parts) <= 0)
- return 0;
+ if (count($parts) <= 0)
+ return 0;
- if (count($parts) == 1)
- return $parts[0];
+ if (count($parts) == 1)
+ return $parts[0];
- return floatval($parts[0]) / floatval($parts[1]);
+ return floatval($parts[0]) / floatval($parts[1]);
}
@@ -835,7 +879,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",
dbesc($profile_id),
intval($channel_id)
- );
+ );
if(! $r)
return;
@@ -844,26 +888,26 @@ function photo_profile_setperms($channel_id,$resource_id,$profile_id) {
$profile_guid = $r[0]['profile_guid'];
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",
dbesc($resource_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",
dbesc($resource_id),
intval($channel_id)
);
}
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",
dbesc('<vp.' . $profile_guid . '>'),
dbesc($resource_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",
dbesc('<vp.' . $profile_guid . '>'),
dbesc($resource_id),
@@ -872,71 +916,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) {
$allowcid = '';
-
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
- 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 FROM profile
+ WHERE profile.uid = %d AND is_default = 1 LIMIT 1",
+ intval($uid)
+ ); //If no profile is given, we update the default profile
+ }
+ if(! $r)
+ return;
- $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile
- WHERE profile.uid = %d AND is_default = 1 LIMIT 1",
- 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'] . ">";
- }
+ $profile = $r[0];
- q("UPDATE photo SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",
- dbesc($allowcid),
- dbesc($resource_id),
- intval($uid)
- );
+ 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'] . ">";
}
- 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)
- );
+ foreach ($r2 as $entry) {
+ $allowcid .= "<" . $entry['abook_xchan'] . ">";
}
- }
- return;
+ 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)
+ );
+ }
}
+}
diff --git a/include/plugin.php b/include/plugin.php
index db20152ea..379d8e799 100755
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -7,7 +7,7 @@
/**
- * @brief unloads an addon.
+ * @brief Unloads an 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
* @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) {
$r = q("select aname from addon where aname = '%s' and installed = 1 limit 1",
dbesc($name)
@@ -121,8 +128,9 @@ function plugin_is_installed($name) {
}
-// reload all updated plugins
-
+/**
+ * @brief Reload all updated plugins.
+ */
function reload_plugins() {
$plugins = get_config('system', 'addon');
if(strlen($plugins)) {
@@ -167,13 +175,18 @@ function reload_plugins() {
}
}
+
+/**
+ * @brief Get a list of non hidden addons.
+ *
+ * @return array
+ */
function visible_plugin_list() {
$r = q("select * from addon where hidden = 0 order by aname asc");
return(($r) ? ids_to_array($r,'aname') : array());
}
-
/**
* @brief registers a hook.
*
@@ -282,7 +295,7 @@ function insert_hook($hook, $fn, $version = 0, $priority = 0) {
* the provided data.
*
* @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) {
$a = 0;
@@ -414,8 +427,8 @@ function check_plugin_versions($info) {
|| stristr($info['serverroles'],'any')
|| stristr($info['serverroles'],$role))) {
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.
*
@@ -532,7 +543,7 @@ function get_theme_info($theme){
*
* 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
*/
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
* 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
* 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
* blocked due to mixed content issues.
+ *
+ * @return string
*/
-
function script_path() {
if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS'])
$scheme = 'https';
@@ -659,6 +671,7 @@ function script_path() {
else {
return z_root();
}
+
return $scheme . '://' . $hostname;
}
@@ -675,10 +688,13 @@ function head_remove_js($src, $priority = 0) {
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
-// added outside the head_add_js construct.
-
+/**
+ * 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 added outside the head_add_js construct.
+ *
+ * @return string
+ */
function head_get_js() {
$str = '';
@@ -694,6 +710,7 @@ function head_get_js() {
}
}
}
+
return $str;
}
@@ -703,6 +720,7 @@ function head_get_main_js() {
if(count($sources))
foreach($sources as $source)
$str .= format_js_if_exists($source,true);
+
return $str;
}
@@ -716,7 +734,7 @@ function format_js_if_exists($source) {
if(substr($source,0,2) === '//') {
$path_prefix = '';
}
- }
+ }
else {
// It's a file from the theme
$path = '/' . theme_include($source);
@@ -781,12 +799,16 @@ function get_markup_template($s, $root = '') {
return $template;
}
+/**
+ * @brief
+ *
+ * @param string $folder
+ * @return boolean|string
+ */
+function folder_exists($folder) {
+ // Get canonicalized absolute pathname
+ $path = realpath($folder);
-function folder_exists($folder)
-{
- // Get canonicalized absolute pathname
- $path = realpath($folder);
-
- // If it exist, check if it's a directory
- return (($path !== false) && is_dir($path)) ? $path : false;
+ // If it exist, check if it's a directory
+ return (($path !== false) && is_dir($path)) ? $path : false;
}
diff --git a/include/queue_fn.php b/include/queue_fn.php
index c9179b953..5fb0d5f1e 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -42,7 +42,7 @@ function update_queue_item($id, $add_priority = 0) {
$next = datetime_convert('UTC','UTC','now + 1 hour');
}
else {
- $next = datetime_convert('UTC','UTC','now + 15 minutes');
+ $next = datetime_convert('UTC','UTC','now + ' . intval($add_priority) . ' minutes');
}
q("UPDATE outq SET outq_updated = '%s',
@@ -158,6 +158,8 @@ function queue_deliver($outq, $immediate = false) {
}
}
+
+
$arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
call_hooks('queue_deliver',$arr);
if($arr['handled'])
@@ -198,14 +200,15 @@ function queue_deliver($outq, $immediate = false) {
}
}
if($piled_up) {
- do_delivery($piled_up);
+ // call do_delivery() with the force flag
+ do_delivery($piled_up, true);
}
}
}
else {
logger('deliver: queue post returned ' . $result['return_code']
. ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
- update_queue_item($outq['outq_posturl']);
+ update_queue_item($outq['outq_hash'],10);
}
return;
}
diff --git a/include/security.php b/include/security.php
index 450cc4f69..8b7e7d076 100644
--- a/include/security.php
+++ b/include/security.php
@@ -264,6 +264,7 @@ function change_channel($change_channel) {
App::set_channel($r[0]);
$_SESSION['theme'] = $r[0]['channel_theme'];
$_SESSION['mobile_theme'] = get_pconfig(local_channel(),'system', 'mobile_theme');
+ $_SESSION['cloud_tiles'] = get_pconfig(local_channel(),'system', 'cloud_tiles');
date_default_timezone_set($r[0]['channel_timezone']);
$ret = $r[0];
}
diff --git a/include/socgraph.php b/include/socgraph.php
index a5b5d1378..26446d9c7 100644
--- a/include/socgraph.php
+++ b/include/socgraph.php
@@ -178,9 +178,11 @@ function poco_load($xchan = '', $url = null) {
);
if(! $r) {
- q("insert into xlink ( xlink_xchan, xlink_link, xlink_updated, xlink_static ) values ( '%s', '%s', '%s', 0 ) ",
+ q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', 0 ) ",
dbesc($xchan),
dbesc($hash),
+ intval(0),
+ dbesc(''),
dbesc(datetime_convert())
);
}
@@ -385,7 +387,7 @@ function poco($a,$extended = false) {
$sql_extra = " and abook_self = 0 ";
if($cid)
- $sql_extra = sprintf(" and abook_id = %d and abook_hidden = 0 ",intval($cid));
+ $sql_extra = sprintf(" and abook_id = %d and abook_hidden = 0 and abook_pending = 0 ",intval($cid));
if($system_mode) {
$r = q("SELECT count(*) as total from abook where abook_self = 1
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 23acaa24d..a646df28c 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -55,18 +55,20 @@ function term_item_parent_query($uid,$table,$s,$type = TERM_UNKNOWN, $type2 = ''
$s = str_replace('*','%',$s);
if($type2) {
- $r = q("select parent from item left join term on term.oid = item.id where term.ttype in (%d, %d) and term.term like '%s' and term.uid = %d and term.otype = 1",
+ $r = q("select parent from item left join term on term.oid = item.id where term.ttype in (%d, %d) and term.term like '%s' and term.uid = %d and term.otype = 1 and item.verb != '%s'",
intval($type),
intval($type2),
dbesc($s),
- intval($uid)
+ intval($uid),
+ dbesc(ACTIVITY_UPDATE)
);
}
else {
- $r = q("select parent from item left join term on term.oid = item.id where term.ttype = %d and term.term like '%s' and term.uid = %d and term.otype = 1",
+ $r = q("select parent from item left join term on term.oid = item.id where term.ttype = %d and term.term like '%s' and term.uid = %d and term.otype = 1 and item.verb != '%s'",
intval($type),
dbesc($s),
- intval($uid)
+ intval($uid),
+ dbesc(ACTIVITY_UPDATE)
);
}
@@ -253,23 +255,86 @@ function card_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0
}
+function article_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $restrict = 0, $type = TERM_CATEGORY) {
+ require_once('include/security.php');
+ if(! perm_is_allowed($uid,get_observer_hash(),'view_pages'))
+ return array();
-function dir_tagadelic($count = 0) {
-
+ $item_normal = item_normal();
+ $sql_options = item_permissions_sql($uid);
$count = intval($count);
+ if($flags) {
+ if($flags === 'wall')
+ $sql_options .= " and item_wall = 1 ";
+ }
+
+ if($authors) {
+ if(! is_array($authors))
+ $authors = array($authors);
+
+ stringify_array_elms($authors,true);
+ $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") ";
+ }
+
+ if($owner) {
+ $sql_options .= " and owner_xchan = '" . dbesc($owner) . "' ";
+ }
+
+
// Fetch tags
- $r = q("select xtag_term as term, count(xtag_term) as total from xtag where xtag_flags = 0
- group by xtag_term order by total desc %s",
+ $r = q("select term, count(term) as total from term left join item on term.oid = item.id
+ where term.uid = %d and term.ttype = %d
+ and otype = %d and item_type = %d and item_private = 0
+ $sql_options $item_normal
+ group by term order by total desc %s",
+ intval($uid),
+ intval($type),
+ intval(TERM_OBJ_POST),
+ intval($restrict),
((intval($count)) ? "limit $count" : '')
);
if(! $r)
return array();
+ return Zotlabs\Text\Tagadelic::calc($r);
+
+}
+
+
+
+
+
+function dir_tagadelic($count = 0) {
+
+ $count = intval($count);
+
+ $dirmode = get_config('system','directory_mode');
+
+ if($dirmode == DIRECTORY_MODE_STANDALONE) {
+ // Fetch tags
+ $r = q("select xtag_term as term, count(xtag_term) as total from xtag
+ left join hubloc on xtag_hash = hubloc_hash
+ where xtag_flags = 0 and hubloc_url = '%s'
+ group by xtag_term order by total desc %s",
+ dbesc(z_root()),
+ ((intval($count)) ? "limit $count" : '')
+ );
+ }
+ else {
+ // Fetch tags
+ $r = q("select xtag_term as term, count(xtag_term) as total from xtag where xtag_flags = 0
+ group by xtag_term order by total desc %s",
+ ((intval($count)) ? "limit $count" : '')
+ );
+ }
+ if(! $r)
+ return array();
+
return Zotlabs\Text\Tagadelic::calc($r);
@@ -395,6 +460,27 @@ function card_catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,$re
}
+function article_catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,$restrict = 0,$type = TERM_CATEGORY) {
+ $o = '';
+
+ $r = article_tagadelic($uid,$count,$authors,$owner,$flags,$restrict,$type);
+
+ if($r) {
+ $c = q("select channel_address from channel where channel_id = %d limit 1",
+ intval($uid)
+ );
+
+ $o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">';
+ foreach($r as $rr) {
+ $o .= '<a href="articles/' . $c[0]['channel_address']. '?f=&cat=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n";
+ }
+ $o .= '</div></div>';
+ }
+
+ return $o;
+}
+
+
function dir_tagblock($link,$r) {
$o = '';
diff --git a/include/text.php b/include/text.php
index c74e515d2..107efe0cb 100644
--- a/include/text.php
+++ b/include/text.php
@@ -1679,9 +1679,9 @@ function prepare_text($text, $content_type = 'text/bbcode', $cache = false) {
require_once('include/bbcode.php');
if(stristr($text,'[nosmile]'))
- $s = bbcode($text,false,true,$cache);
+ $s = bbcode($text, [ 'cache' => $cache ]);
else
- $s = smilies(bbcode($text,false,true,$cache));
+ $s = smilies(bbcode($text, [ 'cache' => $cache ]));
$s = zidify_links($s);
@@ -1754,9 +1754,14 @@ function get_plink($item,$conversation_mode = true) {
else
$key = 'llink';
+ $zidify = true;
+
+ if(array_key_exists('author',$item) && $item['author']['xchan_network'] !== 'zot')
+ $zidify = false;
+
if(x($item,$key)) {
return array(
- 'href' => zid($item[$key]),
+ 'href' => (($zidify) ? zid($item[$key]) : $item[$key]),
'title' => t('Link to Source'),
);
}
@@ -2704,12 +2709,15 @@ function linkify_tags($a, &$body, $uid, $diaspora = false) {
function getIconFromType($type) {
$iconMap = array(
//Folder
- t('Collection') => 'fa-folder',
- 'multipart/mixed' => 'fa-folder', //dirs in attach use this mime type
+ t('Collection') => 'fa-folder-o',
+ 'multipart/mixed' => 'fa-folder-o', //dirs in attach use this mime type
//Common file
'application/octet-stream' => 'fa-file-o',
//Text
'text/plain' => 'fa-file-text-o',
+ 'text/markdown' => 'fa-file-text-o',
+ 'text/bbcode' => 'fa-file-text-o',
+ 'text/html' => 'fa-file-text-o',
'application/msword' => 'fa-file-word-o',
'application/pdf' => 'fa-file-pdf-o',
'application/vnd.oasis.opendocument.text' => 'fa-file-word-o',
@@ -2739,11 +2747,33 @@ function getIconFromType($type) {
'video/x-matroska' => 'fa-file-video-o'
);
- $iconFromType = 'fa-file-o';
+ $catMap = [
+ 'application' => 'fa-file-code-o',
+ 'multipart' => 'fa-folder',
+ 'audio' => 'fa-file-audio-o',
+ 'video' => 'fa-file-video-o',
+ 'text' => 'fa-file-text-o',
+ 'image' => 'fa=file-picture-o',
+ 'message' => 'fa-file-text-o'
+ ];
+
+
+ $iconFromType = '';
if (array_key_exists($type, $iconMap)) {
$iconFromType = $iconMap[$type];
}
+ else {
+ $parts = explode('/',$type);
+ if($parts[0] && $catMap[$parts[0]]) {
+ $iconFromType = $catMap[$parts[0]];
+ }
+ }
+
+ if(! $iconFromType) {
+ $iconFromType = 'fa-file-o';
+ }
+
return $iconFromType;
}
diff --git a/include/zid.php b/include/zid.php
index ce9f70385..6ebc9a6ab 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -21,6 +21,7 @@ function is_matrix_url($url) {
}
$remembered[$m['host']] = false;
}
+
return false;
}
@@ -32,14 +33,8 @@ function is_matrix_url($url) {
* @param boolean $address
* $address to use instead of session environment
* @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='))
return $s;
@@ -74,7 +69,18 @@ function zid($s,$address = '') {
if($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);
return $arr['result'];
@@ -89,36 +95,51 @@ function strip_zids($s) {
return preg_replace('/[\?&]zid=(.*?)(&|$)/ism','$2',$s);
}
+function strip_owt($s) {
+ return preg_replace('/[\?&]owt=(.*?)(&|$)/ism','$2',$s);
+}
+
function strip_zats($s) {
return preg_replace('/[\?&]zat=(.*?)(&|$)/ism','$2',$s);
}
+
+function clean_query_string($s = '') {
+ $x = strip_zids(($s) ? $s : \App::$query_string);
+ $x = strip_owt($x);
+ $x = strip_zats($x);
+
+ return strip_query_param($x,'f');
+}
+
+
/**
* zidify_callback() and zidify_links() work together to turn any HTML a tags with class="zrl" into zid links
* These will typically be generated by a bbcode '[zrl]' tag. This is done inside prepare_text() rather than bbcode()
* because the latter is used for general purpose conversions and the former is used only when preparing text for
* 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.
*
* @param array $match
* @return string
*/
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]) . '"';
- $x = str_replace($match[0],$replace,$match[0]);
+
+ $x = str_replace($match[0], $replace, $match[0]);
return $x;
}
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]) . '"';
- $x = str_replace($match[0],$replace,$match[0]);
+ $x = str_replace($match[0], $replace, $match[0]);
return $x;
}
@@ -132,12 +153,11 @@ function zidify_links($s) {
}
-
-
function zidify_text_callback($match) {
$is_zid = is_matrix_url($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;
}
@@ -146,7 +166,7 @@ function zidify_text_img_callback($match) {
$is_zid = is_matrix_url($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;
}
@@ -157,8 +177,6 @@ function zidify_text($s) {
$s = preg_replace_callback('/\<img(.*?)src\=\"(.*?)\"/ism','zidify_text_img_callback',$s);
return $s;
-
-
}
@@ -198,7 +216,6 @@ function red_zrl_callback($matches) {
* @param array $matches
* @return string
*/
-
function red_escape_zrl_callback($matches) {
// Uncertain why the url/zrl forms weren't picked up by the non-greedy regex.
@@ -234,11 +251,17 @@ function red_zrlify_img_callback($matches) {
return $matches[0];
}
+
+/**
+ * @brief OpenWebAuth authentication.
+ *
+ * @param string $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) {
return;
@@ -262,7 +285,7 @@ function owt_init($token) {
}
if(! $r) {
logger('owt: unable to finger ' . $ob_hash);
- return;
+ return;
}
$hubloc = $r[0];
@@ -296,14 +319,25 @@ function owt_init($token) {
$_SESSION['DNT'] = 1;
}
- $arr = array('xchan' => $hubloc, 'url' => \App::$query_string, 'session' => $_SESSION);
- call_hooks('magic_auth_success',$arr);
+ $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);
require_once('include/security.php');
\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']));
- logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
-
+ logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
} \ No newline at end of file
diff --git a/include/zot.php b/include/zot.php
index 9bb25dd6f..18960db46 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -31,7 +31,6 @@ require_once('include/perm_upgrade.php');
* @param string $channel_nick a unique nickname of controlling entity
* @returns string
*/
-
function zot_new_uid($channel_nick) {
$rawstr = z_root() . '/' . $channel_nick . '.' . mt_rand();
return(base64url_encode(hash('whirlpool', $rawstr, true), true));
@@ -49,7 +48,6 @@ function zot_new_uid($channel_nick) {
* @param string $guid
* @param string $guid_sig
*/
-
function make_xchan_hash($guid, $guid_sig) {
return base64url_encode(hash('whirlpool', $guid . $guid_sig, true));
}
@@ -104,6 +102,8 @@ function zot_get_hublocs($hash) {
* @param string $remote_key
* optional public site key of target hub used to encrypt entire packet
* NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others
+ * @param string $methods
+ * optional comma separated list of encryption methods @ref zot_best_algorithm()
* @param string $secret
* random string, required for packets which require verification/callback
* e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification
@@ -159,29 +159,38 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot
}
/**
- * @brief choose best encryption function from those available on both sites
- *
+ * @brief Choose best encryption function from those available on both sites.
+ *
* @param string $methods
* comma separated list of encryption methods
* @return string first match from our site method preferences crypto_methods() array
* of a method which is common to both sites; or 'aes256cbc' if no matches are found.
*/
-
function zot_best_algorithm($methods) {
- $x = [ 'methods' => $methods, 'result' => '' ];
- call_hooks('zot_best_algorithm',$x);
+ $x = [
+ 'methods' => $methods,
+ 'result' => ''
+ ];
+ /**
+ * @hooks zot_best_algorithm
+ * Called when negotiating crypto algorithms with remote sites.
+ * * \e string \b methods - comma separated list of encryption methods
+ * * \e string \b result - the algorithm to return
+ */
+ call_hooks('zot_best_algorithm', $x);
+
if($x['result'])
return $x['result'];
if($methods) {
- $x = explode(',',$methods);
+ $x = explode(',', $methods);
if($x) {
$y = crypto_methods();
if($y) {
foreach($y as $yv) {
$yv = trim($yv);
- if(in_array($yv,$x)) {
+ if(in_array($yv, $x)) {
return($yv);
}
}
@@ -193,7 +202,6 @@ function zot_best_algorithm($methods) {
}
-
/**
* @brief
*
@@ -210,7 +218,7 @@ function zot_zot($url, $data) {
/**
* @brief Refreshes after permission changed or friending, etc.
*
- * The top half of this function is similar to \Zotlabs\Zot\Finger::run() and could potentially be
+ * The top half of this function is similar to \\Zotlabs\\Zot\\Finger::run() and could potentially be
* consolidated.
*
* zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
@@ -230,21 +238,22 @@ function zot_zot($url, $data) {
*
* @param array $them => xchan structure of sender
* @param array $channel => local channel structure of target recipient, required for "friending" operations
- * @param array $force default false
+ * @param array $force (optional) default false
*
- * @returns boolean true if successful, else false
+ * @return boolean
+ * * \b true if successful
+ * * otherwise \b false
*/
-
function zot_refresh($them, $channel = null, $force = false) {
if (array_key_exists('xchan_network', $them) && ($them['xchan_network'] !== 'zot')) {
- logger('zot_refresh: not got zot. ' . $them['xchan_name']);
+ logger('not got zot. ' . $them['xchan_name']);
return true;
}
- logger('zot_refresh: them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG);
+ logger('them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG);
if ($channel)
- logger('zot_refresh: channel: ' . print_r($channel,true), LOGGER_DATA, LOG_DEBUG);
+ logger('channel: ' . print_r($channel,true), LOGGER_DATA, LOG_DEBUG);
$url = null;
@@ -285,6 +294,16 @@ function zot_refresh($them, $channel = null, $force = false) {
return false;
}
+ $s = q("select site_dead from site where site_url = '%s' limit 1",
+ dbesc($url)
+ );
+
+ if($s && intval($s[0]['site_dead']) && (! $force)) {
+ logger('zot_refresh: site ' . $url . ' is marked dead and force flag is not set. Cancelling operation.');
+ return false;
+ }
+
+
$token = random_string();
$postvars = [];
@@ -305,7 +324,6 @@ function zot_refresh($them, $channel = null, $force = false) {
&& array_key_exists('xchan_guid_sig',$them) && $them['xchan_guid_sig']) {
$postvars['guid'] = $them['xchan_guid'];
$postvars['guid_sig'] = $them['xchan_guid_sig'];
-
}
$rhs = '/.well-known/zot-info';
@@ -320,7 +338,7 @@ function zot_refresh($them, $channel = null, $force = false) {
$j = json_decode($result['body'],true);
if (! (($j) && ($j['success']))) {
- logger('zot_refresh: result not decodable');
+ logger('Result not decodable');
return false;
}
@@ -376,6 +394,7 @@ function zot_refresh($them, $channel = null, $force = false) {
$next_birthday = NULL_DATE;
}
+ $profile_assign = get_pconfig($channel['channel_id'],'system','profile_assign','');
// Keep original perms to check if we need to notify them
$previous_perms = get_all_perms($channel['channel_id'],$x['hash']);
@@ -437,6 +456,7 @@ function zot_refresh($them, $channel = null, $force = false) {
'abook_channel' => intval($channel['channel_id']),
'abook_closeness' => intval($closeness),
'abook_xchan' => $x['hash'],
+ 'abook_profile' => $profile_assign,
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_dob' => $next_birthday,
@@ -474,7 +494,7 @@ function zot_refresh($them, $channel = null, $force = false) {
}
- /** If there is a default group for this channel, add this connection to it */
+ // If there is a default group for this channel, add this connection to it
$default_group = $channel['channel_default_group'];
if($default_group) {
@@ -518,10 +538,10 @@ function zot_refresh($them, $channel = null, $force = false) {
* * \e string \b url_sig => URL signed with conversant's private key
* @param boolean $multiple (optional) default false
*
- * @returns array|null null if site is blacklisted or not found, otherwise an
- * array with an hubloc record
+ * @return array|null
+ * * null if site is blacklisted or not found
+ * * otherwise an array with an hubloc record
*/
-
function zot_gethub($arr, $multiple = false) {
if($arr['guid'] && $arr['guid_sig'] && $arr['url'] && $arr['url_sig']) {
@@ -544,11 +564,11 @@ function zot_gethub($arr, $multiple = false) {
dbesc($arr['url_sig'])
);
if($r) {
- logger('zot_gethub: found', LOGGER_DEBUG);
+ logger('Found', LOGGER_DEBUG);
return (($multiple) ? $r : $r[0]);
}
}
- logger('zot_gethub: not found: ' . print_r($arr,true), LOGGER_DEBUG);
+ logger('Not found: ' . print_r($arr,true), LOGGER_DEBUG);
return false;
}
@@ -567,11 +587,10 @@ function zot_gethub($arr, $multiple = false) {
* * \e string \b url => URL of the origination hub of this communication
* * \e string \b url_sig => URL signed with conversant's private key
*
- * @returns array an associative array with
+ * @return array An associative array with
* * \b success boolean true or false
* * \b message (optional) error string only if success is false
*/
-
function zot_register_hub($arr) {
$result = [ 'success' => false ];
@@ -609,7 +628,7 @@ function zot_register_hub($arr) {
$result['success'] = true;
}
else {
- logger('zot_register_hub: failure to verify returned packet using ' . $method);
+ logger('Failure to verify returned packet using ' . $method);
}
}
}
@@ -632,13 +651,17 @@ function zot_register_hub($arr) {
* If set [typically by update_directory_entry()] indicates a specific update table row and more particularly
* contains a particular address (ud_addr) which needs to be updated in that table.
*
- * @return associative array
+ * @return array An associative array with:
* * \e boolean \b success boolean true or false
* * \e string \b message (optional) error string only if success is false
*/
+function import_xchan($arr, $ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
-function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
-
+ /**
+ * @hooks import_xchan
+ * Called when processing the result of zot_finger() to store the result
+ * * \e array
+ */
call_hooks('import_xchan', $arr);
$ret = array('success' => false);
@@ -648,13 +671,13 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$what = '';
if(! (is_array($arr) && array_key_exists('success',$arr) && $arr['success'])) {
- logger('import_xchan: invalid data packet: ' . print_r($arr,true));
+ logger('Invalid data packet: ' . print_r($arr,true));
$ret['message'] = t('Invalid data packet');
return $ret;
}
if(! ($arr['guid'] && $arr['guid_sig'])) {
- logger('import_xchan: no identity information provided. ' . print_r($arr,true));
+ logger('No identity information provided. ' . print_r($arr,true));
return $ret;
}
@@ -668,7 +691,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
foreach($sig_methods as $method) {
if(! rsa_verify($arr['guid'],base64url_decode($arr['guid_sig']),$arr['key'],$method)) {
- logger('import_xchan: Unable to verify channel signature for ' . $arr['address'] . ' using ' . $method);
+ logger('Unable to verify channel signature for ' . $arr['address'] . ' using ' . $method);
continue;
}
else {
@@ -751,8 +774,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
dbesc($xchan_hash)
);
- logger('import_xchan: update: existing: ' . print_r($r[0],true), LOGGER_DATA, LOG_DEBUG);
- logger('import_xchan: update: new: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Update: existing: ' . print_r($r[0],true), LOGGER_DATA, LOG_DEBUG);
+ logger('Update: new: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
$what .= 'xchan ';
$changed = true;
}
@@ -767,7 +790,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$x = xchan_store_lowlevel(
[
- 'xchan_hash' => $xchan_hash,
+ 'xchan_hash' => $xchan_hash,
'xchan_guid' => $arr['guid'],
'xchan_guid_sig' => $arr['guid_sig'],
'xchan_pubkey' => $arr['key'],
@@ -918,7 +941,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
}
}
else {
- logger('import_xchan: profile not available - hiding');
+ logger('Profile not available - hiding');
// they may have made it private
$r = q("delete from xprof where xprof_hash = '%s'",
dbesc($xchan_hash)
@@ -940,7 +963,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
if(($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) {
$guid = random_string() . '@' . App::get_hostname();
update_modtime($xchan_hash,$guid,$address,$ud_flags);
- logger('import_xchan: changed: ' . $what,LOGGER_DEBUG);
+ logger('Changed: ' . $what,LOGGER_DEBUG);
}
elseif(! $ud_flags) {
// nothing changed but we still need to update the updates record
@@ -956,7 +979,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
$ret['hash'] = $xchan_hash;
}
- logger('import_xchan: result: ' . print_r($ret,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Result: ' . print_r($ret,true), LOGGER_DATA, LOG_DEBUG);
return $ret;
}
@@ -970,19 +993,18 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) {
* @param array $arr - output of z_post_url()
* @param array $outq - The queue structure attached to this request
*/
-
function zot_process_response($hub, $arr, $outq) {
if(! $arr['success']) {
- logger('zot_process_response: failed: ' . $hub);
+ logger('Failed: ' . $hub);
return;
}
$x = json_decode($arr['body'], true);
if(! $x) {
- logger('zot_process_response: No json from ' . $hub);
- logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA, LOG_DEBUG);
+ logger('No json from ' . $hub);
+ logger('Headers: ' . print_r($arr['header'], true), LOGGER_DATA, LOG_DEBUG);
}
if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) {
@@ -990,7 +1012,7 @@ function zot_process_response($hub, $arr, $outq) {
if(array_key_exists('iv',$x['delivery_report'])) {
$j = crypto_unencapsulate($x['delivery_report'],get_config('system','prvkey'));
if($j) {
- $x['delivery_report'] = json_decode($j,true);
+ $x['delivery_report'] = json_decode($j,true);
}
if(! (is_array($x['delivery_report']) && count($x['delivery_report']))) {
logger('encrypted delivery report could not be decrypted');
@@ -1050,7 +1072,6 @@ function zot_process_response($hub, $arr, $outq) {
* decrypted and json decoded notify packet from remote site
* @return array from zot_import()
*/
-
function zot_fetch($arr) {
logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
@@ -1063,7 +1084,7 @@ function zot_fetch($arr) {
$ret_hubs = zot_gethub($arr['sender'],true);
if(! $ret_hubs) {
- logger('zot_fetch: no hub: ' . print_r($arr['sender'],true));
+ logger('No hub: ' . print_r($arr['sender'],true));
return;
}
@@ -1095,7 +1116,6 @@ function zot_fetch($arr) {
}
return;
-
}
/**
@@ -1104,7 +1124,7 @@ function zot_fetch($arr) {
* Process an incoming array of messages which were obtained via pickup, and
* import, update, delete as directed.
*
- * The message types handled here are 'activity' (e.g. posts), 'mail' ,
+ * The message types handled here are 'activity' (e.g. posts), 'mail',
* 'profile', 'location' and 'channel_sync'.
*
* @param array $arr
@@ -1116,18 +1136,17 @@ function zot_fetch($arr) {
* currently processing.
*
* @returns array
- * suitable for logging remotely, enumerating the processing results of each message/recipient combination
- * * [0] => \e string $channel_hash
- * * [1] => \e string $delivery_status
- * * [2] => \e string $address
+ * Suitable for logging remotely, enumerating the processing results of each message/recipient combination
+ * * [0] => \e string $channel_hash
+ * * [1] => \e string $delivery_status
+ * * [2] => \e string $address
*/
-
function zot_import($arr, $sender_url) {
$data = json_decode($arr['body'], true);
if(! $data) {
- logger('zot_import: empty body');
+ logger('Empty body');
return array();
}
@@ -1163,7 +1182,7 @@ function zot_import($arr, $sender_url) {
$i['notify'] = json_decode(crypto_unencapsulate($i['notify'],get_config('system','prvkey')),true);
}
- logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA, LOG_DEBUG);
+ logger('Notify: ' . print_r($i['notify'],true), LOGGER_DATA, LOG_DEBUG);
if(! is_array($i['notify'])) {
logger('decode error');
@@ -1173,7 +1192,7 @@ function zot_import($arr, $sender_url) {
$hub = zot_gethub($i['notify']['sender']);
if((! $hub) || ($hub['hubloc_url'] != $sender_url)) {
- logger('zot_import: potential forgery: wrong site for sender: ' . $sender_url . ' != ' . print_r($i['notify'],true));
+ logger('Potential forgery: wrong site for sender: ' . $sender_url . ' != ' . print_r($i['notify'],true));
continue;
}
@@ -1281,7 +1300,7 @@ function zot_import($arr, $sender_url) {
}
if(! $deliveries) {
- logger('zot_import: no deliveries on this site');
+ logger('No deliveries on this site');
continue;
}
@@ -1361,7 +1380,6 @@ function zot_import($arr, $sender_url) {
* @param array $msg
* @return NULL|array
*/
-
function public_recips($msg) {
require_once('include/channel.php');
@@ -1491,9 +1509,8 @@ function public_recips($msg) {
}
/**
- * @brief
+ * @brief This is the second part of public_recips().
*
- * This is the second part of public_recips().
* We'll find all the channels willing to accept public posts from us, then
* match them against the sender privacy scope and see who in that list that
* the sender is allowing.
@@ -1573,7 +1590,6 @@ function allowed_public_recips($msg) {
* @param boolean $request (optional) default false
* @return array
*/
-
function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $request = false) {
$result = array();
@@ -1584,12 +1600,11 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
if(! $public) {
if($sender['hash'] != $arr['owner_xchan'] && $sender['hash'] != $arr['author_xchan']) {
- logger("process_delivery: sender {$sender['hash']} is not owner {$arr['owner_xchan']} or author {$arr['author_xchan']} - mid {$arr['mid']}");
+ logger("Sender {$sender['hash']} is not owner {$arr['owner_xchan']} or author {$arr['author_xchan']} - mid {$arr['mid']}");
return;
}
}
-
foreach($deliveries as $d) {
$local_public = $public;
@@ -1818,7 +1833,6 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
$DR->update('update ignored');
$result[] = $DR->get();
-
// We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit),
// and at the same time not relay any other relayable posts more than once, because to do so is very wasteful.
if(! intval($r[0]['item_origin']))
@@ -1832,8 +1846,14 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
// if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered.
- if(check_item_source($arr['uid'], $arr))
+ if(check_item_source($arr['uid'], $arr)) {
+ /**
+ * @hooks post_local
+ * Called when an item has been posted on this machine via mod/item.php (also via API).
+ * * \e array with an item
+ */
call_hooks('post_local', $arr);
+ }
$item_id = 0;
@@ -1845,8 +1865,21 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
$item_result = item_store($arr);
if($item_result['success']) {
$item_id = $item_result['item_id'];
- $parr = array('item_id' => $item_id,'item' => $arr,'sender' => $sender,'channel' => $channel);
- call_hooks('activity_received',$parr);
+ $parr = [
+ 'item_id' => $item_id,
+ 'item' => $arr,
+ 'sender' => $sender,
+ 'channel' => $channel
+ ];
+ /**
+ * @hooks activity_received
+ * Called when an activity (post, comment, like, etc.) has been received from a zot source.
+ * * \e int \b item_id
+ * * \e array \b item
+ * * \e array \b sender
+ * * \e array \b channel
+ */
+ call_hooks('activity_received', $parr);
// don't add a source route if it's a relay or later recipients will get a route mismatch
if(! $relay)
add_source_route($item_id,$sender['hash']);
@@ -1865,7 +1898,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
}
if($relay && $item_id) {
- logger('process_delivery: invoking relay');
+ logger('Invoking relay');
Zotlabs\Daemon\Master::Summon(array('Notifier','relay',intval($item_id)));
$DR->addto_update('relayed');
$result[] = $DR->get();
@@ -1875,13 +1908,13 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
if(! $deliveries)
$result[] = array('', 'no recipients', '', $arr['mid']);
- logger('process_delivery: local results: ' . print_r($result, true), LOGGER_DEBUG);
+ logger('Local results: ' . print_r($result, true), LOGGER_DEBUG);
return $result;
}
/**
- * @brief
+ * @brief Remove community tag.
*
* @param array $sender an associative array with
* * \e string \b hash a xchan_hash
@@ -1891,7 +1924,6 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
* * \e int \b mid
* @param int $uid
*/
-
function remove_community_tag($sender, $arr, $uid) {
if(! (activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM)))
@@ -1900,7 +1932,7 @@ function remove_community_tag($sender, $arr, $uid) {
logger('remove_community_tag: invoked');
if(! get_pconfig($uid,'system','blocktags')) {
- logger('remove_community tag: permission denied.');
+ logger('Permission denied.');
return;
}
@@ -1909,12 +1941,12 @@ function remove_community_tag($sender, $arr, $uid) {
intval($uid)
);
if(! $r) {
- logger('remove_community_tag: no item');
+ logger('No item');
return;
}
if(($sender['hash'] != $r[0]['owner_xchan']) && ($sender['hash'] != $r[0]['author_xchan'])) {
- logger('remove_community_tag: sender not authorised.');
+ logger('Sender not authorised.');
return;
}
@@ -1926,7 +1958,7 @@ function remove_community_tag($sender, $arr, $uid) {
$i['object'] = json_decode($i['object'],true);
if(! ($i['target'] && $i['object'])) {
- logger('remove_community_tag: no target/object');
+ logger('No target/object');
return;
}
@@ -1937,7 +1969,7 @@ function remove_community_tag($sender, $arr, $uid) {
intval($uid)
);
if(! $r) {
- logger('remove_community_tag: no parent message');
+ logger('No parent message');
return;
}
@@ -1953,16 +1985,16 @@ function remove_community_tag($sender, $arr, $uid) {
}
/**
- * @brief Just calls item_store_update() and logs result.
+ * @brief Updates an imported item.
*
* @see item_store_update()
*
- * @param array $sender (unused)
+ * @param array $sender
* @param array $item
* @param array $orig
* @param int $uid
+ * @param boolean $tag_delivery
*/
-
function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) {
// If this is a comment being updated, remove any privacy information
@@ -1976,11 +2008,11 @@ function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) {
unset($item['item_private']);
}
- // we need the tag_delivery check for downstream flowing posts as the stored post
- // may have a different owner than the one being transmitted.
+ // we need the tag_delivery check for downstream flowing posts as the stored post
+ // may have a different owner than the one being transmitted.
if(($sender['hash'] != $orig['owner_xchan'] && $sender['hash'] != $orig['author_xchan']) && (! $tag_delivery)) {
- notice('sender is not owner or author');
+ logger('sender is not owner or author');
return;
}
@@ -2014,10 +2046,9 @@ function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) {
* @param boolean $relay
* @return boolean|int post_id
*/
-
function delete_imported_item($sender, $item, $uid, $relay) {
- logger('delete_imported_item invoked', LOGGER_DEBUG);
+ logger('invoked', LOGGER_DEBUG);
$ownership_valid = false;
$item_found = false;
@@ -2176,7 +2207,6 @@ function process_mail_delivery($sender, $arr, $deliveries) {
* * \e string \b hash a xchan_hash
* @param array $arr
*/
-
function process_rating_delivery($sender, $arr) {
logger('process_rating_delivery: ' . print_r($arr,true));
@@ -2236,7 +2266,6 @@ function process_rating_delivery($sender, $arr) {
* @param array $arr
* @param array $deliveries (unused)
*/
-
function process_profile_delivery($sender, $arr, $deliveries) {
logger('process_profile_delivery', LOGGER_DEBUG);
@@ -2248,7 +2277,16 @@ function process_profile_delivery($sender, $arr, $deliveries) {
import_directory_profile($sender['hash'], $arr, $r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0);
}
-function process_location_delivery($sender,$arr,$deliveries) {
+
+/**
+ * @brief
+ *
+ * @param array $sender an associative array
+ * * \e string \b hash a xchan_hash
+ * @param array $arr
+ * @param array $deliveries (unused) deliveries is irrelevant
+ */
+function process_location_delivery($sender, $arr, $deliveries) {
// deliveries is irrelevant
logger('process_location_delivery', LOGGER_DEBUG);
@@ -2261,7 +2299,7 @@ function process_location_delivery($sender,$arr,$deliveries) {
if(array_key_exists('locations',$arr) && $arr['locations']) {
$x = sync_locations($sender,$arr,true);
- logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DEBUG);
+ logger('results: ' . print_r($x,true), LOGGER_DEBUG);
if($x['changed']) {
$guid = random_string() . '@' . App::get_hostname();
update_modtime($sender['hash'],$sender['guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED);
@@ -2270,7 +2308,7 @@ function process_location_delivery($sender,$arr,$deliveries) {
}
/**
- * @brief checks for a moved UNO channel and sets the channel_moved flag
+ * @brief Checks for a moved UNO channel and sets the channel_moved flag.
*
* Currently the effect of this flag is to turn the channel into 'read-only' mode.
* New content will not be processed (there was still an issue with blocking the
@@ -2284,11 +2322,11 @@ function process_location_delivery($sender,$arr,$deliveries) {
* if a new location is reported and there is only one location record.
* The rest of the hubloc syncronisation will be handled within
* sync_locations
+ *
+ * @param string $sender_hash A channel hash
+ * @param array $locations
*/
-
-
-
-function check_location_move($sender_hash,$locations) {
+function check_location_move($sender_hash, $locations) {
if(! $locations)
return;
@@ -2314,11 +2352,18 @@ function check_location_move($sender_hash,$locations) {
// federation plugins may wish to notify connections
// of the move on singleton networks
- $arr = array('channel' => $r[0],'locations' => $locations);
- call_hooks('location_move',$arr);
-
+ $arr = [
+ 'channel' => $r[0],
+ 'locations' => $locations
+ ];
+ /**
+ * @hooks location_move
+ * Called when a new location has been provided to a UNO channel (indicating a move rather than a clone).
+ * * \e array \b channel
+ * * \e array \b locations
+ */
+ call_hooks('location_move', $arr);
}
-
}
@@ -2330,7 +2375,6 @@ function check_location_move($sender_hash,$locations) {
* @param boolean $absolute (optional) default false
* @return array
*/
-
function sync_locations($sender, $arr, $absolute = false) {
$ret = array();
@@ -2340,7 +2384,6 @@ function sync_locations($sender, $arr, $absolute = false) {
if($absolute)
check_location_move($sender['hash'],$arr['locations']);
-
$xisting = q("select hubloc_id, hubloc_url, hubloc_sitekey from hubloc where hubloc_hash = '%s'",
dbesc($sender['hash'])
);
@@ -2362,7 +2405,7 @@ function sync_locations($sender, $arr, $absolute = false) {
foreach($arr['locations'] as $location) {
if(! rsa_verify($location['url'],base64url_decode($location['url_sig']),$sender['key'])) {
- logger('sync_locations: Unable to verify site signature for ' . $location['url']);
+ logger('Unable to verify site signature for ' . $location['url']);
$ret['message'] .= sprintf( t('Unable to verify site signature for %s'), $location['url']) . EOL;
continue;
}
@@ -2375,7 +2418,7 @@ function sync_locations($sender, $arr, $absolute = false) {
}
if(! $location['sitekey']) {
- logger('sync_locations: empty hubloc sitekey. ' . print_r($location,true));
+ logger('Empty hubloc sitekey. ' . print_r($location,true));
continue;
}
@@ -2398,7 +2441,7 @@ function sync_locations($sender, $arr, $absolute = false) {
dbesc($location['sitekey'])
);
if($r) {
- logger('sync_locations: hub exists: ' . $location['url'], LOGGER_DEBUG);
+ logger('Hub exists: ' . $location['url'], LOGGER_DEBUG);
// update connection timestamp if this is the site we're talking to
// This only happens when called from import_xchan
@@ -2500,7 +2543,7 @@ function sync_locations($sender, $arr, $absolute = false) {
dbesc($sender['hash'])
);
}
- logger('sync_locations: new hub: ' . $location['url']);
+ logger('New hub: ' . $location['url']);
$r = hubloc_store_lowlevel(
[
@@ -2509,7 +2552,7 @@ function sync_locations($sender, $arr, $absolute = false) {
'hubloc_hash' => $sender['hash'],
'hubloc_addr' => $location['address'],
'hubloc_network' => 'zot',
- 'hubloc_primary' => $location['primary'],
+ 'hubloc_primary' => intval($location['primary']),
'hubloc_url' => $location['url'],
'hubloc_url_sig' => $location['url_sig'],
'hubloc_host' => $location['host'],
@@ -2538,7 +2581,7 @@ function sync_locations($sender, $arr, $absolute = false) {
if($absolute && $xisting) {
foreach($xisting as $x) {
if(! array_key_exists('updated',$x)) {
- logger('sync_locations: deleting unreferenced hub location ' . $x['hubloc_addr']);
+ logger('Deleting unreferenced hub location ' . $x['hubloc_addr']);
$r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d",
dbesc(datetime_convert()),
intval($x['hubloc_id'])
@@ -2603,11 +2646,10 @@ function zot_encode_locations($channel) {
* @param string $hash
* @param array $profile
* @param string $addr
- * @param number $ud_flags
- * @param number $suppress_update default 0
+ * @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED
+ * @param number $suppress_update (optional) default 0
* @return boolean $updated if something changed
*/
-
function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) {
logger('import_directory_profile', LOGGER_DEBUG);
@@ -2707,7 +2749,7 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA
}
} else {
$update = true;
- logger('import_directory_profile: new profile ');
+ logger('New profile');
q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
dbesc($arr['xprof_hash']),
dbesc($arr['xprof_desc']),
@@ -2727,7 +2769,18 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA
);
}
- $d = array('xprof' => $arr, 'profile' => $profile, 'update' => $update);
+ $d = [
+ 'xprof' => $arr,
+ 'profile' => $profile,
+ 'update' => $update
+ ];
+ /**
+ * @hooks import_directory_profile
+ * Called when processing delivery of a profile structure from an external source (usually for directory storage).
+ * * \e array \b xprof
+ * * \e array \b profile
+ * * \e boolean \b update
+ */
call_hooks('import_directory_profile', $d);
if (($d['update']) && (! $suppress_update))
@@ -2739,10 +2792,9 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA
/**
* @brief
*
- * @param string $hash
+ * @param string $hash An xtag_hash
* @param array $keywords
*/
-
function import_directory_keywords($hash, $keywords) {
$existing = array();
@@ -2787,7 +2839,6 @@ function import_directory_keywords($hash, $keywords) {
* @param string $addr
* @param int $flags (optional) default 0
*/
-
function update_modtime($hash, $guid, $addr, $flags = 0) {
$dirmode = intval(get_config('system', 'directory_mode'));
@@ -2820,13 +2871,12 @@ function update_modtime($hash, $guid, $addr, $flags = 0) {
* @param string $pubkey
* @return boolean true if updated or inserted
*/
-
function import_site($arr, $pubkey) {
if( (! is_array($arr)) || (! $arr['url']) || (! $arr['url_sig']))
return false;
if(! rsa_verify($arr['url'], base64url_decode($arr['url_sig']), $pubkey)) {
- logger('import_site: bad url_sig');
+ logger('Bad url_sig');
return false;
}
@@ -2905,7 +2955,7 @@ function import_site($arr, $pubkey) {
if(array_key_exists('zot',$arr)) {
set_sconfig($arr['url'],'system','zot_version',$arr['zot']);
- }
+ }
if($exists) {
if(($siterecord['site_flags'] != $site_flags)
@@ -2924,7 +2974,6 @@ function import_site($arr, $pubkey) {
// logger('import_site: input: ' . print_r($arr,true));
// logger('import_site: stored: ' . print_r($siterecord,true));
-
$r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s', site_crypto = '%s'
where site_url = '%s'",
dbesc($site_location),
@@ -2942,7 +2991,7 @@ function import_site($arr, $pubkey) {
dbesc($url)
);
if(! $r) {
- logger('import_site: update failed. ' . print_r($arr,true));
+ logger('Update failed. ' . print_r($arr,true));
}
}
else {
@@ -2956,7 +3005,7 @@ function import_site($arr, $pubkey) {
else {
$update = true;
- $r = site_store_lowlevel(
+ $r = site_store_lowlevel(
[
'site_location' => $site_location,
'site_url' => $url,
@@ -2975,7 +3024,7 @@ function import_site($arr, $pubkey) {
);
if(! $r) {
- logger('import_site: record create failed. ' . print_r($arr,true));
+ logger('Record create failed. ' . print_r($arr,true));
}
}
@@ -2984,20 +3033,19 @@ function import_site($arr, $pubkey) {
/**
+ * @brief Builds and sends a sync packet.
+ *
* Send a zot packet to all hubs where this channel is duplicated, refreshing
* such things as personal settings, channel permissions, address book updates, etc.
*
- * @param int $uid
+ * @param int $uid (optional) default 0
* @param array $packet (optional) default null
* @param boolean $groups_changed (optional) default false
*/
-
function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
-
logger('build_sync_packet');
-
$keychange = (($packet && array_key_exists('keychange',$packet)) ? true : false);
if($keychange) {
logger('keychange sync');
@@ -3112,6 +3160,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
);
if($r)
$info['collections'] = $r;
+
$r = q("select groups.hash as collection, group_member.xchan as member from groups left join group_member on groups.id = group_member.gid where group_member.uid = %d",
intval($uid)
);
@@ -3122,7 +3171,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
$interval = ((get_config('system','delivery_interval') !== false)
? intval(get_config('system','delivery_interval')) : 2 );
- logger('build_sync_packet: packet: ' . print_r($info,true), LOGGER_DATA, LOG_DEBUG);
+ logger('Packet: ' . print_r($info,true), LOGGER_DATA, LOG_DEBUG);
$total = count($synchubs);
@@ -3138,6 +3187,15 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
'msg' => json_encode($info)
));
+
+ $x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
+ if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300))) {
+ logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
+ update_queue_item($hash);
+ continue;
+ }
+
+
Zotlabs\Daemon\Master::Summon(array('Deliver', $hash));
$total = $total - 1;
@@ -3154,7 +3212,6 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
* @param array $deliveries
* @return array
*/
-
function process_channel_sync_delivery($sender, $arr, $deliveries) {
require_once('include/import.php');
@@ -3182,7 +3239,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
$max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds');
if($channel['channel_hash'] != $sender['hash']) {
- logger('process_channel_sync_delivery: possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']);
+ logger('Possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']);
$result[] = array($d['hash'],'channel mismatch',$channel['channel_name'],'');
continue;
}
@@ -3198,7 +3255,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
$hash = make_xchan_hash($channel['channel_guid'],$sig);
- $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s',
+ $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s',
channel_hash = '%s' where channel_id = %d",
dbesc($arr['channel']['channel_prvkey']),
dbesc($arr['channel']['channel_pubkey']),
@@ -3341,7 +3398,6 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
$arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x8000;
if($arr['channel']['channel_pageflags'] & 0x1000)
$arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x1000;
-
}
$disallowed = [
@@ -3407,7 +3463,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
$clean = array();
if($abook['abook_xchan'] && $abook['entry_deleted']) {
- logger('process_channel_sync_delivery: removing abook entry for ' . $abook['abook_xchan']);
+ logger('Removing abook entry for ' . $abook['abook_xchan']);
$r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1",
dbesc($abook['abook_xchan']),
@@ -3432,7 +3488,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(! $h) {
$xhash = import_author_xchan(encode_item_xchan($abook));
if(! $xhash) {
- logger('process_channel_sync_delivery: import of ' . $abook['xchan_addr'] . ' failed.');
+ logger('Import of ' . $abook['xchan_addr'] . ' failed.');
continue;
}
}
@@ -3449,7 +3505,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('abook_instance',$clean) && $clean['abook_instance'] && strpos($clean['abook_instance'],z_root()) === false) {
$clean['abook_not_here'] = 1;
- }
+ }
$r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
@@ -3461,11 +3517,11 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(! $r) {
if($max_friends !== false && $total_friends > $max_friends) {
- logger('process_channel_sync_delivery: total_channels service class limit exceeded');
+ logger('total_channels service class limit exceeded');
continue;
}
if($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) {
- logger('process_channel_sync_delivery: total_feeds service class limit exceeded');
+ logger('total_feeds service class limit exceeded');
continue;
}
abook_store_lowlevel(
@@ -3484,6 +3540,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
foreach($clean as $k => $v) {
if($k == 'abook_dob')
$v = dbescdate($v);
+
$r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v)
. "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id']));
}
@@ -3496,7 +3553,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
translate_abook_perms_inbound($channel,$abook);
if($abconfig) {
- // @fixme does not handle sync of del_abconfig
+ /// @fixme does not handle sync of del_abconfig
foreach($abconfig as $abc) {
set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
}
@@ -3688,20 +3745,35 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
* @TODO
* We also need to import local photos if a custom photo is selected
*/
+
+ if((strpos($profile['thumb'],'/photo/profile/l/') !== false) || intval($profile['is_default'])) {
+ $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
+ $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
+ }
+ else {
+ $profile['photo'] = z_root() . '/photo/' . basename($profile['photo']);
+ $profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']);
+ }
}
if(count($clean)) {
foreach($clean as $k => $v) {
$r = dbq("UPDATE profile set " . TQUOT . dbesc($k) . TQUOT . " = '" . dbesc($v)
- . "' where profile_guid = '" . dbesc($profile['profile_guid'])
+ . "' where profile_guid = '" . dbesc($profile['profile_guid'])
. "' and uid = " . intval($channel['channel_id']));
}
}
}
}
- $addon = array('channel' => $channel,'data' => $arr);
- call_hooks('process_channel_sync_delivery',$addon);
+ $addon = ['channel' => $channel, 'data' => $arr];
+ /**
+ * @hooks process_channel_sync_delivery
+ * Called when accepting delivery of a 'sync packet' containing structure and table updates from a channel clone.
+ * * \e array \b channel
+ * * \e array \b data
+ */
+ call_hooks('process_channel_sync_delivery', $addon);
// we should probably do this for all items, but usually we only send one.
@@ -3713,7 +3785,6 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
$DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
$result[] = $DR->get();
-
}
return $result;
@@ -3728,7 +3799,6 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
* * \e string \b xchan_url
* @return string
*/
-
function get_rpost_path($observer) {
if(! $observer)
return '';
@@ -3744,7 +3814,6 @@ function get_rpost_path($observer) {
* @param array $x
* @return boolean|string return false or a hash
*/
-
function import_author_zot($x) {
// Check that we have both a hubloc and xchan record - as occasionally storage calls will fail and
@@ -3778,7 +3847,7 @@ function import_author_zot($x) {
$site_dead = true;
}
- // We have valid and somewhat fresh information.
+ // We have valid and somewhat fresh information.
if($r1 && $r2 && $r1[0]['hubloc_updated'] > datetime_convert('UTC','UTC','now - 1 week')) {
logger('in cache', LOGGER_DEBUG);
@@ -3787,16 +3856,16 @@ function import_author_zot($x) {
logger('not in cache or cache stale - probing: ' . print_r($x,true), LOGGER_DEBUG,LOG_INFO);
- // The primary hub may be dead. Try to find another one associated with this identity that is
- // still alive. If we find one, use that url for the discovery/refresh probe. Otherwise, the dead site
- // is all we have and there is no point probing it. Just return the hash indicating we have a
- // cached entry and the identity is valid. It's just unreachable until they bring back their
- // server from the grave or create another clone elsewhere.
+ // The primary hub may be dead. Try to find another one associated with this identity that is
+ // still alive. If we find one, use that url for the discovery/refresh probe. Otherwise, the dead site
+ // is all we have and there is no point probing it. Just return the hash indicating we have a
+ // cached entry and the identity is valid. It's just unreachable until they bring back their
+ // server from the grave or create another clone elsewhere.
if($site_dead) {
logger('dead site - ignoring', LOGGER_DEBUG,LOG_INFO);
- $r = q("select hubloc_url from hubloc left join site on hubloc_url = site_url
+ $r = q("select hubloc_url from hubloc left join site on hubloc_url = site_url
where hubloc_hash = '%s' and site_dead = 0",
dbesc($hash)
);
@@ -3807,8 +3876,7 @@ function import_author_zot($x) {
else {
return $hash;
}
- }
-
+ }
$them = array('hubloc_url' => $desturl, 'xchan_guid' => $x['guid'], 'xchan_guid_sig' => $x['guid_sig']);
@@ -3835,7 +3903,6 @@ function import_author_zot($x) {
* @param array $data
* @return array
*/
-
function zot_reply_message_request($data) {
$ret = array('success' => false);
@@ -3872,7 +3939,7 @@ function zot_reply_message_request($data) {
if ($messages) {
$env_recips = null;
- $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0",
+ $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0 and site.site_dead = 0 ",
dbesc($sender_hash)
);
if (! $r) {
@@ -3905,6 +3972,14 @@ function zot_reply_message_request($data) {
'msg' => $data_packet
));
+
+ $x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
+ if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300))) {
+ logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
+ update_queue_item($hash);
+ continue;
+ }
+
/*
* invoke delivery to send out the notify packet
*/
@@ -3923,9 +3998,9 @@ function zot_rekey_request($sender,$data) {
// newsig is newkey signed with oldkey
// The original xchan will remain. In Zot/Receiver we will have imported the new xchan and hubloc to verify
- // the packet authenticity. What we will do now is verify that the keychange operation was signed by the
- // oldkey, and if so change all the abook, abconfig, group, and permission elements which reference the
- // old xchan_hash.
+ // the packet authenticity. What we will do now is verify that the keychange operation was signed by the
+ // oldkey, and if so change all the abook, abconfig, group, and permission elements which reference the
+ // old xchan_hash.
if((! $data['old_key']) && (! $data['new_key']) && (! $data['new_sig']))
json_return_and_die($ret);
@@ -4048,10 +4123,18 @@ function zotinfo($arr) {
$id = $e['channel_id'];
- $x = [ 'channel_id' => $id, 'protocols' => ['zot'] ];
- call_hooks('channel_protocols',$x);
- $protocols = $x['protocols'];
+ $x = [
+ 'channel_id' => $id,
+ 'protocols' => ['zot']
+ ];
+ /**
+ * @hooks channel_protocols
+ * * \e int \b channel_id
+ * * \e array \b protocols
+ */
+ call_hooks('channel_protocols', $x);
+ $protocols = $x['protocols'];
$sys_channel = (intval($e['channel_system']) ? true : false);
$special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false);
@@ -4104,6 +4187,7 @@ function zotinfo($arr) {
if($age = age($p[0]['dob'],$e['channel_timezone'],''))
$profile['age'] = $age;
+
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
@@ -4163,7 +4247,6 @@ function zotinfo($arr) {
$ret['deleted_locally'] = true;
-
// premium or other channel desiring some contact with potential followers before connecting.
// This is a template - %s will be replaced with the follow_url we discover for the return channel.
@@ -4207,10 +4290,14 @@ function zotinfo($arr) {
check_zotinfo($e,$x,$ret);
+ /**
+ * @hooks zot_finger
+ * Called when a zot-info packet has been requested (this is our webfinger discovery mechanism).
+ * * \e array The final return array
+ */
+ call_hooks('zot_finger', $ret);
- call_hooks('zot_finger',$ret);
return($ret);
-
}
@@ -4301,11 +4388,17 @@ function zot_site_info($channel_key = '') {
}
return $ret['site'];
-
}
-function check_zotinfo($channel,$locations,&$ret) {
-
+/**
+ * @brief
+ *
+ * @param array $channel
+ * @param array $locations
+ * @param[out] array $ret
+ * \e array \b locations result of zot_encode_locations()
+ */
+function check_zotinfo($channel, $locations, &$ret) {
// logger('locations: ' . print_r($locations,true),LOGGER_DATA, LOG_DEBUG);
@@ -4313,7 +4406,7 @@ function check_zotinfo($channel,$locations,&$ret) {
// 1. Because magic-auth is reliant on it, ensure that the system channel has a valid hubloc
// Force this to be the case if anything is found to be wrong with it.
- // @FIXME ensure that the system channel exists in the first place and has an xchan
+ /// @FIXME ensure that the system channel exists in the first place and has an xchan
if($channel['channel_system']) {
// the sys channel must have a location (hubloc)
@@ -4368,12 +4461,23 @@ function check_zotinfo($channel,$locations,&$ret) {
}
}
+/**
+ * @brief
+ *
+ * @param array $dr
+ * @return boolean
+ */
function delivery_report_is_storable($dr) {
- if(get_config('system','disable_dreport'))
+ if(get_config('system', 'disable_dreport'))
return false;
- call_hooks('dreport_is_storable',$dr);
+ /**
+ * @hooks dreport_is_storable
+ * Called before storing a dreport record to determine whether to store it.
+ * * \e array
+ */
+ call_hooks('dreport_is_storable', $dr);
// let plugins accept or reject - if neither, continue on
if(array_key_exists('accept',$dr) && intval($dr['accept']))
@@ -4428,12 +4532,18 @@ function delivery_report_is_storable($dr) {
return true;
return false;
-
}
-
-function update_hub_connected($hub,$sitekey = '') {
+/**
+ * @brief
+ *
+ * @param array $hub
+ * @param string $sitekey (optional, default empty)
+ *
+ * @return string hubloc_url
+ */
+function update_hub_connected($hub, $sitekey = '') {
if($sitekey) {
@@ -4462,7 +4572,7 @@ function update_hub_connected($hub,$sitekey = '') {
// Update our DB to show when we last communicated successfully with this hub
// This will allow us to prune dead hubs from using up resources
- $t = datetime_convert('UTC','UTC','now - 15 minutes');
+ $t = datetime_convert('UTC', 'UTC', 'now - 15 minutes');
$r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d and hubloc_sitekey = '%s' and hubloc_connected < '%s' ",
dbesc(datetime_convert()),
@@ -4492,14 +4602,18 @@ function update_hub_connected($hub,$sitekey = '') {
return $hub['hubloc_url'];
}
-
+/**
+ * @brief Useful to get a health check on a remote site.
+ *
+ * This will let us know if any important communication details
+ * that we may have stored are no longer valid, regardless of xchan details.
+ *
+ * @return json_return_and_die()
+ */
function zot_reply_ping() {
$ret = array('success'=> false);
- // Useful to get a health check on a remote site.
- // This will let us know if any important communication details
- // that we may have stored are no longer valid, regardless of xchan details.
logger('POST: got ping send pong now back: ' . z_root() , LOGGER_DEBUG );
$ret['success'] = true;
@@ -4507,6 +4621,7 @@ function zot_reply_ping() {
$ret['site']['url'] = z_root();
$ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),get_config('system','prvkey')));
$ret['site']['sitekey'] = get_config('system','pubkey');
+
json_return_and_die($ret);
}
@@ -4524,6 +4639,7 @@ function zot_reply_pickup($data) {
if((! $data['secret']) || (! $data['secret_sig'])) {
$ret['message'] = 'no verification signature';
logger('mod_zot: pickup: ' . $ret['message'], LOGGER_DEBUG);
+
json_return_and_die($ret);
}
@@ -4534,6 +4650,7 @@ function zot_reply_pickup($data) {
if(! $r) {
$ret['message'] = 'site not found';
logger('mod_zot: pickup: ' . $ret['message']);
+
json_return_and_die($ret);
}
@@ -4563,12 +4680,14 @@ function zot_reply_pickup($data) {
if($forgery) {
$ret['message'] = 'possible site forgery';
logger('mod_zot: pickup: ' . $ret['message']);
+
json_return_and_die($ret);
}
if($secret_fail) {
$ret['message'] = 'secret validation failed';
logger('mod_zot: pickup: ' . $ret['message']);
+
json_return_and_die($ret);
}
@@ -4585,6 +4704,7 @@ function zot_reply_pickup($data) {
if(! $r) {
$ret['message'] = 'nothing to pick up';
logger('mod_zot: pickup: ' . $ret['message']);
+
json_return_and_die($ret);
}
@@ -4630,8 +4750,8 @@ function zot_reply_pickup($data) {
$algorithm = zot_best_algorithm(($x) ? $x[0]['site_crypto'] : '');
$encrypted = crypto_encapsulate(json_encode($ret),$sitekey,$algorithm);
- json_return_and_die($encrypted);
+ json_return_and_die($encrypted);
/* pickup: end */
}
@@ -4659,6 +4779,7 @@ function zot_reply_auth_check($data,$encrypted_packet) {
if (! $encrypted_packet) {
logger('mod_zot: auth_check packet was not encrypted.');
$ret['message'] .= 'no packet encryption' . EOL;
+
json_return_and_die($ret);
}
@@ -4667,11 +4788,12 @@ function zot_reply_auth_check($data,$encrypted_packet) {
// garbage collect any old unused notifications
- // This was and should be 10 minutes but my hosting provider has time lag between the DB and
- // the web server. We should probably convert this to webserver time rather than DB time so
- // that the different clocks won't affect it and allow us to keep the time short.
-
- Zotlabs\Zot\Verify::purge('auth','30 MINUTE');
+ /**
+ * @TODO This was and should be 10 minutes but my hosting provider has time lag between the DB and
+ * the web server. We should probably convert this to webserver time rather than DB time so
+ * that the different clocks won't affect it and allow us to keep the time short.
+ */
+ Zotlabs\Zot\Verify::purge('auth', '30 MINUTE');
$y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
dbesc($sender_hash)
@@ -4685,6 +4807,7 @@ function zot_reply_auth_check($data,$encrypted_packet) {
if ((! $y) || (! rsa_verify($data['secret'], base64url_decode($data['secret_sig']),$y[0]['xchan_pubkey']))) {
logger('mod_zot: auth_check: sender not found or secret_sig invalid.');
$ret['message'] .= 'sender not found or sig invalid ' . print_r($y,true) . EOL;
+
json_return_and_die($ret);
}
@@ -4702,6 +4825,7 @@ function zot_reply_auth_check($data,$encrypted_packet) {
if (! $c) {
logger('mod_zot: auth_check: recipient channel not found.');
$ret['message'] .= 'recipient not found.' . EOL;
+
json_return_and_die($ret);
}
@@ -4710,11 +4834,11 @@ function zot_reply_auth_check($data,$encrypted_packet) {
// This additionally checks for forged sites since we already stored the expected result in meta
// and we've already verified that this is them via zot_gethub() and that their key signed our token
-
$z = Zotlabs\Zot\Verify::match('auth',$c[0]['channel_id'],$data['secret'],$data['sender']['url']);
if (! $z) {
logger('mod_zot: auth_check: verification key not found.');
$ret['message'] .= 'verification key not found' . EOL;
+
json_return_and_die($ret);
}
@@ -4742,11 +4866,19 @@ function zot_reply_auth_check($data,$encrypted_packet) {
json_return_and_die($ret);
}
+
json_return_and_die($ret);
}
-
-function zot_reply_purge($sender,$recipients) {
+/**
+ * @brief
+ *
+ * @param array $sender
+ * @param array $recipients
+ *
+ * return json_return_and_die()
+ */
+function zot_reply_purge($sender, $recipients) {
$ret = array('success' => false);
@@ -4784,17 +4916,23 @@ function zot_reply_purge($sender,$recipients) {
json_return_and_die($ret);
}
-
-function zot_reply_refresh($sender,$recipients) {
+/**
+ * @brief Remote channel info (such as permissions or photo or something)
+ * has been updated. Grab a fresh copy and sync it.
+ *
+ * The difference between refresh and force_refresh is that force_refresh
+ * unconditionally creates a directory update record, even if no changes were
+ * detected upon processing.
+ *
+ * @param array $sender
+ * @param array $recipients
+ *
+ * @return json_return_and_die()
+ */
+function zot_reply_refresh($sender, $recipients) {
$ret = array('success' => false);
- // remote channel info (such as permissions or photo or something)
- // has been updated. Grab a fresh copy and sync it.
- // The difference between refresh and force_refresh is that
- // force_refresh unconditionally creates a directory update record,
- // even if no changes were detected upon processing.
-
if($recipients) {
// This would be a permissions update, typically for one connection
@@ -4815,7 +4953,7 @@ function zot_reply_refresh($sender,$recipients) {
}
}
else {
- // system wide refresh
+ // system wide refresh
$x = zot_refresh(array(
'xchan_guid' => $sender['guid'],
@@ -4826,7 +4964,6 @@ function zot_reply_refresh($sender,$recipients) {
$ret['success'] = true;
json_return_and_die($ret);
-
}
@@ -4849,5 +4986,4 @@ function zot_reply_notify($data) {
$ret['success'] = true;
json_return_and_die($ret);
-
}