aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/PermissionDescription.php170
-rw-r--r--include/account.php18
-rw-r--r--include/acl_selectors.php4
-rw-r--r--include/api.php17
-rw-r--r--include/api_auth.php16
-rw-r--r--include/attach.php20
-rw-r--r--include/auth.php143
-rw-r--r--include/bb2diaspora.php4
-rw-r--r--include/bbcode.php34
-rw-r--r--include/cache.php44
-rw-r--r--include/channel.php94
-rw-r--r--include/config.php16
-rw-r--r--include/connections.php16
-rw-r--r--include/conversation.php35
-rw-r--r--include/datetime.php6
-rwxr-xr-xinclude/dba/dba_driver.php5
-rw-r--r--include/event.php4
-rw-r--r--include/features.php1
-rw-r--r--include/feedutils.php4
-rw-r--r--include/group.php18
-rw-r--r--include/help.php17
-rw-r--r--include/import.php69
-rwxr-xr-xinclude/items.php114
-rw-r--r--include/js_strings.php8
-rw-r--r--include/nav.php19
-rw-r--r--include/network.php76
-rw-r--r--include/oauth.php2
-rwxr-xr-xinclude/oembed.php6
-rw-r--r--include/page_widgets.php11
-rw-r--r--include/photos.php79
-rwxr-xr-xinclude/plugin.php68
-rw-r--r--include/reddav.php299
-rw-r--r--include/security.php55
-rw-r--r--include/spam.php35
-rw-r--r--include/taxonomy.php2
-rw-r--r--include/text.php123
-rw-r--r--include/widgets.php63
-rw-r--r--include/wiki.php198
-rw-r--r--include/zot.php29
39 files changed, 990 insertions, 952 deletions
diff --git a/include/PermissionDescription.php b/include/PermissionDescription.php
deleted file mode 100644
index 1f7799406..000000000
--- a/include/PermissionDescription.php
+++ /dev/null
@@ -1,170 +0,0 @@
-<?php
-
-if(class_exists('PermissionDescription')) return;
-
-require_once("include/permissions.php");
-require_once("include/language.php");
-require_once("include/text.php");
-
-
-/**
- * Encapsulates information the ACL dialog requires to describe
- * permission settings for an item with an empty ACL.
- * i.e the caption, icon, and tooltip for the no-ACL option in the ACL dialog.
- */
-class PermissionDescription {
-
- private $global_perm;
- private $channel_perm;
- private $fallback_description;
-
- /**
- * Constructor is private.
- * Use static methods fromGlobalPermission(), fromStandalonePermission(), or fromDescription()
- * to create instances.
- */
- private function __construct($global_perm, $channel_perm, $description = '') {
-
- $this->global_perm = $global_perm;
- $this->channel_perm = $channel_perm;
-
- $this->fallback_description = ($description == '') ? t('Visible to your default audience') : $description;
- }
-
- /**
- * If the interpretation of an empty ACL can't be summarised with a global default permission
- * or a specific permission setting then use this method and describe what it means instead.
- * Remember to localize the description first.
- *
- * @param string $description - the localized caption for the no-ACL option in the ACL dialog.
- * @return a new instance of PermissionDescription
- */
- public static function fromDescription($description) {
- return new PermissionDescription('', 0x80000, $description);
- }
-
-
- /**
- * Use this method only if the interpretation of an empty ACL doesn't fall back to a global
- * default permission. You should pass one of the constants from boot.php - PERMS_PUBLIC,
- * PERMS_NETWORK etc.
- *
- * @param integer $perm - a single enumerated constant permission - PERMS_PUBLIC, PERMS_NETWORK etc.
- * @return a new instance of PermissionDescription
- */
- public static function fromStandalonePermission($perm) {
-
- $result = new PermissionDescription('', $perm);
-
- $checkPerm = $this->get_permission_description();
- if ($checkPerm == $this->fallback_description) {
- $result = null;
- logger('null PermissionDescription from unknown standalone permission: ' . $perm ,LOGGER_DEBUG, LOG_ERROR);
- }
-
- return $result;
- }
-
- /**
- * This is the preferred way to create a PermissionDescription, as it provides the most details.
- * Use this method if you know an empty ACL will result in one of the global default permissions
- * being used, such as channel_r_stream (for which you would pass 'view_stream').
- *
- * @param string $permname - a key for the global perms array from get_perms() in permissions.php,
- * e.g. 'view_stream', 'view_profile', etc.
- * @return a new instance of PermissionDescription
- */
- public static function fromGlobalPermission($permname) {
-
- $result = null;
-
- $global_perms = get_perms();
-
- if (array_key_exists($permname, $global_perms)) {
-
- $permDetails = $global_perms[$permname];
-
- // It should be OK to always just read the permissions from App::$channel
- //
- // App::$profile is a union of channel and profile fields.
- // The distinction is basically that App::$profile is pointing to the resource
- // being observed. App::$channel is referring to the current logged-in channel
- // member (if this is a local channel) e.g. the observer. We only show the ACL
- // widget to the page owner (observer and observed are the same) so in that case
- // I believe either may be safely used here.
- $channelPerm = \App::$channel[$permDetails[0]];
- $result = new PermissionDescription($permDetails[1], $channelPerm);
- } else {
- // The acl dialog can handle null arguments, but it shouldn't happen
- logger('null PermissionDescription from unknown global permission: ' . $permname ,LOGGER_DEBUG, LOG_ERROR);
- }
- return $result;
- }
-
-
- /**
- * Gets a localized description of the permission, or a generic message if the permission
- * is unknown.
- *
- * @return string description
- */
- public function get_permission_description() {
-
- switch($this->channel_perm) {
-
- case 0: return t('Only me');
- case PERMS_PUBLIC: return t('Public');
- case PERMS_NETWORK: return t('Anybody in the $Projectname network');
- case PERMS_SITE: return sprintf(t('Any account on %s'), \App::get_hostname());
- case PERMS_CONTACTS: return t('Any of my connections');
- case PERMS_SPECIFIC: return t('Only connections I specifically allow');
- case PERMS_AUTHED: return t('Anybody authenticated (could include visitors from other networks)');
- case PERMS_PENDING: return t('Any connections including those who haven\'t yet been approved');
- default: return $this->fallback_description;
- }
- }
-
- /**
- * Returns an icon css class name if an appropriate one is available, e.g. "fa-globe" for Public,
- * otherwise returns empty string.
- *
- * @return string icon css class name (often FontAwesome)
- */
- public function get_permission_icon() {
-
- switch($this->channel_perm) {
-
- case 0:/* only me */ return 'fa-eye-slash';
- case PERMS_PUBLIC: return 'fa-globe';
- case PERMS_NETWORK: return 'fa-share-alt-square'; // fa-share-alt-square is very similiar to the hubzilla logo, but we should create our own logo class to use
- case PERMS_SITE: return 'fa-sitemap';
- case PERMS_CONTACTS: return 'fa-group';
- case PERMS_SPECIFIC: return 'fa-list';
- case PERMS_AUTHED: return '';
- case PERMS_PENDING: return '';
- default: return '';
- }
- }
-
-
- /**
- * Returns a localized description of where the permission came from, if this is known.
- * If it's not know, or if the permission is standalone and didn't come from a default
- * permission setting, then empty string is returned.
- *
- * @return string description or empty string
- */
- public function get_permission_origin_description() {
-
- switch($this->global_perm) {
-
- case PERMS_R_STREAM: return t('This is your default setting for the audience of your normal stream, and posts.');
- case PERMS_R_PROFILE: return t('This is your default setting for who can view your default channel profile');
- case PERMS_R_ABOOK: return t('This is your default setting for who can view your connections');
- case PERMS_R_STORAGE: return t('This is your default setting for who can view your file storage and photos');
- case PERMS_R_PAGES: return t('This is your default setting for the audience of your webpages');
- default: return '';
- }
- }
-
-}
diff --git a/include/account.php b/include/account.php
index caf12878e..142ad1bea 100644
--- a/include/account.php
+++ b/include/account.php
@@ -499,11 +499,27 @@ function account_approve($hash) {
intval($register[0]['uid'])
);
+ // get a fresh copy after we've modified it.
+
+ $account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
+ intval($register[0]['uid'])
+ );
+
+ if(! $account)
+ return $ret;
+
+
+
if(get_config('system','auto_channel_create') || UNO)
auto_channel_create($register[0]['uid']);
+ else {
+ $_SESSION['login_return_url'] = 'new_channel';
+ authenticate_success($account[0],null,true,true,false,true);
+ }
+
- info( t('Account verified. Please login.') . EOL );
+ // info( t('Account verified. Please login.') . EOL );
return true;
}
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 89d054e3b..148c67a6c 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -7,8 +7,6 @@
* @package acl_selectors
*/
-require_once("include/PermissionDescription.php");
-
function group_select($selname,$selclass,$preselected = false,$size = 4) {
$o = '';
@@ -231,7 +229,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
if(! $emptyACL_description) {
$showall_caption = t('Visible to your default audience');
- } else if (is_a($emptyACL_description, 'PermissionDescription')) {
+ } else if (is_a($emptyACL_description, '\\Zotlabs\\Lib\\PermissionDescription')) {
$showall_caption = $emptyACL_description->get_permission_description();
$showall_origin = (($role === 'custom') ? $emptyACL_description->get_permission_origin_description() : '');
$showall_icon = $emptyACL_description->get_permission_icon();
diff --git a/include/api.php b/include/api.php
index be525f7e9..df6aba957 100644
--- a/include/api.php
+++ b/include/api.php
@@ -839,7 +839,7 @@ require_once('include/api_auth.php');
$_REQUEST['parent_mid'] = $parent;
if($_REQUEST['namespace'] && $parent) {
- $x = q("select iid from item_id where service = '%s' and sid = '%s' limit 1",
+ $x = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1",
dbesc($_REQUEST['namespace']),
dbesc($parent)
);
@@ -967,20 +967,10 @@ require_once('include/api_auth.php');
$ret = array();
$tmp = array();
- $str = '';
foreach($i as $ii) {
$tmp[] = encode_item($ii,true);
- if($str)
- $str .= ',';
- $str .= $ii['id'];
}
$ret['item'] = $tmp;
- if($str) {
- $r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item.id in ( $str ) ");
-
- if($r)
- $ret['item_id'] = $r;
- }
json_return_and_die($ret);
}
@@ -1462,7 +1452,8 @@ require_once('include/api_auth.php');
}
else {
if($_REQUEST['namespace'] && $_REQUEST['remote_id']) {
- $r = q("select * from item_id where service = '%s' and sid = '%s' and uid = %d limit 1",
+ $r = q("select * from iconfig left join item on iconfig.iid = item.id
+ where cat = 'system' and k = '%s' and v = '%s' and item.uid = %d limit 1",
dbesc($_REQUEST['namespace']),
dbesc($_REQUEST['remote_id']),
intval($user_info['uid'])
@@ -1472,7 +1463,7 @@ require_once('include/api_auth.php');
$id = $r[0]['iid'];
}
if($_REQUEST['namespace'] && $_REQUEST['comment_id']) {
- $r = q("select * from item_id left join item on item.id = item_id.iid where service = '%s' and sid = '%s' and uid = %d and item.id != item.parent limit 1",
+ $r = q("select * from iconfig left join item on item.id = iconfig.iid where cat = 'system' and k = '%s' and v = '%s' and uid = %d and item.id != item.parent limit 1",
dbesc($_REQUEST['namespace']),
dbesc($_REQUEST['comment_id']),
intval($user_info['uid'])
diff --git a/include/api_auth.php b/include/api_auth.php
index dc8492b20..89882f821 100644
--- a/include/api_auth.php
+++ b/include/api_auth.php
@@ -59,21 +59,13 @@ function api_login(&$a){
if(isset($_SERVER['PHP_AUTH_USER'])) {
$channel_login = 0;
$record = account_verify_password($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
- if(! $record) {
- $r = q("select * from channel left join account on account.account_id = channel.channel_account_id
- where channel.channel_address = '%s' limit 1",
- dbesc($_SERVER['PHP_AUTH_USER'])
- );
- if ($r) {
- $record = account_verify_password($r[0]['account_email'],$_SERVER['PHP_AUTH_PW']);
- if($record)
- $channel_login = $r[0]['channel_id'];
- }
+ if($record && $record['channel']) {
+ $channel_login = $record['channel']['channel_id'];
}
}
- if($record) {
- authenticate_success($record);
+ if($record['account']) {
+ authenticate_success($record['account']);
if($channel_login)
change_channel($channel_login);
diff --git a/include/attach.php b/include/attach.php
index 78efde51f..b3ddfee88 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -423,6 +423,8 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$observer = array();
+ $dosync = ((array_key_exists('nosync',$arr) && $arr['nosync']) ? 0 : 1);
+
if($observer_hash) {
$x = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_hash)
@@ -616,7 +618,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
);
if($r) {
$overwrite = get_pconfig($channel_id,'system','overwrite_dup_files');
- if($overwrite) {
+ if(($overwrite) || ($options === 'import')) {
$options = 'replace';
$existing_id = $x[0]['id'];
$existing_size = intval($x[0]['filesize']);
@@ -800,7 +802,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if($is_photo) {
- $args = array( 'source' => $source, 'visible' => $visible, 'resource_id' => $hash, 'album' => basename($pathname), 'os_path' => $os_basepath . $os_relpath, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct);
+ $args = array( 'source' => $source, 'visible' => $visible, 'resource_id' => $hash, 'album' => basename($pathname), 'os_path' => $os_basepath . $os_relpath, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct, 'options' => $options );
if($arr['contact_allow'])
$args['contact_allow'] = $arr['contact_allow'];
if($arr['group_allow'])
@@ -829,6 +831,8 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if($arr['description'])
$args['description'] = $arr['description'];
+ $args['deliver'] = $dosync;
+
$p = photo_upload($channel,$observer,$args);
if($p['success']) {
$ret['body'] = $p['body'];
@@ -865,10 +869,12 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
call_hooks('photo_upload_end',$ret);
}
- $sync = attach_export_data($channel,$hash);
+ if($dosync) {
+ $sync = attach_export_data($channel,$hash);
- if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ }
return $ret;
}
@@ -1462,7 +1468,7 @@ function find_filename_by_hash($channel_id, $attachHash) {
function pipe_streams($in, $out) {
$size = 0;
while (!feof($in))
- $size += fwrite($out, fread($in, 8192));
+ $size += fwrite($out, fread($in, 16384));
return $size;
}
@@ -1903,4 +1909,4 @@ function get_attach_binname($s) {
$p = substr($p,strpos($p,'/')+1);
}
return $p;
-} \ No newline at end of file
+}
diff --git a/include/auth.php b/include/auth.php
index 01fcf0094..f3592cee3 100644
--- a/include/auth.php
+++ b/include/auth.php
@@ -16,55 +16,97 @@ require_once('include/security.php');
/**
* @brief Verify login credentials.
*
- * If system <i>authlog</i> is set a log entry will be added for failed login
+ * If system.authlog is set a log entry will be added for failed login
* attempts.
*
- * @param string $email
- * The email address to verify.
+ * @param string $login
+ * The login to verify (channel address, account email or guest login token).
* @param string $pass
* The provided password to verify.
* @return array|null
* Returns account record on success, null on failure.
+ * The return array is dependent on the login mechanism.
+ * $ret['account'] will be set if either an email or channel address validation was successful (local login).
+ * $ret['channel'] will be set if a channel address validation was successful.
+ * $ret['xchan'] will be set if a guest access token validation was successful.
+ * Keys will exist for invalid return arrays but will be set to null.
+ * This function does not perform a login. It merely validates systems passwords and tokens.
+ *
*/
-function account_verify_password($email, $pass) {
+
+function account_verify_password($login, $pass) {
+
+ $ret = [ 'account' => null, 'channel' => null, 'xchan' => null ];
$email_verify = get_config('system', 'verify_email');
$register_policy = get_config('system', 'register_policy');
+ if(! $login)
+ return null;
+
+ $account = null;
+ $channel = null;
+ $xchan = null;
+
+ if(! strpos($login,'@')) {
+ $channel = channelx_by_nick($login);
+ if(! $channel) {
+ $x = q("select * from atoken where atoken_name = '%s' and atoken_token = '%s' limit 1",
+ dbesc($login),
+ dbesc($pass)
+ );
+ if($x) {
+ $ret['xchan'] = atoken_xchan($x[0]);
+ return $ret;
+ }
+ }
+ }
+ if($channel) {
+ $where = " where account_id = " . intval($channel['channel_account_id']) . " ";
+ }
+ else {
+ $where = " where account_email = '" . dbesc($login) . "' ";
+ }
+
+ $a = q("select * from account $where");
+ if(! $a) {
+ return null;
+ }
+
+ $account = $a[0];
+
// Currently we only verify email address if there is an open registration policy.
// This isn't because of any policy - it's because the workflow gets too complicated if
// you have to verify the email and then go through the account approval workflow before
// letting them login.
- if(($email_verify) && ($register_policy == REGISTER_OPEN) && ($record['account_flags'] & ACCOUNT_UNVERIFIED))
- return null;
-
- $r = q("select * from account where account_email = '%s'",
- dbesc($email)
- );
- if(! ($r && count($r)))
+ if(($email_verify) && ($register_policy == REGISTER_OPEN) && ($account['account_flags'] & ACCOUNT_UNVERIFIED)) {
+ logger('email verification required for ' . $login);
return null;
+ }
- foreach($r as $record) {
- if(($record['account_flags'] == ACCOUNT_OK)
- && (hash('whirlpool', $record['account_salt'] . $pass) === $record['account_password'])) {
- logger('password verified for ' . $email);
- return $record;
- }
+ if(($account['account_flags'] == ACCOUNT_OK)
+ && (hash('whirlpool',$account['account_salt'] . $pass) === $account['account_password'])) {
+ logger('password verified for ' . $login);
+ $ret['account'] = $account;
+ if($channel)
+ $ret['channel'] = $channel;
+ return $ret;
}
- $error = 'password failed for ' . $email;
+
+ $error = 'password failed for ' . $login;
logger($error);
- if($record['account_flags'] & ACCOUNT_UNVERIFIED)
- logger('Account is unverified. account_flags = ' . $record['account_flags']);
- if($record['account_flags'] & ACCOUNT_BLOCKED)
- logger('Account is blocked. account_flags = ' . $record['account_flags']);
- if($record['account_flags'] & ACCOUNT_EXPIRED)
- logger('Account is expired. account_flags = ' . $record['account_flags']);
- if($record['account_flags'] & ACCOUNT_REMOVED)
- logger('Account is removed. account_flags = ' . $record['account_flags']);
- if($record['account_flags'] & ACCOUNT_PENDING)
- logger('Account is pending. account_flags = ' . $record['account_flags']);
+ if($account['account_flags'] & ACCOUNT_UNVERIFIED)
+ logger('Account is unverified. account_flags = ' . $account['account_flags']);
+ if($account['account_flags'] & ACCOUNT_BLOCKED)
+ logger('Account is blocked. account_flags = ' . $account['account_flags']);
+ if($account['account_flags'] & ACCOUNT_EXPIRED)
+ logger('Account is expired. account_flags = ' . $account['account_flags']);
+ if($account['account_flags'] & ACCOUNT_REMOVED)
+ logger('Account is removed. account_flags = ' . $account['account_flags']);
+ if($account['account_flags'] & ACCOUNT_PENDING)
+ logger('Account is pending. account_flags = ' . $account['account_flags']);
log_failed_login($error);
@@ -120,13 +162,21 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
App::$session->new_cookie(60 * 60 * 24); // one day
$_SESSION['last_login_date'] = datetime_convert();
unset($_SESSION['visitor_id']); // no longer a visitor
- authenticate_success($x[0], true, true);
+ authenticate_success($x[0], null, true, true);
}
}
-
- $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1",
- dbesc($_SESSION['visitor_id'])
- );
+ if(array_key_exists('atoken',$_SESSION)) {
+ $y = q("select * from atoken where atoken_id = %d limit 1",
+ intval($_SESSION['atoken'])
+ );
+ if($y)
+ $r = array(atoken_xchan($y[0]));
+ }
+ else {
+ $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1",
+ dbesc($_SESSION['visitor_id'])
+ );
+ }
if($r) {
App::set_observer($r[0]);
}
@@ -158,7 +208,8 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
App::$session->extend_cookie();
$login_refresh = true;
}
- authenticate_success($r[0], false, false, false, $login_refresh);
+ $ch = (($_SESSION['uid']) ? channelx_by_n($_SESSION['uid']) : null);
+ authenticate_success($r[0], null, $ch, false, false, $login_refresh);
}
else {
$_SESSION['account_id'] = 0;
@@ -199,30 +250,38 @@ else {
call_hooks('authenticate', $addon_auth);
+ $atoken = null;
+ $account = null;
+
if(($addon_auth['authenticated']) && (count($addon_auth['user_record']))) {
- $record = $addon_auth['user_record'];
+ $account = $addon_auth['user_record'];
}
else {
- $record = App::$account = account_verify_password($_POST['username'], $_POST['password']);
+ $verify = account_verify_password($_POST['username'], $_POST['password']);
+ if($verify) {
+ $atoken = $verify['xchan'];
+ $channel = $verify['channel'];
+ $account = App::$account = $verify['account'];
+ }
if(App::$account) {
$_SESSION['account_id'] = App::$account['account_id'];
}
+ elseif($atoken) {
+ atoken_login($atoken);
+ }
else {
notice( t('Failed authentication') . EOL);
}
-
- logger('authenticate: ' . print_r(App::$account, true), LOGGER_ALL);
}
- if((! $record) || (! count($record))) {
+ if(! ($account || $atoken)) {
$error = 'authenticate: failed login attempt: ' . notags(trim($_POST['username'])) . ' from IP ' . $_SERVER['REMOTE_ADDR'];
logger($error);
// Also log failed logins to a separate auth log to reduce overhead for server side intrusion prevention
$authlog = get_config('system', 'authlog');
if ($authlog)
@file_put_contents($authlog, datetime_convert() . ':' . session_id() . ' ' . $error . "\n", FILE_APPEND);
-
notice( t('Login failed.') . EOL );
goaway(z_root() . '/login');
}
@@ -252,7 +311,8 @@ else {
// if we haven't failed up this point, log them in.
$_SESSION['last_login_date'] = datetime_convert();
- authenticate_success($record, true, true);
+ if(! $atoken)
+ authenticate_success($account,$channel,true, true);
}
}
@@ -270,6 +330,7 @@ else {
* @return int|bool
* Return channel_id from pconfig or false.
*/
+
function match_openid($authid) {
// Query the uid/channel_id from pconfig for a given value.
$r = q("SELECT uid FROM pconfig WHERE cat = 'system' AND k = 'openid' AND v = '%s' LIMIT 1",
diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php
index c7d0e56b1..16f67dc4a 100644
--- a/include/bb2diaspora.php
+++ b/include/bb2diaspora.php
@@ -302,11 +302,11 @@ function bb2diaspora_itemwallwall(&$item) {
}
}
- if(($wallwall) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) {
+ 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"
- . '[img]' . $item['author']['xchan_photo_m'] . '[/img]'
+ . '[img]' . $item['author']['xchan_photo_s'] . '[/img]'
. '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n"
. $item['body'];
}
diff --git a/include/bbcode.php b/include/bbcode.php
index 42741b392..7f7be4300 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -242,6 +242,13 @@ function bb_ShareAttributes($match) {
if ($matches[1] != "")
$message_id = $matches[1];
+ if(! $message_id) {
+ preg_match("/guid='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $message_id = $matches[1];
+ }
+
+
$reldate = '<span class="autotime" title="' . datetime_convert('UTC', date_default_timezone_get(), $posted, 'c') . '" >' . datetime_convert('UTC', date_default_timezone_get(), $posted, 'r') . '</span>';
$headline = '<div class="shared_container"> <div class="shared_header">';
@@ -484,6 +491,24 @@ function bb_code($match) {
return '<code class="inline-code">' . trim($match[1]) . '</code>';
}
+function bb_highlight($match) {
+ if(in_array(strtolower($match[1]),['php','css','mysql','sql','abap','diff','html','perl','ruby',
+ 'vbscript','avrc','dtd','java','xml','cpp','python','javascript','js','json','sh']))
+ return text_highlight($match[2],strtolower($match[1]));
+ return $match[0];
+}
+
+function bb_fixtable_lf($match) {
+
+ // remove extraneous whitespace between table element tags since newlines will all
+ // be converted to '<br />' and turn your neatly crafted tables into a whole lot of
+ // empty space.
+
+ $x = preg_replace("/\]\s+\[/",'][',$match[1]);
+ return '[table]' . $x . '[/table]';
+
+}
+
// BBcode 2 HTML was written by WAY2WEB.net
@@ -559,6 +584,15 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = str_replace(">", "&gt;", $Text);
+ // Check for [code] text here, before the linefeeds are messed with.
+ // The highlighter will unescape and re-escape the content.
+
+ if (strpos($Text,'[code=') !== false) {
+ $Text = preg_replace_callback("/\[code=(.*?)\](.*?)\[\/code\]/ism", 'bb_highlight', $Text);
+ }
+
+ $Text = preg_replace_callback("/\[table\](.*?)\[\/table\]/ism",'bb_fixtable_lf',$Text);
+
// Convert new line chars to html <br /> tags
// nlbr seems to be hopelessly messed up
diff --git a/include/cache.php b/include/cache.php
deleted file mode 100644
index 4a3f453e1..000000000
--- a/include/cache.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php /** @file */
-
- /**
- * cache api
- */
-
- class Cache {
- public static function get($key){
- $r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
- dbesc($key)
- );
-
- if ($r)
- return $r[0]['v'];
- return null;
- }
-
- public static function set($key,$value) {
-
- $r = q("SELECT * FROM cache WHERE k = '%s' limit 1",
- dbesc($key)
- );
- if($r) {
- q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
- dbesc($value),
- dbesc(datetime_convert()),
- dbesc($key));
- }
- else {
- q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')",
- dbesc($key),
- dbesc($value),
- dbesc(datetime_convert()));
- }
- }
-
-
- public static function clear(){
- q("DELETE FROM cache WHERE updated < '%s'",
- dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
- }
-
- }
-
diff --git a/include/channel.php b/include/channel.php
index 087bd4162..8e0747f25 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -16,7 +16,7 @@ require_once('include/menu.php');
* @param int $account_id
* Account_id used for this request
*
- * @returns assoziative array with:
+ * @returns associative array with:
* * \e boolean \b success boolean true if creating a new channel is allowed for this account
* * \e string \b message (optional) if success is false, optional error text
* * \e int \b total_identities
@@ -496,8 +496,10 @@ function identity_basic_export($channel_id, $items = false) {
$r = q("select * from channel where channel_id = %d limit 1",
intval($channel_id)
);
- if($r)
+ if($r) {
$ret['channel'] = $r[0];
+ $ret['relocate'] = [ 'channel_address' => $r[0]['channel_address'], 'url' => z_root()];
+ }
$r = q("select * from profile where uid = %d",
intval($channel_id)
@@ -514,7 +516,7 @@ function identity_basic_export($channel_id, $items = false) {
for($x = 0; $x < count($ret['abook']); $x ++) {
$xchans[] = $ret['abook'][$x]['abook_chan'];
- $abconfig = load_abconfig($ret['channel']['channel_hash'],$ret['abook'][$x]['abook_xchan']);
+ $abconfig = load_abconfig($channel_id,$ret['abook'][$x]['abook_xchan']);
if($abconfig)
$ret['abook'][$x]['abconfig'] = $abconfig;
}
@@ -676,14 +678,6 @@ function identity_basic_export($channel_id, $items = false) {
$ret['mail'] = $m;
}
- $r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item_id.uid = %d",
- intval($channel_id)
- );
-
- if($r)
- $ret['item_id'] = $r;
-
- //$key = get_config('system','prvkey');
/** @warning this may run into memory limits on smaller systems */
@@ -725,6 +719,10 @@ function identity_export_year($channel_id,$year,$month = 0) {
$ret = array();
+ $ch = channelx_by_n($channel_id);
+ if($ch) {
+ $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
+ }
$mindate = datetime_convert('UTC','UTC',$year . '-' . $target_month . '-01 00:00:00');
if($month && $month < 12)
$maxdate = datetime_convert('UTC','UTC',$year . '-' . $target_month_plus . '-01 00:00:00');
@@ -746,16 +744,43 @@ function identity_export_year($channel_id,$year,$month = 0) {
$ret['item'][] = encode_item($rr,true);
}
- $r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item_id.uid = %d
- and item.created >= '%s' and item.created < '%s' order by created ",
+ return $ret;
+}
+
+// export items within an arbitrary date range. Date/time is in UTC.
+
+function channel_export_items($channel_id,$start,$finish) {
+
+ if(! $start)
+ return array();
+ else
+ $start = datetime_convert('UTC','UTC',$start);
+
+ $finish = datetime_convert('UTC','UTC',(($finish) ? $finish : 'now'));
+ if($finish < $start)
+ return array();
+
+ $ret = array();
+
+ $ch = channelx_by_n($channel_id);
+ if($ch) {
+ $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
+ }
+
+ $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' and resource_type = '' order by created",
+ intval(ITEM_TYPE_POST),
intval($channel_id),
- dbesc($mindate),
- dbesc($maxdate)
+ dbesc($start),
+ dbesc($finish)
);
- if($r)
- $ret['item_id'] = $r;
-
+ if($r) {
+ $ret['item'] = array();
+ xchan_query($r);
+ $r = fetch_post_tags($r,true);
+ foreach($r as $rr)
+ $ret['item'][] = encode_item($rr,true);
+ }
return $ret;
}
@@ -774,11 +799,10 @@ function identity_export_year($channel_id,$year,$month = 0) {
*
* The channel default theme is also selected for use, unless over-riden elsewhere.
*
- * @param[in,out] App &$a
* @param string $nickname
* @param string $profile
*/
-function profile_load(&$a, $nickname, $profile = '') {
+function profile_load($nickname, $profile = '') {
// logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : ''));
@@ -875,7 +899,7 @@ function profile_load(&$a, $nickname, $profile = '') {
);
if($z) {
$p[0]['picdate'] = $z[0]['xchan_photo_date'];
- $p[0]['reddress'] = str_replace('@','&#xff20;',$z[0]['xchan_addr']);
+ $p[0]['reddress'] = str_replace('@','&#x40;',$z[0]['xchan_addr']);
}
// fetch user tags if this isn't the default profile
@@ -1046,6 +1070,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
$diaspora = array(
'podloc' => z_root(),
+ 'guid' => $profile['channel_guid'] . str_replace('.','',App::get_hostname()),
'searchable' => (($block) ? 'false' : 'true'),
'nickname' => $profile['channel_address'],
'fullname' => $profile['channel_name'],
@@ -1243,6 +1268,7 @@ function advanced_profile(&$a) {
$things = get_things(App::$profile['profile_guid'],App::$profile['profile_uid']);
+
// logger('mod_profile: things: ' . print_r($things,true), LOGGER_DATA);
return replace_macros($tpl, array(
@@ -1284,13 +1310,12 @@ function get_my_address() {
* If somebody arrives at our site using a zid, add their xchan to our DB if we don't have it already.
* And if they aren't already authenticated here, attempt reverse magic auth.
*
- * @param App &$a
*
* @hooks 'zid_init'
* string 'zid' - their zid
* string 'url' - the destination url
*/
-function zid_init(&$a) {
+function zid_init() {
$tmp_str = get_my_address();
if(validate_email($tmp_str)) {
Zotlabs\Daemon\Master::Summon(array('Gprobe',bin2hex($tmp_str)));
@@ -1317,6 +1342,29 @@ function zid_init(&$a) {
}
/**
+ * @brief
+ *
+ * If somebody arrives at our site using a zat, authenticate them
+ *
+ */
+
+function zat_init() {
+ if(local_channel() || remote_channel())
+ return;
+
+ $r = q("select * from atoken where atoken_token = '%s' limit 1",
+ dbesc($_REQUEST['zat'])
+ );
+ if($r) {
+ $xchan = atoken_xchan($r[0]);
+ atoken_login($xchan);
+ }
+
+}
+
+
+
+/**
* @brief Adds a zid parameter to a url.
*
* @param string $s
diff --git a/include/config.php b/include/config.php
index 65199283d..08810e298 100644
--- a/include/config.php
+++ b/include/config.php
@@ -98,20 +98,20 @@ function del_aconfig($account_id, $family, $key) {
}
-function load_abconfig($chash,$xhash) {
- Zlib\AbConfig::Load($chash,$xhash);
+function load_abconfig($chan, $xhash, $family = '') {
+ return Zlib\AbConfig::Load($chan,$xhash,$family);
}
-function get_abconfig($chash,$xhash,$family,$key) {
- return Zlib\AbConfig::Get($chash,$xhash,$family,$key);
+function get_abconfig($chan,$xhash,$family,$key) {
+ return Zlib\AbConfig::Get($chan,$xhash,$family,$key);
}
-function set_abconfig($chash,$xhash,$family,$key,$value) {
- return Zlib\AbConfig::Set($chash,$xhash,$family,$key,$value);
+function set_abconfig($chan,$xhash,$family,$key,$value) {
+ return Zlib\AbConfig::Set($chan,$xhash,$family,$key,$value);
}
-function del_abconfig($chash,$xhash,$family,$key) {
- return Zlib\AbConfig::Delete($chash,$xhash,$family,$key);
+function del_abconfig($chan,$xhash,$family,$key) {
+ return Zlib\AbConfig::Delete($chan,$xhash,$family,$key);
}
function load_iconfig(&$item) {
diff --git a/include/connections.php b/include/connections.php
index 2d10b8354..ed4526a09 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -283,18 +283,30 @@ function channel_remove($channel_id, $local = true, $unset_session=false) {
Zotlabs\Daemon\Master::Summon(array('Notifier','purge_all',$channel_id));
}
+
+ $r = q("select * from iconfig left join item on item.id = iconfig.iid
+ where item.uid = %d",
+ intval($channel_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ q("delete from iconfig where iid = %d",
+ intval($rr['iid'])
+ );
+ }
+ }
+
+
q("DELETE FROM `groups` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `group_member` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `event` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `item` WHERE `uid` = %d", intval($channel_id));
- q("DELETE FROM `item_id` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `mail` WHERE `channel_id` = %d", intval($channel_id));
q("DELETE FROM `notify` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `photo` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `attach` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `profile` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `pconfig` WHERE `uid` = %d", intval($channel_id));
- q("DELETE FROM `spam` WHERE `uid` = %d", intval($channel_id));
// @FIXME At this stage we need to remove the file resources located under /store/$nickname
diff --git a/include/conversation.php b/include/conversation.php
index 518193b08..957dbf8e9 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -403,9 +403,12 @@ function count_descendants($item) {
* @return boolean
*/
function visible_activity($item) {
- $hidden_activities = array(ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_AGREE, ACTIVITY_DISAGREE, ACTIVITY_ABSTAIN, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE);
+ $hidden_activities = [ ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_AGREE, ACTIVITY_DISAGREE, ACTIVITY_ABSTAIN, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE ];
- $post_types = array(ACTIVITY_OBJ_NOTE,ACTIVITY_OBJ_COMMENT,basename(ACTIVITY_OBJ_NOTE),basename(ACTIVITY_OBJ_COMMENT));
+ $post_types = [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_COMMENT, basename(ACTIVITY_OBJ_NOTE), basename(ACTIVITY_OBJ_COMMENT)];
+
+ if(intval($item['item_notshown']))
+ return false;
foreach ($hidden_activities as $act) {
if ((activity_match($item['verb'], $act)) && ($item['mid'] != $item['parent_mid'])) {
@@ -1143,6 +1146,8 @@ function status_editor($a, $x, $popup = false) {
$weblink = (($mimetype === 'text/bbcode') ? t('Insert web link') : false);
if(x($x, 'hide_weblink'))
$weblink = false;
+
+ $embedPhotos = t('Embed image from photo albums');
$writefiles = (($mimetype === 'text/bbcode') ? perm_is_allowed($x['profile_uid'], get_observer_hash(), 'write_storage') : false);
if(x($x, 'hide_attach'))
@@ -1178,6 +1183,12 @@ function status_editor($a, $x, $popup = false) {
'$whereareu' => t('Where are you right now?'),
'$editor_autocomplete'=> ((x($x,'editor_autocomplete')) ? $x['editor_autocomplete'] : ''),
'$bbco_autocomplete'=> ((x($x,'bbco_autocomplete')) ? $x['bbco_autocomplete'] : ''),
+ '$modalchooseimages' => t('Choose images to embed'),
+ '$modalchoosealbum' => t('Choose an album'),
+ '$modaldiffalbum' => t('Choose a different album...'),
+ '$modalerrorlist' => t('Error getting album list'),
+ '$modalerrorlink' => t('Error getting photo link'),
+ '$modalerroralbum' => t('Error getting album'),
));
$tpl = get_markup_template('jot.tpl');
@@ -1219,6 +1230,10 @@ function status_editor($a, $x, $popup = false) {
'$code' => t('Code'),
'$attach' => t('Attach file'),
'$weblink' => $weblink,
+ '$embedPhotos' => $embedPhotos,
+ '$embedPhotosModalTitle' => t('Embed an image from your albums'),
+ '$embedPhotosModalCancel' => t('Cancel'),
+ '$embedPhotosModalOK' => t('OK'),
'$setloc' => $setloc,
'$voting' => t('Toggle voting'),
'$feature_voting' => $feature_voting,
@@ -1688,13 +1703,19 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
'title' => t('Manage Webpages'),
'id' => 'webpages-tab',
);
- } else {
- /**
- * @FIXME we probably need a listing of events that were created by
- * this channel and are visible to the observer
- */
+ }
+
+ if(feature_enabled($uid,'wiki') && (! UNO)) {
+ $tabs[] = array(
+ 'label' => t('Wiki'),
+ 'url' => z_root() . '/wiki/' . $nickname,
+ 'sel' => ((argv(0) == 'wiki') ? 'active' : ''),
+ 'title' => t('Wiki'),
+ 'id' => 'wiki-tab',
+ );
}
+
$arr = array('is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => (($tab) ? $tab : false), 'tabs' => $tabs);
call_hooks('profile_tabs', $arr);
diff --git a/include/datetime.php b/include/datetime.php
index 600ad6ec4..76bd6b8d6 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -556,13 +556,13 @@ function update_birthdays() {
$ev['uid'] = $rr['abook_channel'];
$ev['account'] = $rr['abook_account'];
$ev['event_xchan'] = $rr['xchan_hash'];
- $ev['start'] = datetime_convert('UTC', 'UTC', $rr['abook_dob']);
- $ev['finish'] = datetime_convert('UTC', 'UTC', $rr['abook_dob'] . ' + 1 day ');
+ $ev['dtstart'] = datetime_convert('UTC', 'UTC', $rr['abook_dob']);
+ $ev['dtend'] = datetime_convert('UTC', 'UTC', $rr['abook_dob'] . ' + 1 day ');
$ev['adjust'] = intval(feature_enabled($rr['abook_channel'],'smart_birthdays'));
$ev['summary'] = sprintf( t('%1$s\'s birthday'), $rr['xchan_name']);
$ev['description'] = sprintf( t('Happy Birthday %1$s'),
'[zrl=' . $rr['xchan_url'] . ']' . $rr['xchan_name'] . '[/zrl]') ;
- $ev['type'] = 'birthday';
+ $ev['etype'] = 'birthday';
$z = event_store_event($ev);
if ($z) {
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index df072ed76..f6091f6e1 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -90,7 +90,7 @@ abstract class dba_driver {
protected $db;
protected $pdo = array();
- public $debug = 0;
+ public $debug = 0;
public $connected = false;
public $error = false;
@@ -332,6 +332,9 @@ function q($sql) {
else
db_logger('dba: vsprintf error: ' . print_r(debug_backtrace(), true),LOGGER_NORMAL,LOG_CRIT);
}
+ if(\DBA::$dba->debug)
+ db_logger('Sql: ' . $stmt, LOGGER_DEBUG, LOG_INFO);
+
return \DBA::$dba->q($stmt);
}
diff --git a/include/event.php b/include/event.php
index a4118ec78..3d650cd14 100644
--- a/include/event.php
+++ b/include/event.php
@@ -183,7 +183,9 @@ function format_ical_text($s) {
require_once('include/bbcode.php');
require_once('include/html2plain.php');
- return(wordwrap(str_replace(array(',',';','\\'),array('\\,','\\;','\\\\'),html2plain(bbcode($s))),72,"\r\n ",true));
+ $s = html2plain(bbcode($s));
+ $s = str_replace(["\r\n","\n"],["",""],$s);
+ return(wordwrap(str_replace(['\\',',',';'],['\\\\','\\,','\\;'],$s),72,"\r\n ",true));
}
diff --git a/include/features.php b/include/features.php
index 6d38bcfb4..2d71aa9be 100644
--- a/include/features.php
+++ b/include/features.php
@@ -52,6 +52,7 @@ function get_features($filtered = true) {
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'),((UNO) ? 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')),
diff --git a/include/feedutils.php b/include/feedutils.php
index 685b2f982..01ec0687e 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -393,7 +393,7 @@ function get_atom_elements($feed, $item, &$author) {
$terms = array();
$terms[] = array(
'otype' => TERM_OBJ_POST,
- 'type' => TERM_BOOKMARK,
+ 'ttype' => TERM_BOOKMARK,
'url' => $res['plink'],
'term' => $res['title'],
);
@@ -403,7 +403,7 @@ function get_atom_elements($feed, $item, &$author) {
$terms = array();
$terms[] = array(
'otype' => TERM_OBJ_POST,
- 'type' => TERM_BOOKMARK,
+ 'ttype' => TERM_BOOKMARK,
'url' => $res['plink'],
'term' => $res['plink'],
);
diff --git a/include/group.php b/include/group.php
index a4938b848..10853ff6b 100644
--- a/include/group.php
+++ b/include/group.php
@@ -17,7 +17,7 @@ function group_add($uid,$name,$public = 0) {
$z = q("SELECT * FROM `groups` WHERE `id` = %d LIMIT 1",
intval($r)
);
- if(count($z) && $z[0]['deleted']) {
+ if(($z) && $z[0]['deleted']) {
/*$r = q("UPDATE `groups` SET `deleted` = 0 WHERE `uid` = %d AND `gname` = '%s' LIMIT 1",
intval($uid),
dbesc($name)
@@ -129,7 +129,7 @@ function group_byname($uid,$name) {
intval($uid),
dbesc($name)
);
- if(count($r))
+ if($r)
return $r[0]['id'];
return false;
}
@@ -178,11 +178,11 @@ function group_add_member($uid,$name,$member,$gid = 0) {
intval($gid),
dbesc($member)
);
- if(count($r))
+ if($r)
return true; // You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
- if(! count($r))
+ if(! $r)
$r = q("INSERT INTO `group_member` (`uid`, `gid`, `xchan`)
VALUES( %d, %d, '%s' ) ",
intval($uid),
@@ -205,7 +205,7 @@ function group_get_members($gid) {
intval(local_channel()),
intval(local_channel())
);
- if(count($r))
+ if($r)
$ret = $r;
}
return $ret;
@@ -218,7 +218,7 @@ function group_get_members_xchan($gid) {
intval($gid),
intval(local_channel())
);
- if(count($r)) {
+ if($r) {
foreach($r as $rr) {
$ret[] = $rr['xchan'];
}
@@ -236,7 +236,7 @@ function mini_group_select($uid,$group = '') {
intval($uid)
);
$grps[] = array('name' => '', 'hash' => '0', 'selected' => '');
- if(count($r)) {
+ if($r) {
foreach($r as $rr) {
$grps[] = array('name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : ''));
}
@@ -279,7 +279,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id
$member_of = groups_containing(local_channel(),$cid);
}
- if(count($r)) {
+ if($r) {
foreach($r as $rr) {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
@@ -356,7 +356,7 @@ function groups_containing($uid,$c) {
);
$ret = array();
- if(count($r)) {
+ if($r) {
foreach($r as $rr)
$ret[] = $rr['gid'];
}
diff --git a/include/help.php b/include/help.php
index 5518eeb70..7f57f3334 100644
--- a/include/help.php
+++ b/include/help.php
@@ -30,7 +30,8 @@ function search_doc_files($s) {
$regexop = db_getfunc('REGEXP');
- $r = q("select item_id.sid, item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and
+ $r = q("select iconfig.v, item.* from item left join iconfig on item.id = iconfig.iid
+ where iconfig.cat = 'system' and iconfig.k = 'docfile' and
body $regexop '%s' and item_type = %d $pager_sql",
dbesc($s),
intval(ITEM_TYPE_DOC)
@@ -50,7 +51,7 @@ function search_doc_files($s) {
}
}
}
- if(stristr($r[$x]['sid'],$s))
+ if(stristr($r[$x]['v'],$s))
$r[$x]['rank'] ++;
$r[$x]['rank'] += substr_count(strtolower($r[$x]['text']),strtolower($s));
// bias the results to the observer's native language
@@ -123,12 +124,15 @@ function store_doc_file($s) {
$item['owner_xchan'] = $item['author_xchan'] = $sys['channel_hash'];
$item['item_type'] = ITEM_TYPE_DOC;
- $r = q("select item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and
- sid = '%s' and item_type = %d limit 1",
+ $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
+ where iconfig.cat = 'system' and iconfig.k = 'docfile' and
+ iconfig.v = '%s' and item_type = %d limit 1",
dbesc($s),
intval(ITEM_TYPE_DOC)
);
+ \Zotlabs\Lib\IConfig::Set($item,'system','docfile',$s);
+
if($r) {
$item['id'] = $r[0]['id'];
$item['mid'] = $item['parent_mid'] = $r[0]['mid'];
@@ -139,10 +143,7 @@ function store_doc_file($s) {
$x = item_store($item);
}
- if($x['success']) {
- update_remote_id($sys,$x['item_id'],ITEM_TYPE_DOC,$s,'docfile',0,$item['mid']);
- }
-
+ return $x;
}
diff --git a/include/import.php b/include/import.php
index be456bfa9..889b50eb1 100644
--- a/include/import.php
+++ b/include/import.php
@@ -553,7 +553,7 @@ function sync_chatrooms($channel,$chatrooms) {
-function import_items($channel,$items,$sync = false) {
+function import_items($channel,$items,$sync = false,$relocate = null) {
if($channel && $items) {
$allow_code = false;
@@ -575,22 +575,23 @@ function import_items($channel,$items,$sync = false) {
if(! $item)
continue;
+ if($relocate && $item['mid'] === $item['parent_mid']) {
+ item_url_replace($channel,$item,$relocate['url'],z_root(),$relocate['channel_address']);
+ }
+
$r = q("select id, edited from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']),
intval($channel['channel_id'])
);
if($r) {
- if($item['edited'] > $r[0]['edited']) {
+
+ // flags may have changed and we are probably relocating the post,
+ // so force an update even if we have the same timestamp
+
+ if($item['edited'] >= $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
$item_result = item_store_update($item,$allow_code,$deliver);
- if($sync && $item['item_wall']) {
- // deliver singletons if we have any
- if($item_result && $item_result['success']) {
- Zotlabs\Daemon\Master::Summon(array('Notifier','single_activity',$item_result['item_id']));
- }
- }
- continue;
}
}
else {
@@ -598,10 +599,11 @@ function import_items($channel,$items,$sync = false) {
$item['uid'] = $channel['channel_id'];
$item_result = item_store($item,$allow_code,$deliver);
}
+
if($sync && $item['item_wall']) {
// deliver singletons if we have any
if($item_result && $item_result['success']) {
- Zotlabs\Daemon\Master::Summon(array('Notifier','single_activity',$item_result['item_id']));
+ Zotlabs\Daemon\Master::Summon( [ 'Notifier','single_activity',$item_result['item_id'] ]);
}
}
}
@@ -609,8 +611,8 @@ function import_items($channel,$items,$sync = false) {
}
-function sync_items($channel,$items) {
- import_items($channel,$items,true);
+function sync_items($channel,$items,$relocate = null) {
+ import_items($channel,$items,true,$relocate);
}
@@ -624,19 +626,14 @@ function import_item_ids($channel,$itemids) {
);
if(! $r)
continue;
- $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1",
+ $z = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = '%s'
+ and iconfig.v = '%s' and iid = %d limit 1",
dbesc($i['service']),
dbesc($i['sid']),
- intval($r[0]['id']),
- intval($channel['channel_id'])
+ intval($r[0]['id'])
);
if(! $z) {
- q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')",
- intval($r[0]['id']),
- intval($channel['channel_id']),
- dbesc($i['sid']),
- dbesc($i['service'])
- );
+ \Zotlabs\Lib\IConfig::Set($r[0]['id'],'system',$i['service'],$i['sid'],true);
}
}
}
@@ -1007,7 +1004,7 @@ function sync_files($channel,$files) {
$attach_id = $x[0]['id'];
}
- $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['data']);
+ $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
unset($att['id']);
$att['aid'] = $channel['channel_account_id'];
@@ -1205,31 +1202,9 @@ function sync_files($channel,$files) {
}
}
if($f['item']) {
- sync_items($channel,$f['item']);
- foreach($f['item'] as $i) {
- if($i['message_id'] !== $i['message_parent'])
- continue;
- $r = q("select * from item where mid = '%s' and uid = %d limit 1",
- dbesc($i['message_id']),
- intval($channel['channel_id'])
- );
- if($r) {
- $item = $r[0];
- item_url_replace($channel,$item,$oldbase,z_root(),$original_channel);
-
- dbesc_array($item);
- $item_id = $item['id'];
- unset($item['id']);
- $str = '';
- foreach($item as $k => $v) {
- if($str)
- $str .= ",";
- $str .= " `" . $k . "` = '" . $v . "' ";
- }
-
- $r = dbq("update `item` set " . $str . " where id = " . $item_id );
- }
- }
+ sync_items($channel,$f['item'],
+ ['channel_address' => $original_channel,'url' => $oldbase]
+ );
}
}
}
diff --git a/include/items.php b/include/items.php
index 93385c6e6..373090d41 100755
--- a/include/items.php
+++ b/include/items.php
@@ -449,11 +449,7 @@ function post_activity_item($arr) {
call_hooks('post_local_end', $arr);
Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id));
$ret['success'] = true;
- $r = q("select * from item where id = %d limit 1",
- intval($post_id)
- );
- if($r)
- $ret['activity'] = $r[0];
+ $ret['activity'] = $post['item'];
}
return $ret;
@@ -677,13 +673,23 @@ function get_item_elements($x,$allow_code = false) {
$arr['item_flags'] = 0;
- if(array_key_exists('flags',$x) && in_array('consensus',$x['flags']))
- $arr['item_consensus'] = 1;
+ if(array_key_exists('flags',$x)) {
- if(array_key_exists('flags',$x) && in_array('deleted',$x['flags']))
- $arr['item_deleted'] = 1;
- if(array_key_exists('flags',$x) && in_array('hidden',$x['flags']))
- $arr['item_hidden'] = 1;
+ if(in_array('consensus',$x['flags']))
+ $arr['item_consensus'] = 1;
+
+ if(in_array('deleted',$x['flags']))
+ $arr['item_deleted'] = 1;
+
+ if(in_array('notshown',$x['flags']))
+ $arr['item_notshown'] = 1;
+
+ // hidden item are no longer propagated - notshown may be a suitable alternative
+
+ if(in_array('hidden',$x['flags']))
+ $arr['item_hidden'] = 1;
+
+ }
// Here's the deal - the site might be down or whatever but if there's a new person you've never
// seen before sending stuff to your stream, we MUST be able to look them up and import their data from their
@@ -1339,6 +1345,8 @@ function encode_item_flags($item) {
$ret[] = 'deleted';
if(intval($item['item_hidden']))
$ret[] = 'hidden';
+ if(intval($item['item_notshown']))
+ $ret[] = 'notshown';
if(intval($item['item_thread_top']))
$ret[] = 'thread_parent';
if(intval($item['item_nsfw']))
@@ -1877,6 +1885,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
}
+ $ret['item'] = $arr;
call_hooks('post_remote_end',$arr);
@@ -2127,6 +2136,15 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
return $ret;
}
+ // fetch an unescaped complete copy of the stored item
+
+ $r = q("select * from item where id = %d",
+ intval($orig_post_id)
+ );
+ if($r)
+ $arr = $r[0];
+
+
$r = q("delete from term where oid = %d and otype = %d",
intval($orig_post_id),
intval(TERM_OBJ_POST)
@@ -2158,6 +2176,8 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['iconfig'] = $meta;
}
+ $ret['item'] = $arr;
+
call_hooks('post_remote_update_end',$arr);
if($deliver) {
@@ -3266,15 +3286,17 @@ function item_expire($uid,$days) {
$item_normal = item_normal();
- $r = q("SELECT * FROM `item`
- WHERE `uid` = %d
- AND `created` < %s - INTERVAL %s
- AND `id` = `parent`
- $sql_extra
+ $r = q("SELECT id FROM item
+ WHERE uid = %d
+ AND created < %s - INTERVAL %s
AND item_retained = 0
- $item_normal LIMIT $expire_limit ",
+ AND item_thread_top = 1
+ AND resource_type = ''
+ AND item_starred = 0
+ $sql_extra $item_normal LIMIT $expire_limit ",
intval($uid),
- db_utcnow(), db_quoteinterval(intval($days).' DAY')
+ db_utcnow(),
+ db_quoteinterval(intval($days).' DAY')
);
if(! $r)
@@ -3292,17 +3314,6 @@ function item_expire($uid,$days) {
continue;
}
- // Only expire posts, not photos and photo comments
-
- if($item['resource_type'] === 'photo') {
- retain_item($item['id']);
- continue;
- }
- if(intval($item['item_starred'])) {
- retain_item($item['id']);
- continue;
- }
-
drop_item($item['id'],false);
}
@@ -3537,9 +3548,8 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
intval($item['id'])
);
- q("delete from item_id where iid = %d and uid = %d",
- intval($item['id']),
- intval($item['uid'])
+ q("delete from iconfig where iid = %d",
+ intval($item['id'])
);
q("delete from term where oid = %d and otype = %d",
@@ -4105,6 +4115,23 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
return $items;
}
+function webpage_to_namespace($webpage) {
+
+ if($webpage == ITEM_TYPE_WEBPAGE)
+ $page_type = 'WEBPAGE';
+ elseif($webpage == ITEM_TYPE_BLOCK)
+ $page_type = 'BUILDBLOCK';
+ elseif($webpage == ITEM_TYPE_PDL)
+ $page_type = 'PDL';
+ elseif($webpage == ITEM_TYPE_DOC)
+ $page_type = 'docfile';
+ else
+ $page_type = 'unknown';
+ return $page_type;
+
+}
+
+
function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
@@ -4127,32 +4154,19 @@ function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remo
}
if($page_type) {
-
// store page info as an alternate message_id so we can access it via
// https://sitename/page/$channelname/$pagetitle
// if no pagetitle was given or it couldn't be transliterated into a url, use the first
// sixteen bytes of the mid - which makes the link portable and not quite as daunting
// as the entire mid. If it were the post_id the link would be less portable.
- $r = q("select * from item_id where iid = %d and uid = %d and service = '%s' limit 1",
+ \Zotlabs\Lib\IConfig::Set(
intval($post_id),
- intval($channel['channel_id']),
- dbesc($page_type)
+ 'system',
+ $page_type,
+ ($pagetitle) ? $pagetitle : substr($mid,0,16),
+ false
);
- if($r) {
- q("update item_id set sid = '%s' where id = %d",
- dbesc(($pagetitle) ? $pagetitle : substr($mid,0,16)),
- intval($r[0]['id'])
- );
- }
- else {
- q("insert into item_id ( iid, uid, sid, service ) values ( %d, %d, '%s','%s' )",
- intval($post_id),
- intval($channel['channel_id']),
- dbesc(($pagetitle) ? $pagetitle : substr($mid,0,16)),
- dbesc($page_type)
- );
- }
}
}
diff --git a/include/js_strings.php b/include/js_strings.php
index b1817f373..1b4668061 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -4,10 +4,10 @@ function js_strings() {
return replace_macros(get_markup_template('js_strings.tpl'), array(
'$delitem' => t('Delete this item?'),
'$comment' => t('Comment'),
- '$showmore' => t('[+] show all'),
- '$showfewer' => t('[-] show less'),
- '$divgrowmore' => t('[+] expand'),
- '$divgrowless' => t('[-] collapse'),
+ '$showmore' => sprintf( t('%s show all'), '<i class=\'fa fa-chevron-down\'></i>'),
+ '$showfewer' => sprintf( t('%s show less'), '<i class=\'fa fa-chevron-up\'></i>'),
+ '$divgrowmore' => sprintf( t('%s expand'), '<i class=\'fa fa-chevron-down\'></i>'),
+ '$divgrowless' => sprintf( t('%s collapse'),'<i class=\'fa fa-chevron-up\'></i>'),
'$pwshort' => t("Password too short"),
'$pwnomatch' => t("Passwords do not match"),
'$everybody' => t('everybody'),
diff --git a/include/nav.php b/include/nav.php
index 70faec598..1fb0e98dc 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -104,6 +104,8 @@ EOT;
if(feature_enabled($channel['channel_id'],'webpages') && (! UNO))
$nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages'),'webpages_nav_btn');
+ if(feature_enabled($channel['channel_id'],'wiki') && (! UNO))
+ $nav['usermenu'][] = Array('wiki/' . $channel['channel_address'],t('Wiki'),"",t('Your wiki'),'wiki_nav_btn');
}
else {
if(! get_account_id()) {
@@ -126,7 +128,7 @@ EOT;
$nav['lock'] = array('logout','','lock',
sprintf( t('%s - click to logout'), $observer['xchan_addr']));
}
- else {
+ elseif(! $_SESSION['authenticated']) {
$nav['loginmenu'][] = Array('rmagic',t('Remote authentication'),'',t('Click to authenticate to your home hub'),'rmagic_nav_btn');
}
@@ -143,7 +145,7 @@ EOT;
if((App::$module != 'home') && (! (local_channel())))
$nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn');
- if((App::$config['system']['register_policy'] == REGISTER_OPEN) && (! local_channel()) && (! remote_channel()))
+ if((App::$config['system']['register_policy'] == REGISTER_OPEN) && (! $_SESSION['authenticated']))
$nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn');
if(! get_config('system','hide_help')) {
@@ -253,6 +255,19 @@ $powered_by = '';
'$pleasewait' => t('Please wait...')
));
+
+ if(x($_SESSION, 'reload_avatar') && $observer) {
+ // The avatar has been changed on the server but the browser doesn't know that,
+ // force the browser to reload the image from the server instead of its cache.
+ $tpl = get_markup_template('force_image_reload.tpl');
+
+ App::$page['nav'] .= replace_macros($tpl, array(
+ '$imgUrl' => $observer['xchan_photo_m']
+ ));
+ unset($_SESSION['reload_avatar']);
+ }
+
+
call_hooks('page_header', App::$page['nav']);
}
diff --git a/include/network.php b/include/network.php
index 0dd10e29b..47863b680 100644
--- a/include/network.php
+++ b/include/network.php
@@ -21,15 +21,18 @@ function get_capath() {
* TRUE if asked to return binary results (file download)
* @param int $redirects default 0
* internal use, recursion counter
- * @param array $opts (optional parameters) assoziative array with:
+ * @param array $opts (optional parameters) associative array with:
* * \b accept_content => supply Accept: header with 'accept_content' as the value
* * \b timeout => int seconds, default system config value or 60 seconds
* * \b http_auth => username:password
* * \b novalidate => do not validate SSL certs, default is to validate using our CA list
* * \b nobody => only return the header
* * \b filep => stream resource to write body to. header and body are not returned when using this option.
+ * * \b custom => custom request method: e.g. 'PUT', 'DELETE'
+ * * \b cookiejar => cookie file (write)
+ * * \B cookiefile => cookie file (read)
*
- * @return array an assoziative array with:
+ * @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
@@ -59,12 +62,27 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_HEADER, $false);
}
+ if(x($opts,'upload'))
+ @curl_setopt($ch, CURLOPT_UPLOAD, $opts['upload']);
+
+ if(x($opts,'infile'))
+ @curl_setopt($ch, CURLOPT_INFILE, $opts['infile']);
+
+ if(x($opts,'infilesize'))
+ @curl_setopt($ch, CURLOPT_INFILESIZE, $opts['infilesize']);
+
+ if(x($opts,'readfunc'))
+ @curl_setopt($ch, CURLOPT_READFUNCTION, $opts['readfunc']);
+
if(x($opts,'headers'))
@curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
if(x($opts,'nobody'))
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
+ if(x($opts,'custom'))
+ @curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $opts['custom']);
+
if(x($opts,'timeout') && intval($opts['timeout'])) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
}
@@ -78,6 +96,14 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
}
+ if(x($opts,'cookiejar'))
+ @curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
+ if(x($opts,'cookiefile'))
+ @curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
+
+ if(x($opts,'cookie'))
+ @curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
+
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,
((x($opts,'novalidate') && intval($opts['novalidate'])) ? false : true));
@@ -165,7 +191,9 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
* 'http_auth' => username:password
* 'novalidate' => do not validate SSL certs, default is to validate using our CA list
* 'filep' => stream resource to write body to. header and body are not returned when using this option.
- * @return array an assoziative array with:
+ * 'custom' => custom request method: e.g. 'PUT', 'DELETE'
+ *
+ * @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
@@ -174,6 +202,10 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
*/
function z_post_url($url,$params, $redirects = 0, $opts = array()) {
+// logger('url: ' . $url);
+// logger('params: ' . print_r($params,true));
+// logger('opts: ' . print_r($opts,true));
+
$ret = array('return_code' => 0, 'success' => false, 'header' => "", 'body' => "");
$ch = curl_init($url);
@@ -199,12 +231,17 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
if(x($opts,'headers')) {
@curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
-logger('headers: ' . print_r($opts['headers'],true) . 'redir: ' . $redirects);
}
if(x($opts,'nobody'))
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
+ if(x($opts,'custom')) {
+ @curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $opts['custom']);
+ @curl_setopt($ch, CURLOPT_POST,0);
+ }
+
+
if(x($opts,'timeout') && intval($opts['timeout'])) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
}
@@ -218,6 +255,16 @@ logger('headers: ' . print_r($opts['headers'],true) . 'redir: ' . $redirects);
@curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
}
+
+ if(x($opts,'cookiejar'))
+ @curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
+ if(x($opts,'cookiefile'))
+ @curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
+
+
+ if(x($opts,'cookie'))
+ @curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
+
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,
((x($opts,'novalidate') && intval($opts['novalidate'])) ? false : true));
@@ -1296,8 +1343,20 @@ function discover_by_webbie($webbie) {
$fullname = $vcard['fn'];
if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0))
$vcard['photo'] = $diaspora_base . '/' . $vcard['photo'];
+ if(($vcard['key']) && (! $pubkey))
+ $pubkey = $vcard['key'];
if(! $avatar)
$avatar = $vcard['photo'];
+ if($diaspora) {
+ if(($vcard['guid']) && (! $diaspora_guid))
+ $diaspora_guid = $vcard['guid'];
+ if(($vcard['url']) && (! $diaspora_base))
+ $diaspora_base = $vcard['url'];
+
+
+
+
+ }
}
}
@@ -1962,14 +2021,7 @@ function get_site_info() {
else
$service_class = false;
- $visible_plugins = array();
- if(is_array(App::$plugins) && count(App::$plugins)) {
- $r = q("select * from addon where hidden = 0");
- if(count($r))
- foreach($r as $rr)
- $visible_plugins[] = $rr['aname'];
- }
- sort($visible_plugins);
+ $visible_plugins = visible_plugin_list();
if(@is_dir('.git') && function_exists('shell_exec'))
$commit = trim(@shell_exec('git log -1 --format="%h"'));
diff --git a/include/oauth.php b/include/oauth.php
index 984e0e6c6..a3c52bf27 100644
--- a/include/oauth.php
+++ b/include/oauth.php
@@ -170,7 +170,7 @@ class ZotOAuth1 extends OAuth1Server {
);
if($x) {
require_once('include/security.php');
- authenticate_success($x[0],true,false,true,true);
+ authenticate_success($x[0],null,true,false,true,true);
$_SESSION['allow_api'] = true;
}
}
diff --git a/include/oembed.php b/include/oembed.php
index e968a8f65..fe068278e 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -1,6 +1,8 @@
<?php /** @file */
+use Zotlabs\Lib as Zlib;
+
function oembed_replacecb($matches){
$embedurl=$matches[1];
@@ -129,7 +131,7 @@ function oembed_fetch_url($embedurl){
$txt = null;
if($action !== 'block') {
- $txt = Cache::get(App::$videowidth . $embedurl);
+ $txt = Zlib\Cache::get('[' . App::$videowidth . '] ' . $embedurl);
if(strstr($txt,'youtu') && strstr(z_root(),'https:')) {
$txt = str_replace('http:','https:',$txt);
@@ -198,7 +200,7 @@ function oembed_fetch_url($embedurl){
//save in cache
if(! get_config('system','oembed_cache_disable'))
- Cache::set(App::$videowidth . $embedurl,$txt);
+ Zlib\Cache::set('[' . App::$videowidth . '] ' . $embedurl,$txt);
}
diff --git a/include/page_widgets.php b/include/page_widgets.php
index 49d1439be..3270de4a3 100644
--- a/include/page_widgets.php
+++ b/include/page_widgets.php
@@ -1,7 +1,8 @@
<?php
// A basic toolbar for observers with write_pages permissions
-function writepages_widget ($who,$which){
+
+function writepages_widget ($who,$which) {
return replace_macros(get_markup_template('write_pages.tpl'), array(
'$new' => t('New Page'),
'$newurl' => "webpages/$who",
@@ -13,9 +14,11 @@ function writepages_widget ($who,$which){
// Chan is channel_id, $which is channel_address - we'll need to pass observer later too.
-function pagelist_widget ($owner,$which){
- $r = q("select * from item_id left join item on item_id.iid = item.id where item_id.uid = %d and service = 'WEBPAGE' order by item.created desc",
+function pagelist_widget ($owner,$which) {
+
+ $r = q("select * from iconfig left join item on iconfig.iid = item.id where item_id.uid = %d
+ and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' order by item.created desc",
intval($owner)
);
@@ -24,7 +27,7 @@ function pagelist_widget ($owner,$which){
if($r) {
$pages = array();
foreach($r as $rr) {
- $pages[$rr['iid']][] = array('url' => $rr['iid'],'pagetitle' => $rr['sid'],'title' => $rr['title'],'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']),'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']));
+ $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']));
}
}
diff --git a/include/photos.php b/include/photos.php
index c64d662ea..c70478146 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -41,6 +41,10 @@ function photo_upload($channel, $observer, $args) {
else
$visible = 0;
+ $deliver = true;
+ if(array_key_exists('deliver',$args))
+ $deliver = intval($args['deliver']);
+
// Set to default channel permissions. If the parent directory (album) has permissions set,
// use those instead. If we have specific permissions supplied, they take precedence over
// all other settings. 'allow_cid' being passed from an external source takes priority over channel settings.
@@ -330,7 +334,7 @@ function photo_upload($channel, $observer, $args) {
if($item['mid'] === $item['parent_mid']) {
- $item['body'] = $args['body'];
+ $item['body'] = $summary;
$item['obj_type'] = ACTIVITY_OBJ_PHOTO;
$item['obj'] = json_encode($object);
@@ -355,14 +359,14 @@ function photo_upload($channel, $observer, $args) {
if(($item['edited'] > $r[0]['edited']) || $force) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
- item_store_update($item);
+ item_store_update($item,false,$deliver);
continue;
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- $item_result = item_store($item);
+ $item_result = item_store($item,false,$deliver);
}
}
}
@@ -414,10 +418,10 @@ function photo_upload($channel, $observer, $args) {
- $result = item_store($arr);
+ $result = item_store($arr,false,$deliver);
$item_id = $result['item_id'];
- if($visible)
+ if($visible && $deliver)
Zotlabs\Daemon\Master::Summon(array('Notifier', 'wall-new', $item_id));
}
@@ -703,40 +707,65 @@ function gps2Num($coordPart) {
return floatval($parts[0]) / floatval($parts[1]);
}
-function profile_photo_set_profile_perms($profileid = '') {
+function profile_photo_set_profile_perms($uid, $profileid = 0) {
$allowcid = '';
- if (x($profileid)) {
-
- $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile WHERE profile.id = %d OR profile.profile_guid = '%s' LIMIT 1", intval($profileid), dbesc($profileid));
-
- } else {
-
+ if($profileid) {
+ $r = q("SELECT photo, profile_guid, id, is_default, uid
+ FROM profile WHERE uid = %d and ( profile.id = %d OR profile.profile_guid = '%s') LIMIT 1",
+ intval($profileid),
+ dbesc($profileid)
+ );
+ }
+ else {
logger('Resetting permissions on default-profile-photo for user'.local_channel());
- $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile WHERE profile.uid = %d AND is_default = 1 LIMIT 1", intval(local_channel()) ); //If no profile is given, we update the default profile
+
+ $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile
+ WHERE profile.uid = %d AND is_default = 1 LIMIT 1",
+ intval($uid)
+ ); //If no profile is given, we update the default profile
}
+ if(! $r)
+ return;
$profile = $r[0];
- if(x($profile['id']) && x($profile['photo'])) {
- preg_match("@\w*(?=-\d*$)@i", $profile['photo'], $resource_id);
- $resource_id = $resource_id[0];
+
+ if($profile['id'] && $profile['photo']) {
+ preg_match("@\w*(?=-\d*$)@i", $profile['photo'], $resource_id);
+ $resource_id = $resource_id[0];
- if (intval($profile['is_default']) != 1) {
- $r0 = q("SELECT channel_hash FROM channel WHERE channel_id = %d LIMIT 1", intval(local_channel()) );
- $r1 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%d' ", intval($profile['id'])); //Should not be needed in future. Catches old int-profile-ids.
- $r2 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%s'", dbesc($profile['profile_guid']));
+ if (! intval($profile['is_default'])) {
+ $r0 = q("SELECT channel_hash FROM channel WHERE channel_id = %d LIMIT 1",
+ intval($uid)
+ );
+ //Should not be needed in future. Catches old int-profile-ids.
+ $r1 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%d' ",
+ intval($profile['id'])
+ );
+ $r2 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%s'",
+ dbesc($profile['profile_guid'])
+ );
$allowcid = "<" . $r0[0]['channel_hash'] . ">";
foreach ($r1 as $entry) {
$allowcid .= "<" . $entry['abook_xchan'] . ">";
}
foreach ($r2 as $entry) {
- $allowcid .= "<" . $entry['abook_xchan'] . ">";
- }
+ $allowcid .= "<" . $entry['abook_xchan'] . ">";
+ }
- q("UPDATE `photo` SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",dbesc($allowcid),dbesc($resource_id),intval($profile['uid']));
+ q("UPDATE photo SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",
+ dbesc($allowcid),
+ dbesc($resource_id),
+ intval($uid)
+ );
- } else {
- q("UPDATE `photo` SET allow_cid = '' WHERE profile = 1 AND uid = %d",intval($profile['uid'])); //Reset permissions on default profile picture to public
+ }
+ else {
+ //Reset permissions on default profile picture to public
+ q("UPDATE photo SET allow_cid = '' WHERE photo_usage = %d AND uid = %d",
+ intval(PHOTO_PROFILE),
+ intval($uid)
+ );
}
}
diff --git a/include/plugin.php b/include/plugin.php
index be4e92f03..cb206d944 100755
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -167,6 +167,12 @@ function reload_plugins() {
}
}
+function visible_plugin_list() {
+ $r = q("select * from addon where hidden = 0 order by aname asc");
+ return(($r) ? ids_to_array($r,'aname') : array());
+}
+
+
/**
* @brief registers a hook.
@@ -545,15 +551,21 @@ function head_get_css() {
}
function format_css_if_exists($source) {
- if (strpos($source[0], '/') !== false)
+ $path_prefix = script_path() . '/';
+
+ if (strpos($source[0], '/') !== false) {
+ // The source is a URL
$path = $source[0];
- else
+ // If the url starts with // then it's an absolute URL
+ if($source[0][0] === '/' && $source[0][1] === '/') $path_prefix = '';
+ } else {
+ // It's a file from the theme
$path = theme_include($source[0]);
+ }
if($path) {
- $path = script_path() . '/' . $path;
$qstring = ((parse_url($path, PHP_URL_QUERY)) ? '&' : '?') . 'v=' . STD_VERSION;
- return '<link rel="stylesheet" href="' . $path . $qstring . '" type="text/css" media="' . $source[1] . '">' . "\r\n";
+ return '<link rel="stylesheet" href="' . $path_prefix . $path . $qstring . '" type="text/css" media="' . $source[1] . '">' . "\r\n";
}
}
@@ -593,26 +605,38 @@ function script_path() {
return $scheme . '://' . $hostname;
}
-function head_add_js($src) {
- App::$js_sources[] = $src;
+function head_add_js($src, $priority = 0) {
+ if(! is_array(App::$js_sources[$priority]))
+ App::$js_sources[$priority] = array();
+ App::$js_sources[$priority][] = $src;
}
-function head_remove_js($src) {
+function head_remove_js($src, $priority = 0) {
- $index = array_search($src, App::$js_sources);
+ $index = array_search($src, App::$js_sources[$priority]);
if($index !== false)
- unset(App::$js_sources[$index]);
+ unset(App::$js_sources[$priority][$index]);
}
+// We should probably try to register main.js with a high priority, but currently we handle it
+// separately and put it at the end of the html head block in case any other javascript is
+// added outside the head_add_js construct.
+
function head_get_js() {
+
$str = '';
- $sources = App::$js_sources;
- if(count($sources))
- foreach($sources as $source) {
- if($source === 'main.js')
- continue;
- $str .= format_js_if_exists($source);
+ if(App::$js_sources) {
+ ksort(App::$js_sources,SORT_NUMERIC);
+ foreach(App::$js_sources as $sources) {
+ if(count($sources)) {
+ foreach($sources as $source) {
+ if($src === 'main.js')
+ continue;
+ $str .= format_js_if_exists($source);
+ }
+ }
}
+ }
return $str;
}
@@ -626,14 +650,20 @@ function head_get_main_js() {
}
function format_js_if_exists($source) {
- if(strpos($source,'/') !== false)
+ $path_prefix = script_path() . '/';
+
+ if(strpos($source,'/') !== false) {
+ // The source is a URL
$path = $source;
- else
+ // If the url starts with // then it's an absolute URL
+ if($source[0] === '/' && $source[1] === '/') $path_prefix = '';
+ } else {
+ // It's a file from the theme
$path = theme_include($source);
+ }
if($path) {
- $path = script_path() . '/' . $path;
$qstring = ((parse_url($path, PHP_URL_QUERY)) ? '&' : '?') . 'v=' . STD_VERSION;
- return '<script src="' . $path . $qstring . '" ></script>' . "\r\n" ;
+ return '<script src="' . $path_prefix . $path . $qstring . '" ></script>' . "\r\n" ;
}
}
diff --git a/include/reddav.php b/include/reddav.php
deleted file mode 100644
index abf21b86d..000000000
--- a/include/reddav.php
+++ /dev/null
@@ -1,299 +0,0 @@
-<?php
-/**
- * @file include/reddav.php
- * @brief some DAV related functions for Hubzilla.
- *
- * This file contains some functions which did not fit into one of the RedDAV
- * classes.
- *
- * The extended SabreDAV classes you will find in the RedDAV namespace under
- * @ref includes/RedDAV/.
- * The original SabreDAV classes you can find under @ref vendor/sabre/dav/.
- * We need to use SabreDAV 1.8.x for PHP5.3 compatibility. SabreDAV >= 2.0
- * requires PHP >= 5.4.
- *
- * @todo split up the classes into own files.
- *
- * @link http://github.com/friendica/red
- * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
- */
-
-use Sabre\DAV;
-use Zotlabs\Storage;
-
-require_once('vendor/autoload.php');
-require_once('include/attach.php');
-
-/**
- * @brief Returns an array with viewable channels.
- *
- * Get a list of RedDirectory objects with all the channels where the visitor
- * has <b>view_storage</b> perms.
- *
- * @todo Is there any reason why this is not inside RedDirectory class?
- * @fixme function name looks like a class name, should we rename it?
- *
- * @param RedBasicAuth &$auth
- * @return array RedDirectory[]
- */
-function RedChannelList(&$auth) {
- $ret = array();
-
- $r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 AND channel_system = 0 AND NOT (channel_pageflags & %d)>0",
- intval(PAGE_HIDDEN)
- );
-
- if ($r) {
- foreach ($r as $rr) {
- if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
- logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
- // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
- $ret[] = new Zotlabs\Storage\Directory('/cloud/' . $rr['channel_address'], $auth);
- }
- }
- }
- return $ret;
-}
-
-
-/**
- * @brief TODO what exactly does this function?
- *
- * Array with all RedDirectory and RedFile DAV\Node items for the given path.
- *
- * @todo Is there any reason why this is not inside RedDirectory class? Seems
- * only to be used there and we could simplify it a bit there.
- * @fixme function name looks like a class name, should we rename it?
- *
- * @param string $file path to a directory
- * @param RedBasicAuth &$auth
- * @returns null|array \Sabre\DAV\INode[]
- * @throw \Sabre\DAV\Exception\Forbidden
- * @throw \Sabre\DAV\Exception\NotFound
- */
-function RedCollectionData($file, &$auth) {
- $ret = array();
-
- $x = strpos($file, '/cloud');
- if ($x === 0) {
- $file = substr($file, 6);
- }
-
- // return a list of channel if we are not inside a channel
- if ((! $file) || ($file === '/')) {
- return RedChannelList($auth);
- }
-
- $file = trim($file, '/');
- $path_arr = explode('/', $file);
-
- if (! $path_arr)
- return null;
-
- $channel_name = $path_arr[0];
-
- $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' LIMIT 1",
- dbesc($channel_name)
- );
-
- if (! $r)
- return null;
-
- $channel_id = $r[0]['channel_id'];
- $perms = permissions_sql($channel_id);
-
- $auth->owner_id = $channel_id;
-
- $path = '/' . $channel_name;
-
- $folder = '';
- $errors = false;
- $permission_error = false;
-
- for ($x = 1; $x < count($path_arr); $x++) {
- $r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1",
- dbesc($folder),
- dbesc($path_arr[$x]),
- intval($channel_id)
- );
- if (! $r) {
- // path wasn't found. Try without permissions to see if it was the result of permissions.
- $errors = true;
- $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1",
- dbesc($folder),
- basename($path_arr[$x]),
- intval($channel_id)
- );
- if ($r) {
- $permission_error = true;
- }
- break;
- }
-
- if ($r && intval($r[0]['is_dir'])) {
- $folder = $r[0]['hash'];
- $path = $path . '/' . $r[0]['filename'];
- }
- }
-
- if ($errors) {
- if ($permission_error) {
- throw new DAV\Exception\Forbidden('Permission denied.');
- } else {
- throw new DAV\Exception\NotFound('A component of the request file path could not be found.');
- }
- }
-
- // This should no longer be needed since we just returned errors for paths not found
- if ($path !== '/' . $file) {
- logger("Path mismatch: $path !== /$file");
- return NULL;
- }
- if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
- $prefix = 'DISTINCT ON (filename)';
- $suffix = 'ORDER BY filename';
- } else {
- $prefix = '';
- $suffix = 'GROUP BY filename';
- }
- $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix",
- dbesc($folder),
- intval($channel_id)
- );
-
- foreach ($r as $rr) {
- //logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
- if (intval($rr['is_dir'])) {
- $ret[] = new Zotlabs\Storage\Directory($path . '/' . $rr['filename'], $auth);
- } else {
- $ret[] = new Zotlabs\Storage\File($path . '/' . $rr['filename'], $rr, $auth);
- }
- }
-
- return $ret;
-}
-
-
-/**
- * @brief TODO What exactly is this function for?
- *
- * @fixme function name looks like a class name, should we rename it?
- *
- * @param string $file
- * path to file or directory
- * @param RedBasicAuth &$auth
- * @param boolean $test (optional) enable test mode
- * @return RedFile|RedDirectory|boolean|null
- * @throw \Sabre\DAV\Exception\Forbidden
- */
-function RedFileData($file, &$auth, $test = false) {
- logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA);
-
- $x = strpos($file, '/cloud');
- if ($x === 0) {
- $file = substr($file, 6);
- }
- else {
- $x = strpos($file,'/dav');
- if($x === 0)
- $file = substr($file,4);
- }
-
-
- if ((! $file) || ($file === '/')) {
- return new Zotlabs\Storage\Directory('/', $auth);
- }
-
- $file = trim($file, '/');
-
- $path_arr = explode('/', $file);
-
- if (! $path_arr)
- return null;
-
- $channel_name = $path_arr[0];
-
- $r = q("select channel_id from channel where channel_address = '%s' limit 1",
- dbesc($channel_name)
- );
-
- if (! $r)
- return null;
-
- $channel_id = $r[0]['channel_id'];
-
- $path = '/' . $channel_name;
-
- $auth->owner_id = $channel_id;
-
- $permission_error = false;
-
- $folder = '';
-
- require_once('include/security.php');
- $perms = permissions_sql($channel_id);
-
- $errors = false;
-
- for ($x = 1; $x < count($path_arr); $x++) {
- $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms",
- dbesc($folder),
- dbesc($path_arr[$x]),
- intval($channel_id)
- );
-
- if ($r && intval($r[0]['is_dir'])) {
- $folder = $r[0]['hash'];
- $path = $path . '/' . $r[0]['filename'];
- }
- if (! $r) {
- $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
- where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1",
- dbesc($folder),
- dbesc(basename($file)),
- intval($channel_id)
- );
- }
- if (! $r) {
- $errors = true;
- $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
- where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1",
- dbesc($folder),
- dbesc(basename($file)),
- intval($channel_id)
- );
- if ($r)
- $permission_error = true;
- }
- }
-
- if ($path === '/' . $file) {
- if ($test)
- return true;
- // final component was a directory.
- return new Zotlabs\Storage\Directory($file, $auth);
- }
-
- if ($errors) {
- logger('not found ' . $file);
- if ($test)
- return false;
- if ($permission_error) {
- logger('permission error ' . $file);
- throw new DAV\Exception\Forbidden('Permission denied.');
- }
- return;
- }
-
- if ($r) {
- if ($test)
- return true;
-
- if (intval($r[0]['is_dir'])) {
- return new Zotlabs\Storage\Directory($path . '/' . $r[0]['filename'], $auth);
- } else {
- return new Zotlabs\Storage\File($path . '/' . $r[0]['filename'], $r[0], $auth);
- }
- }
- return false;
-} \ No newline at end of file
diff --git a/include/security.php b/include/security.php
index 38045c8a9..2107ed819 100644
--- a/include/security.php
+++ b/include/security.php
@@ -12,7 +12,7 @@
* @param bool $return
* @param bool $update_lastlog
*/
-function authenticate_success($user_record, $login_initial = false, $interactive = false, $return = false, $update_lastlog = false) {
+function authenticate_success($user_record, $channel = null, $login_initial = false, $interactive = false, $return = false, $update_lastlog = false) {
$_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
@@ -23,11 +23,15 @@ function authenticate_success($user_record, $login_initial = false, $interactive
$_SESSION['account_id'] = $user_record['account_id'];
$_SESSION['authenticated'] = 1;
+ if($channel)
+ $uid_to_load = $channel['channel_id'];
- $uid_to_load = (((x($_SESSION,'uid')) && (intval($_SESSION['uid'])))
- ? intval($_SESSION['uid'])
- : intval(App::$account['account_default_channel'])
- );
+ if(! $uid_to_load) {
+ $uid_to_load = (((x($_SESSION,'uid')) && (intval($_SESSION['uid'])))
+ ? intval($_SESSION['uid'])
+ : intval(App::$account['account_default_channel'])
+ );
+ }
if($uid_to_load) {
change_channel($uid_to_load);
@@ -82,6 +86,41 @@ function authenticate_success($user_record, $login_initial = false, $interactive
/* else just return */
}
+function atoken_login($atoken) {
+ if(! $atoken)
+ return false;
+ $_SESSION['authenticated'] = 1;
+ $_SESSION['visitor_id'] = $atoken['xchan_hash'];
+ $_SESSION['atoken'] = $atoken['atoken_id'];
+
+ \App::set_observer($atoken);
+ return true;
+}
+
+
+function atoken_xchan($atoken) {
+
+ $c = channelx_by_n($atoken['atoken_uid']);
+ if($c) {
+ return [
+ 'atoken_id' => $atoken['atoken_id'],
+ 'xchan_hash' => substr($c['channel_hash'],0,16) . '.' . $atoken['atoken_name'],
+ 'xchan_name' => $atoken['atoken_name'],
+ 'xchan_addr' => t('guest:') . $atoken['atoken_name'] . '@' . \App::get_hostname(),
+ 'xchan_network' => 'unknown',
+ 'xchan_hidden' => 1,
+ 'xchan_photo_mimetype' => 'image/jpeg',
+ 'xchan_photo_l' => get_default_profile_photo(300),
+ 'xchan_photo_m' => get_default_profile_photo(80),
+ 'xchan_photo_s' => get_default_profile_photo(48)
+
+ ];
+ }
+ return null;
+}
+
+
+
/**
* @brief Change to another channel with current logged-in account.
*
@@ -125,13 +164,17 @@ function change_channel($change_channel) {
);
if($x) {
$_SESSION['my_url'] = $x[0]['xchan_url'];
- $_SESSION['my_address'] = $r[0]['channel_address'] . '@' . substr(z_root(), strpos(z_root(), '://') + 3);
+ $_SESSION['my_address'] = $r[0]['channel_address'] . '@' . App::get_hostname();
App::set_observer($x[0]);
App::set_perms(get_all_perms(local_channel(), $hash));
}
if(! is_dir('store/' . $r[0]['channel_address']))
@os_mkdir('store/' . $r[0]['channel_address'], STORAGE_DEFAULT_PERMISSIONS,true);
+
+ $arr = [ 'channel_id' => $change_channel, 'chanx' => $ret ];
+ call_hooks('change_channel', $arr);
+
}
return $ret;
diff --git a/include/spam.php b/include/spam.php
deleted file mode 100644
index 8b158b7ae..000000000
--- a/include/spam.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php /** @file */
-
-
-function string_splitter($s) {
-
- if(! $s)
- return array();
-
- $s = preg_replace('/\pP+/','',$s);
-
- $x = mb_split("\[|\]|\s",$s);
-
- $ret = array();
- if($x) {
- foreach($x as $y) {
- if(mb_strlen($y) > 2)
- $ret[] = substr($y,0,64);
- }
- }
- return $ret;
-}
-
-
-
-function get_words($uid,$list) {
-
- stringify($list,true);
-
- $r = q("select * from spam where term in ( " . $list . ") and uid = %d",
- intval($uid)
- );
-
- return $r;
-}
-
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 177215fe8..067bd3246 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -400,7 +400,7 @@ function get_things($profile_hash,$uid) {
if(! $things[$rr['obj_verb']])
$things[$rr['obj_verb']] = array();
- $things[$rr['obj_verb']][] = array('term' => $rr['obj_term'],'url' => $rr['obj_url'],'img' => $rr['obj_imgurl'], 'profile' => $rr['profile_name'],'term_hash' => $rr['obj_obj'], 'likes' => $l,'like_count' => count($l),'like_label' => tt('Like','Likes',count($l),'noun'));
+ $things[$rr['obj_verb']][] = array('term' => $rr['obj_term'],'url' => $rr['obj_url'],'img' => $rr['obj_imgurl'], 'editurl' => z_root() . '/thing/' . $rr['obj_obj'], 'profile' => $rr['profile_name'],'term_hash' => $rr['obj_obj'], 'likes' => $l,'like_count' => count($l),'like_label' => tt('Like','Likes',count($l),'noun'));
}
$sorted_things = array();
if($things) {
diff --git a/include/text.php b/include/text.php
index 1bc19da34..d4d151f2e 100644
--- a/include/text.php
+++ b/include/text.php
@@ -376,30 +376,6 @@ function unxmlify($s) {
return $ret;
}
-/**
- * Convenience wrapper, reverse the operation "bin2hex"
- * This is a built-in function in php >= 5.4
- *
- * @FIXME We already have php >= 5.4 requirements, so can we remove this?
- */
-if(! function_exists('hex2bin')) {
-function hex2bin($s) {
- if(! (is_string($s) && strlen($s)))
- return '';
-
- if(strlen($s) & 1) {
- logger('hex2bin: illegal hex string: ' . $s);
- return $s;
- }
-
- if(! ctype_xdigit($s)) {
- return($s);
- }
-
- return(pack("H*",$s));
-}}
-
-
// Automatic pagination.
// To use, get the count of total items.
// Then call App::set_pager_total($number_items);
@@ -711,7 +687,7 @@ function get_tags($s) {
// ignore anything in a code block
- $s = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$s);
+ $s = preg_replace('/\[code(.*?)\](.*?)\[\/code\]/sm','',$s);
// ignore anything in [style= ]
$s = preg_replace('/\[style=(.*?)\]/sm','',$s);
@@ -798,6 +774,10 @@ function strip_zids($s) {
return preg_replace('/[\?&]zid=(.*?)(&|$)/ism','$2',$s);
}
+function strip_zats($s) {
+ return preg_replace('/[\?&]zat=(.*?)(&|$)/ism','$2',$s);
+}
+
// quick and dirty quoted_printable encoding
@@ -1283,7 +1263,7 @@ function normalise_link($url) {
* is https and the other isn't, or if one is www.something and the other
* isn't - and also ignore case differences.
*
- * @see normalis_link()
+ * @see normalise_link()
*
* @param string $a
* @param string $b
@@ -1635,7 +1615,7 @@ function prepare_text($text, $content_type = 'text/bbcode', $cache = false) {
function create_export_photo_body(&$item) {
if(($item['verb'] === ACTIVITY_POST) && ($item['obj_type'] === ACTIVITY_OBJ_PHOTO)) {
- $j = json_decode($item['object'],true);
+ $j = json_decode($item['obj'],true);
if($j) {
$item['body'] .= "\n\n" . (($j['body']) ? $j['body'] : $j['bbcode']);
$item['sig'] = '';
@@ -1743,7 +1723,8 @@ function unamp($s) {
}
function layout_select($channel_id, $current = '') {
- $r = q("select mid,sid from item left join item_id on iid = item.id where service = 'PDL' and item.uid = item_id.uid and item_id.uid = %d and item_type = %d ",
+ $r = q("select mid, v from item left join iconfig on iconfig.iid = item.id
+ where iconfig.cat = 'system' and iconfig.k = 'PDL' and item.uid = %d and item_type = %d ",
intval($channel_id),
intval(ITEM_TYPE_PDL)
);
@@ -1753,7 +1734,7 @@ function layout_select($channel_id, $current = '') {
$options .= '<option value="" ' . $empty_selected . '>' . t('default') . '</option>';
foreach($r as $rr) {
$selected = (($rr['mid'] == $current) ? ' selected="selected" ' : '');
- $options .= '<option value="' . $rr['mid'] . '"' . $selected . '>' . $rr['sid'] . '</option>';
+ $options .= '<option value="' . $rr['mid'] . '"' . $selected . '>' . $rr['v'] . '</option>';
}
}
@@ -2049,7 +2030,7 @@ function ids_to_array($arr,$idx = 'id') {
$t = array();
if($arr) {
foreach($arr as $x) {
- if(! in_array($x[$idx],$t)) {
+ if(array_key_exists($idx,$x) && strlen($x[$idx]) && (! in_array($x[$idx],$t))) {
$t[] = $x[$idx];
}
}
@@ -2088,9 +2069,9 @@ function xchan_query(&$items,$abook = true,$effective_uid = 0) {
}
foreach($items as $item) {
- if($item['owner_xchan'] && (! in_array($item['owner_xchan'],$arr)))
+ if($item['owner_xchan'] && (! in_array("'" . dbesc($item['owner_xchan']) . "'",$arr)))
$arr[] = "'" . dbesc($item['owner_xchan']) . "'";
- if($item['author_xchan'] && (! in_array($item['author_xchan'],$arr)))
+ if($item['author_xchan'] && (! in_array("'" . dbesc($item['author_xchan']) . "'",$arr)))
$arr[] = "'" . dbesc($item['author_xchan']) . "'";
}
}
@@ -2123,9 +2104,9 @@ function xchan_mail_query(&$item) {
$arr = array();
$chans = null;
if($item) {
- if($item['from_xchan'] && (! in_array($item['from_xchan'],$arr)))
+ if($item['from_xchan'] && (! in_array("'" . dbesc($item['from_xchan']) . "'",$arr)))
$arr[] = "'" . dbesc($item['from_xchan']) . "'";
- if($item['to_xchan'] && (! in_array($item['to_xchan'],$arr)))
+ if($item['to_xchan'] && (! in_array("'" . dbesc($item['to_xchan']) . "'",$arr)))
$arr[] = "'" . dbesc($item['to_xchan']) . "'";
}
@@ -2377,7 +2358,13 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
$str_tags .= $newtag;
}
- return array('replaced' => $replaced, 'termtype' => $termtype, 'term' => $basetag, 'url' => $url, 'contact' => $r[0]);
+ return [
+ 'replaced' => $replaced,
+ 'termtype' => $termtype,
+ 'term' => $basetag,
+ 'url' => $url,
+ 'contact' => $r[0]
+ ];
}
//is it a person tag?
@@ -2568,7 +2555,13 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
}
}
- return array('replaced' => $replaced, 'termtype' => $termtype, 'term' => $newname, 'url' => $url, 'contact' => $r[0]);
+ return [
+ 'replaced' => $replaced,
+ 'termtype' => $termtype,
+ 'term' => $newname,
+ 'url' => $url,
+ 'contact' => $r[0]
+ ];
}
function linkify_tags($a, &$body, $uid, $diaspora = false) {
@@ -2821,13 +2814,16 @@ function expand_acl($s) {
// If it has a pdl we'll load it as we know the mid and pass the body through comanche_parser() which will generate the
// page layout from the given description
+// @FIXME - there is apparently a very similar function called layout_select; this one should probably take precedence
+// and the other should be checked for compatibility and removed
function pdl_selector($uid, $current="") {
$o = '';
$sql_extra = item_permissions_sql($uid);
- $r = q("select item_id.*, mid from item_id left join item on iid = item.id where item_id.uid = %d and item_id.uid = item.uid and service = 'PDL' $sql_extra order by sid asc",
+ $r = q("select iconfig.*, mid from item_id left join item on iconfig.iid = item.id
+ where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' $sql_extra order by v asc",
intval($uid)
);
@@ -2841,7 +2837,7 @@ function pdl_selector($uid, $current="") {
$entries[] = array('title' => t('Default'), 'mid' => '');
foreach($entries as $selection) {
$selected = (($selection == $current) ? ' selected="selected" ' : '');
- $o .= "<option value=\"{$selection['mid']}\" $selected >{$selection['sid']}</option>";
+ $o .= "<option value=\"{$selection['mid']}\" $selected >{$selection['v']}</option>";
}
$o .= '</select>';
@@ -2877,3 +2873,54 @@ function flatten_array_recursive($arr) {
}
return($ret);
}
+
+function text_highlight($s,$lang) {
+
+ if($lang === 'js')
+ $lang = 'javascript';
+
+ if($lang === 'json') {
+ $lang = 'javascript';
+ if(! strpos(trim($s),"\n"))
+ $s = jindent($s);
+ }
+
+ if(! strpos('Text_Highlighter',get_include_path())) {
+ set_include_path(get_include_path() . PATH_SEPARATOR . 'library/Text_Highlighter');
+ }
+ require_once('library/Text_Highlighter/Text/Highlighter.php');
+ require_once('library/Text_Highlighter/Text/Highlighter/Renderer/Html.php');
+ $options = array(
+ 'numbers' => HL_NUMBERS_LI,
+ 'tabsize' => 4,
+ );
+ $tag_added = false;
+ $s = trim(html_entity_decode($s,ENT_COMPAT));
+ $s = str_replace(" ","\t",$s);
+
+ // The highlighter library insists on an opening php tag for php code blocks. If
+ // it isn't present, nothing is highlighted. So we're going to see if it's present.
+ // If not, we'll add it, and then quietly remove it after we get the processed output back.
+
+ if($lang === 'php') {
+ if(strpos('<?php',$s) !== 0) {
+ $s = '<?php' . "\n" . $s;
+ $tag_added = true;
+ }
+
+ }
+ $renderer = new Text_Highlighter_Renderer_HTML($options);
+ $hl = Text_Highlighter::factory($lang);
+ $hl->setRenderer($renderer);
+ $o = $hl->highlight($s);
+ $o = str_replace([" ","\n"],["&nbsp;&nbsp;&nbsp;&nbsp;",''],$o);
+
+ if($tag_added) {
+ $b = substr($o,0,strpos($o,'<li>'));
+ $e = substr($o,strpos($o,'</li>'));
+ $o = $b . $e;
+ }
+
+ return('<code>' . $o . '</code>');
+}
+
diff --git a/include/widgets.php b/include/widgets.php
index 3ca189af0..da73657f5 100644
--- a/include/widgets.php
+++ b/include/widgets.php
@@ -296,7 +296,7 @@ function widget_filer($arr) {
$selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : '');
$terms = array();
- $r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
+ $r = q("select distinct term from term where uid = %d and ttype = %d order by term asc",
intval(local_channel()),
intval(TERM_FILE)
);
@@ -609,6 +609,15 @@ function widget_settings_menu($arr) {
'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
);
+ if(! UNO) {
+ $tabs[] = array(
+ 'label' => t('Guest Access Tokens'),
+ 'url' => z_root() . '/settings/tokens',
+ 'selected' => ((argv(1) === 'tokens') ? 'active' : ''),
+ );
+ }
+
+
if($role === false || $role === 'custom') {
$tabs[] = array(
'label' => t('Connection Default Permissions'),
@@ -743,21 +752,6 @@ function widget_conversations($arr) {
return $o;
}
-function widget_eventsmenu($arr) {
- if (! local_channel())
- return;
-
- return replace_macros(get_markup_template('events_menu_side.tpl'), array(
- '$title' => t('Events Menu'),
- '$day' => t('Day View'),
- '$week' => t('Week View'),
- '$month' => t('Month View'),
- '$export' => t('Export'),
- '$upload' => t('Import'),
- '$submit' => t('Submit')
- ));
-}
-
function widget_eventstools($arr) {
if (! local_channel())
return;
@@ -994,8 +988,9 @@ function widget_item($arr) {
$sql_extra = item_permissions_sql($channel_id);
if($arr['title']) {
- $r = q("select item.* from item left join item_id on item.id = item_id.iid
- where item.uid = %d and sid = '%s' and service = 'WEBPAGE' and item_type = %d $sql_options $revision limit 1",
+ $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
+ where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s'
+ and iconfig.k = 'WEBPAGE' and item_type = %d $sql_options $revision limit 1",
intval($channel_id),
dbesc($arr['title']),
intval(ITEM_TYPE_WEBPAGE)
@@ -1157,7 +1152,7 @@ function widget_cover_photo($arr) {
if(array_key_exists('subtitle', $arr) && isset($arr['subtitle']))
$subtitle = $arr['subtitle'];
else
- $subtitle = $channel['xchan_addr'];
+ $subtitle = str_replace('@','&#x40;',$channel['xchan_addr']);
$c = get_cover_photo($channel_id,'html');
@@ -1253,8 +1248,8 @@ function widget_random_block($arr) {
$randfunc = db_getfunc('RAND');
- $r = q("select item.* from item left join item_id on item.id = item_id.iid
- where item.uid = %d and sid like '%s' and service = 'BUILDBLOCK' and
+ $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
+ where item.uid = %d and iconfig.cat = 'system' and iconfig.v like '%s' and iconfig.k = 'BUILDBLOCK' and
item_type = %d $sql_options order by $randfunc limit 1",
intval($channel_id),
dbesc('%' . $contains . '%'),
@@ -1361,7 +1356,7 @@ function widget_forums($arr) {
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
- $r1 = q("select * from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ",
+ $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ",
intval(PERMS_W_TAGWALL),
intval(PERMS_W_STREAM),
intval(local_channel())
@@ -1375,12 +1370,34 @@ function widget_forums($arr) {
// There also should be a way to update this via ajax.
for($x = 0; $x < count($r1); $x ++) {
- $r = q("select sum(item_unseen) as unseen from item where owner_xchan = '%s' and uid = %d $perms_sql ",
+ $r = q("select sum(item_unseen) as unseen from item where owner_xchan = '%s' and uid = %d and item_unseen = 1 $perms_sql ",
dbesc($r1[$x]['xchan_hash']),
intval(local_channel())
);
if($r)
$r1[$x]['unseen'] = $r[0]['unseen'];
+
+/**
+ * @FIXME
+ * This SQL makes the counts correct when you get forum posts arriving from different routes/sources
+ * (like personal channels). However the network query for these posts doesn't yet include this
+ * correction and it makes the SQL for that query pretty hairy so this is left as a future exercise.
+ * It may make more sense in that query to look for the mention in the body rather than another join,
+ * but that makes it very inefficient.
+ *
+ $r = q("select sum(item_unseen) as unseen from item left join term on oid = id where otype = %d and owner_xchan != '%s' and item.uid = %d and url = '%s' and ttype = %d $perms_sql ",
+ intval(TERM_OBJ_POST),
+ dbesc($r1[$x]['xchan_hash']),
+ intval(local_channel()),
+ dbesc($r1[$x]['xchan_url']),
+ intval(TERM_MENTION)
+ );
+ if($r)
+ $r1[$x]['unseen'] = ((array_key_exists('unseen',$r1[$x])) ? $r1[$x]['unseen'] + $r[0]['unseen'] : $r[0]['unseen']);
+ *
+ * end @FIXME
+ */
+
}
if($r1) {
diff --git a/include/wiki.php b/include/wiki.php
index 4aa3fc1b4..424b2d9a0 100644
--- a/include/wiki.php
+++ b/include/wiki.php
@@ -51,7 +51,7 @@ function wiki_init_wiki($channel, $wiki) {
return null;
}
// Create GitRepo object
- $git = new GitRepo($channel['channel_address'], null, false, $name, __DIR__ . '/../' . $path);
+ $git = new GitRepo($channel['channel_address'], null, false, $wiki['urlName'], __DIR__ . '/../' . $path);
if(!$git->initRepo()) {
logger('Error creating new git repo in ' . $git->path);
return null;
@@ -82,7 +82,7 @@ function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) {
$ac = $acl->get();
$mid = item_message_id();
$arr = array(); // Initialize the array of parameters for the post
- $item_hidden = 0; // TODO: Allow form creator to send post to ACL about new game automatically
+ $item_hidden = ((intval($wiki['postVisible']) === 0) ? 1 : 0);
$wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
@@ -231,6 +231,32 @@ function wiki_create_page($name, $resource_id) {
}
+function wiki_rename_page($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $pageNewName = ((array_key_exists('pageNewName',$arr)) ? $arr['pageNewName'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('message' => 'Wiki not found.', 'success' => false);
+ }
+ $page_path_old = $w['path'].'/'.$pageUrlName.'.md';
+ if (!is_readable($page_path_old) === true) {
+ return array('message' => 'Cannot read wiki page: ' . $page_path_old, 'success' => false);
+ }
+ $page = array('rawName' => $pageNewName, 'htmlName' => escape_tags($pageNewName), 'urlName' => urlencode(escape_tags($pageNewName)), 'fileName' => urlencode(escape_tags($pageNewName)).'.md');
+ $page_path_new = $w['path'] . '/' . $page['fileName'] ;
+ if (is_file($page_path_new)) {
+ return array('message' => 'Page already exists.', 'success' => false);
+ }
+ // Rename the page file in the wiki repo
+ if(!rename($page_path_old, $page_path_new)) {
+ return array('message' => 'Error renaming page file.', 'success' => false);
+ } else {
+ return array('page' => $page, 'message' => '', 'success' => true);
+ }
+
+}
+
function wiki_get_page_content($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
@@ -319,7 +345,7 @@ function wiki_revert_page($arr) {
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$commitHash = ((array_key_exists('commitHash',$arr)) ? $arr['commitHash'] : null);
if (! $commitHash) {
- return array('content' => $content, 'message' => 'No commit has provided', 'success' => false);
+ return array('content' => $content, 'message' => 'No commit was provided', 'success' => false);
}
$w = wiki_get_wiki($resource_id);
if (!$w['path']) {
@@ -342,7 +368,7 @@ function wiki_revert_page($arr) {
}
}
} catch (\PHPGit\Exception\GitException $e) {
- json_return_and_die(array('content' => $content, 'message' => 'GitRepo error thrown', 'success' => false));
+ return array('content' => $content, 'message' => 'GitRepo error thrown', 'success' => false);
}
return array('content' => $content, 'message' => '', 'success' => true);
} else {
@@ -350,11 +376,62 @@ function wiki_revert_page($arr) {
}
}
+function wiki_compare_page($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $currentCommit = ((array_key_exists('currentCommit',$arr)) ? $arr['currentCommit'] : 'HEAD');
+ $compareCommit = ((array_key_exists('compareCommit',$arr)) ? $arr['compareCommit'] : null);
+ if (! $compareCommit) {
+ return array('message' => 'No compare commit was provided', 'success' => false);
+ }
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('message' => 'Error reading wiki', 'success' => false);
+ }
+ $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ if (is_readable($page_path) === true) {
+ $reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo');
+ if($reponame === '') {
+ $reponame = 'repo';
+ }
+ $git = new GitRepo('', null, false, $w['wiki']['title'], $w['path']);
+ $compareContent = $currentContent = '';
+ try {
+ foreach ($git->git->tree($currentCommit) as $object) {
+ if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) {
+ $currentContent = $git->git->cat->blob($object['hash']);
+ }
+ }
+ foreach ($git->git->tree($compareCommit) as $object) {
+ if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) {
+ $compareContent = $git->git->cat->blob($object['hash']);
+ }
+ }
+ require_once('library/class.Diff.php');
+ $diff = Diff::toTable(Diff::compare($currentContent, $compareContent));
+ } catch (\PHPGit\Exception\GitException $e) {
+ return array('message' => 'GitRepo error thrown', 'success' => false);
+ }
+ return array('diff' => $diff, 'message' => '', 'success' => true);
+ } else {
+ return array('message' => 'Page file not writable', 'success' => false);
+ }
+}
+
function wiki_git_commit($arr) {
$files = ((array_key_exists('files', $arr)) ? $arr['files'] : null);
+ $all = ((array_key_exists('all', $arr)) ? $arr['all'] : false);
$commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : 'Repo updated');
- $resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : json_return_and_die(array('message' => 'Wiki resource_id required for git commit', 'success' => false)));
- $observer = ((array_key_exists('observer', $arr)) ? $arr['observer'] : json_return_and_die(array('message' => 'Observer required for git commit', 'success' => false)));
+ if(array_key_exists('resource_id', $arr)) {
+ $resource_id = $arr['resource_id'];
+ } else {
+ return array('message' => 'Wiki resource_id required for git commit', 'success' => false);
+ }
+ if(array_key_exists('observer', $arr)) {
+ $observer = $arr['observer'];
+ } else {
+ return array('message' => 'Observer required for git commit', 'success' => false);
+ }
$w = wiki_get_wiki($resource_id);
if (!$w['path']) {
return array('message' => 'Error reading wiki', 'success' => false);
@@ -369,23 +446,23 @@ function wiki_git_commit($arr) {
if ($files === null) {
$options = array('all' => true); // git commit option to include all changes
} else {
- $options = array(); // git commit options
+ $options = array('all' => $all); // git commit options\
foreach ($files as $file) {
if (!$git->git->add($file)) { // add specified files to the git repo stage
if (!$git->git->reset->hard()) {
- json_return_and_die(array('message' => 'Error adding file to git stage: ' . $file . '. Error resetting git repo.', 'success' => false));
+ return array('message' => 'Error adding file to git stage: ' . $file . '. Error resetting git repo.', 'success' => false);
}
- json_return_and_die(array('message' => 'Error adding file to git stage: ' . $file, 'success' => false));
+ return array('message' => 'Error adding file to git stage: ' . $file, 'success' => false);
}
}
}
if ($git->commit($commit_msg, $options)) {
- json_return_and_die(array('message' => 'Wiki repo commit succeeded', 'success' => true));
+ return array('message' => 'Wiki repo commit succeeded', 'success' => true);
} else {
- json_return_and_die(array('message' => 'Wiki repo commit failed', 'success' => false));
+ return array('message' => 'Wiki repo commit failed', 'success' => false);
}
} catch (\PHPGit\Exception\GitException $e) {
- json_return_and_die(array('message' => 'GitRepo error thrown', 'success' => false));
+ return array('message' => 'GitRepo error thrown', 'success' => false);
}
}
@@ -396,4 +473,99 @@ function wiki_generate_page_filename($name) {
} else {
return $file . '.md';
}
-} \ No newline at end of file
+}
+
+function wiki_convert_links($s, $wikiURL) {
+
+ if (strpos($s,'[[') !== false) {
+ preg_match_all("/\[\[(.*?)\]\]/", $s, $match);
+ $pages = $pageURLs = array();
+ foreach ($match[1] as $m) {
+ // TODO: Why do we need to double urlencode for this to work?
+ $pageURLs[] = urlencode(urlencode(escape_tags($m)));
+ $pages[] = $m;
+ }
+ $idx = 0;
+ while(strpos($s,'[[') !== false) {
+ $replace = '<a href="'.$wikiURL.'/'.$pageURLs[$idx].'">'.$pages[$idx].'</a>';
+ $s = preg_replace("/\[\[(.*?)\]\]/", $replace, $s, 1);
+ $idx++;
+ }
+ }
+ return $s;
+}
+
+function wiki_generate_toc($s) {
+
+ if (strpos($s,'[toc]') !== false) {
+ //$toc_md = wiki_toc($s); // Generate Markdown-formatted list prior to HTML render
+ $toc_md = '<ul id="wiki-toc"></ul>'; // use the available jQuery plugin http://ndabas.github.io/toc/
+ $s = preg_replace("/\[toc\]/", $toc_md, $s, -1);
+ }
+ return $s;
+}
+
+// This function is derived from
+// http://stackoverflow.com/questions/32068537/generate-table-of-contents-from-markdown-in-php
+function wiki_toc($content) {
+ // ensure using only "\n" as line-break
+ $source = str_replace(["\r\n", "\r"], "\n", $content);
+
+ // look for markdown TOC items
+ preg_match_all(
+ '/^(?:=|-|#).*$/m',
+ $source,
+ $matches,
+ PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
+ );
+
+ // preprocess: iterate matched lines to create an array of items
+ // where each item is an array(level, text)
+ $file_size = strlen($source);
+ foreach ($matches[0] as $item) {
+ $found_mark = substr($item[0], 0, 1);
+ if ($found_mark == '#') {
+ // text is the found item
+ $item_text = $item[0];
+ $item_level = strrpos($item_text, '#') + 1;
+ $item_text = substr($item_text, $item_level);
+ } else {
+ // text is the previous line (empty if <hr>)
+ $item_offset = $item[1];
+ $prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
+ $item_text =
+ substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
+ $item_text = trim($item_text);
+ $item_level = $found_mark == '=' ? 1 : 2;
+ }
+ if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
+ // item is an horizontal separator or a table header, don't mind
+ continue;
+ }
+ $raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
+ }
+ $o = '';
+ foreach($raw_toc as $t) {
+ $level = intval($t['level']);
+ $text = $t['text'];
+ switch ($level) {
+ case 1:
+ $li = '* ';
+ break;
+ case 2:
+ $li = ' * ';
+ break;
+ case 3:
+ $li = ' * ';
+ break;
+ case 4:
+ $li = ' * ';
+ break;
+ default:
+ $li = '* ';
+ break;
+ }
+ $o .= $li . $text . "\n";
+ }
+ return $o;
+}
diff --git a/include/zot.php b/include/zot.php
index 043139e2f..45347ef22 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -552,7 +552,7 @@ function zot_refresh($them, $channel = null, $force = false) {
unset($new_connection[0]['abook_account']);
unset($new_connection[0]['abook_channel']);
- $abconfig = load_abconfig($channel['channel_hash'],$new_connection['abook_xchan']);
+ $abconfig = load_abconfig($channel['channel_id'],$new_connection['abook_xchan']);
if($abconfig)
$new_connection['abconfig'] = $abconfig;
@@ -3014,7 +3014,12 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
if($x['hubloc_host'] == App::get_hostname())
continue;
- $synchubs[] = $x;
+ $y = q("select site_dead from site where site_url = '%s' limit 1",
+ dbesc($x['hubloc_url'])
+ );
+
+ if((! $y) || ($y[0]['site_dead'] == 0))
+ $synchubs[] = $x;
}
if(! $synchubs)
@@ -3031,7 +3036,8 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
$info = (($packet) ? $packet : array());
$info['type'] = 'channel_sync';
- $info['encoding'] = 'red'; // note: not zot, this packet is very red specific
+ $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific
+ $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ];
if(array_key_exists($uid,App::$config) && array_key_exists('transient',App::$config[$uid])) {
$settings = App::$config[$uid]['transient'];
@@ -3169,10 +3175,13 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
sync_events($channel,$arr['event']);
if(array_key_exists('event_item',$arr) && $arr['event_item'])
- sync_items($channel,$arr['event_item']);
+ sync_items($channel,$arr['event_item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null));
if(array_key_exists('item',$arr) && $arr['item'])
- sync_items($channel,$arr['item']);
+ sync_items($channel,$arr['item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null));
+
+ // deprecated, maintaining for a few months for upward compatibility
+ // this should sync webpages, but the logic is a bit subtle
if(array_key_exists('item_id',$arr) && $arr['item_id'])
sync_items($channel,$arr['item_id']);
@@ -3331,8 +3340,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if($abconfig) {
// @fixme does not handle sync of del_abconfig
foreach($abconfig as $abc) {
- if($abc['chan'] === $channel['channel_hash'])
- set_abconfig($abc['chan'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
+ set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
}
}
}
@@ -3529,13 +3537,6 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
}
}
-
- if(array_key_exists('item',$arr) && $arr['item'])
- sync_items($channel,$arr['item']);
-
- if(array_key_exists('item_id',$arr) && $arr['item_id'])
- sync_items($channel,$arr['item_id']);
-
$addon = array('channel' => $channel,'data' => $arr);
call_hooks('process_channel_sync_delivery',$addon);