aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMario Vavti <mario@mariovavti.com>2016-10-12 12:13:44 +0200
committerMario Vavti <mario@mariovavti.com>2016-10-12 12:13:44 +0200
commitcf547be1d6900d12719a9372cbc1a5d433d31863 (patch)
tree03a525cf40905adafc21b0c4146e467bad288437 /include
parent29617737ca2c03c800ebbe4701dc21cf9f25ce22 (diff)
parent16da1a4e810889448eecbd13d68183a820bcebe2 (diff)
downloadvolse-hubzilla-cf547be1d6900d12719a9372cbc1a5d433d31863.tar.gz
volse-hubzilla-cf547be1d6900d12719a9372cbc1a5d433d31863.tar.bz2
volse-hubzilla-cf547be1d6900d12719a9372cbc1a5d433d31863.zip
Merge branch '1.14RC'
Diffstat (limited to 'include')
-rw-r--r--include/account.php93
-rw-r--r--include/acl_selectors.php126
-rw-r--r--include/api.php336
-rw-r--r--include/attach.php269
-rw-r--r--include/bb2diaspora.php16
-rw-r--r--include/bbcode.php32
-rw-r--r--include/channel.php35
-rw-r--r--include/connections.php2
-rw-r--r--include/contact_widgets.php2
-rw-r--r--include/conversation.php46
-rw-r--r--include/datetime.php22
-rwxr-xr-xinclude/dba/dba_driver.php27
-rw-r--r--include/dir_fns.php6
-rw-r--r--include/event.php14
-rw-r--r--include/features.php439
-rw-r--r--include/feedutils.php4
-rw-r--r--include/help.php114
-rw-r--r--include/html2bbcode.php2
-rw-r--r--include/import.php237
-rwxr-xr-xinclude/items.php230
-rw-r--r--include/message.php24
-rw-r--r--include/nav.php5
-rw-r--r--include/network.php74
-rwxr-xr-xinclude/oembed.php80
-rw-r--r--include/permissions.php6
-rw-r--r--include/photo/photo_driver.php14
-rw-r--r--include/photos.php2
-rwxr-xr-xinclude/plugin.php12
-rw-r--r--include/security.php2
-rw-r--r--include/text.php137
-rw-r--r--include/widgets.php114
-rw-r--r--include/zot.php51
32 files changed, 1975 insertions, 598 deletions
diff --git a/include/account.php b/include/account.php
index 5c44f13ca..b78c3e56d 100644
--- a/include/account.php
+++ b/include/account.php
@@ -14,6 +14,13 @@ require_once('include/crypto.php');
require_once('include/channel.php');
+function get_account_by_id($account_id) {
+ $r = q("select * from account where account_id = %d",
+ intval($account_id)
+ );
+ return (($r) ? $r[0] : false);
+}
+
function check_account_email($email) {
$result = array('error' => false, 'message' => '');
@@ -112,6 +119,7 @@ function create_account($arr) {
$flags = ((x($arr,'account_flags')) ? intval($arr['account_flags']) : ACCOUNT_OK);
$roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 );
$expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE);
+ $techlevel = ((array_key_exists('techlevel',$arr)) ? intval($arr['techlevel']) : intval(get_config('system','techlevel')));
$default_service_class = get_config('system','default_service_class');
@@ -171,16 +179,17 @@ function create_account($arr) {
$r = q("INSERT INTO account
( account_parent, account_salt, account_password, account_email, account_language,
- account_created, account_flags, account_roles, account_expires, account_service_class )
- VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s' )",
+ account_created, account_flags, account_roles, account_level, account_expires, account_service_class )
+ VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s' )",
intval($parent),
dbesc($salt),
dbesc($password_encoded),
dbesc($email),
dbesc(get_best_language()),
dbesc(datetime_convert()),
- dbesc($flags),
- dbesc($roles),
+ intval($flags),
+ intval($roles),
+ intval($techlevel),
dbesc($expires),
dbesc($default_service_class)
);
@@ -237,20 +246,23 @@ function verify_email_address($arr) {
dbesc($arr['account']['account_language'])
);
+//@fixme - get correct language template
+
$email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'), array(
'$sitename' => get_config('system','sitename'),
- '$siteurl' => z_root(),
+ '$siteurl' => z_root(),
'$email' => $arr['email'],
'$uid' => $arr['account']['account_id'],
'$hash' => $hash,
'$details' => $details
));
- $res = mail($arr['email'], email_header_encode(sprintf( t('Registration confirmation for %s'), get_config('system','sitename'))),
- $email_msg,
- 'From: ' . 'Administrator' . '@' . App::get_hostname() . "\n"
- . 'Content-type: text/plain; charset=UTF-8' . "\n"
- . 'Content-transfer-encoding: 8bit'
+ $res = z_mail(
+ [
+ 'toEmail' => $arr['email'],
+ 'messageSubject' => sprintf( t('Registration confirmation for %s'), get_config('system','sitename')),
+ 'textVersion' => $email_msg,
+ ]
);
if($res)
@@ -312,11 +324,12 @@ function send_reg_approval_email($arr) {
'$details' => $details
));
- $res = mail($admin['email'], sprintf( t('Registration request at %s'), get_config('system','sitename')),
- $email_msg,
- 'From: ' . t('Administrator') . '@' . App::get_hostname() . "\n"
- . 'Content-type: text/plain; charset=UTF-8' . "\n"
- . 'Content-transfer-encoding: 8bit'
+ $res = z_mail(
+ [
+ 'toEmail' => $admin['email'],
+ 'messageSubject' => sprintf( t('Registration request at %s'), get_config('system','sitename')),
+ 'textVersion' => $email_msg,
+ ]
);
if($res)
@@ -339,12 +352,14 @@ function send_register_success_email($email,$password) {
'$password' => t('your registration password'),
));
- $res = mail($email, sprintf( t('Registration details for %s'), get_config('system','sitename')),
- $email_msg,
- 'From: ' . t('Administrator') . '@' . App::get_hostname() . "\n"
- . 'Content-type: text/plain; charset=UTF-8' . "\n"
- . 'Content-transfer-encoding: 8bit'
+ $res = z_mail(
+ [
+ 'toEmail' => $email,
+ 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')),
+ 'textVersion' => $email_msg,
+ ]
);
+
return($res ? true : false);
}
@@ -390,7 +405,7 @@ function account_allow($hash) {
push_lang($register[0]['lang']);
$email_tpl = get_intltext_template("register_open_eml.tpl");
- $email_tpl = replace_macros($email_tpl, array(
+ $email_msg = replace_macros($email_tpl, array(
'$sitename' => get_config('system','sitename'),
'$siteurl' => z_root(),
'$username' => $account[0]['account_email'],
@@ -399,11 +414,13 @@ function account_allow($hash) {
'$uid' => $account[0]['account_id']
));
- $res = mail($account[0]['account_email'], sprintf( t('Registration details for %s'), get_config('system','sitename')),
- $email_tpl,
- 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
- . 'Content-type: text/plain; charset=UTF-8' . "\n"
- . 'Content-transfer-encoding: 8bit' );
+ $res = z_mail(
+ [
+ 'toEmail' => $account[0]['account_email'],
+ 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')),
+ 'textVersion' => $email_msg,
+ ]
+ );
pop_lang();
@@ -539,8 +556,8 @@ function account_approve($hash) {
*/
function downgrade_accounts() {
- $r = q("select * from account where not ( account_flags & %d )>0
- and account_expires != '%s'
+ $r = q("select * from account where not ( account_flags & %d ) > 0
+ and account_expires > '%s'
and account_expires < %s ",
intval(ACCOUNT_EXPIRED),
dbesc(NULL_DATE),
@@ -751,3 +768,23 @@ function upgrade_bool_message($bbcode = false) {
$x = upgrade_link($bbcode);
return t('This action is not available under your subscription plan.') . (($x) ? ' ' . $x : '') ;
}
+
+
+function get_account_techlevel($account_id = 0) {
+
+ $role = \Zotlabs\Lib\System::get_server_role();
+ if($role == 'basic')
+ return 0;
+ if($role == 'standard')
+ return 5;
+
+ if(! $account_id) {
+ $x = \App::get_account();
+ }
+ else {
+ $x = get_account_by_id($account_id);
+ }
+
+ return (($x) ? intval($x['account_level']) : 0);
+
+} \ No newline at end of file
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 148c67a6c..362776b44 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -13,7 +13,7 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\" >\r\n";
- $r = q("SELECT * FROM `groups` WHERE `deleted` = 0 AND `uid` = %d ORDER BY `gname` ASC",
+ $r = q("SELECT * FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
@@ -44,112 +44,6 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
return $o;
}
-/* MicMee 20130114 function contact_selector no longer in use, sql table contact does no longer exist
-function contact_selector($selname, $selclass, $preselected = false, $options) {
-
-
- $mutual = false;
- $networks = null;
- $single = false;
- $exclude = false;
- $size = 4;
-
- if(is_array($options)) {
- if(x($options,'size'))
- $size = $options['size'];
-
- if(x($options,'mutual_friends'))
- $mutual = true;
- if(x($options,'single'))
- $single = true;
- if(x($options,'multiple'))
- $single = false;
- if(x($options,'exclude'))
- $exclude = $options['exclude'];
-
- if(x($options,'networks')) {
- switch($options['networks']) {
- case 'DFRN_ONLY':
- $networks = array('dfrn');
- break;
- case 'PRIVATE':
- $networks = array('dfrn','face','mail', 'dspr');
- break;
- case 'TWO_WAY':
- $networks = array('dfrn','face','mail','dspr','stat');
- break;
- default:
- break;
- }
- }
- }
-
- $x = array('options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks);
-
- call_hooks('contact_select_options', $x);
-
- $o = '';
-
- $sql_extra = '';
-
- if($x['mutual']) {
- $sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
- }
-
- if(intval($x['exclude']))
- $sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude']));
-
- if(is_array($x['networks']) && count($x['networks'])) {
- for($y = 0; $y < count($x['networks']) ; $y ++)
- $x['networks'][$y] = "'" . dbesc($x['networks'][$y]) . "'";
- $str_nets = implode(',',$x['networks']);
- $sql_extra .= " AND `network` IN ( $str_nets ) ";
- }
-
- $tabindex = (x($options, 'tabindex') ? "tabindex=\"" . $options["tabindex"] . "\"" : "");
-
- if($x['single'])
- $o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"" . $x['size'] . "\" $tabindex >\r\n";
- else
- $o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"" . $x['size'] . "$\" $tabindex >\r\n";
-
- $r = q("SELECT `id`, `name`, `url`, `network` FROM `contact`
- WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 AND `notify` != ''
- $sql_extra
- ORDER BY `name` ASC ",
- intval(local_channel())
- );
-
-
- $arr = array('contact' => $r, 'entry' => $o);
-
- // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
-
- call_hooks(App::$module . '_pre_' . $selname, $arr);
-
- if(count($r)) {
- foreach($r as $rr) {
- if((is_array($preselected)) && in_array($rr['id'], $preselected))
- $selected = " selected=\"selected\" ";
- else
- $selected = '';
-
- $trimmed = mb_substr($rr['name'],0,20);
-
- $o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}|{$rr['url']}\" >$trimmed</option>\r\n";
- }
-
- }
-
- $o .= "</select>\r\n";
-
- call_hooks(App::$module . '_post_' . $selname, $o);
-
- return $o;
-}*/
-
-
-
function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false, $privatenet = false, $tabindex = null) {
@@ -254,20 +148,26 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
array_walk($deny_cid,'fixacl');
array_walk($deny_gid,'fixacl');
}
-
- $jotnets = '';
- if($show_jotnets) {
- call_hooks('jot_networks', $jotnets);
+
+ $r = q("SELECT id, hash, gname FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
+ intval(local_channel())
+ );
+
+ if($r) {
+ foreach($r as $rr) {
+ $groups .= '<option id="' . $rr['id'] . '" value="' . $rr['hash'] . '">' . $rr['gname'] . '</option>' . "\r\n";
+ }
}
$tpl = get_markup_template("acl_selector.tpl");
$o = replace_macros($tpl, array(
'$showall' => $showall_caption,
'$onlyme' => t('Only me'),
+ '$groups' => $groups,
'$showallOrigin' => $showall_origin,
'$showallIcon' => $showall_icon,
'$select_label' => t('Who can see this?'),
- '$showlimited' => t('Custom selection'),
+ '$custom' => t('Custom selection'),
'$showlimitedDesc' => t('Select "Show" to allow viewing. "Don\'t show" lets you override and limit the scope of "Show".'),
'$show' => t("Show"),
'$hide' => t("Don't show"),
@@ -276,8 +176,6 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
'$allowgid' => json_encode($allow_gid),
'$denycid' => json_encode($deny_cid),
'$denygid' => json_encode($deny_gid),
- '$jnetModalTitle' => t('Other networks and post services'),
- '$jotnets' => $jotnets,
'$aclModalTitle' => t('Permissions'),
'$aclModalDesc' => $dialog_description,
'$aclModalDismiss' => t('Close'),
diff --git a/include/api.php b/include/api.php
index 2587a72bb..692baf563 100644
--- a/include/api.php
+++ b/include/api.php
@@ -61,10 +61,8 @@ require_once('include/api_auth.php');
}
- function api_register_func($path, $func, $auth=false){
- global $API;
- $API[$path] = array('func'=>$func,
- 'auth'=>$auth);
+ function api_register_func($path, $func, $auth=false) {
+ \Zotlabs\Lib\Api_router::register($path,$func,$auth);
}
@@ -72,76 +70,88 @@ require_once('include/api_auth.php');
* MAIN API ENTRY POINT *
**************************/
- function api_call($a){
- GLOBAL $API, $called_api;
+ function api_call(){
- // preset
- $type="json";
+ $p = App::$cmd;
+ $type = null;
- foreach ($API as $p=>$info){
- if (strpos(App::$query_string, $p)===0){
- $called_api= explode("/",$p);
- //unset($_SERVER['PHP_AUTH_USER']);
- if ($info['auth'] === true && api_user() === false) {
- api_login($a);
- }
+ if(strrpos($p,'.')) {
+ $type = substr($p,strrpos($p,'.')+1);
+ if(strpos($type,'/') === false) {
+ $p = substr($p,0,strrpos($p,'.'));
+ // recalculate App argc,argv since we just extracted the type from it
+ App::$argv = explode('/',$p);
+ App::$argc = count(App::$argv);
+ }
+ }
+
+ if((! $type) || (! in_array($type, [ 'json', 'xml', 'rss', 'as', 'atom' ])))
+ $type = 'json';
+
+ $info = \Zotlabs\Lib\Api_router::find($p);
+
+ logger('info: ' . $p . ' type: ' . $type . ' ' . print_r($info,true));
+
+ if($info) {
- load_contact_links(api_user());
+ if ($info['auth'] === true && api_user() === false) {
+ api_login($a);
+ }
- $channel = App::get_channel();
+ load_contact_links(api_user());
- logger('API call for ' . $channel['channel_name'] . ': ' . App::$query_string);
- logger('API parameters: ' . print_r($_REQUEST,true));
+ $channel = App::get_channel();
- $type="json";
+ logger('API call for ' . $channel['channel_name'] . ': ' . App::$query_string);
+ logger('API parameters: ' . print_r($_REQUEST,true));
- if (strpos(App::$query_string, ".xml")>0) $type="xml";
- if (strpos(App::$query_string, ".json")>0) $type="json";
- if (strpos(App::$query_string, ".rss")>0) $type="rss";
- if (strpos(App::$query_string, ".atom")>0) $type="atom";
- if (strpos(App::$query_string, ".as")>0) $type="as";
+ $r = call_user_func($info['func'],$type);
- $r = call_user_func($info['func'], $a, $type);
- if ($r===false) return;
+ if($r === false)
+ return;
- switch($type){
- case "xml":
- $r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
- header ("Content-Type: text/xml");
- return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
- break;
- case "json":
- header ("Content-Type: application/json");
- foreach($r as $rr) {
- if(! $rr)
- $rr = array();
- $json = json_encode($rr);
+ switch($type) {
+ case "xml":
+ $r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
+ header ("Content-Type: text/xml");
+ return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
+ break;
+ case "json":
+ header ("Content-Type: application/json");
+ if($r) {
+ foreach($r as $rv) {
+ $json = json_encode($rv);
}
- if ($_GET['callback'])
- $json = $_GET['callback']."(".$json.")";
- return $json;
- break;
- case "rss":
- header ("Content-Type: application/rss+xml");
- return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
- break;
- case "atom":
- header ("Content-Type: application/atom+xml");
- return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
- break;
- case "as":
- //header ("Content-Type: application/json");
- //foreach($r as $rr)
- // return json_encode($rr);
- return json_encode($r);
- break;
+ }
+ // Lookup JSONP to understand these lines. They provide cross-domain AJAX ability.
+ if ($_GET['callback'])
+ $json = $_GET['callback'] . '(' . $json . ')' ;
+ return $json;
+ break;
+ case "rss":
+ header ("Content-Type: application/rss+xml");
+ return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
+ break;
+ case "atom":
+ header ("Content-Type: application/atom+xml");
+ return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
+ break;
+ case "as":
+ if($r) {
+ foreach($r as $rv) {
+ $json = json_encode($rv);
+ }
+ }
+ return $json;
+ break;
- }
- //echo "<pre>"; var_dump($r); die();
}
+
}
+
+
header("HTTP/1.1 404 Not Found");
- logger('API call not implemented: '.App::$query_string." - ".print_r($_REQUEST,true));
+ logger('API call not implemented: ' . App::$query_string . ' - ' . print_r($_REQUEST,true));
$r = '<status><error>not implemented</error></status>';
switch($type){
case "xml":
@@ -166,7 +176,8 @@ require_once('include/api_auth.php');
/**
* RSS extra info
*/
- function api_rss_extra($a, $arr, $user_info){
+
+ function api_rss_extra( $arr, $user_info){
if (is_null($user_info)) $user_info = api_get_user($a);
$arr['$user'] = $user_info;
$arr['$rss'] = array(
@@ -186,8 +197,8 @@ require_once('include/api_auth.php');
* Returns user info array.
*/
- function api_get_user($a, $contact_id = null, $contact_xchan = null){
- global $called_api;
+ function api_get_user( $contact_id = null, $contact_xchan = null){
+
$user = null;
$extra_query = "";
@@ -212,26 +223,12 @@ require_once('include/api_auth.php');
if (api_user()!==false)
$extra_query .= " AND abook_channel = ".intval(api_user());
}
-
- if (is_null($user) && argc() > (count($called_api)-1) && (strstr(App::$cmd,'/users'))){
- $argid = count($called_api);
- list($xx, $null) = explode(".",argv($argid));
- if(is_numeric($xx)){
- $user = intval($xx);
- $extra_query = " AND abook_id = %d ";
- } else {
- $user = dbesc($xx);
- $extra_query = " AND xchan_addr like '%s@%%' ";
- if (api_user() !== false)
- $extra_query .= " AND abook_channel = ".intval(api_user());
- }
- }
}
if (! $user) {
if (api_user() === false) {
api_login($a);
- return False;
+ return false;
} else {
$user = local_channel();
$extra_query = " AND abook_channel = %d AND abook_self = 1 ";
@@ -239,7 +236,8 @@ require_once('include/api_auth.php');
}
- logger('api_user: ' . $extra_query . ', user: ' . $user);
+ logger('api_user: ' . $extra_query . ', user: ' . $user, LOGGER_DATA, LOG_INFO);
+
// user info
$uinfo = q("SELECT * from abook left join xchan on abook_xchan = xchan_hash
@@ -349,14 +347,13 @@ require_once('include/api_auth.php');
$x = api_get_status($uinfo[0]['xchan_hash']);
if($x)
$ret['status'] = $x;
-
// logger('api_get_user: ' . print_r($ret,true));
return $ret;
}
- function api_client_register($a,$type) {
+ function api_client_register($type) {
$ret = array();
$key = random_string(16);
@@ -389,12 +386,12 @@ require_once('include/api_auth.php');
- function api_item_get_user($a, $item) {
+ function api_item_get_user( $item) {
// The author is our direct contact, in a conversation with us.
if($item['author']['abook_id']) {
- return api_get_user($a,$item['author']['abook_id']);
+ return api_get_user($item['author']['abook_id']);
}
// We don't know this person directly.
@@ -461,9 +458,11 @@ require_once('include/api_auth.php');
$ret = replace_macros($tpl, $data);
break;
case "json":
+ default:
$ret = $data;
break;
}
+
return $ret;
}
@@ -473,17 +472,16 @@ require_once('include/api_auth.php');
* returns a 401 status code and an error message if not.
* http://developer.twitter.com/doc/get/account/verify_credentials
*/
- function api_account_verify_credentials($a, $type){
+ function api_account_verify_credentials( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
-
return api_apply_template("user", $type, array('$user' => $user_info));
}
api_register_func('api/account/verify_credentials','api_account_verify_credentials', true);
- function api_account_logout($a, $type){
+ function api_account_logout( $type){
require_once('include/auth.php');
App::$session->nuke();
return api_apply_template("user", $type, array('$user' => null));
@@ -507,7 +505,7 @@ require_once('include/api_auth.php');
* Red basic channel export
*/
- function api_export_basic($a, $type) {
+ function api_export_basic( $type) {
if(api_user() === false) {
logger('api_export_basic: no user');
return false;
@@ -519,9 +517,10 @@ require_once('include/api_auth.php');
}
api_register_func('api/export/basic','api_export_basic', true);
api_register_func('api/red/channel/export/basic','api_export_basic', true);
+ api_register_func('api/hz/1.0/channel/export/basic','api_export_basic', true);
- function api_channel_stream($a, $type) {
+ function api_channel_stream( $type) {
if(api_user() === false) {
logger('api_channel_stream: no user');
return false;
@@ -536,18 +535,20 @@ require_once('include/api_auth.php');
}
}
api_register_func('api/red/channel/stream','api_channel_stream', true);
+ api_register_func('api/hz/1.0/channel/stream','api_channel_stream', true);
- function api_attach_list($a,$type) {
+ function api_attach_list($type) {
logger('api_user: ' . api_user());
json_return_and_die(attach_list_files(api_user(),get_observer_hash(),'','','','created asc'));
}
api_register_func('api/red/files','api_attach_list', true);
+ api_register_func('api/hz/1.0/files','api_attach_list', true);
- function api_file_meta($a,$type) {
+ function api_file_meta($type) {
if (api_user()===false) return false;
if(! $_REQUEST['file_id']) return false;
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
@@ -563,9 +564,10 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/filemeta', 'api_file_meta', true);
+ api_register_func('api/hz/1.0/filemeta', 'api_file_meta', true);
- function api_file_data($a,$type) {
+ function api_file_data($type) {
if (api_user()===false) return false;
if(! $_REQUEST['file_id']) return false;
$start = (($_REQUEST['start']) ? intval($_REQUEST['start']) : 0);
@@ -606,10 +608,11 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/filedata', 'api_file_data', true);
+ api_register_func('api/hz/1.0/filedata', 'api_file_data', true);
- function api_file_detail($a,$type) {
+ function api_file_detail($type) {
if (api_user()===false) return false;
if(! $_REQUEST['file_id']) return false;
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
@@ -631,20 +634,23 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/file', 'api_file_detail', true);
+ api_register_func('api/hz/1.0/file', 'api_file_detail', true);
- function api_albums($a,$type) {
+ function api_albums($type) {
json_return_and_die(photos_albums_list(App::get_channel(),App::get_observer()));
}
api_register_func('api/red/albums','api_albums', true);
+ api_register_func('api/hz/1.0/albums','api_albums', true);
- function api_photos($a,$type) {
+ function api_photos($type) {
$album = $_REQUEST['album'];
json_return_and_die(photos_list_photos(App::get_channel(),App::get_observer(),$album));
}
api_register_func('api/red/photos','api_photos', true);
+ api_register_func('api/hz/1.0/photos','api_photos', true);
- function api_photo_detail($a,$type) {
+ function api_photo_detail($type) {
if (api_user()===false) return false;
if(! $_REQUEST['photo_id']) return false;
$scale = ((array_key_exists('scale',$_REQUEST)) ? intval($_REQUEST['scale']) : 0);
@@ -684,9 +690,10 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/photo', 'api_photo_detail', true);
+ api_register_func('api/hz/1.0/photo', 'api_photo_detail', true);
- function api_group_members($a,$type) {
+ function api_group_members($type) {
if(api_user() === false)
return false;
@@ -706,11 +713,12 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/group_members','api_group_members', true);
+ api_register_func('api/hz/1.0/group_members','api_group_members', true);
- function api_group($a,$type) {
+ function api_group($type) {
if(api_user() === false)
return false;
@@ -720,9 +728,10 @@ require_once('include/api_auth.php');
json_return_and_die($r);
}
api_register_func('api/red/group','api_group', true);
+ api_register_func('api/hz/1.0/group','api_group', true);
- function api_red_xchan($a,$type) {
+ function api_red_xchan($type) {
logger('api_xchan');
if(api_user() === false)
@@ -738,9 +747,10 @@ require_once('include/api_auth.php');
};
api_register_func('api/red/xchan','api_red_xchan',true);
+ api_register_func('api/hz/1.0/xchan','api_red_xchan',true);
- function api_statuses_mediap($a, $type) {
+ function api_statuses_mediap( $type) {
if (api_user() === false) {
logger('api_statuses_update: no user');
return false;
@@ -782,11 +792,11 @@ require_once('include/api_auth.php');
$mod->post();
// this should output the last post (the one we just posted).
- return api_status_show($a,$type);
+ return api_status_show($type);
}
api_register_func('api/statuses/mediap','api_statuses_mediap', true);
- function api_statuses_update($a, $type) {
+ function api_statuses_update( $type) {
if (api_user() === false) {
logger('api_statuses_update: no user');
return false;
@@ -901,13 +911,13 @@ require_once('include/api_auth.php');
$mod->post();
// this should output the last post (the one we just posted).
- return api_status_show($a,$type);
+ return api_status_show($type);
}
api_register_func('api/statuses/update_with_media','api_statuses_update', true);
api_register_func('api/statuses/update','api_statuses_update', true);
- function red_item_new($a, $type) {
+ function red_item_new( $type) {
if (api_user() === false) {
logger('api_red_item_new: no user');
@@ -939,9 +949,10 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/item/new','red_item_new', true);
+ api_register_func('api/hz/1.0/item/new','red_item_new', true);
- function red_item($a, $type) {
+ function red_item( $type) {
if (api_user() === false) {
logger('api_red_item_full: no user');
@@ -977,6 +988,7 @@ require_once('include/api_auth.php');
}
api_register_func('api/red/item/full','red_item', true);
+ api_register_func('api/hz/1.0/item/full','red_item', true);
@@ -1042,7 +1054,7 @@ require_once('include/api_auth.php');
return $status_info;
}
- function api_status_show($a, $type){
+ function api_status_show( $type){
$user_info = api_get_user($a);
// get last public message
@@ -1120,7 +1132,7 @@ require_once('include/api_auth.php');
// FIXME - this is essentially the same as api_status_show except for the template formatting at the end. Consolidate.
- function api_users_show($a, $type){
+ function api_users_show( $type){
$user_info = api_get_user($a);
require_once('include/security.php');
@@ -1192,7 +1204,7 @@ require_once('include/api_auth.php');
* TODO: Add reply info
*/
- function api_statuses_home_timeline($a, $type){
+ function api_statuses_home_timeline( $type){
if (api_user() === false)
return false;
@@ -1259,10 +1271,10 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
break;
case "as":
- $as = api_format_as($a, $ret, $user_info);
+ $as = api_format_as( $ret, $user_info);
$as['title'] = App::$config['sitename']." Home Timeline";
$as['link']['url'] = z_root()."/".$user_info["screen_name"]."/all";
return($as);
@@ -1274,7 +1286,7 @@ require_once('include/api_auth.php');
api_register_func('api/statuses/home_timeline','api_statuses_home_timeline', true);
api_register_func('api/statuses/friends_timeline','api_statuses_home_timeline', true);
- function api_statuses_public_timeline($a, $type){
+ function api_statuses_public_timeline( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -1320,10 +1332,10 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
break;
case "as":
- $as = api_format_as($a, $ret, $user_info);
+ $as = api_format_as( $ret, $user_info);
$as['title'] = App::$config['sitename']. " " . t('Public Timeline');
$as['link']['url'] = z_root()."/";
return($as);
@@ -1338,7 +1350,7 @@ require_once('include/api_auth.php');
*
*/
- function api_statuses_show($a, $type){
+ function api_statuses_show( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -1377,7 +1389,7 @@ require_once('include/api_auth.php');
/*switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
}*/
return api_apply_template("status", $type, $data);
}
@@ -1388,7 +1400,7 @@ require_once('include/api_auth.php');
/**
*
*/
- function api_statuses_repeat($a, $type){
+ function api_statuses_repeat( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -1434,7 +1446,7 @@ require_once('include/api_auth.php');
*
*/
- function api_statuses_destroy($a, $type){
+ function api_statuses_destroy( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -1498,7 +1510,7 @@ require_once('include/api_auth.php');
*/
- function api_statuses_mentions($a, $type){
+ function api_statuses_mentions( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -1548,10 +1560,10 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
break;
case "as":
- $as = api_format_as($a, $ret, $user_info);
+ $as = api_format_as( $ret, $user_info);
$as["title"] = App::$config['sitename']." Mentions";
$as['link']['url'] = z_root()."/";
return($as);
@@ -1565,7 +1577,7 @@ require_once('include/api_auth.php');
api_register_func('api/statuses/replies','api_statuses_mentions', true);
- function api_statuses_user_timeline($a, $type){
+ function api_statuses_user_timeline( $type){
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -1633,7 +1645,7 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
}
return api_apply_template("timeline", $type, $data);
@@ -1649,7 +1661,7 @@ require_once('include/api_auth.php');
*
* api v1 : https://web.archive.org/web/20131019055350/https://dev.twitter.com/docs/api/1/post/favorites/create/%3Aid
*/
- function api_favorites_create_destroy($a, $type){
+ function api_favorites_create_destroy( $type){
logger('favorites_create_destroy');
@@ -1706,7 +1718,7 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
}
return api_apply_template("status", $type, $data);
@@ -1717,7 +1729,7 @@ require_once('include/api_auth.php');
- function api_favorites($a, $type){
+ function api_favorites( $type){
if (api_user()===false)
return false;
@@ -1770,10 +1782,10 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
break;
case "as":
- $as = api_format_as($a, $ret, $user_info);
+ $as = api_format_as( $ret, $user_info);
$as['title'] = App::$config['sitename']." Home Timeline";
$as['link']['url'] = z_root()."/".$user_info["screen_name"]."/all";
return($as);
@@ -1789,7 +1801,7 @@ require_once('include/api_auth.php');
- function api_format_as($a, $ret, $user_info) {
+ function api_format_as( $ret, $user_info) {
$as = array();
$as['title'] = App::$config['sitename']." Public Timeline";
@@ -1907,7 +1919,7 @@ require_once('include/api_auth.php');
localize_item($item);
- $status_user = (($item['author_xchan']==$user_info['guid'])?$user_info: api_item_get_user($a,$item));
+ $status_user = (($item['author_xchan']==$user_info['guid'])?$user_info: api_item_get_user($item));
if(array_key_exists('status',$status_user))
unset($status_user['status']);
@@ -1986,7 +1998,7 @@ require_once('include/api_auth.php');
}
- function api_account_rate_limit_status($a,$type) {
+ function api_account_rate_limit_status($type) {
$hash = array(
'reset_time_in_seconds' => strtotime('now + 1 hour'),
@@ -2002,7 +2014,7 @@ require_once('include/api_auth.php');
}
api_register_func('api/account/rate_limit_status','api_account_rate_limit_status',true);
- function api_help_test($a,$type) {
+ function api_help_test($type) {
if ($type == 'xml')
$ok = "true";
@@ -2019,7 +2031,7 @@ require_once('include/api_auth.php');
* This function is deprecated by Twitter
* returns: json, xml
**/
- function api_statuses_f($a, $type, $qtype) {
+ function api_statuses_f( $type, $qtype) {
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -2054,20 +2066,20 @@ require_once('include/api_auth.php');
$ret = array();
foreach($r as $cid){
- $ret[] = api_get_user($a, $cid['abook_id']);
+ $ret[] = api_get_user( $cid['abook_id']);
}
return array('$users' => $ret);
}
- function api_statuses_friends($a, $type){
- $data = api_statuses_f($a,$type,"friends");
+ function api_statuses_friends( $type){
+ $data = api_statuses_f($type,"friends");
if ($data===false) return false;
return api_apply_template("friends", $type, $data);
}
- function api_statuses_followers($a, $type){
- $data = api_statuses_f($a,$type,"followers");
+ function api_statuses_followers( $type){
+ $data = api_statuses_f($type,"followers");
if ($data===false) return false;
return api_apply_template("friends", $type, $data);
}
@@ -2079,7 +2091,7 @@ require_once('include/api_auth.php');
- function api_statusnet_config($a,$type) {
+ function api_statusnet_config($type) {
load_config('system');
@@ -2115,8 +2127,9 @@ require_once('include/api_auth.php');
api_register_func('api/statusnet/config','api_statusnet_config',false);
api_register_func('api/friendica/config','api_statusnet_config',false);
api_register_func('api/red/config','api_statusnet_config',false);
+ api_register_func('api/hz/1.0/config','api_statusnet_config',false);
- function api_statusnet_version($a,$type) {
+ function api_statusnet_version($type) {
// liar
@@ -2134,7 +2147,7 @@ require_once('include/api_auth.php');
api_register_func('api/statusnet/version','api_statusnet_version',false);
- function api_friendica_version($a,$type) {
+ function api_friendica_version($type) {
if($type === 'xml') {
header("Content-type: application/xml");
@@ -2149,9 +2162,10 @@ require_once('include/api_auth.php');
}
api_register_func('api/friendica/version','api_friendica_version',false);
api_register_func('api/red/version','api_friendica_version',false);
+ api_register_func('api/hz/1.0/version','api_friendica_version',false);
- function api_ff_ids($a,$type,$qtype) {
+ function api_ff_ids($type,$qtype) {
if(! api_user())
return false;
@@ -2187,17 +2201,17 @@ require_once('include/api_auth.php');
}
}
- function api_friends_ids($a,$type) {
- api_ff_ids($a,$type,'friends');
+ function api_friends_ids($type) {
+ api_ff_ids($type,'friends');
}
- function api_followers_ids($a,$type) {
- api_ff_ids($a,$type,'followers');
+ function api_followers_ids($type) {
+ api_ff_ids($type,'followers');
}
api_register_func('api/friends/ids','api_friends_ids',true);
api_register_func('api/followers/ids','api_followers_ids',true);
- function api_direct_messages_new($a, $type) {
+ function api_direct_messages_new( $type) {
if (api_user()===false) return false;
if (!x($_POST, "text") || !x($_POST,"screen_name")) return;
@@ -2213,7 +2227,7 @@ require_once('include/api_auth.php');
dbesc($_POST['screen_name'] . '@%')
);
- $recipient = api_get_user($a, $r[0]['abook_id']);
+ $recipient = api_get_user( $r[0]['abook_id']);
$replyto = '';
$sub = '';
if (x($_REQUEST,'replyto')) {
@@ -2247,7 +2261,7 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
}
return api_apply_template("direct_messages", $type, $data);
@@ -2255,7 +2269,7 @@ require_once('include/api_auth.php');
}
api_register_func('api/direct_messages/new','api_direct_messages_new',true);
- function api_direct_messages_box($a, $type, $box) {
+ function api_direct_messages_box( $type, $box) {
if (api_user()===false) return false;
$user_info = api_get_user($a);
@@ -2292,10 +2306,10 @@ require_once('include/api_auth.php');
foreach($r as $item) {
if ($item['from_xchan'] == $channel['channel_hash']) {
$sender = $user_info;
- $recipient = api_get_user($a, null, $item['to_xchan']);
+ $recipient = api_get_user( null, $item['to_xchan']);
}
else {
- $sender = api_get_user($a, null, $item['from_xchan']);
+ $sender = api_get_user( null, $item['from_xchan']);
$recipient = $user_info;
}
@@ -2308,24 +2322,24 @@ require_once('include/api_auth.php');
switch($type){
case "atom":
case "rss":
- $data = api_rss_extra($a, $data, $user_info);
+ $data = api_rss_extra( $data, $user_info);
}
return api_apply_template("direct_messages", $type, $data);
}
- function api_direct_messages_sentbox($a, $type){
- return api_direct_messages_box($a, $type, "sentbox");
+ function api_direct_messages_sentbox( $type){
+ return api_direct_messages_box( $type, "sentbox");
}
- function api_direct_messages_inbox($a, $type){
- return api_direct_messages_box($a, $type, "inbox");
+ function api_direct_messages_inbox( $type){
+ return api_direct_messages_box( $type, "inbox");
}
- function api_direct_messages_all($a, $type){
- return api_direct_messages_box($a, $type, "all");
+ function api_direct_messages_all( $type){
+ return api_direct_messages_box( $type, "all");
}
- function api_direct_messages_conversation($a, $type){
- return api_direct_messages_box($a, $type, "conversation");
+ function api_direct_messages_conversation( $type){
+ return api_direct_messages_box( $type, "conversation");
}
api_register_func('api/direct_messages/conversation','api_direct_messages_conversation',true);
api_register_func('api/direct_messages/all','api_direct_messages_all',true);
@@ -2333,7 +2347,7 @@ require_once('include/api_auth.php');
api_register_func('api/direct_messages','api_direct_messages_inbox',true);
- function api_oauth_request_token($a, $type){
+ function api_oauth_request_token( $type){
try{
$oauth = new ZotOAuth1();
$req = OAuth1Request::from_request();
@@ -2348,7 +2362,7 @@ require_once('include/api_auth.php');
killme();
}
- function api_oauth_access_token($a, $type){
+ function api_oauth_access_token( $type){
try{
$oauth = new ZotOAuth1();
$req = OAuth1Request::from_request();
diff --git a/include/attach.php b/include/attach.php
index 172840b96..b5c334d3e 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -229,7 +229,7 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $
* @param int $rev Revision
* @return array
*/
-function attach_by_hash($hash, $rev = 0) {
+function attach_by_hash($hash, $observer_hash, $rev = 0) {
$ret = array('success' => false);
@@ -249,12 +249,12 @@ function attach_by_hash($hash, $rev = 0) {
return $ret;
}
- if(! perm_is_allowed($r[0]['uid'], get_observer_hash(), 'view_storage')) {
+ if(! perm_is_allowed($r[0]['uid'], $observer_hash, 'view_storage')) {
$ret['message'] = t('Permission denied.');
return $ret;
}
- $sql_extra = permissions_sql($r[0]['uid']);
+ $sql_extra = permissions_sql($r[0]['uid'],$observer_hash);
// Now we'll see if we can access the attachment
@@ -269,7 +269,7 @@ function attach_by_hash($hash, $rev = 0) {
}
if($r[0]['folder']) {
- $x = attach_can_view_folder($r[0]['uid'],get_observer_hash(),$r[0]['folder']);
+ $x = attach_can_view_folder($r[0]['uid'],$observer_hash,$r[0]['folder']);
if(! $x) {
$ret['message'] = t('Permission denied.');
return $ret;
@@ -315,7 +315,7 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
* * \e string \b message (optional) only when success is false
* * \e array \b data array of attach DB entry without data component
*/
-function attach_by_hash_nodata($hash, $rev = 0) {
+function attach_by_hash_nodata($hash, $observer_hash, $rev = 0) {
$ret = array('success' => false);
@@ -335,12 +335,12 @@ function attach_by_hash_nodata($hash, $rev = 0) {
return $ret;
}
- if(! perm_is_allowed($r[0]['uid'],get_observer_hash(),'view_storage')) {
+ if(! perm_is_allowed($r[0]['uid'],$observer_hash,'view_storage')) {
$ret['message'] = t('Permission denied.');
return $ret;
}
- $sql_extra = permissions_sql($r[0]['uid']);
+ $sql_extra = permissions_sql($r[0]['uid'],$observer_hash);
// Now we'll see if we can access the attachment
@@ -355,7 +355,7 @@ function attach_by_hash_nodata($hash, $rev = 0) {
}
if($r[0]['folder']) {
- $x = attach_can_view_folder($r[0]['uid'],get_observer_hash(),$r[0]['folder']);
+ $x = attach_can_view_folder($r[0]['uid'],$observer_hash,$r[0]['folder']);
if(! $x) {
$ret['message'] = t('Permission denied.');
return $ret;
@@ -709,6 +709,9 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$os_relpath .= $hash;
+ // not yet used
+ $os_path = '';
+
if($src)
@file_put_contents($os_basepath . $os_relpath,@file_get_contents($src));
@@ -723,7 +726,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$edited = $created;
if($options === 'replace') {
- $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', filesize = %d, os_storage = %d, is_photo = %d, content = '%s', edited = '%s' where id = %d and uid = %d",
+ $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', filesize = %d, os_storage = %d, is_photo = %d, content = '%s', edited = '%s', os_path = '%s' where id = %d and uid = %d",
dbesc($filename),
dbesc($mimetype),
dbesc($folder_hash),
@@ -732,13 +735,14 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($is_photo),
dbesc($os_basepath . $os_relpath),
dbesc($created),
+ dbesc($os_path),
intval($existing_id),
intval($channel_id)
);
}
elseif($options === 'revise') {
- $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
+ $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, os_path, allow_cid, allow_gid, deny_cid, deny_gid )
+ VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
intval($x[0]['aid']),
intval($channel_id),
dbesc($x[0]['hash']),
@@ -753,6 +757,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
dbesc($os_basepath . $os_relpath),
dbesc($created),
dbesc($created),
+ dbesc($os_path),
dbesc($x[0]['allow_cid']),
dbesc($x[0]['allow_gid']),
dbesc($x[0]['deny_cid']),
@@ -760,7 +765,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,
+ $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, os_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']),
@@ -768,6 +773,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
dbesc($created),
dbesc((array_key_exists('os_storage',$arr)) ? $arr['os_storage'] : $x[0]['os_storage']),
dbesc((array_key_exists('is_photo',$arr)) ? $arr['is_photo'] : $x[0]['is_photo']),
+ dbesc((array_key_exists('os_path',$arr)) ? $arr['os_path'] : $x[0]['os_path']),
dbesc((array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : $x[0]['allow_cid']),
dbesc((array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : $x[0]['allow_gid']),
dbesc((array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : $x[0]['deny_cid']),
@@ -778,8 +784,8 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
}
else {
- $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, allow_cid, allow_gid,deny_cid, deny_gid )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
+ $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, os_path, allow_cid, allow_gid,deny_cid, deny_gid )
+ VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
intval($channel['channel_account_id']),
intval($channel_id),
dbesc($hash),
@@ -794,6 +800,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
dbesc($os_basepath . $os_relpath),
dbesc($created),
dbesc($created),
+ dbesc($os_path),
dbesc(($arr && array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : $str_contact_allow),
dbesc(($arr && array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : $str_group_allow),
dbesc(($arr && array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : $str_contact_deny),
@@ -1191,7 +1198,11 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
* @param string $deny_gid
* @param boolean $recurse (optional) default false
*/
-function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse = false) {
+function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse = false, $sync = false) {
+
+ $channel = channelx_by_n($channel_id);
+ if(! $channel)
+ return;
$r = q("select hash, flags, is_dir, is_photo from attach where hash = '%s' and uid = %d limit 1",
dbesc($resource),
@@ -1209,7 +1220,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
);
if($r) {
foreach($r as $rr) {
- attach_change_permissions($channel_id, $rr['hash'], $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse);
+ attach_change_permissions($channel_id, $rr['hash'], $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse, $sync);
}
}
}
@@ -1233,6 +1244,13 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
intval($channel_id)
);
}
+
+ if($sync) {
+ $data = attach_export_data($channel,$resource);
+
+ if($data)
+ build_sync_packet($channel['channel_id'],array('file' => array($data)));
+ }
}
/**
@@ -1994,3 +2012,222 @@ function get_filename_by_cloudname($cloudname, $channel, $storepath) {
}
return null;
}
+
+
+// recursively copy a directory into cloud files
+function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpath)
+{
+ if (!is_dir($srcpath) || !is_readable($srcpath)) {
+ logger('Error reading source path: ' . $srcpath, LOGGER_NORMAL);
+ return false;
+ }
+ $nodes = array_diff(scandir($srcpath), array('.', '..'));
+ foreach ($nodes as $node) {
+ $clouddir = $cloudpath . '/' . $node; // Sub-folder in cloud files destination
+ $nodepath = $srcpath . '/' . $node; // Sub-folder in source path
+ if(is_dir($nodepath)) {
+ $x = attach_mkdirp($channel, $observer_hash, array('pathname' => $clouddir));
+ if(!$x['success']) {
+ logger('Error creating cloud path: ' . $clouddir, LOGGER_NORMAL);
+ return false;
+ }
+ // Recursively call this function where the source and destination are the subfolders
+ $success = copy_folder_to_cloudfiles($channel, $observer_hash, $nodepath, $clouddir);
+ if(!$success) {
+ logger('Error copying contents of folder: ' . $nodepath, LOGGER_NORMAL);
+ return false;
+ }
+ } elseif (is_file($nodepath) && is_readable($nodepath)) {
+ $x = attach_store($channel, $observer_hash, 'import',
+ array(
+ 'directory' => $cloudpath,
+ 'src' => $nodepath,
+ 'filename' => $node,
+ 'filesize' => @filesize($nodepath),
+ 'preserve_original' => true)
+ );
+ if(!$x['success']) {
+ logger('Error copying file: ' . $nodepath , LOGGER_NORMAL);
+ logger('Return value: ' . json_encode($x), LOGGER_NORMAL);
+ return false;
+ }
+ } else {
+ logger('Error scanning source path', LOGGER_NORMAL);
+ return false;
+ }
+ }
+
+ return true;
+}
+/**
+ * attach_move()
+ * This function performs an in place directory-to-directory move of a stored attachment or photo.
+ * The data is physically moved in the store/nickname storage location and the paths adjusted
+ * in the attach structure (and if applicable the photo table). The new 'album name' is recorded
+ * for photos and will show up immediately there.
+ * This takes a channel_id, attach.hash of the file to move (this is the same as a photo resource_id), and
+ * 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 !!
+ */
+
+function attach_move($channel_id,$resource_id,$new_folder_hash) {
+
+ $c = channelx_by_n($channel_id);
+ if(! $c)
+ return false;
+
+ $r = q("select * from attach where hash = '%s' and uid = %d limit 1",
+ dbesc($resource_id),
+ intval($channel_id)
+ );
+ if(! $r)
+ return false;
+
+ $oldstorepath = $r[0]['content'];
+
+ if($new_folder_hash) {
+ $n = q("select * from attach where hash = '%s' and uid = %d limit 1",
+ dbesc($new_folder_hash),
+ intval($channel_id)
+ );
+ if(! $n)
+ return;
+ $newdirname = $n[0]['filename'];
+ $newstorepath = $n[0]['content'] . '/' . $resource_id;
+ }
+ else {
+ $newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id;
+ }
+
+ rename($oldstorepath,$newstorepath);
+
+ // duplicate detection. If 'overwrite' is specified, return false because we can't yet do that.
+
+ $filename = $r[0]['filename'];
+
+ $s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ",
+ dbesc($filename),
+ dbesc($new_folder_hash)
+ );
+
+ if($s) {
+ $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files');
+ if($overwrite) {
+ // @fixme
+ return;
+ }
+ else {
+ if(strpos($filename,'.') !== false) {
+ $basename = substr($filename,0,strrpos($filename,'.'));
+ $ext = substr($filename,strrpos($filename,'.'));
+ }
+ else {
+ $basename = $filename;
+ $ext = '';
+ }
+
+ $v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ",
+ dbesc($basename . $ext),
+ dbesc($basename . '(%)' . $ext),
+ dbesc($new_folder_hash)
+ );
+
+ if($v) {
+ $x = 1;
+
+ do {
+ $found = false;
+ foreach($v as $vv) {
+ if($vv['filename'] === $basename . '(' . $x . ')' . $ext) {
+ $found = true;
+ break;
+ }
+ }
+ if($found)
+ $x++;
+ }
+ while($found);
+ $filename = $basename . '(' . $x . ')' . $ext;
+ }
+ else
+ $filename = $basename . $ext;
+ }
+ }
+
+ $t = q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d",
+ dbesc($newstorepath),
+ dbesc($new_folder_hash),
+ dbesc($filename),
+ intval($r[0]['id'])
+ );
+
+ if($r[0]['is_photo']) {
+ $t = q("update photo set album = '%s', filename = '%s' where resource_id = '%s' and uid = %d",
+ dbesc($newdirname),
+ dbesc($filename),
+ dbesc($resource_id),
+ intval($channel_id)
+ );
+
+ $t = q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0",
+ dbesc($newstorepath),
+ dbesc($resource_id),
+ intval($channel_id)
+ );
+ }
+
+ return true;
+
+}
+
+
+function attach_folder_select_list($channel_id) {
+
+ $r = q("select * from attach where is_dir = 1 and uid = %d",
+ intval($channel_id)
+ );
+
+ $out = [];
+ $out[''] = '/';
+
+ if($r) {
+ foreach($r as $rv) {
+ $x = attach_folder_rpaths($r,$rv);
+ if($x)
+ $out[$x[0]] = $x[1];
+ }
+ }
+ return $out;
+}
+
+function attach_folder_rpaths($all_folders,$that_folder) {
+
+ $path = '/' . $that_folder['filename'];
+ $current_hash = $that_folder['hash'];
+ $parent_hash = $that_folder['folder'];
+ $error = false;
+ $found = false;
+
+ if($parent_hash) {
+ do {
+ foreach($all_folders as $selected) {
+ if(! $selected['is_dir'])
+ continue;
+ if($selected['hash'] == $parent_hash) {
+ $path = '/' . $selected['filename'] . $path;
+ $current_hash = $selected['hash'];
+ $parent_hash = $selected['folder'];
+ $found = true;
+ break;
+ }
+ }
+ if(! $found)
+ $error = true;
+ }
+ while((! $found) && (! $error) && ($parent_hash != ''));
+ }
+ return (($error) ? false : [ $current_hash , $path ]);
+
+} \ No newline at end of file
diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php
index 16f67dc4a..d3f88e17c 100644
--- a/include/bb2diaspora.php
+++ b/include/bb2diaspora.php
@@ -268,7 +268,7 @@ function bb2dmention_callback($match) {
}
-function bb2diaspora_itemwallwall(&$item) {
+function bb2diaspora_itemwallwall(&$item,$uplink = false) {
// We will provide wallwall (embedded author on the Diaspora side) if
// 1. It is a wall-to-wall post
@@ -302,13 +302,19 @@ function bb2diaspora_itemwallwall(&$item) {
}
}
+ if($uplink)
+ $wallwall = true;
+
if(($wallwall) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_s']) {
logger('bb2diaspora_itemwallwall: wall to wall post',LOGGER_DEBUG);
// post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author.
$item['body'] = "\n\n"
+ . '[quote]'
. '[img]' . $item['author']['xchan_photo_s'] . '[/img]'
- . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n"
- . $item['body'];
+ . ' '
+ . '[url=' . $item['author']['xchan_url'] . '][b]' . $item['author']['xchan_name'] . '[/b][/url]' . "\n\n"
+ . $item['body']
+ . '[/quote]';
}
// $item['author'] might cause a surprise further down the line if it wasn't expected to be here.
@@ -318,7 +324,7 @@ function bb2diaspora_itemwallwall(&$item) {
}
-function bb2diaspora_itembody($item, $force_update = false, $have_channel = false) {
+function bb2diaspora_itembody($item, $force_update = false, $have_channel = false, $uplink) {
if(! get_iconfig($item,'diaspora','fields')) {
@@ -362,7 +368,7 @@ function bb2diaspora_itembody($item, $force_update = false, $have_channel = fals
}
if(! $have_channel)
- bb2diaspora_itemwallwall($newitem);
+ bb2diaspora_itemwallwall($newitem,$uplink);
$title = $newitem['title'];
$body = preg_replace('/\#\^http/i', 'http', $newitem['body']);
diff --git a/include/bbcode.php b/include/bbcode.php
index db3a1011b..a82b658b1 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -12,16 +12,27 @@ require_once('include/hubloc.php');
function tryoembed($match) {
$url = ((count($match) == 2) ? $match[1] : $match[2]);
-
$o = oembed_fetch_url($url);
- if ($o->type == 'error')
+ if ($o['type'] == 'error')
return $match[0];
$html = oembed_format_object($o);
return $html;
}
+
+function nakedoembed($match) {
+ $url = ((count($match) == 2) ? $match[1] : $match[2]);
+
+ $o = oembed_fetch_url($url);
+
+ if ($o['type'] == 'error')
+ return $match[0];
+
+ return '[embed]' . $url . '[/embed]';
+}
+
function tryzrlaudio($match) {
$link = $match[1];
$zrl = is_matrix_url($link);
@@ -516,6 +527,9 @@ function bb_fixtable_lf($match) {
function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) {
+
+ call_hooks('bbcode_filter', $Text);
+
// Hide all [noparse] contained bbtags by spacefying them
if (strpos($Text,'[noparse]') !== false) {
$Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_spacefy',$Text);
@@ -642,6 +656,9 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$urlchars = '[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,\@]';
if (strpos($Text,'http') !== false) {
+ if($tryoembed) {
+ $Text = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ism", 'tryoembed', $Text);
+ }
$Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ism", '$1<a href="$2" target="_blank" >$2</a>', $Text);
}
@@ -666,8 +683,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" >$2</a>', $Text);
}
- // Remove bookmarks from UNO
- if (get_config('system','server_role') === 'basic')
+ if (get_account_techlevel() < 2)
$Text = str_replace('<span class="bookmark-identifier">#^</span>', '', $Text);
// Perform MAIL Search
@@ -769,11 +785,14 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
}
// Check for list text
$Text = str_replace("[*]", "<li>", $Text);
+ $Text = str_replace("[]", "<li><input type=\"checkbox\" disabled=\"disabled\">", $Text);
+ $Text = str_replace("[x]", "<li><input type=\"checkbox\" checked=\"checked\" disabled=\"disabled\">", $Text);
// handle nested lists
$endlessloop = 0;
while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) ||
+ ((strpos($Text, "[/checklist]") !== false) && (strpos($Text, "[checklist]") !== false)) ||
((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) ||
((strpos($Text, "[/dl]") !== false) && (strpos($Text, "[dl") !== false)) ||
@@ -785,6 +804,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '<ul class="listupperroman" style="list-style-type: upper-roman;">$2</ul>', $Text);
$Text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '<ul class="listloweralpha" style="list-style-type: lower-alpha;">$2</ul>', $Text);
$Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '<ul class="listupperalpha" style="list-style-type: upper-alpha;">$2</ul>', $Text);
+ $Text = preg_replace("/\[checklist\](.*?)\[\/checklist\]/ism", '<ul class="checklist" style="list-style-type: none;">$1</ul>', $Text);
$Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>', $Text);
$Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>', $Text);
$Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '<li>$1</li>', $Text);
@@ -942,13 +962,13 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace_callback("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
- $Text = preg_replace_callback("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus))\[\/audio\]/ism", 'tryzrlaudio', $Text);
+ $Text = preg_replace_callback("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/audio\]/ism", 'tryzrlaudio', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
$Text = preg_replace_callback("/\[zvideo\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
- $Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
+ $Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
}
// Try to Oembed
diff --git a/include/channel.php b/include/channel.php
index bfd300a0d..c86cea6f1 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -297,7 +297,7 @@ function create_identity($arr) {
dbesc($guid),
dbesc($sig),
dbesc($hash),
- dbesc($ret['channel']['channel_address'] . '@' . App::get_hostname()),
+ dbesc(channel_reddress($ret['channel'])),
intval($primary),
dbesc(z_root()),
dbesc(base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey']))),
@@ -319,7 +319,7 @@ function create_identity($arr) {
dbesc(z_root() . "/photo/profile/l/{$newuid}"),
dbesc(z_root() . "/photo/profile/m/{$newuid}"),
dbesc(z_root() . "/photo/profile/s/{$newuid}"),
- dbesc($ret['channel']['channel_address'] . '@' . App::get_hostname()),
+ dbesc(channel_reddress($ret['channel'])),
dbesc(z_root() . '/channel/' . $ret['channel']['channel_address']),
dbesc(z_root() . '/follow?f=&url=%s'),
dbesc(z_root() . '/poco/' . $ret['channel']['channel_address']),
@@ -918,7 +918,7 @@ function profile_load($nickname, $profile = '') {
App::$profile = $p[0];
App::$profile_uid = $p[0]['profile_uid'];
- App::$page['title'] = App::$profile['channel_name'] . " - " . App::$profile['channel_address'] . "@" . App::get_hostname();
+ App::$page['title'] = App::$profile['channel_name'] . " - " . channel_reddress(App::$profile);
App::$profile['permission_to_view'] = $can_view_profile;
@@ -936,7 +936,7 @@ function profile_load($nickname, $profile = '') {
* load/reload current theme info
*/
- $_SESSION['theme'] = $p[0]['channel_theme'];
+// $_SESSION['theme'] = $p[0]['channel_theme'];
}
@@ -1033,7 +1033,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
$connect_url = rconnect_url($profile['uid'],get_observer_hash());
$connect = (($connect_url) ? t('Connect') : '');
if($connect_url)
- $connect_url = sprintf($connect_url,urlencode($profile['channel_address'] . '@' . App::get_hostname()));
+ $connect_url = sprintf($connect_url,urlencode(channel_reddress($profile)));
// premium channel - over-ride
@@ -1103,8 +1103,8 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
require_once('include/widgets.php');
- if(! feature_enabled($profile['uid'],'hide_rating'))
- $z = widget_rating(array('target' => $profile['channel_hash']));
+// if(! feature_enabled($profile['uid'],'hide_rating'))
+ $z = widget_rating(array('target' => $profile['channel_hash']));
$o .= replace_macros($tpl, array(
'$zcard' => $zcard,
@@ -1212,7 +1212,7 @@ function advanced_profile(&$a) {
if(App::$profile['partner'])
$profile['marital']['partner'] = bbcode(App::$profile['partner']);
- if(strlen(App::$profile['howlong']) && App::$profile['howlong'] !== NULL_DATE) {
+ if(strlen(App::$profile['howlong']) && App::$profile['howlong'] > NULL_DATE) {
$profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s'));
}
@@ -1381,6 +1381,11 @@ function zid($s,$address = '') {
if (! strlen($s) || strpos($s,'zid='))
return $s;
+ $m = parse_url($s);
+ $fragment = ((array_key_exists('fragment',$m) && $m['fragment']) ? $m['fragment'] : false);
+ if($fragment !== false)
+ $s = str_replace('#' . $fragment,'',$s);
+
$has_params = ((strpos($s,'?')) ? true : false);
$num_slashes = substr_count($s, '/');
if (! $has_params)
@@ -1401,6 +1406,11 @@ function zid($s,$address = '') {
else
$zurl = $s;
+ // put fragment at the end
+
+ if($fragment)
+ $zurl .= '#' . $fragment;
+
$arr = array('url' => $s, 'zid' => urlencode($myaddr), 'result' => $zurl);
call_hooks('zid', $arr);
@@ -1769,7 +1779,7 @@ function get_zcard($channel,$observer_hash = '',$args = array()) {
// $translate = intval(($scale / 1.0) * 100);
- $channel['channel_addr'] = $channel['channel_address'] . '@' . App::get_hostname();
+ $channel['channel_addr'] = channel_reddress($channel);
$zcard = array('chan' => $channel);
$r = q("select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
@@ -1831,7 +1841,7 @@ function get_zcard_embed($channel,$observer_hash = '',$args = array()) {
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
}
- $channel['channel_addr'] = $channel['channel_address'] . '@' . App::get_hostname();
+ $channel['channel_addr'] = channel_reddress($channel);
$zcard = array('chan' => $channel);
$r = q("select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
@@ -1884,3 +1894,8 @@ function channelx_by_n($id) {
return(($r) ? $r[0] : false);
}
+function channel_reddress($channel) {
+ if(! ($channel && array_key_exists('channel_address',$channel)))
+ return '';
+ return strtolower($channel['channel_address'] . '@' . App::get_hostname());
+} \ No newline at end of file
diff --git a/include/connections.php b/include/connections.php
index 4f685388c..017117dda 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -608,7 +608,7 @@ function random_profile() {
for($i = 0; $i < $retryrandom; $i++) {
- $r = q("select xchan_url from xchan left join hubloc on hubloc_hash = xchan_hash where xchan_addr not like '%s' and hubloc_connected > %s - interval %s order by $randfunc limit 1",
+ $r = q("select xchan_url from xchan left join hubloc on hubloc_hash = xchan_hash where xchan_addr not like '%s' and xchan_hidden = 0 and hubloc_connected > %s - interval %s order by $randfunc limit 1",
dbesc('sys@%'),
db_utcnow(), db_quoteinterval('30 day')
);
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index 85c46b0d1..8f76bb4bc 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -13,7 +13,7 @@ function findpeople_widget() {
}
}
- $advanced_search = ((local_channel() && get_pconfig(local_channel(),'feature','expert')) ? t('Advanced') : false);
+ $advanced_search = ((local_channel() && feature_enabled(local_channel(),'advanced_dirsearch')) ? t('Advanced') : false);
return replace_macros(get_markup_template('peoplefind.tpl'),array(
'$findpeople' => t('Find Channels'),
diff --git a/include/conversation.php b/include/conversation.php
index b53498d20..287dd4983 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -712,10 +712,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
'forged' => $forged,
'txt_cats' => t('Categories:'),
'txt_folders' => t('Filed under:'),
- 'has_cats' => ((count($categories)) ? 'true' : ''),
- 'has_folders' => ((count($folders)) ? 'true' : ''),
- 'categories' => $categories,
- 'folders' => $folders,
+ 'has_cats' => ((count($body['categories'])) ? 'true' : ''),
+ 'has_folders' => ((count($body['folders'])) ? 'true' : ''),
'text' => strip_tags($body['html']),
'ago' => relative_date($item['created']),
'app' => $item['app'],
@@ -723,7 +721,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
'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')):''),
+ 'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
'location' => $location,
'indent' => '',
'owner_name' => $owner_name,
@@ -941,12 +939,9 @@ function item_photo_menu($item){
$clean_url = normalise_link($item['author-link']);
}
- $poco_rating = get_config('system','poco_rating_enable');
- // if unset default to enabled
- if($poco_rating === false)
- $poco_rating = true;
+ $rating_enabled = get_config('system','rating_enabled');
- $ratings_url = (($poco_rating) ? z_root() . '/ratings/' . urlencode($item['author_xchan']) : '');
+ $ratings_url = (($rating_enabled) ? z_root() . '/ratings/' . urlencode($item['author_xchan']) : '');
$post_menu = Array(
t("View Source") => $vsrc_link,
@@ -1056,6 +1051,9 @@ function builtin_activity_puller($item, &$conv_responses) {
$conv_responses[$mode][$item['thr_parent']] ++;
$conv_responses[$mode][$item['thr_parent'] . '-l'][] = $url;
+ if(get_observer_hash() && get_observer_hash() === $item['author_xchan']) {
+ $conv_responses[$mode][$item['thr_parent'] . '-m'] = true;
+ }
// there can only be one activity verb per item so if we found anything, we can stop looking
return;
@@ -1121,6 +1119,10 @@ function status_editor($a, $x, $popup = false) {
$feature_voting = feature_enabled($x['profile_uid'], 'consensus_tools');
if(x($x, 'hide_voting'))
$feature_voting = false;
+
+ $feature_nocomment = feature_enabled($x['profile_uid'], 'disable_comments');
+ if(x($x, 'disable_comments'))
+ $feature_nocomment = false;
$feature_expire = ((feature_enabled($x['profile_uid'], 'content_expire') && (! $webpage)) ? true : false);
if(x($x, 'hide_expire'))
@@ -1190,12 +1192,12 @@ function status_editor($a, $x, $popup = false) {
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
+ '$nocomment_enabled' => t('Comments enabled'),
+ '$nocomment_disabled' => t('Comments disabled'),
));
$tpl = get_markup_template('jot.tpl');
- $jotplugins = '';
-
$preview = t('Preview');
if(x($x, 'hide_preview'))
$preview = '';
@@ -1212,8 +1214,18 @@ function status_editor($a, $x, $popup = false) {
if(! $cipher)
$cipher = 'aes256';
+ // avoid illegal offset errors
+ if(! array_key_exists('permissions',$x))
+ $x['permissions'] = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
+
+ $jotplugins = '';
call_hooks('jot_tool', $jotplugins);
+ $jotnets = '';
+ if(x($x,'jotnets')) {
+ call_hooks('jot_networks', $jotnets);
+ }
+
$o .= replace_macros($tpl, array(
'$return_path' => ((x($x, 'return_path')) ? $x['return_path'] : App::$query_string),
'$action' => z_root() . '/item',
@@ -1239,6 +1251,10 @@ function status_editor($a, $x, $popup = false) {
'$voting' => t('Toggle voting'),
'$feature_voting' => $feature_voting,
'$consensus' => 0,
+ '$nocommenttitle' => t('Disable comments'),
+ '$nocommenttitlesub' => t('Toggle comments'),
+ '$feature_nocomment' => $feature_nocomment,
+ '$nocomment' => 0,
'$clearloc' => $clearloc,
'$title' => ((x($x, 'title')) ? htmlspecialchars($x['title'], ENT_COMPAT,'UTF-8') : ''),
'$placeholdertitle' => ((x($x, 'placeholdertitle')) ? $x['placeholdertitle'] : t('Title (optional)')),
@@ -1266,6 +1282,8 @@ function status_editor($a, $x, $popup = false) {
'$preview' => $preview,
'$source' => ((x($x, 'source')) ? $x['source'] : ''),
'$jotplugins' => $jotplugins,
+ '$jotnets' => $jotnets,
+ '$jotnets_label' => t('Other networks and post services'),
'$defexpire' => $defexpire,
'$feature_expire' => $feature_expire,
'$expires' => t('Set expiration date'),
@@ -1608,6 +1626,8 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
$uid = ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : local_channel());
+ $account_id = ((App::$profile['profile_uid']) ? App::$profile['channel_account_id'] : App::$channel['channel_account_id']);
+
if($uid == local_channel()) {
$cal_link = '';
@@ -1710,7 +1730,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
);
}
- if(feature_enabled($uid,'wiki') && (get_config('system','server_role') !== 'basic')) {
+ if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) {
$tabs[] = array(
'label' => t('Wiki'),
'url' => z_root() . '/wiki/' . $nickname,
diff --git a/include/datetime.php b/include/datetime.php
index 76bd6b8d6..cd08ab367 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -24,6 +24,13 @@ function timezone_cmp($a, $b) {
return ( t($a) < t($b)) ? -1 : 1;
}
+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.
*
@@ -78,15 +85,20 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
if( ($s === '') || (! is_string($s)) )
$s = 'now';
+ if(is_null_date($s)) {
+ $d = new DateTime('0001-01-01 00:00:00', new DateTimeZone('UTC'));
+ return $d->format($fmt);
+ }
+
// Slight hackish adjustment so that 'zero' datetime actually returns what is intended
// otherwise we end up with -0001-11-30 ...
// add 32 days so that we at least get year 00, and then hack around the fact that
// months and days always start with 1.
- if(substr($s,0,10) == '0000-00-00') {
- $d = new DateTime($s . ' + 32 days', new DateTimeZone('UTC'));
- return str_replace('1', '0', $d->format($fmt));
- }
+// if(substr($s,0,10) == '0000-00-00') {
+// $d = new DateTime($s . ' + 32 days', new DateTimeZone('UTC'));
+// return str_replace('1', '0', $d->format($fmt));
+// }
try {
$from_obj = new DateTimeZone($from);
@@ -268,7 +280,7 @@ function relative_date($posted_date, $format = null) {
$abs = strtotime($localtime);
- if (is_null($posted_date) || $posted_date === NULL_DATE || $abs === false) {
+ if (is_null($posted_date) || is_null_date($posted_date) || $abs === false) {
return t('never');
}
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index 1905241a7..852dc16af 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -62,6 +62,8 @@ class DBA {
if(is_object(self::$dba) && self::$dba->connected) {
+ if($server === 'localhost')
+ $port = $set_port;
$dns = ((self::$dbtype == DBTYPE_POSTGRES) ? 'postgres' : 'mysql')
. ':host=' . $server . (is_null($port) ? '' : ';port=' . $port)
. ';dbname=' . $db;
@@ -84,7 +86,7 @@ class DBA {
abstract class dba_driver {
// legacy behavior
const INSTALL_SCRIPT='install/schema_mysql.sql';
- const NULL_DATE = '0000-00-00 00:00:00';
+ const NULL_DATE = '0001-01-01 00:00:00';
const UTC_NOW = 'UTC_TIMESTAMP()';
protected $db;
@@ -260,11 +262,8 @@ function dbg($state) {
*/
function dbesc($str) {
- if(ACTIVE_DBTYPE == DBTYPE_POSTGRES && $str === '0000-00-00 00:00:00') {
+ if(is_null_date($str))
$str = NULL_DATE;
- } else if(ACTIVE_DBTYPE != DBTYPE_POSTGRES && $str === '0001-01-01 00:00:00') {
- $str = NULL_DATE;
- }
if(\DBA::$dba && \DBA::$dba->connected)
return(\DBA::$dba->escape($str));
@@ -280,12 +279,9 @@ function dbunescbin($str) {
}
function dbescdate($date) {
- if(ACTIVE_DBTYPE == DBTYPE_POSTGRES && $date === '0000-00-00 00:00:00') {
- $date = NULL_DATE;
- } else if(ACTIVE_DBTYPE != DBTYPE_POSTGRES && $date === '0001-01-01 00:00:00') {
- $date = NULL_DATE;
- }
- return $date;
+ if(is_null_date($date))
+ return \DBA::$dba->escape(NULL_DATE);
+ return \DBA::$dba->escape($date);
}
function db_quoteinterval($txt) {
@@ -380,11 +376,8 @@ function dbq($sql) {
function dbesc_array_cb(&$item, $key) {
if(is_string($item)) {
- if($item == '0000-00-00 00:00:00' && ACTIVE_DBTYPE == DBTYPE_POSTGRES)
- $item = '0001-01-01 00:00:00';
- else if($item == '0001-01-01 00:00:00' && ACTIVE_DBTYPE == DBTYPE_MYSQL)
- $item = '0000-00-00 00:00:00';
-
+ if(is_null_date($item))
+ $item = NULL_DATE;
$item = dbesc($item);
}
}
@@ -439,4 +432,4 @@ function db_logger($s,$level = LOGGER_NORMAL,$syslog = LOG_INFO) {
logger($s,$level,$syslog);
\DBA::$logging = false;
\DBA::$dba->debug = $saved;
-} \ No newline at end of file
+}
diff --git a/include/dir_fns.php b/include/dir_fns.php
index 9f1be1a42..03cc2706a 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -227,7 +227,7 @@ function sync_directories($dirmode) {
$token = get_config('system','realm_token');
- $syncdate = (($rr['site_sync'] === NULL_DATE) ? datetime_convert('UTC','UTC','now - 2 days') : $rr['site_sync']);
+ $syncdate = (($rr['site_sync'] <= NULL_DATE) ? datetime_convert('UTC','UTC','now - 2 days') : $rr['site_sync']);
$x = z_fetch_url($rr['site_directory'] . '?f=&sync=' . urlencode($syncdate) . (($token) ? '&t=' . $token : ''));
if (! $x['success'])
@@ -423,7 +423,7 @@ function local_dir_update($uid, $force) {
$arr = array('channel_id' => $uid, 'hash' => $hash, 'profile' => $profile);
call_hooks('local_dir_update', $arr);
- $address = $p[0]['channel_address'] . '@' . App::get_hostname();
+ $address = channel_reddress($p[0]);
if (perm_is_allowed($uid, '', 'view_profile')) {
import_directory_profile($hash, $arr['profile'], $address, 0);
@@ -439,5 +439,5 @@ function local_dir_update($uid, $force) {
}
$ud_hash = random_string() . '@' . App::get_hostname();
- update_modtime($hash, $ud_hash, $p[0]['channel_address'] . '@' . App::get_hostname(),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
+ update_modtime($hash, $ud_hash, channel_reddress($p[0]),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
}
diff --git a/include/event.php b/include/event.php
index 3d650cd14..153654120 100644
--- a/include/event.php
+++ b/include/event.php
@@ -343,6 +343,13 @@ function event_store_event($arr) {
}
}
+ $hook_info = [ 'event' => $arr, 'existing_event' => $existing_event, 'cancel' => false ];
+ call_hooks('event_store_event',$hook_info);
+ if($hook_info['cancel'])
+ return false;
+
+ $arr = $hook_info['event'];
+ $existing_event = $hook_info['existing_event'];
if($existing_event) {
@@ -371,6 +378,7 @@ function event_store_event($arr) {
`event_repeat` = '%s',
`event_sequence` = %d,
`event_priority` = %d,
+ `event_vdata` = '%s',
`allow_cid` = '%s',
`allow_gid` = '%s',
`deny_cid` = '%s',
@@ -392,6 +400,7 @@ function event_store_event($arr) {
dbesc($arr['event_repeat']),
intval($arr['event_sequence']),
intval($arr['event_priority']),
+ dbesc($arr['event_vdata']),
dbesc($arr['allow_cid']),
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
@@ -412,8 +421,8 @@ function event_store_event($arr) {
$hash = random_string() . '@' . App::get_hostname();
$r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,dtstart,dtend,summary,description,location,etype,
- adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, event_priority, allow_cid,allow_gid,deny_cid,deny_gid)
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s' ) ",
+ adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, event_priority, event_vdata, allow_cid,allow_gid,deny_cid,deny_gid)
+ VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' ) ",
intval($arr['uid']),
intval($arr['account']),
dbesc($arr['event_xchan']),
@@ -434,6 +443,7 @@ function event_store_event($arr) {
dbesc($arr['event_repeat']),
intval($arr['event_sequence']),
intval($arr['event_priority']),
+ dbesc($arr['event_vdata']),
dbesc($arr['allow_cid']),
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
diff --git a/include/features.php b/include/features.php
index 041c028c6..1ccdbf015 100644
--- a/include/features.php
+++ b/include/features.php
@@ -36,96 +36,419 @@ function get_feature_default($feature) {
}
+function feature_level($feature,$def) {
+ $x = get_config('feature_level',$feature);
+ if($x !== false)
+ return intval($x);
+ return $def;
+}
+
function get_features($filtered = true) {
- $server_role = get_config('system','server_role');
+ $server_role = \Zotlabs\Lib\System::get_server_role();
if($server_role === 'basic' && $filtered)
return array();
- $arr = array(
+ $arr = [
// General
- 'general' => array(
+ 'general' => [
+
t('General Features'),
- // This is per post, and different from fixed expiration 'expire' which isn't working yet
- array('content_expire', t('Content Expiration'), t('Remove posts/comments and/or private messages at a future time'), false, get_config('feature_lock','content_expire')),
- array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles'), false, get_config('feature_lock','multi_profiles')),
- array('advanced_profiles', t('Advanced Profiles'), t('Additional profile sections and selections'),false,get_config('feature_lock','advanced_profiles')),
- array('profile_export', t('Profile Import/Export'), t('Save and load profile details across sites/channels'),false,get_config('feature_lock','profile_export')),
- array('webpages', t('Web Pages'), t('Provide managed web pages on your channel'),false,get_config('feature_lock','webpages')),
- array('wiki', t('Wiki'), t('Provide a wiki for your channel'),(($server_role === 'basic') ? false : true),get_config('feature_lock','wiki')),
- array('hide_rating', t('Hide Rating'), t('Hide the rating buttons on your channel and profile pages. Note: People can still rate you somewhere else.'),false,get_config('feature_lock','hide_rating')),
- array('private_notes', t('Private Notes'), t('Enables a tool to store notes and reminders (note: not encrypted)'),false,get_config('feature_lock','private_notes')),
- array('nav_channel_select', t('Navigation Channel Select'), t('Change channels directly from within the navigation dropdown menu'),false,get_config('feature_lock','nav_channel_select')),
- array('photo_location', t('Photo Location'), t('If location data is available on uploaded photos, link this to a map.'),false,get_config('feature_lock','photo_location')),
- array('ajaxchat', t('Access Controlled Chatrooms'), t('Provide chatrooms and chat services with access control.'),true,get_config('feature_lock','ajaxchat')),
- array('smart_birthdays', t('Smart Birthdays'), t('Make birthday events timezone aware in case your friends are scattered across the planet.'),true,get_config('feature_lock','smart_birthdays')),
- array('expert', t('Expert Mode'), t('Enable Expert Mode to provide advanced configuration options'),false,get_config('feature_lock','expert')),
- array('premium_channel', t('Premium Channel'), t('Allows you to set restrictions and terms on those that connect with your channel'),false,get_config('feature_lock','premium_channel')),
- ),
+
+
+ [
+ 'multi_profiles',
+ t('Multiple Profiles'),
+ t('Ability to create multiple profiles'),
+ false,
+ get_config('feature_lock','multi_profiles'),
+ feature_level('multi_profiles',3),
+ ],
+
+ [
+ 'advanced_profiles',
+ t('Advanced Profiles'),
+ t('Additional profile sections and selections'),
+ false,
+ get_config('feature_lock','advanced_profiles'),
+ feature_level('advanced_profiles',1),
+ ],
+
+ [
+ 'profile_export',
+ t('Profile Import/Export'),
+ t('Save and load profile details across sites/channels'),
+ false,
+ get_config('feature_lock','profile_export'),
+ feature_level('profile_export',3),
+ ],
+
+ [
+ 'webpages',
+ t('Web Pages'),
+ t('Provide managed web pages on your channel'),
+ false,
+ get_config('feature_lock','webpages'),
+ feature_level('webpages',3),
+ ],
+
+ [
+ 'wiki',
+ t('Wiki'),
+ t('Provide a wiki for your channel'),
+ false,
+ get_config('feature_lock','wiki'),
+ feature_level('wiki',2),
+ ],
+/*
+ [
+ 'hide_rating',
+ t('Hide Rating'),
+ t('Hide the rating buttons on your channel and profile pages. Note: People can still rate you somewhere else.'),
+ false,
+ get_config('feature_lock','hide_rating'),
+ feature_level('hide_rating',3),
+ ],
+*/
+ [
+ 'private_notes',
+ t('Private Notes'),
+ t('Enables a tool to store notes and reminders (note: not encrypted)'),
+ false,
+ get_config('feature_lock','private_notes'),
+ feature_level('private_notes',1),
+ ],
+
+ [
+ 'nav_channel_select',
+ t('Navigation Channel Select'),
+ t('Change channels directly from within the navigation dropdown menu'),
+ false,
+ get_config('feature_lock','nav_channel_select'),
+ feature_level('nav_channel_select',3),
+ ],
+
+ [
+ 'photo_location',
+ t('Photo Location'),
+ t('If location data is available on uploaded photos, link this to a map.'),
+ false,
+ get_config('feature_lock','photo_location'),
+ feature_level('photo_location',2),
+ ],
+
+ [
+ 'ajaxchat',
+ t('Access Controlled Chatrooms'),
+ t('Provide chatrooms and chat services with access control.'),
+ true,
+ get_config('feature_lock','ajaxchat'),
+ feature_level('ajaxchat',1),
+ ],
+
+ [
+ 'smart_birthdays',
+ t('Smart Birthdays'),
+ t('Make birthday events timezone aware in case your friends are scattered across the planet.'),
+ true,
+ get_config('feature_lock','smart_birthdays'),
+ feature_level('smart_birthdays',2),
+ ],
+
+ [
+ 'advanced_dirsearch',
+ t('Advanced Directory Search'),
+ t('Allows creation of complex directory search queries'),
+ false,
+ get_config('feature_lock','advanced_dirsearch'),
+ feature_level('advanced_dirsearch',4),
+ ],
+
+ [
+ 'advanced_theming',
+ t('Advanced Theme and Layout Settings'),
+ t('Allows fine tuning of themes and page layouts'),
+ false,
+ get_config('feature_lock','advanced_theming'),
+ feature_level('advanced_theming',4),
+ ],
+ ],
// Post composition
- 'composition' => array(
+ 'composition' => [
+
t('Post Composition Features'),
-// array('richtext', t('Richtext Editor'), t('Enable richtext editor'),falseget_config('feature_lock','richtext')),
-// array('markdown', t('Use Markdown'), t('Allow use of "Markdown" to format posts'),false,get_config('feature_lock','markdown')),
- array('large_photos', t('Large Photos'), t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),false,get_config('feature_lock','large_photos')),
- array('channel_sources', t('Channel Sources'), t('Automatically import channel content from other channels or feeds'),false,get_config('feature_lock','channel_sources')),
- array('content_encrypt', t('Even More Encryption'), t('Allow optional encryption of content end-to-end with a shared secret key'),false,get_config('feature_lock','content_encrypt')),
- array('consensus_tools', t('Enable Voting Tools'), t('Provide a class of post which others can vote on'),false,get_config('feature_lock','consensus_tools')),
- array('delayed_posting', t('Delayed Posting'), t('Allow posts to be published at a later date'),false,get_config('feature_lock','delayed_posting')),
- array('suppress_duplicates', t('Suppress Duplicate Posts/Comments'), t('Prevent posts with identical content to be published with less than two minutes in between submissions.'),true,get_config('feature_lock','suppress_duplicates')),
- ),
+ [
+ 'large_photos',
+ t('Large Photos'),
+ t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),
+ false,
+ get_config('feature_lock','large_photos'),
+ feature_level('large_photos',1),
+ ],
+
+ [
+ 'channel_sources',
+ t('Channel Sources'),
+ t('Automatically import channel content from other channels or feeds'),
+ false,
+ get_config('feature_lock','channel_sources'),
+ feature_level('channel_sources',3),
+ ],
+
+ [
+ 'content_encrypt',
+ t('Even More Encryption'),
+ t('Allow optional encryption of content end-to-end with a shared secret key'),
+ false,
+ get_config('feature_lock','content_encrypt'),
+ feature_level('content_encrypt',3),
+ ],
+
+ [
+ 'consensus_tools',
+ t('Enable Voting Tools'),
+ t('Provide a class of post which others can vote on'),
+ false,
+ get_config('feature_lock','consensus_tools'),
+ feature_level('consensus_tools',3),
+ ],
+
+ [
+ 'disable_comments',
+ t('Disable Comments'),
+ t('Provide the option to disable comments for a post'),
+ false,
+ get_config('feature_lock','disable_comments'),
+ feature_level('disable_comments',2),
+ ],
+
+ [
+ 'delayed_posting',
+ t('Delayed Posting'),
+ t('Allow posts to be published at a later date'),
+ false,
+ get_config('feature_lock','delayed_posting'),
+ feature_level('delayed_posting',2),
+ ],
+
+ [
+ 'content_expire',
+ t('Content Expiration'),
+ t('Remove posts/comments and/or private messages at a future time'),
+ false,
+ get_config('feature_lock','content_expire'),
+ feature_level('content_expire',1),
+ ],
+
+ [
+ 'suppress_duplicates',
+ t('Suppress Duplicate Posts/Comments'),
+ t('Prevent posts with identical content to be published with less than two minutes in between submissions.'),
+ true,
+ get_config('feature_lock','suppress_duplicates'),
+ feature_level('suppress_duplicates',1),
+ ],
+
+ ],
// Network Tools
- 'net_module' => array(
+ 'net_module' => [
+
t('Network and Stream Filtering'),
- array('archives', t('Search by Date'), t('Ability to select posts by date ranges'),false,get_config('feature_lock','archives')),
- array('groups', t('Privacy Groups'), t('Enable management and selection of privacy groups'),true,get_config('feature_lock','groups')),
- array('savedsearch', t('Saved Searches'), t('Save search terms for re-use'),false,get_config('feature_lock','savedsearch')),
- array('personal_tab', t('Network Personal Tab'), t('Enable tab to display only Network posts that you\'ve interacted on'),false,get_config('feature_lock','personal_tab')),
- array('new_tab', t('Network New Tab'), t('Enable tab to display all new Network activity'),false,get_config('feature_lock','new_tab')),
- array('affinity', t('Affinity Tool'), t('Filter stream activity by depth of relationships'),false,get_config('feature_lock','affinity')),
- array('connfilter', t('Connection Filtering'), t('Filter incoming posts from connections based on keywords/content'),false,get_config('feature_lock','connfilter')),
- array('suggest', t('Suggest Channels'), t('Show channel suggestions'),false,get_config('feature_lock','suggest')),
- ),
+
+ [
+ 'archives',
+ t('Search by Date'),
+ t('Ability to select posts by date ranges'),
+ false,
+ get_config('feature_lock','archives'),
+ feature_level('archives',1),
+ ],
+
+ [
+ 'groups',
+ t('Privacy Groups'),
+ t('Enable management and selection of privacy groups'),
+ true,
+ get_config('feature_lock','groups'),
+ feature_level('groups',0),
+ ],
+
+ [
+ 'savedsearch',
+ t('Saved Searches'),
+ t('Save search terms for re-use'),
+ false,
+ get_config('feature_lock','savedsearch'),
+ feature_level('savedsearch',2),
+ ],
+
+ [
+ 'personal_tab',
+ t('Network Personal Tab'),
+ t('Enable tab to display only Network posts that you\'ve interacted on'),
+ false,
+ get_config('feature_lock','personal_tab'),
+ feature_level('personal_tab',1),
+ ],
+
+ [
+ 'new_tab',
+ t('Network New Tab'),
+ t('Enable tab to display all new Network activity'),
+ false,
+ get_config('feature_lock','new_tab'),
+ feature_level('new_tab',2),
+ ],
+
+ [
+ 'affinity',
+ t('Affinity Tool'),
+ t('Filter stream activity by depth of relationships'),
+ false,
+ get_config('feature_lock','affinity'),
+ feature_level('affinity',1),
+ ],
+
+ [
+ 'suggest',
+ t('Suggest Channels'),
+ t('Show friend and connection suggestions'),
+ false,
+ get_config('feature_lock','suggest'),
+ feature_level('suggest',1),
+ ],
+
+ [
+ 'connfilter',
+ t('Connection Filtering'),
+ t('Filter incoming posts from connections based on keywords/content'),
+ false,
+ get_config('feature_lock','connfilter'),
+ feature_level('connfilter',3),
+ ],
+
+
+ ],
// Item tools
- 'tools' => array(
+ 'tools' => [
+
t('Post/Comment Tools'),
- array('commtag', t('Community Tagging'), t('Ability to tag existing posts'),false,get_config('feature_lock','commtag')),
- array('categories', t('Post Categories'), t('Add categories to your posts'),false,get_config('feature_lock','categories')),
- array('emojis', t('Emoji Reactions'), t('Add emoji reaction ability to posts'),true,get_config('feature_lock','emojis')),
- array('filing', t('Saved Folders'), t('Ability to file posts under folders'),false,get_config('feature_lock','filing')),
- array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments'),false,get_config('feature_lock','dislike')),
- array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator'),false,get_config('feature_lock','star_posts')),
- array('tagadelic', t('Tag Cloud'), t('Provide a personal tag cloud on your channel page'),false,get_config('feature_lock','tagedelic')),
- ),
- );
+
+ [
+ 'commtag',
+ t('Community Tagging'),
+ t('Ability to tag existing posts'),
+ false,
+ get_config('feature_lock','commtag'),
+ feature_level('commtag',1),
+ ],
+
+ [
+ 'categories',
+ t('Post Categories'),
+ t('Add categories to your posts'),
+ false,
+ get_config('feature_lock','categories'),
+ feature_level('categories',1),
+ ],
+
+ [
+ 'emojis',
+ t('Emoji Reactions'),
+ t('Add emoji reaction ability to posts'),
+ true,
+ get_config('feature_lock','emojis'),
+ feature_level('emojis',1),
+ ],
+
+ [
+ 'filing',
+ t('Saved Folders'),
+ t('Ability to file posts under folders'),
+ false,
+ get_config('feature_lock','filing'),
+ feature_level('filing',2),
+ ],
+
+ [
+ 'dislike',
+ t('Dislike Posts'),
+ t('Ability to dislike posts/comments'),
+ false,
+ get_config('feature_lock','dislike'),
+ feature_level('dislike',1),
+ ],
+
+ [
+ 'star_posts',
+ t('Star Posts'),
+ t('Ability to mark special posts with a star indicator'),
+ false,
+ get_config('feature_lock','star_posts'),
+ feature_level('star_posts',1),
+ ],
+
+ [
+ 'tagadelic',
+ t('Tag Cloud'),
+ t('Provide a personal tag cloud on your channel page'),
+ false,
+ get_config('feature_lock','tagadelic'),
+ feature_level('tagadelic',2),
+ ],
+ ],
+ ];
+
+
+ if($server_role === 'pro') {
+ $arr['general'][] = [
+ 'premium_channel',
+ t('Premium Channel'),
+ t('Allows you to set restrictions and terms on those that connect with your channel'),
+ false,
+ get_config('feature_lock','premium_channel'),
+ feature_level('premium_channel',4),
+ ];
+ }
+
+ $techlevel = get_account_techlevel();
// removed any locked features and remove the entire category if this makes it empty
if($filtered) {
+ $narr = [];
foreach($arr as $k => $x) {
+ $narr[$k] = [ $arr[$k][0] ];
$has_items = false;
- for($y = 0; $y < count($arr[$k]); $y ++) {
+ for($y = 0; $y < count($arr[$k]); $y ++) {
+ $disabled = false;
if(is_array($arr[$k][$y])) {
- if($arr[$k][$y][4] === false) {
- $has_items = true;
+ if($arr[$k][$y][5] > $techlevel) {
+ $disabled = true;
+ }
+ if($arr[$k][$y][4] !== false) {
+ $disabled = true;
}
- else {
- unset($arr[$k][$y]);
+ if(! $disabled) {
+ $has_items = true;
+ $narr[$k][$y] = $arr[$k][$y];
}
}
}
if(! $has_items) {
- unset($arr[$k]);
+ unset($narr[$k]);
}
}
}
-
- call_hooks('get_features',$arr);
- return $arr;
+ else {
+ $narr = $arr;
+ }
+ call_hooks('get_features',$narr);
+ return $narr;
}
diff --git a/include/feedutils.php b/include/feedutils.php
index 01ec0687e..1d58ec317 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -33,7 +33,7 @@ function get_public_feed($channel, $params) {
// put a sane lower limit on feed requests if not specified
-// if($params['begin'] === NULL_DATE)
+// if($params['begin'] <= NULL_DATE)
// $params['begin'] = datetime_convert('UTC','UTC','now - 1 month');
switch($params['type']) {
@@ -884,7 +884,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
$datarray['owner_xchan'] = $contact['xchan_hash'];
- if(array_key_exists('created',$datarray) && $datarray['created'] != NULL_DATE && $expire_days) {
+ if(array_key_exists('created',$datarray) && $datarray['created'] > NULL_DATE && $expire_days) {
$t1 = $datarray['created'];
$t2 = datetime_convert('UTC','UTC','now - ' . $expire_days . 'days');
if($t1 < $t2) {
diff --git a/include/help.php b/include/help.php
index 7f57f3334..3081ae41f 100644
--- a/include/help.php
+++ b/include/help.php
@@ -1,5 +1,107 @@
<?php
+function get_help_content($tocpath = false) {
+
+ global $lang;
+
+ $doctype = 'markdown';
+
+ $text = '';
+
+ $path = (($tocpath !== false) ? $tocpath : '');
+
+ if($tocpath === false && argc() > 1) {
+ $path = '';
+ for($x = 1; $x < argc(); $x ++) {
+ if(strlen($path))
+ $path .= '/';
+ $path .= argv($x);
+ }
+ }
+
+ if($path) {
+ $title = basename($path);
+ if(! $tocpath)
+ \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title)));
+
+ $text = load_doc_file('doc/' . $path . '.md');
+
+ if(! $text) {
+ $text = load_doc_file('doc/' . $path . '.bb');
+ if($text)
+ $doctype = 'bbcode';
+ }
+ if(! $text) {
+ $text = load_doc_file('doc/' . $path . '.html');
+ if($text)
+ $doctype = 'html';
+ }
+ }
+
+ if(($tocpath) && (! $text))
+ return '';
+
+ if($tocpath === false) {
+ if(! $text) {
+ $text = load_doc_file('doc/Site.md');
+ \App::$page['title'] = t('Help');
+ }
+ if(! $text) {
+ $doctype = 'bbcode';
+ $text = load_doc_file('doc/main.bb');
+ \App::$page['title'] = t('Help');
+ }
+
+ if(! $text) {
+ header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found'));
+ $tpl = get_markup_template("404.tpl");
+ return replace_macros($tpl, array(
+ '$message' => t('Page not found.' )
+ ));
+ }
+ }
+
+ if($doctype === 'html')
+ $content = $text;
+ if($doctype === 'markdown') {
+ require_once('library/markdown.php');
+ # escape #include tags
+ $text = preg_replace('/#include/ism', '%%include', $text);
+ $content = Markdown($text);
+ $content = preg_replace('/%%include/ism', '#include', $content);
+ }
+ if($doctype === 'bbcode') {
+ require_once('include/bbcode.php');
+ $content = bbcode($text);
+ // bbcode retargets external content to new windows. This content is internal.
+ $content = str_replace(' target="_blank"','',$content);
+ }
+
+ $content = preg_replace_callback("/#include (.*?)\;/ism", 'preg_callback_help_include', $content);
+ return translate_projectname($content);
+
+}
+
+function preg_callback_help_include($matches) {
+
+ if($matches[1]) {
+ $include = str_replace($matches[0],load_doc_file($matches[1]),$matches[0]);
+ if(preg_match('/\.bb$/', $matches[1]) || preg_match('/\.txt$/', $matches[1])) {
+ require_once('include/bbcode.php');
+ $include = bbcode($include);
+ $include = str_replace(' target="_blank"','',$include);
+ }
+ elseif(preg_match('/\.md$/', $matches[1])) {
+ require_once('library/markdown.php');
+ $include = Markdown($include);
+ }
+ return $include;
+ }
+
+}
+
+
+
function load_doc_file($s) {
$lang = \App::$language;
if(! isset($lang))
@@ -17,8 +119,9 @@ function load_doc_file($s) {
}
function find_doc_file($s) {
- if(file_exists($s))
+ if(file_exists($s)) {
return file_get_contents($s);
+ }
return '';
}
@@ -40,8 +143,13 @@ function search_doc_files($s) {
$r = fetch_post_tags($r,true);
for($x = 0; $x < count($r); $x ++) {
-
- $r[$x]['text'] = $r[$x]['body'];
+ $position = stripos($r[$x]['body'], $s);
+ $dislen = 300;
+ $start = $position-floor($dislen/2);
+ if ( $start < 0) {
+ $start = 0;
+ }
+ $r[$x]['text'] = substr($r[$x]['body'], $start, $dislen);
$r[$x]['rank'] = 0;
if($r[$x]['term']) {
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index 9ffc85a82..29880a627 100644
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -2,7 +2,7 @@
/*
html2bbcode.php
Converter for HTML to BBCode
-Made by: ike@piratenpartei.de
+Made by: Mike@piratenpartei.de
Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom
https://github.com/annando/Syncom
*/
diff --git a/include/import.php b/include/import.php
index 5bbed828f..479e45cc2 100644
--- a/include/import.php
+++ b/include/import.php
@@ -422,9 +422,9 @@ function sync_apps($channel,$apps) {
);
}
- if(! $app['app_created'] || $app['app_created'] === NULL_DATE)
+ if((! $app['app_created']) || ($app['app_created'] <= NULL_DATE))
$app['app_created'] = datetime_convert();
- if(! $app['app_edited'] || $app['app_edited'] === NULL_DATE)
+ if((! $app['app_edited']) || ($app['app_edited'] <= NULL_DATE))
$app['app_edited'] = datetime_convert();
$app['app_channel'] = $channel['channel_id'];
@@ -536,9 +536,9 @@ function sync_chatrooms($channel,$chatrooms) {
unset($chatroom['cr_aid']);
unset($chatroom['cr_uid']);
- if(! $chatroom['cr_created'] || $chatroom['cr_created'] === NULL_DATE)
+ if((! $chatroom['cr_created']) || ($chatroom['cr_created'] <= NULL_DATE))
$chatroom['cr_created'] = datetime_convert();
- if(! $chatroom['cr_edited'] || $chatroom['cr_edited'] === NULL_DATE)
+ if((! $chatroom['cr_edited']) || ($chatroom['cr_edited'] <= NULL_DATE))
$chatroom['cr_edited'] = datetime_convert();
$chatroom['cr_aid'] = $channel['channel_account_id'];
@@ -629,6 +629,10 @@ function import_items($channel,$items,$sync = false,$relocate = null) {
$item_result = item_store($item,$allow_code,$deliver);
}
+ fix_attached_photo_permissions($channel['channel_id'],$item['author_xchan'],$item['body'],$item['allow_cid'],$item['allow_gid'],$item['deny_cid'],$item['deny_gid']);
+
+ fix_attached_file_permissions($channel,$item['author_xchan'],$item['body'],$item['allow_cid'],$item['allow_gid'],$item['deny_cid'],$item['deny_gid']);
+
if($sync && $item['item_wall']) {
// deliver singletons if we have any
if($item_result && $item_result['success']) {
@@ -1032,7 +1036,7 @@ function sync_files($channel,$files) {
}
$attach_exists = false;
- $x = attach_by_hash($att['hash']);
+ $x = attach_by_hash($att['hash'],$channel['channel_hash']);
logger('sync_files duplicate check: attach_exists=' . $attach_exists, LOGGER_DEBUG);
logger('sync_files duplicate check: att=' . print_r($att,true), LOGGER_DEBUG);
logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
@@ -1102,8 +1106,11 @@ function sync_files($channel,$files) {
// If the hash ever contains any escapable chars this could cause
// problems. Currently it does not.
- dbesc_array($att);
+ // @TODO implement os_path
+ if(!isset($att['os_path']))
+ $att['os_path'] = '';
+ dbesc_array($att);
if($attach_exists) {
logger('sync_files attach exists: ' . print_r($att,true), LOGGER_DEBUG);
@@ -1213,6 +1220,9 @@ function sync_files($channel,$files) {
$p['content'] = base64_decode($p['content']);
+ if(!isset($p['display_path']))
+ $p['display_path'] = '';
+
$exists = q("select * from photo where resource_id = '%s' and imgscale = %d and uid = %d limit 1",
dbesc($p['resource_id']),
intval($p['imgscale']),
@@ -1308,8 +1318,12 @@ function scan_webpage_elements($path, $type, $cloud = false) {
}
$content = file_get_contents($folder . '/' . $contentfilename);
if (!$content) {
- logger('Failed to get file content for ' . $metadata['contentfile']);
- return false;
+ if(is_readable($folder . '/' . $contentfilename)) {
+ $content = '';
+ } else {
+ logger('Failed to get file content for ' . $metadata['contentfile']);
+ return false;
+ }
}
$elements[] = $metadata;
}
@@ -1391,12 +1405,12 @@ function scan_webpage_elements($path, $type, $cloud = false) {
);
$arr['mid'] = $arr['parent_mid'] = $iteminfo[0]['mid'];
$arr['created'] = $iteminfo[0]['created'];
- $arr['edited'] = (($element['edited']) ? datetime_convert('UTC', 'UTC', $element['edited']) : datetime_convert());
} else { // otherwise, generate the creation times and unique id
- $arr['created'] = (($element['created']) ? datetime_convert('UTC', 'UTC', $element['created']) : datetime_convert());
- $arr['edited'] = datetime_convert('UTC', 'UTC', '0000-00-00 00:00:00');
+ $arr['created'] = datetime_convert('UTC', 'UTC');
$arr['mid'] = $arr['parent_mid'] = item_message_id();
}
+ // Update the edited time whether or not the element already exists
+ $arr['edited'] = datetime_convert('UTC', 'UTC');
// Import the actual element content
$arr['body'] = file_get_contents($element['path']);
// The element owner is the channel importing the elements
@@ -1411,7 +1425,7 @@ function scan_webpage_elements($path, $type, $cloud = false) {
'application/x-pdl',
'application/x-php'
];
- // Blocks and pages can have any mimetype, but layouts must be text/bbcode
+ // Blocks and pages can have any of the valid mimetypes, but layouts must be text/bbcode
if((in_array($element['mimetype'], $mimetypes)) && ($type === 'page' || $type === 'block') ) {
$arr['mimetype'] = $element['mimetype'];
} else {
@@ -1420,7 +1434,7 @@ function scan_webpage_elements($path, $type, $cloud = false) {
// Verify ability to use html or php!!!
$execflag = false;
- if ($arr['mimetype'] === 'application/x-php') {
+ if ($arr['mimetype'] === 'application/x-php' || $arr['mimetype'] === 'text/html') {
$z = q("select account_id, account_roles, channel_pageflags from account "
. "left join channel on channel_account_id = account_id where channel_id = %d limit 1",
intval(local_channel())
@@ -1428,10 +1442,15 @@ function scan_webpage_elements($path, $type, $cloud = false) {
if ($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) {
$execflag = true;
+ } else {
+ logger('Unable to import element "' . $name .'" because AllowCode permission is denied.');
+ notice( t('Unable to import element "' . $name .'" because AllowCode permission is denied.') . EOL);
+ $element['import_success'] = 0;
+ return $element;
}
}
- $z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'service' limit 1",
+ $z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'system' limit 1",
dbesc($name),
dbesc($namespace)
);
@@ -1468,3 +1487,193 @@ function scan_webpage_elements($path, $type, $cloud = false) {
return $element;
}
+
+function get_webpage_elements($channel, $type = 'all') {
+ $elements = array();
+ if(!$channel['channel_id']) {
+ return null;
+ }
+ switch ($type) {
+ case 'all':
+ // If all, execute all the pages, layouts, blocks case statements
+ case 'pages':
+ $elements['pages'] = null;
+ $owner = $channel['channel_id'];
+
+ $sql_extra = item_permissions_sql($owner);
+
+
+ $r = q("select * from iconfig left join item on iconfig.iid = item.id
+ where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_WEBPAGE)
+ );
+
+ $pages = null;
+
+ if($r) {
+ $elements['pages'] = array();
+ $pages = array();
+ foreach($r as $rr) {
+ unobscure($rr);
+
+ //$lockstate = (($rr['allow_cid'] || $rr['allow_gid'] || $rr['deny_cid'] || $rr['deny_gid']) ? 'lock' : 'unlock');
+
+ $element_arr = array(
+ 'type' => 'webpage',
+ 'title' => $rr['title'],
+ 'body' => $rr['body'],
+ 'created' => $rr['created'],
+ 'edited' => $rr['edited'],
+ 'mimetype' => $rr['mimetype'],
+ 'pagetitle' => $rr['v'],
+ 'mid' => $rr['mid'],
+ 'layout_mid' => $rr['layout_mid']
+ );
+ $pages[$rr['iid']][] = array(
+ 'url' => $rr['iid'],
+ 'pagetitle' => $rr['v'],
+ 'title' => $rr['title'],
+ 'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']),
+ 'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']),
+ 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]',
+ //'lockstate' => $lockstate
+ );
+ $elements['pages'][] = $element_arr;
+ }
+
+ }
+ if($type !== 'all') {
+ break;
+ }
+
+ case 'layouts':
+ $elements['layouts'] = null;
+ $owner = $channel['channel_id'];
+
+ $sql_extra = item_permissions_sql($owner);
+
+
+ $r = q("select * from iconfig left join item on iconfig.iid = item.id
+ where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_PDL)
+ );
+
+ $layouts = null;
+
+ if($r) {
+ $elements['layouts'] = array();
+ $layouts = array();
+ foreach($r as $rr) {
+ unobscure($rr);
+
+ $elements['layouts'][] = array(
+ 'type' => 'layout',
+ 'description' => $rr['title'], // description of the layout
+ 'body' => $rr['body'],
+ 'created' => $rr['created'],
+ 'edited' => $rr['edited'],
+ 'mimetype' => $rr['mimetype'],
+ 'name' => $rr['v'], // name of reference for the layout
+ 'mid' => $rr['mid'],
+ );
+ }
+
+ }
+
+ if($type !== 'all') {
+ break;
+ }
+
+ case 'blocks':
+ $elements['blocks'] = null;
+ $owner = $channel['channel_id'];
+
+ $sql_extra = item_permissions_sql($owner);
+
+
+ $r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig
+ left join item on iconfig.iid = item.id
+ where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'
+ and item_type = %d order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_BLOCK)
+ );
+
+ $blocks = null;
+
+ if($r) {
+ $elements['blocks'] = array();
+ $blocks = array();
+ foreach($r as $rr) {
+ unobscure($rr);
+
+ $elements['blocks'][] = array(
+ 'type' => 'block',
+ 'title' => $rr['title'],
+ 'body' => $rr['body'],
+ 'created' => $rr['created'],
+ 'edited' => $rr['edited'],
+ 'mimetype' => $rr['mimetype'],
+ 'name' => $rr['v'],
+ 'mid' => $rr['mid']
+ );
+ }
+
+ }
+
+ if($type !== 'all') {
+ break;
+ }
+
+ default:
+ break;
+ }
+ return $elements;
+}
+
+/* creates a compressed zip file */
+
+function create_zip_file($files = array(), $destination = '', $overwrite = false) {
+ //if the zip file already exists and overwrite is false, return false
+ if (file_exists($destination) && !$overwrite) {
+ return false;
+ }
+ //vars
+ $valid_files = array();
+ //if files were passed in...
+ if (is_array($files)) {
+ //cycle through each file
+ foreach ($files as $file) {
+ //make sure the file exists
+ if (file_exists($file)) {
+ $valid_files[] = $file;
+ }
+ }
+ }
+
+ //if we have good files...
+ if (count($valid_files)) {
+ //create the archive
+ $zip = new ZipArchive();
+ if ($zip->open($destination, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
+ return false;
+ }
+ //add the files
+ foreach ($valid_files as $file) {
+ $zip->addFile($file, $file);
+ }
+ //debug
+ //echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
+ //close the zip -- done!
+ $zip->close();
+
+ //check to make sure the file exists
+ return file_exists($destination);
+ } else {
+ return false;
+ }
+}
diff --git a/include/items.php b/include/items.php
index 5bd0b0968..c62d53c3e 100755
--- a/include/items.php
+++ b/include/items.php
@@ -113,6 +113,26 @@ function collect_recipients($item, &$private_envelope) {
// if($policy === 'pub')
// $recipients[] = $sys['xchan_hash'];
}
+
+ // Add the authors of any posts in this thread, if they are known to us.
+ // This is specifically designed to forward wall-to-wall posts to the original author,
+ // in case they aren't a connection but have permission to write on our wall.
+ // This is important for issue tracker channels. It should be a no-op for most channels.
+ // Whether or not they will accept the delivery is not determined here, but should
+ // be taken into account by zot:process_delivery()
+
+ $r = q("select author_xchan from item where parent = %d",
+ intval($item['parent'])
+ );
+ if($r) {
+ foreach($r as $rv) {
+ if(! in_array($rv['author_xchan'],$recipients)) {
+ $recipients[] = $rv['author_xchan'];
+ }
+ }
+ }
+
+
}
// This is a somewhat expensive operation but important.
@@ -143,7 +163,7 @@ function collect_recipients($item, &$private_envelope) {
}
function comments_are_now_closed($item) {
- if($item['comments_closed'] !== NULL_DATE) {
+ if($item['comments_closed'] > NULL_DATE) {
$d = datetime_convert();
if($d > $item['comments_closed'])
return true;
@@ -214,11 +234,10 @@ function can_comment_on_post($observer_xchan, $item) {
return true;
break;
case 'public':
- // We don't allow public comments yet, until a policy
- // for dealing with anonymous comments is in place with
- // a means to moderate comments. Until that time, return
- // false.
- return false;
+ // We don't really allow or support public comments yet, but anonymous
+ // folks won't ever reach this point (as $observer_xchan will be empty).
+ // This means the viewer has an xchan and we can identify them.
+ return true;
break;
case 'any connections':
case 'contacts':
@@ -695,8 +714,9 @@ function get_item_elements($x,$allow_code = false) {
// hub and verify that they are legit - or else we're going to toss the post. We only need to do this
// once, and after that your hub knows them. Sure some info is in the post, but it's only a transit identifier
// and not enough info to be able to look you up from your hash - which is the only thing stored with the post.
-
- if(($xchan_hash = import_author_xchan($x['author'])) !== false)
+
+ $xchan_hash = import_author_xchan($x['author']);
+ if($xchan_hash)
$arr['author_xchan'] = $xchan_hash;
else
return array();
@@ -705,7 +725,8 @@ function get_item_elements($x,$allow_code = false) {
if($arr['author_xchan'] === make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig']))
$arr['owner_xchan'] = $arr['author_xchan'];
else {
- if(($xchan_hash = import_author_xchan($x['owner'])) !== false)
+ $xchan_hash = import_author_xchan($x['owner']);
+ if($xchan_hash)
$arr['owner_xchan'] = $xchan_hash;
else
return array();
@@ -1069,7 +1090,7 @@ function encode_item($item,$mirror = false) {
if($y = encode_item_flags($item))
$x['flags'] = $y;
- if($item['comments_closed'] !== NULL_DATE)
+ if($item['comments_closed'] > NULL_DATE)
$x['comments_closed'] = $item['comments_closed'];
$x['public_scope'] = $scope;
@@ -1166,7 +1187,7 @@ function encode_item_xchan($xchan) {
$ret['name'] = $xchan['xchan_name'];
$ret['address'] = $xchan['xchan_addr'];
- $ret['url'] = (($xchan['hubloc_url']) ? $xchan['hubloc_url'] : $xchan['xchan_url']);
+ $ret['url'] = $xchan['xchan_url'];
$ret['network'] = $xchan['xchan_network'];
$ret['photo'] = array('mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m']);
$ret['guid'] = $xchan['xchan_guid'];
@@ -1418,7 +1439,7 @@ function get_mail_elements($x) {
$arr['conv_guid'] = (($x['conv_guid'])? htmlspecialchars($x['conv_guid'],ENT_COMPAT,'UTF-8',false) : '');
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
- if((! array_key_exists('expires',$x)) || ($x['expires'] === NULL_DATE))
+ if((! array_key_exists('expires',$x)) || ($x['expires'] <= NULL_DATE))
$arr['expires'] = NULL_DATE;
else
$arr['expires'] = datetime_convert('UTC','UTC',$x['expires']);
@@ -1569,6 +1590,9 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['item_wall'] = ((x($arr,'item_wall')) ? intval($arr['item_wall']) : 0 );
$arr['item_type'] = ((x($arr,'item_type')) ? intval($arr['item_type']) : 0 );
+ // obsolete, but needed so as not to throw not-null constraints on some database driveres
+ $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 );
+
// only detect language if we have text content, and if the post is private but not yet
// obscured, make it so.
@@ -1624,9 +1648,23 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : NULL_DATE);
$arr['commented'] = ((x($arr,'commented') !== false) ? datetime_convert('UTC','UTC',$arr['commented']) : datetime_convert());
$arr['comments_closed'] = ((x($arr,'comments_closed') !== false) ? datetime_convert('UTC','UTC',$arr['comments_closed']) : NULL_DATE);
+ $arr['html'] = ((array_key_exists('html',$arr)) ? $arr['html'] : '');
+
+ if($deliver) {
+ $arr['received'] = datetime_convert();
+ $arr['changed'] = datetime_convert();
+ }
+ else {
+
+ // When deliver flag is false, we are *probably* performing an import or bulk migration.
+ // If one updates the changed timestamp it will be made available to zotfeed and delivery
+ // will still take place through backdoor methods. Since these fields are rarely used
+ // otherwise, just preserve the original timestamp.
+
+ $arr['received'] = ((x($arr,'received') !== false) ? datetime_convert('UTC','UTC',$arr['received']) : datetime_convert());
+ $arr['changed'] = ((x($arr,'changed') !== false) ? datetime_convert('UTC','UTC',$arr['changed']) : datetime_convert());
+ }
- $arr['received'] = datetime_convert();
- $arr['changed'] = datetime_convert();
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : '');
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : '');
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : '');
@@ -2027,14 +2065,28 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['edited'] = ((x($arr,'edited') !== false) ? datetime_convert('UTC','UTC',$arr['edited']) : datetime_convert());
$arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : $orig[0]['expires']);
- if(array_key_exists('comments_closed',$arr) && $arr['comments_closed'] != NULL_DATE)
+ if(array_key_exists('comments_closed',$arr) && $arr['comments_closed'] > NULL_DATE)
$arr['comments_closed'] = datetime_convert('UTC','UTC',$arr['comments_closed']);
else
$arr['comments_closed'] = $orig[0]['comments_closed'];
$arr['commented'] = $orig[0]['commented'];
- $arr['received'] = datetime_convert();
- $arr['changed'] = datetime_convert();
+
+ if($deliver) {
+ $arr['received'] = datetime_convert();
+ $arr['changed'] = datetime_convert();
+ }
+ else {
+
+ // When deliver flag is false, we are *probably* performing an import or bulk migration.
+ // If one updates the changed timestamp it will be made available to zotfeed and delivery
+ // will still take place through backdoor methods. Since these fields are rarely used
+ // otherwise, just preserve the original timestamp.
+
+ $arr['received'] = $orig[0]['received'];
+ $arr['changed'] = $orig[0]['changed'];
+ }
+
$arr['route'] = ((array_key_exists('route',$arr)) ? trim($arr['route']) : $orig[0]['route']);
$arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : $orig[0]['diaspora_meta']);
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']);
@@ -2213,7 +2265,7 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id,
logger('storing diaspora comment signature',LOGGER_DEBUG);
- $diaspora_handle = $channel['channel_address'] . '@' . App::get_hostname();
+ $diaspora_handle = channel_reddress($channel);
$signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
@@ -2243,6 +2295,11 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id,
function send_status_notifications($post_id,$item) {
+ // only send notifications for comments
+
+ if($item['mid'] == $item['parent_mid'])
+ return;
+
$notify = false;
$unfollowed = false;
@@ -2258,6 +2315,7 @@ function send_status_notifications($post_id,$item) {
if($item['author_xchan'] === $r[0]['channel_hash'])
return;
+
// I'm the owner - notify me
if($item['owner_hash'] === $r[0]['channel_hash'])
@@ -3774,7 +3832,7 @@ function zot_feed($uid,$observer_hash,$arr) {
$limit = " LIMIT 100 ";
- if($mindate != NULL_DATE) {
+ if($mindate > NULL_DATE) {
$sql_extra .= " and ( created > '$mindate' or changed > '$mindate' ) ";
}
@@ -4327,3 +4385,137 @@ function sync_an_item($channel_id,$item_id) {
build_sync_packet($channel_d,array('item' => array(encode_item($sync_item[0],true)),'item_id' => $rid));
}
}
+
+
+function fix_attached_photo_permissions($uid,$xchan_hash,$body,
+ $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) {
+
+ if(get_pconfig($uid,'system','force_public_uploads')) {
+ $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = '';
+ }
+
+ $match = null;
+ // match img and zmg image links
+ if(preg_match_all("/\[[zi]mg(.*?)\](.*?)\[\/[zi]mg\]/",$body,$match)) {
+ $images = $match[2];
+ if($images) {
+ foreach($images as $image) {
+ if(! stristr($image,z_root() . '/photo/'))
+ continue;
+ $image_uri = substr($image,strrpos($image,'/') + 1);
+ if(strpos($image_uri,'-') !== false)
+ $image_uri = substr($image_uri,0, strpos($image_uri,'-'));
+ if(strpos($image_uri,'.') !== false)
+ $image_uri = substr($image_uri,0, strpos($image_uri,'.'));
+ if(! strlen($image_uri))
+ continue;
+ $srch = '<' . $xchan_hash . '>';
+
+ $r = q("select folder from attach where hash = '%s' and uid = %d limit 1",
+ dbesc($image_uri),
+ intval($uid)
+ );
+ if($r && $r[0]['folder']) {
+ $f = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1",
+ dbesc($r[0]['folder']),
+ intval($uid)
+ );
+ if(($f) && (($f[0]['allow_cid']) || ($f[0]['allow_gid']) || ($f[0]['deny_cid']) || ($f[0]['deny_gid']))) {
+ $str_contact_allow = $f[0]['allow_cid'];
+ $str_group_allow = $f[0]['allow_gid'];
+ $str_contact_deny = $f[0]['deny_cid'];
+ $str_group_deny = $f[0]['deny_gid'];
+ }
+ }
+
+ $r = q("SELECT id FROM photo
+ WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = ''
+ AND resource_id = '%s' AND uid = %d LIMIT 1",
+ dbesc($srch),
+ dbesc($image_uri),
+ intval($uid)
+ );
+
+ if($r) {
+ $r = q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s'
+ WHERE resource_id = '%s' AND uid = %d ",
+ dbesc($str_contact_allow),
+ dbesc($str_group_allow),
+ dbesc($str_contact_deny),
+ dbesc($str_group_deny),
+ dbesc($image_uri),
+ intval($uid)
+ );
+
+ // also update the linked item (which is probably invisible)
+
+ $r = q("select id from item
+ WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = ''
+ AND resource_id = '%s' and resource_type = 'photo' AND uid = %d LIMIT 1",
+ dbesc($srch),
+ dbesc($image_uri),
+ intval($uid)
+ );
+ if($r) {
+ $private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false);
+
+ $r = q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d
+ WHERE id = %d AND uid = %d",
+ dbesc($str_contact_allow),
+ dbesc($str_group_allow),
+ dbesc($str_contact_deny),
+ dbesc($str_group_deny),
+ intval($private),
+ intval($r[0]['id']),
+ intval($uid)
+ );
+ }
+ $r = q("select id from attach where hash = '%s' and uid = %d limit 1",
+ dbesc($image_uri),
+ intval($uid)
+ );
+ if($r) {
+ q("update attach SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s'
+ WHERE id = %d AND uid = %d",
+ dbesc($str_contact_allow),
+ dbesc($str_group_allow),
+ dbesc($str_contact_deny),
+ dbesc($str_group_deny),
+ intval($r[0]['id']),
+ intval($uid)
+ );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+function fix_attached_file_permissions($channel,$observer_hash,$body,
+ $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) {
+
+ if(get_pconfig($channel['channel_id'],'system','force_public_uploads')) {
+ $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = '';
+ }
+
+ $match = false;
+
+ if(preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",$body,$match)) {
+ $attaches = $match[1];
+ if($attaches) {
+ foreach($attaches as $attach) {
+ $hash = substr($attach,0,strpos($attach,','));
+ $rev = intval(substr($attach,strpos($attach,',')));
+ attach_store($channel,$observer_hash,$options = 'update', array(
+ 'hash' => $hash,
+ 'revision' => $rev,
+ 'allow_cid' => $str_contact_allow,
+ 'allow_gid' => $str_group_allow,
+ 'deny_cid' => $str_contact_deny,
+ 'deny_gid' => $str_group_deny
+ ));
+ }
+ }
+ }
+}
diff --git a/include/message.php b/include/message.php
index d3d8181ae..748689206 100644
--- a/include/message.php
+++ b/include/message.php
@@ -75,7 +75,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
if($recip)
$recip_handle = $recip[0]['xchan_addr'];
- $sender_handle = $channel['channel_address'] . '@' . App::get_hostname();
+ $sender_handle = channel_reddress($channel);
$handles = $recip_handle . ';' . $sender_handle;
@@ -166,7 +166,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
foreach($match[2] as $mtch) {
$hash = substr($mtch,0,strpos($mtch,','));
$rev = intval(substr($mtch,strpos($mtch,',')));
- $r = attach_by_hash_nodata($hash,$rev);
+ $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
if($r['success']) {
$attachments[] = array(
'href' => z_root() . '/attach/' . $r['data']['hash'],
@@ -299,14 +299,30 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) {
break;
case 'combined':
- $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";
+ $parents = q("SELECT parent_mid FROM mail WHERE mid = parent_mid AND channel_id = %d ORDER BY created DESC",
+ 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;
}
}
- $r = q($sql);
+ if($parents) {
+ foreach($parents as $parent) {
+ $all[] = q("SELECT * FROM mail WHERE parent_mid = '%s' AND channel_id = %d ORDER BY created DESC",
+ dbesc($parent['parent_mid']),
+ dbesc($local_channel)
+ );
+ }
+ foreach($all as $single)
+ $r[] = $single[0];
+ }
+ else {
+ $r = q($sql);
+ }
if(! $r) {
return array();
diff --git a/include/nav.php b/include/nav.php
index 025da71b3..c2a058457 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -63,6 +63,7 @@ EOT;
$server_role = get_config('system','server_role');
$basic = (($server_role === 'basic') ? true : false);
+ $techlevel = get_account_techlevel();
// nav links: array of array('href', 'text', 'extra css classes', 'title')
$nav = Array();
@@ -144,10 +145,10 @@ EOT;
$homelink = (($observer) ? $observer['xchan_url'] : '');
}
- if((App::$module != 'home') && (! (local_channel())))
+ if(! local_channel())
$nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn');
- if((App::$config['system']['register_policy'] == REGISTER_OPEN) && (! $_SESSION['authenticated']))
+ if(((get_config('system','register_policy') == REGISTER_OPEN) || (get_config('system','register_policy') == REGISTER_APPROVE)) && (! $_SESSION['authenticated']))
$nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn');
if(! get_config('system','hide_help')) {
diff --git a/include/network.php b/include/network.php
index fe001b362..7851f8976 100644
--- a/include/network.php
+++ b/include/network.php
@@ -1148,8 +1148,10 @@ function discover_by_webbie($webbie) {
if($link['rel'] === PROTOCOL_ZOT) {
logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG);
- if(array_key_exists('zot',$x) && $x['zot']['success'])
+ if(array_key_exists('zot',$x) && $x['zot']['success']) {
$i = import_xchan($x['zot']);
+ return true;
+ }
else {
$z = z_fetch_url($link['href']);
if($z['success']) {
@@ -1937,7 +1939,9 @@ function format_and_send_email($sender,$xchan,$item) {
$hostname = App::get_hostname();
if(strpos($hostname,':'))
$hostname = substr($hostname,0,strpos($hostname,':'));
- $sender_email = 'noreply' . '@' . $hostname;
+ $sender_email = get_config('system','reply_address');
+ if(! $sender_email)
+ $sender_email = 'noreply' . '@' . $hostname;
// use the EmailNotification library to send the message
@@ -2008,11 +2012,11 @@ function get_site_info() {
$admin = array();
foreach($r as $rr) {
if($rr['channel_pageflags'] & PAGE_HUBADMIN)
- $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . App::get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']);
+ $admin[] = array( 'name' => $rr['channel_name'], 'address' => channel_reddress($rr), 'channel' => z_root() . '/channel/' . $rr['channel_address']);
}
if(! $admin) {
foreach($r as $rr) {
- $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . App::get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']);
+ $admin[] = array( 'name' => $rr['channel_name'], 'address' => channel_reddress($rr), 'channel' => z_root() . '/channel/' . $rr['channel_address']);
}
}
}
@@ -2222,3 +2226,65 @@ function network_to_name($s) {
return str_replace($search,$replace,$s);
}
+
+
+function z_mail($params) {
+
+ /**
+ * @brief Send a text email message
+ *
+ * @param array $params an assoziative 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
+ * * \e string \b toEmail destination email address
+ * * \e string \b messageSubject subject of the message
+ * * \e string \b htmlVersion html version of the message
+ * * \e string \b textVersion text only version of the message
+ * * \e string \b additionalMailHeader additions to the smtp mail header
+ */
+
+ if(! $params['fromEmail']) {
+ $params['fromEmail'] = get_config('system','from_email');
+ if(! $params['fromEmail'])
+ $params['fromEmail'] = 'Administrator' . '@' . App::get_hostname();
+ }
+ if(! $params['fromName']) {
+ $params['fromName'] = get_config('system','from_email_name');
+ if(! $params['fromName'])
+ $params['fromName'] = Zotlabs\Lib\System::get_site_name();
+ }
+ if(! $params['replyTo']) {
+ $params['replyTo'] = get_config('system','reply_address');
+ if(! $params['replyTo'])
+ $params['replyTo'] = 'noreply' . '@' . App::get_hostname();
+ }
+
+ $params['sent'] = false;
+ $params['result'] = false;
+
+ call_hooks('email_send', $params);
+
+ if($params['sent']) {
+ logger('notification: z_mail returns ' . $params['result'], LOGGER_DEBUG);
+ return $params['result'];
+ }
+
+ $fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
+ $messageSubject = email_header_encode(html_entity_decode($params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
+
+ $messageHeader =
+ $params['additionalMailHeader'] .
+ "From: $fromName <{$params['fromEmail']}>\n" .
+ "Reply-To: $fromName <{$params['replyTo']}>";
+
+ // send the message
+ $res = mail(
+ $params['toEmail'], // send to address
+ $messageSubject, // subject
+ $params['textVersion'],
+ $messageHeader // message headers
+ );
+ logger('notification: z_mail returns ' . $res, LOGGER_DEBUG);
+ return $res;
+}
diff --git a/include/oembed.php b/include/oembed.php
index fe6f10d71..1780e7046 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -105,7 +105,7 @@ function oembed_action($embedurl) {
function oembed_process($url) {
$j = oembed_fetch_url($url);
logger('oembed_process: ' . print_r($j,true));
- if($j && $j->type !== 'error')
+ if($j && $j['type'] !== 'error')
return '[embed]' . $url . '[/embed]';
return false;
}
@@ -117,7 +117,7 @@ function oembed_fetch_url($embedurl){
// These media files should now be caught in bbcode.php
// left here as a fallback in case this is called from another source
- $noexts = array(".mp3",".mp4",".ogg",".ogv",".oga",".ogm",".webm",".opus");
+ $noexts = [ '.mp3', '.mp4', '.ogg', '.ogv', '.oga', '.ogm', '.webm', '.opus', '.m4a' ];
$result = oembed_action($embedurl);
@@ -156,9 +156,12 @@ function oembed_fetch_url($embedurl){
if ($action !== 'block') {
// try oembed autodiscovery
$redirects = 0;
- $result = z_fetch_url($furl, false, $redirects, array('timeout' => 15, 'accept_content' => "text/*", 'novalidate' => true ));
+ $result = z_fetch_url($furl, false, $redirects, array('timeout' => 30, 'accept_content' => "text/*", 'novalidate' => true ));
+
if($result['success'])
$html_text = $result['body'];
+ else
+ logger('fetch failure: ' . $furl);
if($html_text) {
$dom = @DOMDocument::loadHTML($html_text);
@@ -171,7 +174,10 @@ function oembed_fetch_url($embedurl){
foreach($entries as $e){
$href = $e->getAttributeNode("href")->nodeValue;
$x = z_fetch_url($href . '&maxwidth=' . App::$videowidth);
- $txt = $x['body'];
+ if($x['success'])
+ $txt = $x['body'];
+ else
+ logger('fetch failed: ' . $href);
break;
}
// soundcloud is now using text/json+oembed instead of application/json+oembed,
@@ -180,7 +186,10 @@ function oembed_fetch_url($embedurl){
foreach($entries as $e){
$href = $e->getAttributeNode("href")->nodeValue;
$x = z_fetch_url($href . '&maxwidth=' . App::$videowidth);
- $txt = $x['body'];
+ if($x['success'])
+ $txt = $x['body'];
+ else
+ logger('json fetch failed: ' . $href);
break;
}
}
@@ -206,26 +215,29 @@ function oembed_fetch_url($embedurl){
}
- $j = json_decode($txt);
+ $j = json_decode($txt,true);
+
+ if(! $j)
+ $j = [];
if($action === 'filter') {
- if($j->html) {
- $orig = $j->html;
+ if($j['html']) {
+ $orig = $j['html'];
$allow_position = (($zrl) ? true : false);
- $j->html = purify_html($j->html,$allow_position);
- if($j->html != $orig) {
- logger('oembed html was purified. original: ' . $orig . ' purified: ' . $j->html, LOGGER_DEBUG, LOG_INFO);
+ $j['html'] = purify_html($j['html'],$allow_position);
+ if($j['html'] != $orig) {
+ logger('oembed html was purified. original: ' . $orig . ' purified: ' . $j['html'], LOGGER_DEBUG, LOG_INFO);
}
$orig_len = mb_strlen(preg_replace('/\s+/','',$orig));
- $new_len = mb_strlen(preg_replace('/\s+/','',$j->html));
+ $new_len = mb_strlen(preg_replace('/\s+/','',$j['html']));
if(stripos($orig,'<script') || (! $new_len))
- $j->type = 'error';
+ $j['type'] = 'error';
elseif($orig_len) {
$ratio = $new_len / $orig_len;
if($ratio < 0.5) {
- $j->type = 'error';
+ $j['type'] = 'error';
logger('oembed html truncated: ' . $ratio, LOGGER_DEBUG, LOG_INFO);
}
}
@@ -233,7 +245,7 @@ function oembed_fetch_url($embedurl){
}
}
- $j->embedurl = $embedurl;
+ $j['embedurl'] = $embedurl;
// logger('fetch return: ' . print_r($j,true));
@@ -244,27 +256,27 @@ function oembed_fetch_url($embedurl){
function oembed_format_object($j){
- $embedurl = $j->embedurl;
+ $embedurl = $j['embedurl'];
// logger('format: ' . print_r($j,true));
- $jhtml = oembed_iframe($j->embedurl,(isset($j->width) ? $j->width : null), (isset($j->height) ? $j->height : null));
+ $jhtml = oembed_iframe($j['embedurl'],(isset($j['width']) ? $j['width'] : null), (isset($j['height']) ? $j['height'] : null));
- $ret="<span class='oembed ".$j->type."'>";
- switch ($j->type) {
+ $ret="<span class='oembed " . $j['type'] . "'>";
+ switch ($j['type']) {
case "video": {
- if (isset($j->thumbnail_url)) {
- $tw = (isset($j->thumbnail_width)) ? $j->thumbnail_width:200;
- $th = (isset($j->thumbnail_height)) ? $j->thumbnail_height:180;
+ if (isset($j['thumbnail_url'])) {
+ $tw = (isset($j['thumbnail_width'])) ? $j['thumbnail_width'] : 200;
+ $th = (isset($j['thumbnail_height'])) ? $j['thumbnail_height'] : 180;
$tr = $tw/$th;
$th=120; $tw = $th*$tr;
$tpl=get_markup_template('oembed_video.tpl');
if(strstr($embedurl,'youtu') && strstr(z_root(),'https:')) {
$embedurl = str_replace('http:','https:',$embedurl);
- $j->thumbnail_url = str_replace('http:','https:', $j->thumbnail_url);
+ $j['thumbnail_url'] = str_replace('http:','https:', $j['thumbnail_url']);
$jhtml = str_replace('http:','https:', $jhtml);
- $j->html = str_replace('http:','https:', $j->html);
+ $j['html'] = str_replace('http:','https:', $j['html']);
}
$ret.=replace_macros($tpl, array(
@@ -273,7 +285,7 @@ function oembed_format_object($j){
'$escapedhtml'=>base64_encode($jhtml),
'$tw'=>$tw,
'$th'=>$th,
- '$turl'=>$j->thumbnail_url,
+ '$turl'=> $j['thumbnail_url'],
));
} else {
@@ -282,19 +294,19 @@ function oembed_format_object($j){
$ret.="<br>";
}; break;
case "photo": {
- $ret.= "<img width='".$j->width."' src='".$j->url."'>";
+ $ret.= "<img width='".$j['width']."' src='".$j['url']."'>";
$ret.="<br>";
}; break;
case "link": {
- if($j->thumbnail_url) {
+ if($j['thumbnail_url']) {
if(is_matrix_url($embedurl)) {
$embedurl = zid($embedurl);
- $j->thumbnail_url = zid($j->thumbnail_url);
+ $j['thumbnail_url'] = zid($j['thumbnail_url']);
}
- $ret = '<a href="' . $embedurl . '" ><img src="' . $j->thumbnail_url . '" alt="thumbnail" /></a><br /><br />';
+ $ret = '<a href="' . $embedurl . '" ><img src="' . $j['thumbnail_url'] . '" alt="thumbnail" /></a><br /><br />';
}
- //$ret = "<a href='".$embedurl."'>".$j->title."</a>";
+ //$ret = "<a href='".$embedurl."'>".$j['title']."</a>";
}; break;
case "rich": {
// not so safe..
@@ -303,12 +315,12 @@ function oembed_format_object($j){
}
// add link to source if not present in "rich" type
- if ( $j->type!='rich' || !strpos($j->html,$embedurl) ){
- $embedlink = (isset($j->title))?$j->title:$embedurl;
+ if ( $j['type'] != 'rich' || !strpos($j['html'],$embedurl) ){
+ $embedlink = (isset($j['title']))?$j['title'] : $embedurl;
$ret .= '<br />' . "<a href='$embedurl' rel='oembed'>$embedlink</a>";
$ret .= "<br />";
- if (isset($j->author_name)) $ret.=" by ".$j->author_name;
- if (isset($j->provider_name)) $ret.=" on ".$j->provider_name;
+ if (isset($j['author_name'])) $ret .= t(' by ') . $j['author_name'];
+ if (isset($j['provider_name'])) $ret .= t(' on ') . $j['provider_name'];
} else {
// add <a> for html2bbcode conversion
$ret .= "<br /><a href='$embedurl' rel='oembed'>$embedurl</a>";
diff --git a/include/permissions.php b/include/permissions.php
index 637193973..d21b45550 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -6,8 +6,14 @@ require_once('include/security.php');
* @file include/permissions.php
*
* This file conntains functions to check and work with permissions.
+ *
+ * Most of this file is obsolete and has been superceded by extensible permissions in v1.12; it is left here
+ * for reference and because we haven't yet checked that all functions have been replaced and are available
+ * elsewhere (typically Zotlabs/Access/*).
*/
+
+
/**
* @brief Return an array with all available permissions.
*
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 6de75d497..9b6d38cc1 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -328,6 +328,7 @@ abstract class photo_driver {
$p['photo_usage'] = intval($arr['photo_usage']);
$p['os_storage'] = intval($arr['os_storage']);
$p['os_path'] = $arr['os_path'];
+ $p['display_path'] = (($arr['display_path']) ? $arr['display_path'] : '');
if(! intval($p['imgscale']))
logger('save: ' . print_r($arr,true), LOGGER_DATA);
@@ -358,6 +359,8 @@ abstract class photo_driver {
`photo_usage` = %d,
`title` = '%s',
`description` = '%s',
+ `os_path` = '%s',
+ `display_path` = '%s',
`allow_cid` = '%s',
`allow_gid` = '%s',
`deny_cid` = '%s',
@@ -382,6 +385,8 @@ abstract class photo_driver {
intval($p['photo_usage']),
dbesc($p['title']),
dbesc($p['description']),
+ dbesc($p['os_path']),
+ dbesc($p['display_path']),
dbesc($p['allow_cid']),
dbesc($p['allow_gid']),
dbesc($p['deny_cid']),
@@ -391,8 +396,8 @@ abstract class photo_driver {
}
else {
$r = q("INSERT INTO `photo`
- ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, mimetype, `album`, `height`, `width`, `content`, `os_storage`, `filesize`, `imgscale`, `photo_usage`, `title`, `description`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s' )",
+ ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, mimetype, `album`, `height`, `width`, `content`, `os_storage`, `filesize`, `imgscale`, `photo_usage`, `title`, `description`, `os_path`, `display_path`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
+ VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
intval($p['aid']),
intval($p['uid']),
dbesc($p['xchan']),
@@ -411,6 +416,8 @@ abstract class photo_driver {
intval($p['photo_usage']),
dbesc($p['title']),
dbesc($p['description']),
+ dbesc($p['os_path']),
+ dbesc($p['display_path']),
dbesc($p['allow_cid']),
dbesc($p['allow_gid']),
dbesc($p['deny_cid']),
@@ -420,6 +427,9 @@ abstract class photo_driver {
return $r;
}
+
+ // should be obsolete now
+
public function store($aid, $uid, $xchan, $rid, $filename, $album, $scale, $usage = PHOTO_NORMAL, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') {
$x = q("select id from photo where `resource_id` = '%s' and uid = %d and `xchan` = '%s' and `imgscale` = %d limit 1",
diff --git a/include/photos.php b/include/photos.php
index bd25fe8b7..a3018816c 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -588,6 +588,8 @@ function photos_album_rename($channel_id, $oldname, $newname) {
);
}
+
+
/**
* @brief
*
diff --git a/include/plugin.php b/include/plugin.php
index cb206d944..663d17959 100755
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -404,6 +404,18 @@ function check_plugin_versions($info) {
return false;
}
}
+ if(array_key_exists('serverroles',$info)) {
+ $role = \Zotlabs\Lib\System::get_server_role();
+ if(! (
+ stristr($info['serverroles'],'*')
+ || stristr($info['serverroles'],'any')
+ || stristr($info['serverroles'],$role))) {
+ logger('serverrole limit: ' . $info['name'],LOGGER_NORMAL,LOG_WARNING);
+ return false;
+
+ }
+ }
+
if(array_key_exists('requires',$info)) {
$arr = explode(',',$info['requires']);
diff --git a/include/security.php b/include/security.php
index 83bf51bc0..9b508d339 100644
--- a/include/security.php
+++ b/include/security.php
@@ -265,7 +265,7 @@ function change_channel($change_channel) {
);
if($x) {
$_SESSION['my_url'] = $x[0]['xchan_url'];
- $_SESSION['my_address'] = $r[0]['channel_address'] . '@' . App::get_hostname();
+ $_SESSION['my_address'] = channel_reddress($r[0]);
App::set_observer($x[0]);
App::set_perms(get_all_perms(local_channel(), $hash));
diff --git a/include/text.php b/include/text.php
index ac210b336..9c4a4a5c5 100644
--- a/include/text.php
+++ b/include/text.php
@@ -138,31 +138,74 @@ function purify_html($s, $allow_position = false) {
$def = $config->getHTMLDefinition(true);
//data- attributes used by the foundation library
- $def->info_global_attr['data-options'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-magellan-expedition'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-magellan-destination'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-magellan-arrival'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-offcanvas'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-topbar'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-orbit'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-orbit-slide-number'] = new HTMLPurifier_AttrDef_Text;
+
+ // f6 navigation
+
+ //dropdown menu
+ $def->info_global_attr['data-dropdown-menu'] = new HTMLPurifier_AttrDef_Text;
+ //drilldown menu
+ $def->info_global_attr['data-drilldown'] = new HTMLPurifier_AttrDef_Text;
+ //accordion menu
+ $def->info_global_attr['data-accordion-menu'] = new HTMLPurifier_AttrDef_Text;
+ //responsive navigation
+ $def->info_global_attr['data-responsive-menu'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-responsive-toggle'] = new HTMLPurifier_AttrDef_Text;
+ //magellan
+ $def->info_global_attr['data-magellan'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-magellan-target'] = new HTMLPurifier_AttrDef_Text;
+
+ // f6 containers
+
+ //accordion
+ $def->info_global_attr['data-accordion'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-accordion-item'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-tab-content'] = new HTMLPurifier_AttrDef_Text;
+ //dropdown
$def->info_global_attr['data-dropdown'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-dropdown-content'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-reveal-id'] = new HTMLPurifier_AttrDef_Text;
+ //off-canvas
+ $def->info_global_attr['data-off-canvas-wrapper'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-off-canvas'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-off-canvas-content'] = new HTMLPurifier_AttrDef_Text;
+ //reveal
$def->info_global_attr['data-reveal'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-alert'] = new HTMLPurifier_AttrDef_Text;
+ //tabs
+ $def->info_global_attr['data-tabs'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-tabs-content'] = new HTMLPurifier_AttrDef_Text;
+
+ // f6 media
+
+ //orbit
+ $def->info_global_attr['data-orbit'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-slide'] = new HTMLPurifier_AttrDef_Text;
+ //tooltip
$def->info_global_attr['data-tooltip'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-joyride'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-id'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-text'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-class'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-prev-tex'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-button'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-accordion'] = new HTMLPurifier_AttrDef_Text;
- $def->info_global_attr['data-tab'] = new HTMLPurifier_AttrDef_Text;
+
+ // f6 plugins
+
+ //abide - the use is pointless since we can't do anything with forms
+
+ //equalizer
$def->info_global_attr['data-equalizer'] = new HTMLPurifier_AttrDef_Text;
$def->info_global_attr['data-equalizer-watch'] = new HTMLPurifier_AttrDef_Text;
+ //interchange - potentially dangerous since it can load content
+
+ //toggler
+ $def->info_global_attr['data-toggler'] = new HTMLPurifier_AttrDef_Text;
+
+ //sticky
+ $def->info_global_attr['data-sticky'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-sticky-container'] = new HTMLPurifier_AttrDef_Text;
+
+ // f6 common
+
+ $def->info_global_attr['data-options'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-toggle'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-close'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-open'] = new HTMLPurifier_AttrDef_Text;
+ $def->info_global_attr['data-position'] = new HTMLPurifier_AttrDef_Text;
+
+
//data- attributes used by the bootstrap library
$def->info_global_attr['data-dismiss'] = new HTMLPurifier_AttrDef_Text;
$def->info_global_attr['data-target'] = new HTMLPurifier_AttrDef_Text;
@@ -191,12 +234,15 @@ function purify_html($s, $allow_position = false) {
$def->info_global_attr['data-offset-bottom'] = new HTMLPurifier_AttrDef_Text;
//some html5 elements
+ //Block
$def->addElement('section', 'Block', 'Flow', 'Common');
$def->addElement('nav', 'Block', 'Flow', 'Common');
$def->addElement('article', 'Block', 'Flow', 'Common');
$def->addElement('aside', 'Block', 'Flow', 'Common');
$def->addElement('header', 'Block', 'Flow', 'Common');
$def->addElement('footer', 'Block', 'Flow', 'Common');
+ //Inline
+ $def->addElement('button', 'Inline', 'Inline', 'Common');
if($allow_position) {
@@ -936,7 +982,7 @@ function searchbox($s,$id='search-box',$url='/search',$save = false) {
'$action_url' => z_root() . '/' . $url,
'$search_label' => t('Search'),
'$save_label' => t('Save'),
- '$savedsearch' => feature_enabled(local_channel(),'savedsearch')
+ '$savedsearch' => ($save && feature_enabled(local_channel(),'savedsearch'))
));
}
@@ -2267,11 +2313,11 @@ function design_tools() {
}
/**
- * @brief Creates website import tools menu
+ * @brief Creates website portation tools menu
*
* @return string
*/
-function website_import_tools() {
+function website_portation_tools() {
$channel = App::get_channel();
$sys = false;
@@ -2282,7 +2328,7 @@ function website_import_tools() {
$sys = true;
}
- return replace_macros(get_markup_template('website_import_tools.tpl'), array(
+ return replace_macros(get_markup_template('website_portation_tools.tpl'), array(
'$title' => t('Import'),
'$import_label' => t('Import website...'),
'$import_placeholder' => t('Select folder to import'),
@@ -2290,7 +2336,15 @@ function website_import_tools() {
'$file_import_text' => t('Import from cloud files:'),
'$desc' => t('/cloud/channel/path/to/folder'),
'$hint' => t('Enter path to website files'),
- '$select' => t('Select folder'),
+ '$select' => t('Select folder'),
+ '$export_label' => t('Export website...'),
+ '$file_download_text' => t('Export to a zip file'),
+ '$filename_desc' => t('website.zip'),
+ '$filename_hint' => t('Enter a name for the zip file.'),
+ '$cloud_export_text' => t('Export to cloud files'),
+ '$cloud_export_desc' => t('/path/to/export/folder'),
+ '$cloud_export_hint' => t('Enter a path to a cloud files destination.'),
+ '$cloud_export_select' => t('Specify folder'),
));
}
@@ -2975,3 +3029,38 @@ function text_highlight($s,$lang) {
return('<code>' . $o . '</code>');
}
+// function to convert multi-dimensional array to xml
+// create new instance of simplexml
+
+// $xml = new SimpleXMLElement('<root/>');
+
+// function callback
+// array2XML($xml, $my_array);
+
+// save as xml file
+// echo (($xml->asXML('data.xml')) ? 'Your XML file has been generated successfully!' : 'Error generating XML file!');
+
+function arrtoxml($root_elem,$arr) {
+ $xml = new SimpleXMLElement('<' . $root_elem . '/>');
+ array2XML($xml,$arr);
+ return $xml->asXML();
+}
+
+function array2XML($obj, $array)
+{
+ foreach ($array as $key => $value)
+ {
+ if(is_numeric($key))
+ $key = 'item' . $key;
+
+ if (is_array($value))
+ {
+ $node = $obj->addChild($key);
+ array2XML($node, $value);
+ }
+ else
+ {
+ $obj->addChild($key, htmlspecialchars($value));
+ }
+ }
+}
diff --git a/include/widgets.php b/include/widgets.php
index 68db74703..2e1e58717 100644
--- a/include/widgets.php
+++ b/include/widgets.php
@@ -209,7 +209,9 @@ function widget_savedsearch($arr) {
if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch')))
return '';
- $search = ((x($_GET,'search')) ? $_GET['search'] : '');
+ $search = ((x($_GET,'netsearch')) ? $_GET['netsearch'] : '');
+ if(! $search)
+ $search = ((x($_GET,'search')) ? $_GET['search'] : '');
if(x($_GET,'searchsave') && $search) {
$r = q("select * from `term` where `uid` = %d and `ttype` = %d and `term` = '%s' limit 1",
@@ -287,6 +289,40 @@ function widget_savedsearch($arr) {
return $o;
}
+function widget_sitesearch($arr) {
+
+ $search = ((x($_GET,'search')) ? $_GET['search'] : '');
+
+ $srchurl = App::$query_string;
+
+ $srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
+
+
+ $hasq = ((strpos($srchurl,'?') !== false) ? true : false);
+ $hasamp = ((strpos($srchurl,'&') !== false) ? true : false);
+
+ if(($hasamp) && (! $hasq))
+ $srchurl = substr($srchurl,0,strpos($srchurl,'&')) . '?f=&' . substr($srchurl,strpos($srchurl,'&')+1);
+
+ $o = '';
+
+ $saved = array();
+
+ $tpl = get_markup_template("sitesearch.tpl");
+ $o = replace_macros($tpl, array(
+ '$title' => t('Search'),
+ '$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), false),
+ '$saved' => $saved,
+ ));
+
+ return $o;
+}
+
+
+
+
function widget_filer($arr) {
if(! local_channel())
@@ -566,7 +602,7 @@ function widget_settings_menu($arr) {
);
- if(get_features()) {
+ if(get_account_techlevel() > 0 && get_features()) {
$tabs[] = array(
'label' => t('Additional features'),
'url' => z_root().'/settings/features',
@@ -594,14 +630,11 @@ function widget_settings_menu($arr) {
);
}
- // IF can go away when UNO export and import is fully functional
- if(get_config('system','server_role') !== 'basic') {
- $tabs[] = array(
- 'label' => t('Export channel'),
- 'url' => z_root() . '/uexport',
- 'selected' => ''
- );
- }
+ $tabs[] = array(
+ 'label' => t('Export channel'),
+ 'url' => z_root() . '/uexport',
+ 'selected' => ''
+ );
$tabs[] = array(
'label' => t('Connected apps'),
@@ -609,7 +642,7 @@ function widget_settings_menu($arr) {
'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
);
- if(get_config('system','server_role') !== 'basic') {
+ if(get_account_techlevel() > 2) {
$tabs[] = array(
'label' => t('Guest Access Tokens'),
'url' => z_root() . '/settings/tokens',
@@ -779,7 +812,7 @@ function widget_design_tools($arr) {
return design_tools();
}
-function widget_website_import_tools($arr) {
+function widget_website_portation_tools($arr) {
// mod menu doesn't load a profile. For any modules which load a profile, check it.
// otherwise local_channel() is sufficient for permissions.
@@ -791,7 +824,7 @@ function widget_website_import_tools($arr) {
if(! local_channel())
return '';
- return website_import_tools();
+ return website_portation_tools();
}
function widget_findpeople($arr) {
@@ -963,6 +996,14 @@ function widget_suggestedchats($arr) {
if(! feature_enabled(App::$profile['profile_uid'],'ajaxchat'))
return '';
+ // There are reports that this tool does not ever remove chatrooms on dead sites,
+ // and also will happily link to private chats which you cannot enter.
+ // For those reasons, it will be disabled until somebody decides it's worth
+ // fixing and comes up with a plan for doing so.
+
+ return '';
+
+
// probably should restrict this to your friends, but then the widget will only work
// if you are logged in locally.
@@ -1286,8 +1327,8 @@ function widget_random_block($arr) {
function widget_rating($arr) {
- $poco_rating = get_config('system','poco_rating_enable');
- if((! $poco_rating) && ($poco_rating !== false)) {
+ $rating_enabled = get_config('system','rating_enabled');
+ if(! $rating_enabled) {
return;
}
@@ -1459,13 +1500,42 @@ function widget_tasklist($arr) {
function widget_helpindex($arr) {
- $o .= '<div class="widget">' . '<h3>' . t('Documentation') . '</h3>';
- $o .= '<ul class="nav nav-pills nav-stacked">';
- $o .= '<li><a href="help/general">' . t('Project/Site Information') . '</a></li>';
- $o .= '<li><a href="help/members">' . t('For Members') . '</a></li>';
- $o .= '<li><a href="help/admins">' . t('For Administrators') . '</a></li>';
- $o .= '<li><a href="help/develop">' . t('For Developers') . '</a></li>';
- $o .= '</ul></div>';
+
+ $o .= '<div class="widget">';
+ $o .= '<h3>' . t('Documentation') . '</h3>';
+
+ $level_0 = get_help_content('sitetoc');
+ if(! $level_0)
+ $level_0 = get_help_content('toc');
+
+ $level_0 = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills nav-stacked">',$level_0);
+
+ $levels = array();
+
+
+ if(argc() > 2) {
+ $path = '';
+ for($x = 1; $x < argc(); $x ++) {
+ $path .= argv($x) . '/';
+ $y = get_help_content($path . 'sitetoc');
+ if(! $y)
+ $y = get_help_content($path . 'toc');
+ if($y)
+ $levels[] = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills nav-stacked">',$y);
+ }
+ }
+
+ if($level_0)
+ $o .= $level_0;
+ if($levels) {
+ foreach($levels as $l) {
+ $o .= '<br /><br />';
+ $o .= $l;
+ }
+ }
+
+ $o .= '</div>';
+
return $o;
}
diff --git a/include/zot.php b/include/zot.php
index c3c924113..1df600abd 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -1593,7 +1593,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
}
$channel = $r[0];
- $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . App::get_hostname() . '>');
+ $DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
/* blacklisted channels get a permission denied, no special message to tip them off */
@@ -2082,7 +2082,7 @@ function process_mail_delivery($sender, $arr, $deliveries) {
}
$channel = $r[0];
- $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . App::get_hostname() . '>');
+ $DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
/* blacklisted channels get a permission denied, no special message to tip them off */
@@ -2844,6 +2844,7 @@ function import_site($arr, $pubkey) {
$site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false);
$site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false);
$site_project = htmlspecialchars($arr['project'],ENT_COMPAT,'UTF-8',false);
+ $site_version = ((array_key_exists('version',$arr)) ? htmlspecialchars($arr['version'],ENT_COMPAT,'UTF-8',false) : '');
// You can have one and only one primary directory per realm.
// Downgrade any others claiming to be primary. As they have
@@ -2863,14 +2864,16 @@ function import_site($arr, $pubkey) {
|| ($siterecord['site_location'] != $site_location)
|| ($siterecord['site_register'] != $register_policy)
|| ($siterecord['site_project'] != $site_project)
- || ($siterecord['site_realm'] != $site_realm)) {
+ || ($siterecord['site_realm'] != $site_realm)
+ || ($siterecord['site_version'] != $site_version) ) {
+
$update = true;
// 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'
+ $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'
where site_url = '%s'",
dbesc($site_location),
intval($site_directory),
@@ -2882,6 +2885,7 @@ function import_site($arr, $pubkey) {
dbesc($site_realm),
intval(SITE_TYPE_ZOT),
dbesc($site_project),
+ dbesc($site_version),
dbesc($url)
);
if(! $r) {
@@ -2899,8 +2903,8 @@ function import_site($arr, $pubkey) {
else {
$update = true;
- $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project )
- values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s' )",
+ $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project, site_version )
+ values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s' )",
dbesc($site_location),
dbesc($url),
intval($access_policy),
@@ -2911,7 +2915,8 @@ function import_site($arr, $pubkey) {
dbesc($sellpage),
dbesc($site_realm),
intval(SITE_TYPE_ZOT),
- dbesc($site_project)
+ dbesc($site_project),
+ dbesc($site_version)
);
if(! $r) {
logger('import_site: record create failed. ' . print_r($arr,true));
@@ -3159,7 +3164,10 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) {
- translate_channel_perms_inbound($arr['channel']);
+ $remote_channel = $arr['channel'];
+ $remote_channel['channel_id'] = $channel['channel_id'];
+ translate_channel_perms_inbound($remote_channel);
+
if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) {
// These flags cannot be sync'd.
@@ -3527,7 +3535,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('item',$arr) && is_array($arr['item'][0])) {
$DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],$arr['item'][0]['message_id'],'channel sync processed');
- $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . App::get_hostname() . '>');
+ $DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
}
else
$DR = new Zotlabs\Zot\DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
@@ -3638,8 +3646,7 @@ function zot_reply_message_request($data) {
if ($messages) {
$env_recips = null;
- $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0
- group by hubloc_sitekey",
+ $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0",
dbesc($sender_hash)
);
if (! $r) {
@@ -3787,18 +3794,12 @@ function zotinfo($arr) {
}
elseif($ztarget_hash) {
// check if it has characteristics of a public forum based on custom permissions.
- $t = q("select * from abconfig where abconfig.cat = 'my_perms' and abconfig.chan = %d and abconfig.xchan = '%s' and abconfig.k in ('tag_deliver', 'send_stream') ",
- intval($e['channel_id']),
- dbesc($ztarget_hash)
- );
-
- $ch = 0;
-
- if($t) {
- foreach($t as $tt) {
- if($tt['k'] == 'tag_deliver' && $tt['v'] == 1)
+ $m = \Zotlabs\Access\Permissions::FilledAutoperms($e['channel_id']);
+ if($m) {
+ foreach($m as $k => $v) {
+ if($k == 'tag_deliver' && intval($v) == 1)
$ch ++;
- if($tt['k'] == 'send_stream' && $tt['v'] == 0)
+ if($k == 'send_stream' && intval($v) == 0)
$ch ++;
}
if($ch == 2)
@@ -3964,9 +3965,6 @@ function zotinfo($arr) {
require_once('include/channel.php');
$ret['site']['channels'] = channel_total();
-
- $ret['site']['version'] = Zotlabs\Lib\System::get_platform_name() . ' ' . STD_VERSION . '[' . DB_UPDATE_VERSION . ']';
-
$ret['site']['admin'] = get_config('system','admin_email');
$visible_plugins = array();
@@ -3984,6 +3982,7 @@ function zotinfo($arr) {
$ret['site']['location'] = get_config('system','site_location');
$ret['site']['realm'] = get_directory_realm();
$ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role();
+ $ret['site']['version'] = Zotlabs\Lib\System::get_project_version();
}
@@ -4035,7 +4034,7 @@ function check_zotinfo($channel,$locations,&$ret) {
dbesc($channel['channel_guid']),
dbesc($channel['channel_guid_sig']),
dbesc($channel['channel_hash']),
- dbesc($channel['channel_address'] . '@' . App::get_hostname()),
+ dbesc(channel_reddress($channel)),
intval(1),
dbesc(z_root()),
dbesc(base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))),