aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Access/AccessList.php128
-rw-r--r--Zotlabs/Access/PermissionLimits.php2
-rw-r--r--Zotlabs/Access/Permissions.php159
-rw-r--r--Zotlabs/Daemon/Cron.php6
-rw-r--r--Zotlabs/Daemon/Cron_daily.php10
-rw-r--r--Zotlabs/Daemon/Deliver.php3
-rw-r--r--Zotlabs/Daemon/Gprobe.php2
-rwxr-xr-xZotlabs/Daemon/Importdoc.php14
-rw-r--r--Zotlabs/Daemon/Importfile.php47
-rw-r--r--Zotlabs/Daemon/Notifier.php246
-rw-r--r--Zotlabs/Daemon/Onepoll.php24
-rw-r--r--Zotlabs/Extend/Hook.php9
-rw-r--r--Zotlabs/Lib/ActivityStreams.php199
-rw-r--r--Zotlabs/Lib/Apps.php196
-rw-r--r--Zotlabs/Lib/Cache.php12
-rw-r--r--Zotlabs/Lib/Config.php2
-rw-r--r--Zotlabs/Lib/DB_Upgrade.php121
-rw-r--r--Zotlabs/Lib/Enotify.php24
-rw-r--r--Zotlabs/Lib/JSalmon.php38
-rw-r--r--Zotlabs/Lib/LDSignatures.php135
-rw-r--r--Zotlabs/Lib/MarkdownSoap.php103
-rw-r--r--Zotlabs/Lib/NativeWiki.php90
-rw-r--r--Zotlabs/Lib/NativeWikiPage.php131
-rw-r--r--Zotlabs/Lib/PConfig.php11
-rw-r--r--Zotlabs/Lib/SConfig.php25
-rw-r--r--Zotlabs/Lib/System.php21
-rw-r--r--Zotlabs/Lib/Techlevels.php12
-rw-r--r--Zotlabs/Lib/ThreadItem.php66
-rw-r--r--Zotlabs/Lib/ThreadStream.php18
-rw-r--r--Zotlabs/Module/Acl.php91
-rw-r--r--Zotlabs/Module/Admin.php25
-rw-r--r--Zotlabs/Module/Admin/Plugins.php82
-rw-r--r--Zotlabs/Module/Admin/Site.php40
-rw-r--r--Zotlabs/Module/Admin/Themes.php89
-rw-r--r--Zotlabs/Module/Appman.php19
-rw-r--r--Zotlabs/Module/Apporder.php45
-rw-r--r--Zotlabs/Module/Apps.php7
-rw-r--r--Zotlabs/Module/Attach.php2
-rw-r--r--Zotlabs/Module/Authorize.php71
-rw-r--r--Zotlabs/Module/Block.php2
-rw-r--r--Zotlabs/Module/Bookmarks.php6
-rw-r--r--Zotlabs/Module/Cal.php3
-rw-r--r--Zotlabs/Module/Card_edit.php138
-rw-r--r--Zotlabs/Module/Cards.php187
-rw-r--r--Zotlabs/Module/Cdav.php1259
-rw-r--r--Zotlabs/Module/Changeaddr.php88
-rw-r--r--Zotlabs/Module/Channel.php70
-rw-r--r--Zotlabs/Module/Chanview.php19
-rw-r--r--Zotlabs/Module/Chat.php13
-rw-r--r--Zotlabs/Module/Cloud.php13
-rw-r--r--Zotlabs/Module/Common.php31
-rw-r--r--Zotlabs/Module/Connections.php27
-rw-r--r--Zotlabs/Module/Connedit.php103
-rw-r--r--Zotlabs/Module/Cover_photo.php64
-rw-r--r--Zotlabs/Module/Dav.php74
-rw-r--r--Zotlabs/Module/Directory.php5
-rw-r--r--Zotlabs/Module/Display.php155
-rw-r--r--Zotlabs/Module/Editblock.php7
-rw-r--r--Zotlabs/Module/Editlayout.php1
-rw-r--r--Zotlabs/Module/Editpost.php18
-rw-r--r--Zotlabs/Module/Editwebpage.php23
-rw-r--r--Zotlabs/Module/Embedphotos.php1
-rw-r--r--Zotlabs/Module/Events.php2
-rw-r--r--Zotlabs/Module/Feed.php49
-rw-r--r--Zotlabs/Module/File_upload.php29
-rw-r--r--Zotlabs/Module/Filer.php4
-rw-r--r--Zotlabs/Module/Filestorage.php28
-rw-r--r--Zotlabs/Module/Getfile.php37
-rw-r--r--Zotlabs/Module/Group.php4
-rw-r--r--Zotlabs/Module/Hcard.php27
-rw-r--r--Zotlabs/Module/Help.php79
-rw-r--r--Zotlabs/Module/Impel.php14
-rw-r--r--Zotlabs/Module/Import.php287
-rw-r--r--Zotlabs/Module/Import_items.php94
-rw-r--r--Zotlabs/Module/Invite.php6
-rw-r--r--Zotlabs/Module/Item.php154
-rw-r--r--Zotlabs/Module/Lang.php1
-rw-r--r--Zotlabs/Module/Layouts.php1
-rw-r--r--Zotlabs/Module/Like.php11
-rw-r--r--Zotlabs/Module/Linkinfo.php2
-rw-r--r--Zotlabs/Module/Lockview.php22
-rw-r--r--Zotlabs/Module/Logout.php12
-rw-r--r--Zotlabs/Module/Magic.php31
-rw-r--r--Zotlabs/Module/Mail.php118
-rw-r--r--Zotlabs/Module/Manage.php162
-rw-r--r--Zotlabs/Module/Moderate.php90
-rw-r--r--Zotlabs/Module/Mood.php8
-rw-r--r--Zotlabs/Module/Network.php74
-rw-r--r--Zotlabs/Module/New_channel.php4
-rw-r--r--Zotlabs/Module/Notifications.php37
-rw-r--r--Zotlabs/Module/Notify.php16
-rw-r--r--Zotlabs/Module/Oembed.php2
-rw-r--r--Zotlabs/Module/Oep.php208
-rw-r--r--Zotlabs/Module/Ofeed.php48
-rw-r--r--Zotlabs/Module/Owa.php53
-rw-r--r--Zotlabs/Module/Page.php60
-rw-r--r--Zotlabs/Module/Pdledit.php26
-rw-r--r--Zotlabs/Module/Photo.php9
-rw-r--r--Zotlabs/Module/Photos.php258
-rw-r--r--Zotlabs/Module/Ping.php205
-rw-r--r--Zotlabs/Module/Poke.php34
-rw-r--r--Zotlabs/Module/Post.php8
-rw-r--r--Zotlabs/Module/Probe.php4
-rw-r--r--Zotlabs/Module/Profile.php33
-rw-r--r--Zotlabs/Module/Profile_photo.php35
-rw-r--r--Zotlabs/Module/Profiles.php43
-rw-r--r--Zotlabs/Module/Pubsites.php3
-rw-r--r--Zotlabs/Module/Pubstream.php100
-rw-r--r--Zotlabs/Module/Randprof.php2
-rw-r--r--Zotlabs/Module/React.php4
-rw-r--r--Zotlabs/Module/Register.php28
-rw-r--r--Zotlabs/Module/Rmagic.php8
-rw-r--r--Zotlabs/Module/Rpost.php84
-rw-r--r--Zotlabs/Module/Search.php14
-rw-r--r--Zotlabs/Module/Settings.php2
-rw-r--r--Zotlabs/Module/Settings/Account.php2
-rw-r--r--Zotlabs/Module/Settings/Channel.php17
-rw-r--r--Zotlabs/Module/Settings/Display.php87
-rw-r--r--Zotlabs/Module/Settings/Featured.php18
-rw-r--r--Zotlabs/Module/Settings/Permcats.php6
-rw-r--r--Zotlabs/Module/Setup.php53
-rw-r--r--Zotlabs/Module/Share.php2
-rw-r--r--Zotlabs/Module/Sharedwithme.php8
-rw-r--r--Zotlabs/Module/Siteinfo.php7
-rw-r--r--Zotlabs/Module/Siteinfo_json.php14
-rw-r--r--Zotlabs/Module/Suggest.php6
-rw-r--r--Zotlabs/Module/Tasks.php3
-rw-r--r--Zotlabs/Module/Thing.php4
-rw-r--r--Zotlabs/Module/Token.php40
-rw-r--r--Zotlabs/Module/Update_cards.php39
-rw-r--r--Zotlabs/Module/Update_display.php18
-rw-r--r--Zotlabs/Module/Viewconnections.php2
-rw-r--r--Zotlabs/Module/Viewsrc.php17
-rw-r--r--Zotlabs/Module/Wall_attach.php71
-rw-r--r--Zotlabs/Module/Webpages.php25
-rw-r--r--Zotlabs/Module/Wfinger.php182
-rw-r--r--Zotlabs/Module/Wiki.php232
-rw-r--r--Zotlabs/Module/Xrd.php22
-rw-r--r--Zotlabs/Module/Zfinger.php30
-rw-r--r--Zotlabs/Module/Zotfeed.php3
-rw-r--r--Zotlabs/Render/Comanche.php75
-rw-r--r--Zotlabs/Render/Theme.php12
-rw-r--r--Zotlabs/Storage/BasicAuth.php11
-rw-r--r--Zotlabs/Storage/Browser.php28
-rw-r--r--Zotlabs/Storage/Directory.php64
-rw-r--r--Zotlabs/Storage/File.php18
-rw-r--r--Zotlabs/Web/CheckJS.php6
-rw-r--r--Zotlabs/Web/HTTPHeaders.php60
-rw-r--r--Zotlabs/Web/HTTPSig.php313
-rw-r--r--Zotlabs/Web/Router.php21
-rw-r--r--Zotlabs/Web/WebServer.php63
-rw-r--r--Zotlabs/Widget/Activity.php61
-rw-r--r--Zotlabs/Widget/Admin.php68
-rw-r--r--Zotlabs/Widget/Affinity.php60
-rw-r--r--Zotlabs/Widget/Album.php106
-rw-r--r--Zotlabs/Widget/Appcategories.php49
-rw-r--r--Zotlabs/Widget/Appcloud.php13
-rw-r--r--Zotlabs/Widget/Archive.php55
-rw-r--r--Zotlabs/Widget/Bookmarkedchats.php28
-rw-r--r--Zotlabs/Widget/Catcloud_wall.php19
-rw-r--r--Zotlabs/Widget/Categories.php32
-rw-r--r--Zotlabs/Widget/Cdav.php176
-rw-r--r--Zotlabs/Widget/Chatroom_list.php24
-rw-r--r--Zotlabs/Widget/Chatroom_members.php15
-rw-r--r--Zotlabs/Widget/Clock.php63
-rw-r--r--Zotlabs/Widget/Collections.php51
-rw-r--r--Zotlabs/Widget/Common_friends.php19
-rw-r--r--Zotlabs/Widget/Conversations.php74
-rw-r--r--Zotlabs/Widget/Cover_photo.php59
-rw-r--r--Zotlabs/Widget/Design_tools.php21
-rw-r--r--Zotlabs/Widget/Dirsort.php11
-rw-r--r--Zotlabs/Widget/Dirtags.php13
-rw-r--r--Zotlabs/Widget/Eventstools.php19
-rw-r--r--Zotlabs/Widget/Filer.php36
-rw-r--r--Zotlabs/Widget/Findpeople.php12
-rw-r--r--Zotlabs/Widget/Follow.php37
-rw-r--r--Zotlabs/Widget/Forums.php97
-rw-r--r--Zotlabs/Widget/Fullprofile.php16
-rw-r--r--Zotlabs/Widget/Helpindex.php55
-rw-r--r--Zotlabs/Widget/Item.php54
-rw-r--r--Zotlabs/Widget/Mailmenu.php36
-rw-r--r--Zotlabs/Widget/Menu_preview.php16
-rw-r--r--Zotlabs/Widget/Notes.php23
-rw-r--r--Zotlabs/Widget/Notifications.php150
-rw-r--r--Zotlabs/Widget/Photo.php55
-rw-r--r--Zotlabs/Widget/Photo_albums.php25
-rw-r--r--Zotlabs/Widget/Photo_rand.php66
-rw-r--r--Zotlabs/Widget/Portfolio.php108
-rw-r--r--Zotlabs/Widget/Profile.php13
-rw-r--r--Zotlabs/Widget/Pubsites.php16
-rw-r--r--Zotlabs/Widget/Random_block.php46
-rw-r--r--Zotlabs/Widget/Rating.php67
-rw-r--r--Zotlabs/Widget/Savedsearch.php91
-rw-r--r--Zotlabs/Widget/Settings_menu.php139
-rw-r--r--Zotlabs/Widget/Shortprofile.php18
-rw-r--r--Zotlabs/Widget/Sitesearch.php38
-rw-r--r--Zotlabs/Widget/Suggestedchats.php37
-rw-r--r--Zotlabs/Widget/Suggestions.php58
-rw-r--r--Zotlabs/Widget/Tagcloud.php33
-rw-r--r--Zotlabs/Widget/Tagcloud_wall.php20
-rw-r--r--Zotlabs/Widget/Tasklist.php30
-rw-r--r--Zotlabs/Widget/Vcard.php12
-rw-r--r--Zotlabs/Widget/Website_portation_tools.php22
-rw-r--r--Zotlabs/Widget/Wiki_list.php23
-rw-r--r--Zotlabs/Widget/Wiki_page_history.php27
-rw-r--r--Zotlabs/Widget/Wiki_pages.php66
-rw-r--r--Zotlabs/Widget/Zcard.php11
-rw-r--r--Zotlabs/Zot/Auth.php16
-rw-r--r--Zotlabs/Zot/Finger.php27
-rw-r--r--Zotlabs/Zot/IHandler.php2
-rw-r--r--Zotlabs/Zot/Receiver.php8
-rw-r--r--Zotlabs/Zot/Verify.php16
-rw-r--r--Zotlabs/Zot/ZotHandler.php4
213 files changed, 9562 insertions, 1985 deletions
diff --git a/Zotlabs/Access/AccessList.php b/Zotlabs/Access/AccessList.php
index b073f9d3c..6471b0b1d 100644
--- a/Zotlabs/Access/AccessList.php
+++ b/Zotlabs/Access/AccessList.php
@@ -2,21 +2,55 @@
namespace Zotlabs\Access;
-
+/**
+ * @brief AccessList class.
+ *
+ * A class to hold an AccessList object with allowed and denied contacts and
+ * groups.
+ */
class AccessList {
-
+ /**
+ * @brief Allow contacts
+ * @var string
+ */
private $allow_cid;
+ /**
+ * @brief Allow groups
+ * @var string
+ */
private $allow_gid;
+ /**
+ * @brief Deny contacts
+ * @var string
+ */
private $deny_cid;
+ /**
+ * @brief Deny groups
+ * @var string
+ */
private $deny_gid;
+ /**
+ * @brief Indicates if we are using the default constructor values or
+ * values that have been set explicitly.
+ * @var boolean
+ */
+ private $explicit;
- /* indicates if we are using the default constructor values or values that have been set explicitly. */
-
- private $explicit;
+ /**
+ * @brief Constructor for AccessList class.
+ *
+ * @note The array to pass to the constructor is different from the array
+ * that you provide to the set() or set_from_array() functions.
+ *
+ * @param array $channel A channel array, where these entries are evaluated:
+ * * \e string \b channel_allow_cid => string of allowed cids
+ * * \e string \b channel_allow_gid => string of allowed gids
+ * * \e string \b channel_deny_cid => string of denied cids
+ * * \e string \b channel_deny_gid => string of denied gids
+ */
function __construct($channel) {
-
- if($channel) {
+ if($channel) {
$this->allow_cid = $channel['channel_allow_cid'];
$this->allow_gid = $channel['channel_allow_gid'];
$this->deny_cid = $channel['channel_deny_cid'];
@@ -32,61 +66,95 @@ class AccessList {
$this->explicit = false;
}
+ /**
+ * @brief Get if we are using the default constructor values
+ * or values that have been set explicitly.
+ *
+ * @return boolean
+ */
function get_explicit() {
return $this->explicit;
}
/**
- * Set AccessList from strings such as those in already
- * existing stored data items
+ * @brief Set access list from strings such as those in already
+ * existing stored data items.
+ *
+ * @note The array to pass to this set function is different from the array
+ * that you provide to the constructor or set_from_array().
+ *
+ * @param array $arr
+ * * \e string \b allow_cid => string of allowed cids
+ * * \e string \b allow_gid => string of allowed gids
+ * * \e string \b deny_cid => string of denied cids
+ * * \e string \b deny_gid => string of denied gids
+ * @param boolean $explicit (optional) default true
*/
-
- function set($arr,$explicit = true) {
+ function set($arr, $explicit = true) {
$this->allow_cid = $arr['allow_cid'];
$this->allow_gid = $arr['allow_gid'];
$this->deny_cid = $arr['deny_cid'];
$this->deny_gid = $arr['deny_gid'];
- $this->explicit = $explicit;
+ $this->explicit = $explicit;
}
/**
- * return an array consisting of the current
- * access list components where the elements
- * are directly storable.
+ * @brief Return an array consisting of the current access list components
+ * where the elements are directly storable.
+ *
+ * @return Associative array with:
+ * * \e string \b allow_cid => string of allowed cids
+ * * \e string \b allow_gid => string of allowed gids
+ * * \e string \b deny_cid => string of denied cids
+ * * \e string \b deny_gid => string of denied gids
*/
-
function get() {
- return array(
+ return [
'allow_cid' => $this->allow_cid,
'allow_gid' => $this->allow_gid,
'deny_cid' => $this->deny_cid,
'deny_gid' => $this->deny_gid,
- );
+ ];
}
/**
- * Set AccessList from arrays, such as those provided by
- * acl_selector(). For convenience, a string (or non-array) input is
- * assumed to be a comma-separated list and auto-converted into an array.
- */
-
- function set_from_array($arr,$explicit = true) {
- $this->allow_cid = perms2str((is_array($arr['contact_allow']))
- ? $arr['contact_allow'] : explode(',',$arr['contact_allow']));
+ * @brief Set access list components from arrays, such as those provided by
+ * acl_selector().
+ *
+ * For convenience, a string (or non-array) input is assumed to be a
+ * comma-separated list and auto-converted into an array.
+ *
+ * @note The array to pass to this set function is different from the array
+ * that you provide to the constructor or set().
+ *
+ * @param array $arr An associative array with:
+ * * \e array|string \b contact_allow => array with cids or comma-seperated string
+ * * \e array|string \b group_allow => array with gids or comma-seperated string
+ * * \e array|string \b contact_deny => array with cids or comma-seperated string
+ * * \e array|string \b group_deny => array with gids or comma-seperated string
+ * @param boolean $explicit (optional) default true
+ */
+ function set_from_array($arr, $explicit = true) {
+ $this->allow_cid = perms2str((is_array($arr['contact_allow']))
+ ? $arr['contact_allow'] : explode(',', $arr['contact_allow']));
$this->allow_gid = perms2str((is_array($arr['group_allow']))
- ? $arr['group_allow'] : explode(',',$arr['group_allow']));
+ ? $arr['group_allow'] : explode(',', $arr['group_allow']));
$this->deny_cid = perms2str((is_array($arr['contact_deny']))
- ? $arr['contact_deny'] : explode(',',$arr['contact_deny']));
+ ? $arr['contact_deny'] : explode(',', $arr['contact_deny']));
$this->deny_gid = perms2str((is_array($arr['group_deny']))
- ? $arr['group_deny'] : explode(',',$arr['group_deny']));
+ ? $arr['group_deny'] : explode(',', $arr['group_deny']));
$this->explicit = $explicit;
}
+ /**
+ * @brief Returns true if any access lists component is set.
+ *
+ * @return boolean Return true if any of allow_* deny_* values is set.
+ */
function is_private() {
return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false);
}
}
-
diff --git a/Zotlabs/Access/PermissionLimits.php b/Zotlabs/Access/PermissionLimits.php
index 909b654d5..8caeedb91 100644
--- a/Zotlabs/Access/PermissionLimits.php
+++ b/Zotlabs/Access/PermissionLimits.php
@@ -10,7 +10,7 @@ class PermissionLimits {
$perms = Permissions::Perms();
$limits = array();
foreach($perms as $k => $v) {
- if(strstr($k,'view'))
+ if(strstr($k,'view') || $k === 'post_comments')
$limits[$k] = PERMS_PUBLIC;
else
$limits[$k] = PERMS_SPECIFIC;
diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php
index d51e4d0ea..62c4af0ff 100644
--- a/Zotlabs/Access/Permissions.php
+++ b/Zotlabs/Access/Permissions.php
@@ -1,45 +1,52 @@
<?php
-
namespace Zotlabs\Access;
use Zotlabs\Lib as Zlib;
+/**
+ * @brief Extensible permissions.
+ *
+ * To add new permissions, add to the list of $perms below, with a simple description.
+ *
+ * Also visit PermissionRoles.php and add to the $ret['perms_connect'] property for any role
+ * if this permission should be granted to new connections.
+ *
+ * Next look at PermissionRoles::new_custom_perms() and provide a handler for updating custom
+ * permission roles. You will want to set a default PermissionLimit for each channel and also
+ * provide a sane default for any existing connections. You may or may not wish to provide a
+ * default auto permission. If in doubt, leave this alone as custom permissions by definition
+ * are the responsibility of the channel owner to manage. You just don't want to create any
+ * suprises or break things so you have an opportunity to provide sane settings.
+ *
+ * Update the version here and in PermissionRoles.
+ *
+ *
+ * Permissions with 'view' in the name are considered read permissions. Anything
+ * else requires authentication. Read permission limits are PERMS_PUBLIC and anything else
+ * is given PERMS_SPECIFIC.
+ *
+ * PermissionLimits::Std_limits() retrieves the standard limits. A permission role
+ * MAY alter an individual setting after retrieving the Std_limits if you require
+ * something different for a specific permission within the given role.
+ *
+ */
class Permissions {
- /**
- * Extensible permissions.
- * To add new permissions, add to the list of $perms below, with a simple description.
- *
- * Also visit PermissionRoles.php and add to the $ret['perms_connect'] property for any role
- * if this permission should be granted to new connections.
- *
- * Next look at PermissionRoles::new_custom_perms() and provide a handler for updating custom
- * permission roles. You will want to set a default PermissionLimit for each channel and also
- * provide a sane default for any existing connections. You may or may not wish to provide a
- * default auto permission. If in doubt, leave this alone as custom permissions by definition
- * are the responsibility of the channel owner to manage. You just don't want to create any
- * suprises or break things so you have an opportunity to provide sane settings.
- *
- * Update the version here and in PermissionRoles
- *
- *
- * Permissions with 'view' in the name are considered read permissions. Anything
- * else requires authentication. Read permission limits are PERMS_PUBLIC and anything else
- * is given PERMS_SPECIFIC.
- *
- * PermissionLimits::Std_limits() retrieves the standard limits. A permission role
- * MAY alter an individual setting after retrieving the Std_limits if you require
- * something different for a specific permission within the given role.
- *
- */
-
static public function version() {
// This must match the version in PermissionRoles.php before permission updates can run.
return 2;
}
-
+ /**
+ * @brief Return an array with Permissions.
+ *
+ * @hooks permissions_list
+ * * \e array \b permissions
+ * * \e string \b filter
+ * @param string $filter (optional) only passed to hook permission_list
+ * @return Associative array with permissions and short description.
+ */
static public function Perms($filter = '') {
$perms = [
@@ -63,18 +70,27 @@ class Permissions {
'delegate' => t('Can administer my channel')
];
- $x = array('permissions' => $perms, 'filter' => $filter);
- call_hooks('permissions_list',$x);
- return($x['permissions']);
+ $x = [
+ 'permissions' => $perms,
+ 'filter' => $filter
+ ];
+ call_hooks('permissions_list', $x);
+ return($x['permissions']);
}
+ /**
+ * @brief Perms from the above list that are blocked from anonymous observers.
+ *
+ * e.g. you must be authenticated.
+ *
+ * @hooks write_perms
+ * * \e array \b permissions
+ * @return Associative array with permissions and short description.
+ */
static public function BlockedAnonPerms() {
- // Perms from the above list that are blocked from anonymous observers.
- // e.g. you must be authenticated.
-
- $res = array();
+ $res = [];
$perms = PermissionLimits::Std_limits();
foreach($perms as $perm => $limit) {
if($limit != PERMS_PUBLIC) {
@@ -82,17 +98,22 @@ class Permissions {
}
}
- $x = array('permissions' => $res);
- call_hooks('write_perms',$x);
- return($x['permissions']);
+ $x = ['permissions' => $res];
+ call_hooks('write_perms', $x);
+ return($x['permissions']);
}
- // converts [ 0 => 'view_stream', ... ]
- // to [ 'view_stream' => 1 ]
- // for any permissions in $arr;
- // Undeclared permissions are set to 0
-
+ /**
+ * @brief Converts indexed perms array to associative perms array.
+ *
+ * Converts [ 0 => 'view_stream', ... ]
+ * to [ 'view_stream' => 1 ] for any permissions in $arr;
+ * Undeclared permissions which exist in Perms() are added and set to 0.
+ *
+ * @param array $arr
+ * @return array
+ */
static public function FilledPerms($arr) {
if(is_null($arr)) {
btlogger('FilledPerms: null');
@@ -101,15 +122,26 @@ class Permissions {
$everything = self::Perms();
$ret = [];
foreach($everything as $k => $v) {
- if(in_array($k,$arr))
+ if(in_array($k, $arr))
$ret[$k] = 1;
else
$ret[$k] = 0;
}
- return $ret;
+ return $ret;
}
+ /**
+ * @brief Convert perms array to indexed array.
+ *
+ * Converts [ 'view_stream' => 1 ] for any permissions in $arr
+ * to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ]
+ *
+ * @param array $arr associative perms array 'view_stream' => 1
+ * @return Indexed array with elements that look like
+ * * \e string \b name the perm name (e.g. view_stream)
+ * * \e int \b value the value of the perm (e.g. 1)
+ */
static public function OPerms($arr) {
$ret = [];
if($arr) {
@@ -120,7 +152,12 @@ class Permissions {
return $ret;
}
-
+ /**
+ * @brief
+ *
+ * @param int $channel_id
+ * @return boolean|array
+ */
static public function FilledAutoperms($channel_id) {
if(! intval(get_pconfig($channel_id,'system','autoperms')))
return false;
@@ -137,16 +174,34 @@ class Permissions {
return $arr;
}
- static public function PermsCompare($p1,$p2) {
+ /**
+ * @brief Compares that all Permissions from $p1 exist also in $p2.
+ *
+ * @param array $p1 The perms that have to exist in $p2
+ * @param array $p2 The perms to compare against
+ * @return boolean true if all perms from $p1 exist also in $p2
+ */
+ static public function PermsCompare($p1, $p2) {
foreach($p1 as $k => $v) {
- if(! array_key_exists($k,$p2))
+ if(! array_key_exists($k, $p2))
return false;
+
if($p1[$k] != $p2[$k])
return false;
}
+
return true;
}
+ /**
+ * @brief
+ *
+ * @param int $channel_id A channel id
+ * @return associative array
+ * * \e array \b perms Permission array
+ * * \e int \b automatic 0 or 1
+ */
+
static public function connect_perms($channel_id) {
$my_perms = [];
@@ -155,7 +210,7 @@ class Permissions {
// If a default permcat exists, use that
- $pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default');
+ $pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default');
if(! in_array($pc, [ '','default' ])) {
$pcp = new Zlib\Permcat($channel_id);
$permcat = $pcp->fetch($pc);
@@ -167,7 +222,7 @@ class Permissions {
}
// look up the permission role to see if it specified auto-connect
- // and if there was no permcat or a default permcat, set the perms
+ // and if there was no permcat or a default permcat, set the perms
// from the role
$role = get_pconfig($channel_id,'system','permissions_role');
@@ -195,7 +250,7 @@ class Permissions {
}
// If we reached this point with no permissions, the channel is using
- // custom perms but they are not automatic. They will be stored in abconfig with
+ // custom perms but they are not automatic. They will be stored in abconfig with
// the channel's channel_hash (the 'self' connection).
if(! $my_perms) {
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index 350dda7a0..65edbedfa 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -121,6 +121,9 @@ class Cron {
}
}
+ require_once('include/attach.php');
+ attach_upgrade();
+
$abandon_days = intval(get_config('system','account_abandon_days'));
if($abandon_days < 1)
$abandon_days = 0;
@@ -171,7 +174,8 @@ class Cron {
// pull in some public posts
- if(! get_config('system','disable_discover_tab'))
+ $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
+ if(! $disable_discover_tab)
Master::Summon(array('Externals'));
$generation = 0;
diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php
index 0f0001890..f0351fcdd 100644
--- a/Zotlabs/Daemon/Cron_daily.php
+++ b/Zotlabs/Daemon/Cron_daily.php
@@ -38,12 +38,20 @@ class Cron_daily {
db_utcnow(), db_quoteinterval('30 DAY')
);
+ // expire any unread notifications over a year old
+
+ q("delete from notify where seen = 0 and created < %s - INTERVAL %s",
+ db_utcnow(), db_quoteinterval('1 YEAR')
+ );
+
+
//update statistics in config
require_once('include/statistics_fns.php');
update_channels_total_stat();
update_channels_active_halfyear_stat();
update_channels_active_monthly_stat();
update_local_posts_stat();
+ update_local_comments_stat();
// expire old delivery reports
@@ -80,7 +88,7 @@ class Cron_daily {
call_hooks('cron_daily',datetime_convert());
- set_config('system','last_expire_day',$d2);
+ set_config('system','last_expire_day',intval(datetime_convert('UTC','UTC','now','d')));
/**
* End Cron Daily
diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php
index dbc311cf5..394a7bf3e 100644
--- a/Zotlabs/Daemon/Deliver.php
+++ b/Zotlabs/Daemon/Deliver.php
@@ -53,6 +53,9 @@ class Deliver {
remove_queue_item($r[0]['outq_hash']);
if($dresult && is_array($dresult)) {
+
+ // delivery reports for local deliveries do not require encryption
+
foreach($dresult as $xx) {
if(is_array($xx) && array_key_exists('message_id',$xx)) {
if(delivery_report_is_storable($xx)) {
diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php
index 43cce93c3..f1ffb2d81 100644
--- a/Zotlabs/Daemon/Gprobe.php
+++ b/Zotlabs/Daemon/Gprobe.php
@@ -17,7 +17,7 @@ class Gprobe {
if(! strpos($url,'@'))
return;
- $r = q("select * from xchan where xchan_addr = '%s' limit 1",
+ $r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($url)
);
diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php
index 3109a5d86..0ca589e4a 100755
--- a/Zotlabs/Daemon/Importdoc.php
+++ b/Zotlabs/Daemon/Importdoc.php
@@ -21,12 +21,18 @@ class Importdoc {
$files = glob("$d/$f");
if($files) {
foreach($files as $fi) {
- if($fi === 'doc/html')
+ if($fi === 'doc/html') {
continue;
- if(is_dir($fi))
+ }
+ if(is_dir($fi)) {
self::update_docs_dir("$fi/*");
- else
- store_doc_file($fi);
+ }
+ else {
+ // don't update media content
+ if(strpos(z_mime_content_type($fi),'text') === 0) {
+ store_doc_file($fi);
+ }
+ }
}
}
}
diff --git a/Zotlabs/Daemon/Importfile.php b/Zotlabs/Daemon/Importfile.php
new file mode 100644
index 000000000..c68ed21cf
--- /dev/null
+++ b/Zotlabs/Daemon/Importfile.php
@@ -0,0 +1,47 @@
+<?php /** @file */
+
+namespace Zotlabs\Daemon;
+
+class Importfile {
+
+ static public function run($argc,$argv){
+
+ logger('Importfile: ' . print_r($argv,true));
+
+ if($argc < 3)
+ return;
+
+ $channel = channelx_by_n($argv[1]);
+ if(! $channel)
+ return;
+
+ $srcfile = $argv[2];
+ $folder = (($argc > 3) ? $argv[3] : '');
+ $dstname = (($argc > 4) ? $argv[4] : '');
+
+ $hash = random_string();
+
+ $arr = [
+ 'src' => $srcfile,
+ 'filename' => (($dstname) ? $dstname : basename($srcfile)),
+ 'hash' => $hash,
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid'],
+ 'preserve_original' => true,
+ 'replace' => true
+ ];
+
+ if($folder)
+ $arr['folder'] = $folder;
+
+ attach_store($channel,$channel['channel_hash'],'import',$arr);
+
+ $sync = attach_export_data($channel,$hash);
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 63ced4f56..84212270f 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -5,6 +5,11 @@ namespace Zotlabs\Daemon;
require_once('include/queue_fn.php');
require_once('include/html2plain.php');
require_once('include/conversation.php');
+require_once('include/zot.php');
+require_once('include/items.php');
+require_once('include/bbcode.php');
+
+
/*
* This file was at one time responsible for doing all deliveries, but this caused
@@ -54,6 +59,8 @@ require_once('include/conversation.php');
*
* ZOT
* permission_create abook_id
+ * permission_accept abook_id
+ * permission_reject abook_id
* permission_update abook_id
* refresh_all channel_id
* purge_all channel_id
@@ -64,17 +71,11 @@ require_once('include/conversation.php');
* location channel_id
* request channel_id xchan_hash message_id
* rating xlink_id
+ * keychange channel_id
*
*/
-require_once('include/zot.php');
-require_once('include/queue_fn.php');
-require_once('include/datetime.php');
-require_once('include/items.php');
-require_once('include/bbcode.php');
-require_once('include/channel.php');
-
class Notifier {
@@ -98,16 +99,6 @@ class Notifier {
$deliveries = array();
- $dead_hubs = array();
-
- $dh = q("select site_url from site where site_dead = 1");
- if($dh) {
- foreach($dh as $dead) {
- $dead_hubs[] = $dead['site_url'];
- }
- }
-
-
$request = false;
$mail = false;
$top_level = false;
@@ -158,7 +149,21 @@ class Notifier {
$packet_type = 'request';
$normal_mode = false;
}
- elseif($cmd == 'permission_update' || $cmd == 'permission_create') {
+ elseif($cmd === 'keychange') {
+ $channel = channelx_by_n($item_id);
+ $r = q("select abook_xchan from abook where abook_channel = %d",
+ intval($item_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $recipients[] = $rr['abook_xchan'];
+ }
+ }
+ $private = false;
+ $packet_type = 'keychange';
+ $normal_mode = false;
+ }
+ elseif(in_array($cmd, [ 'permission_update', 'permission_reject', 'permission_accept', 'permission_create' ])) {
// Get the (single) recipient
$r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0",
intval($item_id)
@@ -170,8 +175,12 @@ class Notifier {
if($channel) {
$perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
- if($cmd == 'permission_create')
+ if($cmd === 'permission_create')
call_hooks('permissions_create',$perm_update);
+ elseif($cmd === 'permission_accept')
+ call_hooks('permissions_accept',$perm_update);
+ elseif($cmd === 'permission_reject')
+ call_hooks('permissions_reject',$perm_update);
else
call_hooks('permissions_update',$perm_update);
@@ -275,14 +284,15 @@ class Notifier {
$deleted_item = true;
}
- if(intval($target_item['item_type']) != ITEM_TYPE_POST) {
+ if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities
- if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
+ if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
+ intval($target_item['item_blocked']) ||
( intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) {
logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
return;
@@ -403,7 +413,6 @@ class Notifier {
return;
}
}
-
}
$walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false);
@@ -420,7 +429,7 @@ class Notifier {
if(! $recipients)
return;
-// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
+ // logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
$env_recips = (($private) ? array() : null);
@@ -433,40 +442,40 @@ class Notifier {
foreach($details as $d) {
$recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
- if($private)
- $env_recips[] = array('guid' => $d['xchan_guid'],'guid_sig' => $d['xchan_guid_sig'],'hash' => $d['xchan_hash']);
-
- if($d['xchan_network'] === 'mail' && $normal_mode) {
- $delivery_options = get_xconfig($d['xchan_hash'],'system','delivery_mode');
- if(! $delivery_options)
- format_and_send_email($channel,$d,$target_item);
+ if($private) {
+ $env_recips[] = [
+ 'guid' => $d['xchan_guid'],
+ 'guid_sig' => $d['xchan_guid_sig'],
+ 'hash' => $d['xchan_hash']
+ ];
}
}
}
- $narr = array(
- 'channel' => $channel,
- 'upstream' => $upstream,
- 'env_recips' => $env_recips,
- 'packet_recips' => $packet_recips,
- 'recipients' => $recipients,
- 'item' => $item,
- 'target_item' => $target_item,
+ $narr = [
+ 'channel' => $channel,
+ 'upstream' => $upstream,
+ 'env_recips' => $env_recips,
+ 'packet_recips' => $packet_recips,
+ 'recipients' => $recipients,
+ 'item' => $item,
+ 'target_item' => $target_item,
+ 'parent_item' => $parent_item,
'top_level_post' => $top_level_post,
- 'private' => $private,
+ 'private' => $private,
'relay_to_owner' => $relay_to_owner,
- 'uplink' => $uplink,
- 'cmd' => $cmd,
- 'mail' => $mail,
- 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
- 'location' => $location,
- 'request' => $request,
- 'normal_mode' => $normal_mode,
- 'packet_type' => $packet_type,
- 'walltowall' => $walltowall,
- 'queued' => array()
- );
+ 'uplink' => $uplink,
+ 'cmd' => $cmd,
+ 'mail' => $mail,
+ 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
+ 'location' => $location,
+ 'request' => $request,
+ 'normal_mode' => $normal_mode,
+ 'packet_type' => $packet_type,
+ 'walltowall' => $walltowall,
+ 'queued' => []
+ ];
call_hooks('notifier_process', $narr);
if($narr['queued']) {
@@ -489,10 +498,10 @@ class Notifier {
// Now we have collected recipients (except for external mentions, FIXME)
- // Let's reduce this to a set of hubs.
+ // Let's reduce this to a set of hubs; checking that the site is not dead.
- $r = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . implode(',',$recipients) . ")
- and hubloc_error = 0 and hubloc_deleted = 0"
+ $r = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . implode(',',$recipients) . ")
+ and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) "
);
@@ -503,73 +512,78 @@ class Notifier {
$hubs = $r;
-
-
/**
- * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been
- * a re-install which has not yet been detected and pruned.
+ * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey,
+ * since it may have been a re-install which has not yet been detected and pruned.
* For other networks which don't have or require sitekeys, we'll have to use the URL
*/
- $hublist = array(); // this provides an easily printable list for the logs
- $dhubs = array(); // delivery hubs where we store our resulting unique array
- $keys = array(); // array of keys to check uniquness for zot hubs
- $urls = array(); // array of urls to check uniqueness of hubs from other networks
-
+ $hublist = []; // this provides an easily printable list for the logs
+ $dhubs = []; // delivery hubs where we store our resulting unique array
+ $keys = []; // array of keys to check uniquness for zot hubs
+ $urls = []; // array of urls to check uniqueness of hubs from other networks
+ $hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
foreach($hubs as $hub) {
- if(in_array($hub['hubloc_url'],$dead_hubs)) {
- logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG, LOG_INFO);
- continue;
+
+ if($env_recips) {
+ foreach($env_recips as $er) {
+ if($hub['hubloc_hash'] === $er['hash']) {
+ if(! array_key_exists($hub['hubloc_host'] . $hub['hubloc_sitekey'], $hub_env)) {
+ $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] = [];
+ }
+ $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']][] = $er;
+ }
+ }
}
+
if($hub['hubloc_network'] == 'zot') {
if(! in_array($hub['hubloc_sitekey'],$keys)) {
- $hublist[] = $hub['hubloc_host'];
- $dhubs[] = $hub;
- $keys[] = $hub['hubloc_sitekey'];
+ $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
+ $dhubs[] = $hub;
+ $keys[] = $hub['hubloc_sitekey'];
}
}
else {
if(! in_array($hub['hubloc_url'],$urls)) {
- $hublist[] = $hub['hubloc_host'];
- $dhubs[] = $hub;
- $urls[] = $hub['hubloc_url'];
+ $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
+ $dhubs[] = $hub;
+ $urls[] = $hub['hubloc_url'];
}
}
}
logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG);
-
foreach($dhubs as $hub) {
if($hub['hubloc_network'] !== 'zot') {
-
- $narr = array(
- 'channel' => $channel,
- 'upstream' => $upstream,
- 'env_recips' => $env_recips,
- 'packet_recips' => $packet_recips,
- 'recipients' => $recipients,
- 'item' => $item,
- 'target_item' => $target_item,
- 'hub' => $hub,
+ $narr = [
+ 'channel' => $channel,
+ 'upstream' => $upstream,
+ 'env_recips' => $env_recips,
+ 'packet_recips' => $packet_recips,
+ 'recipients' => $recipients,
+ 'item' => $item,
+ 'target_item' => $target_item,
+ 'parent_item' => $parent_item,
+ 'hub' => $hub,
'top_level_post' => $top_level_post,
- 'private' => $private,
+ 'private' => $private,
'relay_to_owner' => $relay_to_owner,
- 'uplink' => $uplink,
- 'cmd' => $cmd,
- 'mail' => $mail,
- 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
- 'location' => $location,
- 'request' => $request,
- 'normal_mode' => $normal_mode,
- 'packet_type' => $packet_type,
- 'walltowall' => $walltowall,
- 'queued' => array()
- );
+ 'uplink' => $uplink,
+ 'cmd' => $cmd,
+ 'mail' => $mail,
+ 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
+ 'location' => $location,
+ 'request' => $request,
+ 'normal_mode' => $normal_mode,
+ 'packet_type' => $packet_type,
+ 'walltowall' => $walltowall,
+ 'queued' => []
+ ];
call_hooks('notifier_hub',$narr);
@@ -582,13 +596,13 @@ class Notifier {
}
// singleton deliveries by definition 'not got zot'.
- // Single deliveries are other federated networks (plugins) and we're essentially
+ // Single deliveries are other federated networks (plugins) and we're essentially
// delivering only to those that have this site url in their abook_instance
// and only from within a sync operation. This means if you post from a clone,
// and a connection is connected to one of your other clones; assuming that hub
// is running it will receive a sync packet. On receipt of this sync packet it
// will invoke a delivery to those connections which are connected to just that
- // hub instance.
+ // hub instance.
if($cmd === 'single_mail' || $cmd === 'single_activity') {
continue;
@@ -596,14 +610,20 @@ class Notifier {
// default: zot protocol
- $hash = random_string();
+ $hash = random_string();
$packet = null;
+ $pmsg = '';
if($packet_type === 'refresh' || $packet_type === 'purge') {
$packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
}
+ if($packet_type === 'keychange') {
+ $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
+ $pmsg = get_pconfig($channel['channel_id'],'system','keychange');
+ }
elseif($packet_type === 'request') {
- $packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hub['site_crypto'],
+ $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
+ $packet = zot_build_packet($channel,$packet_type,$env,$hub['hubloc_sitekey'],$hub['site_crypto'],
$hash, array('message_id' => $request_message_id)
);
}
@@ -614,19 +634,23 @@ class Notifier {
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
'posturl' => $hub['hubloc_callback'],
- 'notify' => $packet
+ 'notify' => $packet,
+ 'msg' => (($pmsg) ? json_encode($pmsg) : '')
));
}
else {
- $packet = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
- queue_insert(array(
- 'hash' => $hash,
- 'account_id' => $target_item['aid'],
- 'channel_id' => $target_item['uid'],
- 'posturl' => $hub['hubloc_callback'],
- 'notify' => $packet,
- 'msg' => json_encode($encoded_item)
- ));
+ $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
+ $packet = zot_build_packet($channel,'notify',$env,(($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
+ queue_insert(
+ [
+ 'hash' => $hash,
+ 'account_id' => $target_item['aid'],
+ 'channel_id' => $target_item['uid'],
+ 'posturl' => $hub['hubloc_callback'],
+ 'notify' => $packet,
+ 'msg' => json_encode($encoded_item)
+ ]
+ );
// only create delivery reports for normal undeleted items
if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
@@ -647,9 +671,9 @@ class Notifier {
if($normal_mode) {
$x = q("select * from hook where hook = 'notifier_normal'");
- if($x)
- Master::Summon(array('Deliver_hooks',$target_item['id']));
-
+ if($x) {
+ Master::Summon( [ 'Deliver_hooks', $target_item['id'] ] );
+ }
}
if($deliveries)
diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php
index 33b244dc5..920916828 100644
--- a/Zotlabs/Daemon/Onepoll.php
+++ b/Zotlabs/Daemon/Onepoll.php
@@ -118,13 +118,29 @@ class Onepoll {
if($fetch_feed) {
- $feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
- $feedurl .= '?f=&mindate=' . urlencode($last_update);
+ if(strpos($contact['xchan_connurl'],z_root()) === 0) {
+ // local channel - save a network fetch
+ $c = channelx_by_hash($contact['xchan_hash']);
+ if($c) {
+ $x = [
+ 'success' => true,
+ 'body' => json_encode( [
+ 'success' => true,
+ 'messages' => zot_feed($c['channel_id'], $importer['xchan_hash'], [ 'mindate' => $last_update ])
+ ])
+ ];
+ }
+ }
+ else {
+ // remote fetch
- $x = z_fetch_url($feedurl);
+ $feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
+ $feedurl .= '?f=&mindate=' . urlencode($last_update) . '&zid=' . $importer['channel_address'] . '@' . \App::get_hostname();
+ $recurse = 0;
+ $x = z_fetch_url($feedurl, false, $recurse, [ 'session' => true ]);
+ }
logger('feed_update: ' . print_r($x,true), LOGGER_DATA);
-
}
if(($x) && ($x['success'])) {
diff --git a/Zotlabs/Extend/Hook.php b/Zotlabs/Extend/Hook.php
index fef3ebe9b..c6f9ea850 100644
--- a/Zotlabs/Extend/Hook.php
+++ b/Zotlabs/Extend/Hook.php
@@ -40,6 +40,15 @@ class Hook {
return $r;
}
+ static public function register_array($file,$arr) {
+ if($arr) {
+ foreach($arr as $k => $v) {
+ self::register($k,$file,$v);
+ }
+ }
+ }
+
+
static public function unregister($hook,$file,$function,$version = 1,$priority = 0) {
if(is_array($function)) {
$function = serialize($function);
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
new file mode 100644
index 000000000..379e78a59
--- /dev/null
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -0,0 +1,199 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+class ActivityStreams {
+
+ public $data;
+ public $valid = false;
+ public $id = '';
+ public $type = '';
+ public $actor = null;
+ public $obj = null;
+ public $tgt = null;
+ public $origin = null;
+ public $owner = null;
+ public $signer = null;
+ public $ldsig = null;
+ public $sigok = false;
+ public $recips = null;
+ public $raw_recips = null;
+
+ function __construct($string) {
+
+ $this->data = json_decode($string,true);
+ if($this->data) {
+ $this->valid = true;
+ }
+
+ if($this->is_valid()) {
+ $this->id = $this->get_property_obj('id');
+ $this->type = $this->get_primary_type();
+ $this->actor = $this->get_compound_property('actor');
+ $this->obj = $this->get_compound_property('object');
+ $this->tgt = $this->get_compound_property('target');
+ $this->origin = $this->get_compound_property('origin');
+ $this->recips = $this->collect_recips();
+
+ $this->ldsig = $this->get_compound_property('signature');
+ if($this->ldsig) {
+ $this->signer = $this->get_compound_property('creator',$this->ldsig);
+ if($this->signer && $this->signer['publicKey'] && $this->signer['publicKey']['publicKeyPem']) {
+ $this->sigok = \Zotlabs\Lib\LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
+ }
+ }
+
+ if(($this->type === 'Note') && (! $this->obj)) {
+ $this->obj = $this->data;
+ $this->type = 'Create';
+ }
+ }
+ }
+
+ function is_valid() {
+ return $this->valid;
+ }
+
+ function set_recips($arr) {
+ $this->saved_recips = $arr;
+ }
+
+ function collect_recips($base = '',$namespace = '') {
+ $x = [];
+ $fields = [ 'to','cc','bto','bcc','audience'];
+ foreach($fields as $f) {
+ $y = $this->get_compound_property($f,$base,$namespace);
+ if($y) {
+ $x = array_merge($x,$y);
+ if(! is_array($this->raw_recips))
+ $this->raw_recips = [];
+ $this->raw_recips[$f] = $x;
+ }
+ }
+// not yet ready for prime time
+// $x = $this->expand($x,$base,$namespace);
+ return $x;
+ }
+
+ function expand($arr,$base = '',$namespace = '') {
+ $ret = [];
+
+ // right now use a hardwired recursion depth of 5
+
+ for($z = 0; $z < 5; $z ++) {
+ if(is_array($arr) && $arr) {
+ foreach($arr as $a) {
+ if(is_array($a)) {
+ $ret[] = $a;
+ }
+ else {
+ $x = $this->get_compound_property($a,$base,$namespace);
+ if($x) {
+ $ret = array_merge($ret,$x);
+ }
+ }
+ }
+ }
+ }
+
+ // @fixme de-duplicate
+
+ return $ret;
+ }
+
+ function get_namespace($base,$namespace) {
+
+ if(! $namespace)
+ return '';
+
+ $key = null;
+
+
+ foreach( [ $this->data, $base ] as $b ) {
+ if(! $b)
+ continue;
+ if(array_key_exists('@context',$b)) {
+ if(is_array($b['@context'])) {
+ foreach($b['@context'] as $ns) {
+ if(is_array($ns)) {
+ foreach($ns as $k => $v) {
+ if($namespace === $v)
+ $key = $k;
+ }
+ }
+ else {
+ if($namespace === $ns) {
+ $key = '';
+ }
+ }
+ }
+ }
+ else {
+ if($namespace === $b['@context']) {
+ $key = '';
+ }
+ }
+ }
+ }
+ return $key;
+ }
+
+
+ function get_property_obj($property,$base = '',$namespace = '' ) {
+ $prefix = $this->get_namespace($base,$namespace);
+ if($prefix === null)
+ return null;
+ $base = (($base) ? $base : $this->data);
+ $propname = (($prefix) ? $prefix . ':' : '') . $property;
+ return ((array_key_exists($propname,$base)) ? $base[$propname] : null);
+ }
+
+ function fetch_property($url) {
+ $redirects = 0;
+ if(! check_siteallowed($url)) {
+ logger('blacklisted: ' . $url);
+ return null;
+ }
+
+ $x = z_fetch_url($url,true,$redirects,
+ ['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json' ]]);
+ if($x['success'])
+ return json_decode($x['body'],true);
+ return null;
+ }
+
+ function get_compound_property($property,$base = '',$namespace = '') {
+ $x = $this->get_property_obj($property,$base,$namespace);
+ if($this->is_url($x)) {
+ $x = $this->fetch_property($x);
+ }
+ return $x;
+ }
+
+ function is_url($url) {
+ if(($url) && (! is_array($url)) && (strpos($url,'http') === 0)) {
+ return true;
+ }
+ return false;
+ }
+
+ function get_primary_type($base = '',$namespace = '') {
+ if(! $base)
+ $base = $this->data;
+ $x = $this->get_property_obj('type',$base,$namespace);
+ if(is_array($x)) {
+ foreach($x as $y) {
+ if(strpos($y,':') === false) {
+ return $y;
+ }
+ }
+ }
+ return $x;
+ }
+
+ function debug() {
+ $x = var_export($this,true);
+ return $x;
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 1432cbdcf..f13fbe362 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -34,7 +34,7 @@ class Apps {
if($files) {
foreach($files as $f) {
$path = explode('/',$f);
- $plugin = $path[1];
+ $plugin = trim($path[1]);
if(plugin_is_installed($plugin)) {
$x = self::parse_app_description($f,$translate);
if($x) {
@@ -169,6 +169,14 @@ class Apps {
$requires = explode(',',$ret['requires']);
foreach($requires as $require) {
$require = trim(strtolower($require));
+ $config = false;
+
+ if(substr($require, 0, 7) == 'config:') {
+ $config = true;
+ $require = ltrim($require, 'config:');
+ $require = explode('=', $require);
+ }
+
switch($require) {
case 'nologin':
if(local_channel())
@@ -191,10 +199,13 @@ class Apps {
unset($ret);
break;
default:
- if(! (local_channel() && feature_enabled(local_channel(),$require)))
+ if($config)
+ $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true);
+ else
+ $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
+ if($unset)
unset($ret);
break;
-
}
}
}
@@ -209,7 +220,9 @@ class Apps {
static public function translate_system_apps(&$arr) {
$apps = array(
- 'Site Admin' => t('Site Admin'),
+ 'Apps' => t('Apps'),
+ 'Cards' => t('Cards'),
+ 'Admin' => t('Site Admin'),
'Report Bug' => t('Report Bug'),
'View Bookmarks' => t('View Bookmarks'),
'My Chatrooms' => t('My Chatrooms'),
@@ -219,7 +232,7 @@ class Apps {
'Suggest Channels' => t('Suggest Channels'),
'Login' => t('Login'),
'Channel Manager' => t('Channel Manager'),
- 'Grid' => t('Grid'),
+ 'Grid' => t('Activity'),
'Settings' => t('Settings'),
'Files' => t('Files'),
'Webpages' => t('Webpages'),
@@ -245,9 +258,19 @@ class Apps {
'Profile Photo' => t('Profile Photo')
);
- if(array_key_exists($arr['name'],$apps)) {
- $arr['name'] = $apps[$arr['name']];
+ if(array_key_exists('name',$arr)) {
+ if(array_key_exists($arr['name'],$apps)) {
+ $arr['name'] = $apps[$arr['name']];
+ }
+ }
+ else {
+ for($x = 0; $x < count($arr); $x++) {
+ if(array_key_exists($arr[$x]['name'],$apps)) {
+ $arr[$x]['name'] = $apps[$arr[$x]['name']];
+ }
+ }
}
+
}
@@ -275,7 +298,7 @@ class Apps {
self::translate_system_apps($papp);
- if(($papp['plugin']) && (! plugin_is_installed($papp['plugin'])))
+ if(trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
return '';
$papp['papp'] = self::papp_encode($papp);
@@ -294,8 +317,17 @@ class Apps {
if($k === 'requires') {
$requires = explode(',',$v);
+
foreach($requires as $require) {
$require = trim(strtolower($require));
+ $config = false;
+
+ if(substr($require, 0, 7) == 'config:') {
+ $config = true;
+ $require = ltrim($require, 'config:');
+ $require = explode('=', $require);
+ }
+
switch($require) {
case 'nologin':
if(local_channel())
@@ -319,10 +351,13 @@ class Apps {
return '';
break;
default:
- if(! (local_channel() && feature_enabled(local_channel(),$require)))
+ if($config)
+ $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true);
+ else
+ $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
+ if($unset)
return '';
break;
-
}
}
}
@@ -348,6 +383,13 @@ class Apps {
$install_action = (($installed) ? t('Update') : t('Install'));
$icon = ((strpos($papp['photo'],'icon:') === 0) ? substr($papp['photo'],5) : '');
+ if($mode === 'navbar') {
+ return replace_macros(get_markup_template('app_nav.tpl'),array(
+ '$app' => $papp,
+ '$icon' => $icon,
+ ));
+ }
+
return replace_macros(get_markup_template('app.tpl'),array(
'$app' => $papp,
'$icon' => $icon,
@@ -360,7 +402,10 @@ class Apps {
'$deleted' => $papp['deleted'],
'$feature' => (($papp['embed']) ? false : true),
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
- '$navapps' => (($mode == 'nav') ? true : false)
+ '$navapps' => (($mode == 'nav') ? true : false),
+ '$order' => (($mode == 'nav-order') ? true : false),
+ '$add' => t('Add to app-tray'),
+ '$remove' => t('Remove from app-tray')
));
}
@@ -527,6 +572,129 @@ class Apps {
return($r);
}
+ static public function app_order($uid,$apps) {
+
+ if(! $apps)
+ return $apps;
+
+ $x = (($uid) ? get_pconfig($uid,'system','app_order') : get_config('system','app_order'));
+ if(($x) && (! is_array($x))) {
+ $y = explode(',',$x);
+ $y = array_map('trim',$y);
+ $x = $y;
+ }
+
+ if(! (is_array($x) && ($x)))
+ return $apps;
+
+ $ret = [];
+ foreach($x as $xx) {
+ $y = self::find_app_in_array($xx,$apps);
+ if($y) {
+ $ret[] = $y;
+ }
+ }
+ foreach($apps as $ap) {
+ if(! self::find_app_in_array($ap['name'],$ret)) {
+ $ret[] = $ap;
+ }
+ }
+ return $ret;
+
+ }
+
+ static function find_app_in_array($name,$arr) {
+ if(! $arr)
+ return false;
+ foreach($arr as $x) {
+ if($x['name'] === $name) {
+ return $x;
+ }
+ }
+ return false;
+ }
+
+ static function moveup($uid,$guid) {
+ $syslist = array();
+ $list = self::app_list($uid, false, 'nav_featured_app');
+ if($list) {
+ foreach($list as $li) {
+ $syslist[] = self::app_encode($li);
+ }
+ }
+ self::translate_system_apps($syslist);
+
+ usort($syslist,'self::app_name_compare');
+
+ $syslist = self::app_order($uid,$syslist);
+
+ if(! $syslist)
+ return;
+
+ $newlist = [];
+
+ foreach($syslist as $k => $li) {
+ if($li['guid'] === $guid) {
+ $position = $k;
+ break;
+ }
+ }
+ if(! $position)
+ return;
+ $dest_position = $position - 1;
+ $saved = $syslist[$dest_position];
+ $syslist[$dest_position] = $syslist[$position];
+ $syslist[$position] = $saved;
+
+ $narr = [];
+ foreach($syslist as $x) {
+ $narr[] = $x['name'];
+ }
+
+ set_pconfig($uid,'system','app_order',implode(',',$narr));
+
+ }
+
+ static function movedown($uid,$guid) {
+ $syslist = array();
+ $list = self::app_list($uid, false, 'nav_featured_app');
+ if($list) {
+ foreach($list as $li) {
+ $syslist[] = self::app_encode($li);
+ }
+ }
+ self::translate_system_apps($syslist);
+
+ usort($syslist,'self::app_name_compare');
+
+ $syslist = self::app_order($uid,$syslist);
+
+ if(! $syslist)
+ return;
+
+ $newlist = [];
+
+ foreach($syslist as $k => $li) {
+ if($li['guid'] === $guid) {
+ $position = $k;
+ break;
+ }
+ }
+ if($position >= count($syslist) - 1)
+ return;
+ $dest_position = $position + 1;
+ $saved = $syslist[$dest_position];
+ $syslist[$dest_position] = $syslist[$position];
+ $syslist[$position] = $saved;
+
+ $narr = [];
+ foreach($syslist as $x) {
+ $narr[] = $x['name'];
+ }
+
+ set_pconfig($uid,'system','app_order',implode(',',$narr));
+
+ }
static public function app_decode($s) {
$x = base64_decode(str_replace(array('<br />',"\r","\n",' '),array('','','',''),$s));
@@ -563,7 +731,7 @@ class Apps {
$darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : '');
$darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : '');
$darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : '');
- $darray['app_plugin'] = ((x($arr,'plugin')) ? escape_tags($arr['plugin']) : '');
+ $darray['app_plugin'] = ((x($arr,'plugin')) ? escape_tags(trim($arr['plugin'])) : '');
$darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : '');
$darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0);
$darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0);
@@ -641,7 +809,7 @@ class Apps {
$darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : '');
$darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : '');
$darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : '');
- $darray['app_plugin'] = ((x($arr,'plugin')) ? escape_tags($arr['plugin']) : '');
+ $darray['app_plugin'] = ((x($arr,'plugin')) ? escape_tags(trim($arr['plugin'])) : '');
$darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : '');
$darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0);
$darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0);
@@ -751,7 +919,7 @@ class Apps {
$ret['system'] = $app['app_system'];
if($app['app_plugin'])
- $ret['plugin'] = $app['app_plugin'];
+ $ret['plugin'] = trim($app['app_plugin']);
if($app['app_deleted'])
$ret['deleted'] = $app['app_deleted'];
diff --git a/Zotlabs/Lib/Cache.php b/Zotlabs/Lib/Cache.php
index f211269be..cea075659 100644
--- a/Zotlabs/Lib/Cache.php
+++ b/Zotlabs/Lib/Cache.php
@@ -9,10 +9,10 @@ namespace Zotlabs\Lib;
class Cache {
public static function get($key) {
- $key = substr($key,0,254);
+ $hash = hash('whirlpool',$key);
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
- dbesc($key)
+ dbesc($hash)
);
if ($r)
@@ -22,20 +22,20 @@ class Cache {
public static function set($key,$value) {
- $key = substr($key,0,254);
+ $hash = hash('whirlpool',$key);
$r = q("SELECT * FROM cache WHERE k = '%s' limit 1",
- dbesc($key)
+ dbesc($hash)
);
if($r) {
q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
dbesc($value),
dbesc(datetime_convert()),
- dbesc($key));
+ dbesc($hash));
}
else {
q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')",
- dbesc($key),
+ dbesc($hash),
dbesc($value),
dbesc(datetime_convert()));
}
diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php
index 5625a3f79..6e042feba 100644
--- a/Zotlabs/Lib/Config.php
+++ b/Zotlabs/Lib/Config.php
@@ -53,7 +53,7 @@ class Config {
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
- if(get_config($family, $key) === false || (! self::get_from_storage($family, $key))) {
+ if(self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
$ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ",
dbesc($family),
dbesc($key),
diff --git a/Zotlabs/Lib/DB_Upgrade.php b/Zotlabs/Lib/DB_Upgrade.php
new file mode 100644
index 000000000..8f0488f6f
--- /dev/null
+++ b/Zotlabs/Lib/DB_Upgrade.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+
+class DB_Upgrade {
+
+ public $config_name = '';
+ public $func_prefix = '';
+
+ function __construct($db_revision) {
+
+ $platform_name = System::get_platform_name();
+
+ $update_file = 'install/' . $platform_name . '/update.php';
+ if(! file_exists($update_file)) {
+ $update_file = 'install/update.php';
+ $this->config_name = 'db_version';
+ $this->func_prefix = 'update_r';
+ }
+ else {
+ $this->config_name = $platform_name . '_db_version';
+ $this->func_prefix = $platform_name . '_update_';
+ }
+
+ $build = get_config('system', $this->config_name, 0);
+ if(! intval($build))
+ $build = set_config('system', $this->config_name, $db_revision);
+
+ if($build == $db_revision) {
+ // Nothing to be done.
+ return;
+ }
+ else {
+ $stored = intval($build);
+ if(! $stored) {
+ logger('Critical: check_config unable to determine database schema version');
+ return;
+ }
+
+ $current = intval($db_revision);
+
+ if(($stored < $current) && file_exists($update_file)) {
+
+ Config::Load('database');
+
+ // We're reporting a different version than what is currently installed.
+ // Run any existing update scripts to bring the database up to current.
+
+ require_once($update_file);
+
+ // make sure that boot.php and update.php are the same release, we might be
+ // updating from git right this very second and the correct version of the update.php
+ // file may not be here yet. This can happen on a very busy site.
+
+ if($db_revision == UPDATE_VERSION) {
+ for($x = $stored; $x < $current; $x ++) {
+ $func = $this->func_prefix . $x;
+ if(function_exists($func)) {
+ // There could be a lot of processes running or about to run.
+ // We want exactly one process to run the update command.
+ // So store the fact that we're taking responsibility
+ // after first checking to see if somebody else already has.
+
+ // If the update fails or times-out completely you may need to
+ // delete the config entry to try again.
+
+ if(get_config('database', $func))
+ break;
+ set_config('database',$func, '1');
+ // call the specific update
+
+ $retval = $func();
+ if($retval) {
+
+ // Prevent sending hundreds of thousands of emails by creating
+ // a lockfile.
+
+ $lockfile = 'store/[data]/mailsent';
+
+ if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400)))
+ return;
+ @unlink($lockfile);
+ //send the administrator an e-mail
+ file_put_contents($lockfile, $x);
+
+ $r = q("select account_language from account where account_email = '%s' limit 1",
+ dbesc(\App::$config['system']['admin_email'])
+ );
+ push_lang(($r) ? $r[0]['account_language'] : 'en');
+
+ z_mail(
+ [
+ 'toEmail' => \App::$config['system']['admin_email'],
+ 'messageSubject' => sprintf( t('Update Error at %s'), z_root()),
+ 'textVersion' => replace_macros(get_intltext_template('update_fail_eml.tpl'),
+ [
+ '$sitename' => \App::$config['system']['sitename'],
+ '$siteurl' => z_root(),
+ '$update' => $x,
+ '$error' => sprintf( t('Update %s failed. See error logs.'), $x)
+ ]
+ )
+ ]
+ );
+
+ //try the logger
+ logger('CRITICAL: Update Failed: ' . $x);
+ pop_lang();
+ }
+ else {
+ set_config('database',$func, 'success');
+ }
+ }
+ }
+ set_config('system', $this->config_name, $db_revision);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 257687567..e82c11a35 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -67,7 +67,7 @@ class Enotify {
$sender_name = $product;
$hostname = \App::get_hostname();
if(strpos($hostname,':'))
- $hostname = substr($hostname,0,strpos($hostname,':'));
+ $hostname = substr($hostname,0,strpos($hostname,':'));
// Do not translate 'noreply' as it must be a legal 7-bit email address
@@ -77,7 +77,7 @@ class Enotify {
$sender_email = get_config('system','from_email');
if(! $sender_email)
- $sender_email = 'Administrator' . '@' . \App::get_hostname();
+ $sender_email = 'Administrator' . '@' . $hostname;
$sender_name = get_config('system','from_email_name');
if(! $sender_name)
@@ -130,7 +130,9 @@ class Enotify {
if ($params['type'] == NOTIFY_COMMENT) {
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
- $itemlink = $params['link'];
+ $moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
+
+ $itemlink = $params['link'];
// ignore like/unlike activity on posts - they probably require a separate notification preference
@@ -170,7 +172,6 @@ class Enotify {
xchan_query($p);
-
$item_post_type = item_post_type($p[0]);
// $private = $p[0]['item_private'];
$parent_id = $p[0]['id'];
@@ -208,13 +209,21 @@ class Enotify {
// Before this we have the name of the replier on the subject rendering
// differents subjects for messages on the same thread.
- $subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
+ if($moderated)
+ $subject = sprintf( t('[$Projectname:Notify] Moderated Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
+ else
+ $subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
$preamble = sprintf( t('%1$s, %2$s commented on an item/conversation you have been following.'), $recip['channel_name'], $sender['xchan_name']);
$epreamble = $dest_str;
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
+ if($moderated) {
+ $tsitelink .= "\n\n" . sprintf( t('Please visit %s to approve or reject this comment.'), z_root() . '/moderate' );
+ $hsitelink .= "<br><br>" . sprintf( t('Please visit %s to approve or reject this comment.'), '<a href="' . z_root() . '/moderate">' . z_root() . '/moderate</a>' );
+ }
+
}
if ($params['type'] == NOTIFY_LIKE) {
@@ -495,13 +504,14 @@ class Enotify {
}
}
- $r = q("insert into notify (hash,xname,url,photo,created,aid,uid,link,parent,seen,ntype,verb,otype)
- values('%s','%s','%s','%s','%s',%d,%d,'%s','%s',%d,%d,'%s','%s')",
+ $r = q("insert into notify (hash,xname,url,photo,created,msg,aid,uid,link,parent,seen,ntype,verb,otype)
+ values('%s','%s','%s','%s','%s','%s',%d,%d,'%s','%s',%d,%d,'%s','%s')",
dbesc($datarray['hash']),
dbesc($datarray['xname']),
dbesc($datarray['url']),
dbesc($datarray['photo']),
dbesc($datarray['created']),
+ dbesc(''), // will fill this in below after the record is created
intval($datarray['aid']),
intval($datarray['uid']),
dbesc($datarray['link']),
diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php
new file mode 100644
index 000000000..43d5f9d09
--- /dev/null
+++ b/Zotlabs/Lib/JSalmon.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+
+class JSalmon {
+
+ static function sign($data,$key_id,$key) {
+
+ $arr = $data;
+ $data = json_encode($data,JSON_UNESCAPED_SLASHES);
+ $data = base64url_encode($data, false); // do not strip padding
+ $data_type = 'application/x-zot+json';
+ $encoding = 'base64url';
+ $algorithm = 'RSA-SHA256';
+
+ $data = preg_replace('/\s+/','',$data);
+
+ // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
+
+ $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
+
+ $signature = base64url_encode(rsa_sign($data . $precomputed, $key), false);
+
+ return ([
+ 'signed' => true,
+ 'data' => $data,
+ 'data_type' => $data_type,
+ 'encoding' => $encoding,
+ 'alg' => $algorithm,
+ 'sigs' => [
+ 'value' => $signature,
+ 'key_id' => base64url_encode($key_id)
+ ]
+ ]);
+
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php
new file mode 100644
index 000000000..6d7127cde
--- /dev/null
+++ b/Zotlabs/Lib/LDSignatures.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+require_once('library/jsonld/jsonld.php');
+
+class LDSignatures {
+
+
+ static function verify($data,$pubkey) {
+
+ $ohash = self::hash(self::signable_options($data['signature']));
+ $dhash = self::hash(self::signable_data($data));
+
+ $x = rsa_verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
+ logger('LD-verify: ' . intval($x));
+
+ return $x;
+ }
+
+ static function dopplesign(&$data,$channel) {
+ // remove for the time being - performance issues
+ // $data['magicEnv'] = self::salmon_sign($data,$channel);
+ return self::sign($data,$channel);
+ }
+
+ static function sign($data,$channel) {
+
+ $options = [
+ 'type' => 'RsaSignature2017',
+ 'nonce' => random_string(64),
+ 'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
+ 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
+ ];
+
+ $ohash = self::hash(self::signable_options($options));
+ $dhash = self::hash(self::signable_data($data));
+ $options['signatureValue'] = base64_encode(rsa_sign($ohash . $dhash,$channel['channel_prvkey']));
+
+ $signed = array_merge([
+ '@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1' ],
+ ],$options);
+
+ return $signed;
+ }
+
+
+ static function signable_data($data) {
+
+ $newdata = [];
+ if($data) {
+ foreach($data as $k => $v) {
+ if(! in_array($k,[ 'signature' ])) {
+ $newdata[$k] = $v;
+ }
+ }
+ }
+ return json_encode($newdata,JSON_UNESCAPED_SLASHES);
+ }
+
+
+ static function signable_options($options) {
+
+ $newopts = [ '@context' => 'https://w3id.org/identity/v1' ];
+ if($options) {
+ foreach($options as $k => $v) {
+ if(! in_array($k,[ 'type','id','signatureValue' ])) {
+ $newopts[$k] = $v;
+ }
+ }
+ }
+ return json_encode($newopts,JSON_UNESCAPED_SLASHES);
+ }
+
+ static function hash($obj) {
+
+ return hash('sha256',self::normalise($obj));
+ }
+
+ static function normalise($data) {
+ if(is_string($data)) {
+ $data = json_decode($data);
+ }
+
+ if(! is_object($data))
+ return '';
+
+ jsonld_set_document_loader('jsonld_document_loader');
+
+ try {
+ $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
+ }
+ catch (\Exception $e) {
+ logger('normalise error:' . print_r($e,true));
+ logger('normalise error: ' . print_r($data,true));
+ }
+
+ return $d;
+ }
+
+ static function salmon_sign($data,$channel) {
+
+ $arr = $data;
+ $data = json_encode($data,JSON_UNESCAPED_SLASHES);
+ $data = base64url_encode($data, false); // do not strip padding
+ $data_type = 'application/activity+json';
+ $encoding = 'base64url';
+ $algorithm = 'RSA-SHA256';
+ $keyhash = base64url_encode(z_root() . '/channel/' . $channel['channel_address']);
+
+ $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data);
+
+ // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
+
+ $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
+
+ $signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey']));
+
+ return ([
+ 'id' => $arr['id'],
+ 'meData' => $data,
+ 'meDataType' => $data_type,
+ 'meEncoding' => $encoding,
+ 'meAlgorithm' => $algorithm,
+ 'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
+ 'meSignatureValue' => $signature
+ ]);
+
+ }
+
+
+
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/MarkdownSoap.php b/Zotlabs/Lib/MarkdownSoap.php
new file mode 100644
index 000000000..fa279b07c
--- /dev/null
+++ b/Zotlabs/Lib/MarkdownSoap.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+/**
+ * MarkdownSoap
+ * Purify Markdown for storage
+ * $x = new MarkdownSoap($string_to_be_cleansed);
+ * $text = $x->clean();
+ *
+ * What this does:
+ * 1. extracts code blocks and privately escapes them from processing
+ * 2. Run html purifier on the content
+ * 3. put back the code blocks
+ * 4. run htmlspecialchars on the entire content for safe storage
+ *
+ * At render time:
+ * $markdown = \Zotlabs\Lib\MarkdownSoap::unescape($text);
+ * $html = \Michelf\MarkdownExtra::DefaultTransform($markdown);
+ */
+
+
+
+class MarkdownSoap {
+
+ private $token;
+
+ private $str;
+
+ function __construct($s) {
+ $this->str = $s;
+ $this->token = random_string(20);
+ }
+
+
+ function clean() {
+
+ $x = $this->extract_code($this->str);
+
+ $x = $this->purify($x);
+
+ $x = $this->putback_code($x);
+
+ $x = $this->escape($x);
+
+ return $x;
+ }
+
+ function extract_code($s) {
+
+ $text = preg_replace_callback('{
+ (?:\n\n|\A\n?)
+ ( # $1 = the code block -- one or more lines, starting with a space/tab
+ (?>
+ [ ]{'.'4'.'} # Lines must start with a tab or a tab-width of spaces
+ .*\n+
+ )+
+ )
+ ((?=^[ ]{0,'.'4'.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
+ }xm',
+ [ $this , 'encode_code' ], $s);
+
+ return $text;
+ }
+
+ function encode_code($matches) {
+ return $this->token . ';' . base64_encode($matches[0]) . ';' ;
+ }
+
+ function decode_code($matches) {
+ return base64_decode($matches[1]);
+ }
+
+ function putback_code($s) {
+ $text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm',[ $this, 'decode_code' ], $s);
+ return $text;
+ }
+
+ function purify($s) {
+ $s = $this->protect_autolinks($s);
+ $s = purify_html($s);
+ $s = $this->unprotect_autolinks($s);
+ return $s;
+ }
+
+ function protect_autolinks($s) {
+ $s = preg_replace('/\<(https?\:\/\/)(.*?)\>/','[$1$2]($1$2)',$s);
+ return $s;
+ }
+
+ function unprotect_autolinks($s) {
+ return $s;
+
+ }
+
+ function escape($s) {
+ return htmlspecialchars($s,ENT_QUOTES,'UTF-8',false);
+ }
+
+ static public function unescape($s) {
+ return htmlspecialchars_decode($s,ENT_QUOTES);
+ }
+}
diff --git a/Zotlabs/Lib/NativeWiki.php b/Zotlabs/Lib/NativeWiki.php
index 519102d24..7642dbb3e 100644
--- a/Zotlabs/Lib/NativeWiki.php
+++ b/Zotlabs/Lib/NativeWiki.php
@@ -18,11 +18,18 @@ class NativeWiki {
if($wikis) {
foreach($wikis as &$w) {
+
+ $w['json_allow_cid'] = acl2json($w['allow_cid']);
+ $w['json_allow_gid'] = acl2json($w['allow_gid']);
+ $w['json_deny_cid'] = acl2json($w['deny_cid']);
+ $w['json_deny_gid'] = acl2json($w['deny_gid']);
+
$w['rawName'] = get_iconfig($w, 'wiki', 'rawName');
$w['htmlName'] = escape_tags($w['rawName']);
$w['urlName'] = urlencode(urlencode($w['rawName']));
$w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType');
- $w['lock'] = (($w['item_private'] || $w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? true : false);
+ $w['typelock'] = get_iconfig($w, 'wiki', 'typelock');
+ $w['lockstate'] = (($w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? 'lock' : 'unlock');
}
}
// TODO: query db for wikis the observer can access. Return with two lists, for read and write access
@@ -75,6 +82,8 @@ class NativeWiki {
$arr['obj_type'] = ACTIVITY_OBJ_WIKI;
$arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
+ $arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_wiki'),true);
+
// Save the wiki name information using iconfig. This is shareable.
if(! set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) {
return array('item' => null, 'success' => false);
@@ -82,7 +91,9 @@ class NativeWiki {
if(! set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) {
return array('item' => null, 'success' => false);
}
-
+
+ set_iconfig($arr,'wiki','typelock',$wiki['typelock'],true);
+
$post = item_store($arr);
$item_id = $post['item_id'];
@@ -96,16 +107,77 @@ class NativeWiki {
}
}
+ function update_wiki($channel_id, $observer_hash, $arr, $acl) {
+
+ $w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
+ $item = $w['wiki'];
+
+ if(! $item) {
+ return array('item' => null, 'success' => false);
+ }
+
+ $x = $acl->get();
+
+ $item['allow_cid'] = $x['allow_cid'];
+ $item['allow_gid'] = $x['allow_gid'];
+ $item['deny_cid'] = $x['deny_cid'];
+ $item['deny_gid'] = $x['deny_gid'];
+ $item['item_private'] = intval($acl->is_private());
+
+ $update_title = false;
+
+ if($item['title'] !== $arr['updateRawName']) {
+ $update_title = true;
+ $item['title'] = $arr['updateRawName'];
+ }
+
+ $update = item_store_update($item);
+
+ $item_id = $update['item_id'];
+
+ // update acl for any existing wiki pages
+
+ q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d where resource_type = 'nwikipage' and resource_id = '%s'",
+ dbesc($item['allow_cid']),
+ dbesc($item['allow_gid']),
+ dbesc($item['deny_cid']),
+ dbesc($item['deny_gid']),
+ dbesc($item['item_private']),
+ dbesc($arr['resource_id'])
+ );
+
+
+ if($update['item_id']) {
+ info( t('Wiki updated successfully'));
+ if($update_title) {
+ // Update the wiki name information using iconfig.
+ if(! set_iconfig($update['item_id'], 'wiki', 'rawName', $arr['updateRawName'], true)) {
+ return array('item' => null, 'success' => false);
+ }
+ }
+ return array('item' => $update['item'], 'item_id' => $update['item_id'], 'success' => $update['success']);
+ }
+ else {
+ return array('item' => null, 'success' => false);
+ }
+ }
+
static public function sync_a_wiki_item($uid,$id,$resource_id) {
- $r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = %d )) ",
+ $r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ",
intval($uid),
intval($id),
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
- intval($resource_id)
+ dbesc($resource_id)
);
if($r) {
+ $q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
+ dbesc($r[0]['resource_type'])
+ );
+ if($q) {
+ $r = array_merge($r,$q);
+ }
xchan_query($r);
$sync_item = fetch_post_tags($r);
build_sync_packet($uid,array('wiki' => array(encode_item($sync_item[0],true))));
@@ -148,13 +220,15 @@ class NativeWiki {
// Get wiki metadata
$rawName = get_iconfig($w, 'wiki', 'rawName');
$mimeType = get_iconfig($w, 'wiki', 'mimeType');
+ $typelock = get_iconfig($w, 'wiki', 'typelock');
return array(
- 'wiki' => $w,
- 'rawName' => $rawName,
+ 'wiki' => $w,
+ 'rawName' => $rawName,
'htmlName' => escape_tags($rawName),
- 'urlName' => urlencode(urlencode($rawName)),
- 'mimeType' => $mimeType
+ 'urlName' => urlencode(urlencode($rawName)),
+ 'mimeType' => $mimeType,
+ 'typelock' => $typelock
);
}
}
diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php
index 1467a1cfb..209a5ef3c 100644
--- a/Zotlabs/Lib/NativeWikiPage.php
+++ b/Zotlabs/Lib/NativeWikiPage.php
@@ -21,19 +21,30 @@ class NativeWikiPage {
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and item_deleted = 0
- $sql_extra group by mid",
+ $sql_extra order by title asc",
dbesc($resource_id),
intval($channel_id)
);
if($r) {
- $items = fetch_post_tags($r,true);
+ $x = [];
+ $y = [];
+
+ foreach($r as $rv) {
+ if(! in_array($rv['mid'],$x)) {
+ $y[] = $rv;
+ $x[] = $rv['mid'];
+ }
+ }
+
+ $items = fetch_post_tags($y,true);
+
foreach($items as $page_item) {
$title = get_iconfig($page_item['id'],'nwikipage','pagetitle',t('(No Title)'));
if(urldecode($title) !== 'Home') {
$pages[] = [
'resource_id' => $resource_id,
'title' => escape_tags($title),
- 'url' => urlencode(urlencode($title)),
+ 'url' => str_replace('%2F','/',urlencode(str_replace('%2F','/',urlencode($title)))),
'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $page_item['id']
];
}
@@ -44,17 +55,34 @@ class NativeWikiPage {
}
- static public function create_page($channel_id, $observer_hash, $name, $resource_id) {
+ static public function create_page($channel_id, $observer_hash, $name, $resource_id, $mimetype = 'text/bbcode') {
+
+ logger('mimetype: ' . $mimetype);
+
+ if(! in_array($mimetype,[ 'text/markdown','text/bbcode','text/plain','text/html' ]))
+ $mimetype = 'text/markdown';
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
+ if (! $w['wiki']) {
+ return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
+ }
+
// create an empty activity
$arr = [];
- $arr['uid'] = $channel_id;
- $arr['author_xchan'] = $observer_hash;
+ $arr['uid'] = $channel_id;
+ $arr['author_xchan'] = $observer_hash;
+ $arr['mimetype'] = $mimetype;
+ $arr['title'] = $name;
$arr['resource_type'] = 'nwikipage';
- $arr['resource_id'] = $resource_id;
+ $arr['resource_id'] = $resource_id;
+ $arr['allow_cid'] = $w['wiki']['allow_cid'];
+ $arr['allow_gid'] = $w['wiki']['allow_gid'];
+ $arr['deny_cid'] = $w['wiki']['deny_cid'];
+ $arr['deny_gid'] = $w['wiki']['deny_gid'];
+
+ $arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel_id,'view_wiki'),true);
// We may wish to change this some day.
$arr['item_unpublished'] = 1;
@@ -112,8 +140,14 @@ class NativeWikiPage {
if($ic) {
foreach($ic as $c) {
set_iconfig($c['item_id'],'nwikipage','pagetitle',$pageNewName);
+ $ids[] = $c['item_id'];
}
+ $str_ids = implode(',', $ids);
+ q("update item set title = '%s' where id in ($str_ids)",
+ dbesc($pageNewName)
+ );
+
$page = [
'rawName' => $pageNewName,
'htmlName' => escape_tags($pageNewName),
@@ -146,10 +180,11 @@ class NativeWikiPage {
$content = $item['body'];
return [
- 'content' => json_encode($content),
- 'mimeType' => $w['mimeType'],
- 'message' => '',
- 'success' => true
+ 'content' => $content,
+ 'mimeType' => $w['mimeType'],
+ 'pageMimeType' => $item['mimetype'],
+ 'message' => '',
+ 'success' => true
];
}
@@ -180,7 +215,7 @@ class NativeWikiPage {
$processed ++;
$history[] = [
'revision' => $item['revision'],
- 'date' => datetime_convert('UTC',date_default_timezone_get(),$item['created']),
+ 'date' => datetime_convert('UTC',date_default_timezone_get(),$item['edited']),
'name' => $item['author']['xchan_name'],
'title' => get_iconfig($item,'nwikipage','commit_msg')
];
@@ -225,6 +260,7 @@ class NativeWikiPage {
}
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
+
if($revision == (-1))
$sql_extra .= " order by revision desc ";
elseif($revision)
@@ -277,6 +313,7 @@ class NativeWikiPage {
}
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
+
$sql_extra .= " order by revision desc ";
$r = null;
@@ -295,48 +332,21 @@ class NativeWikiPage {
return null;
}
-
-
- static public function prepare_content($s) {
-
- $text = preg_replace_callback('{
- (?:\n\n|\A\n?)
- ( # $1 = the code block -- one or more lines, starting with a space/tab
- (?>
- [ ]{'.'4'.'} # Lines must start with a tab or a tab-width of spaces
- .*\n+
- )+
- )
- ((?=^[ ]{0,'.'4'.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
- }xm',
- 'self::nwiki_prepare_content_callback', $s);
-
- return $text;
- }
-
- static public function nwiki_prepare_content_callback($matches) {
- $codeblock = $matches[1];
-
- $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES, UTF8, false);
- return "\n\n" . $codeblock ;
- }
-
-
-
static public function save_page($arr) {
- $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
- $content = ((array_key_exists('content',$arr)) ? purify_html(Zlib\NativeWikiPage::prepare_content($arr['content'])) : '');
- $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $content = ((array_key_exists('content',$arr)) ? $arr['content'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
- $revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : 0);
+ $revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (!$w['wiki']) {
return array('message' => t('Error reading wiki'), 'success' => false);
}
+
// fetch the most recently saved revision.
@@ -345,6 +355,8 @@ class NativeWikiPage {
return array('message' => t('Page not found'), 'success' => false);
}
+ $mimetype = $item['mimetype'];
+
// change just the fields we need to change to create a revision;
unset($item['id']);
@@ -355,6 +367,7 @@ class NativeWikiPage {
$item['author_xchan'] = $observer_hash;
$item['revision'] = (($arr['revision']) ? intval($arr['revision']) + 1 : intval($item['revision']) + 1);
$item['edited'] = datetime_convert();
+ $item['mimetype'] = $mimetype;
if($item['iconfig'] && is_array($item['iconfig']) && count($item['iconfig'])) {
for($x = 0; $x < count($item['iconfig']); $x ++) {
@@ -522,6 +535,29 @@ class NativeWikiPage {
}
return $s;
}
+
+ static public function render_page_history($arr) {
+
+ $pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
+
+ $pageHistory = self::page_history([
+ 'channel_id' => \App::$profile_uid,
+ 'observer_hash' => get_observer_hash(),
+ 'resource_id' => $resource_id,
+ 'pageUrlName' => $pageUrlName
+ ]);
+
+ return replace_macros(get_markup_template('nwiki_page_history.tpl'), array(
+ '$pageHistory' => $pageHistory['history'],
+ '$permsWrite' => $arr['permsWrite'],
+ '$name_lbl' => t('Name'),
+ '$msg_label' => t('Message','wiki_history')
+ ));
+
+ }
+
+
/**
* Replace the instances of the string [toc] with a list element that will be populated by
@@ -578,10 +614,13 @@ class NativeWikiPage {
}
static public function get_file_ext($arr) {
- if($arr['mimeType'] == 'text/bbcode')
+ if($arr['mimetype'] === 'text/bbcode')
return '.bb';
- else
+ elseif($arr['mimetype'] === 'text/markdown')
return '.md';
+ elseif($arr['mimetype'] === 'text/plain')
+ return '.txt';
+
}
// This function is derived from
diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php
index d70697fbc..2a0b18aac 100644
--- a/Zotlabs/Lib/PConfig.php
+++ b/Zotlabs/Lib/PConfig.php
@@ -20,11 +20,12 @@ class PConfig {
if(is_null($uid) || $uid === false)
return false;
- if(! array_key_exists($uid, \App::$config))
- \App::$config[$uid] = array();
-
if(! is_array(\App::$config)) {
- btlogger('App::$config not an array: ' . $uid);
+ btlogger('App::$config not an array');
+ }
+
+ if(! array_key_exists($uid, \App::$config)) {
+ \App::$config[$uid] = array();
}
if(! is_array(\App::$config[$uid])) {
@@ -119,7 +120,7 @@ class PConfig {
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
- if(get_pconfig($uid, $family, $key) === false) {
+ if(self::Get($uid, $family, $key) === false) {
if(! array_key_exists($uid, \App::$config))
\App::$config[$uid] = array();
if(! array_key_exists($family, \App::$config[$uid]))
diff --git a/Zotlabs/Lib/SConfig.php b/Zotlabs/Lib/SConfig.php
new file mode 100644
index 000000000..ca0d133b2
--- /dev/null
+++ b/Zotlabs/Lib/SConfig.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+// account configuration storage is built on top of the under-utilised xconfig
+
+class SConfig {
+
+ static public function Load($server_id) {
+ return XConfig::Load('s_' . $server_id);
+ }
+
+ static public function Get($server_id,$family,$key,$default = false) {
+ return XConfig::Get('s_' . $server_id,$family,$key, $default);
+ }
+
+ static public function Set($server_id,$family,$key,$value) {
+ return XConfig::Set('s_' . $server_id,$family,$key,$value);
+ }
+
+ static public function Delete($server_id,$family,$key) {
+ return XConfig::Delete('s_' . $server_id,$family,$key);
+ }
+
+}
diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php
index 306c90f4a..c3e11eb6a 100644
--- a/Zotlabs/Lib/System.php
+++ b/Zotlabs/Lib/System.php
@@ -19,6 +19,9 @@ class System {
static public function get_project_version() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
return '';
+ if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('std_version',\App::$config['system']))
+ return \App::$config['system']['std_version'];
+
return self::get_std_version();
}
@@ -54,12 +57,15 @@ class System {
return 'https://github.com/redmatrix/hubzilla';
}
+ static public function get_server_role() {
+ return 'pro';
+ }
- static public function get_server_role() {
- if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['server_role'])
- return \App::$config['system']['server_role'];
- return 'standard';
+ static public function get_zot_revision() {
+ $x = [ 'revision' => ZOT_REVISION ];
+ call_hooks('zot_revision',$x);
+ return $x['revision'];
}
static public function get_std_version() {
@@ -72,11 +78,8 @@ class System {
if(get_directory_realm() != DIRECTORY_REALM)
return true;
-
- foreach(['hubzilla','zap'] as $t) {
- if(stristr($p,$t))
- return true;
- }
+ if(in_array(strtolower($p),['hubzilla','zap','red']))
+ return true;
return false;
}
}
diff --git a/Zotlabs/Lib/Techlevels.php b/Zotlabs/Lib/Techlevels.php
index 6a8c36fb3..380901678 100644
--- a/Zotlabs/Lib/Techlevels.php
+++ b/Zotlabs/Lib/Techlevels.php
@@ -7,12 +7,12 @@ class Techlevels {
static public function levels() {
$techlevels = [
- '0' => t('Beginner/Basic'),
- '1' => t('Novice - not skilled but willing to learn'),
- '2' => t('Intermediate - somewhat comfortable'),
- '3' => t('Advanced - very comfortable'),
- '4' => t('Expert - I can write computer code'),
- '5' => t('Wizard - I probably know more than you do')
+ '0' => t('0. Beginner/Basic'),
+ '1' => t('1. Novice - not skilled but willing to learn'),
+ '2' => t('2. Intermediate - somewhat comfortable'),
+ '3' => t('3. Advanced - very comfortable'),
+ '4' => t('4. Expert - I can write computer code'),
+ '5' => t('5. Wizard - I probably know more than you do')
];
return $techlevels;
}
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 0ee8e6680..67a507025 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -29,6 +29,7 @@ class ThreadItem {
private $visiting = false;
private $channel = null;
private $display_mode = 'normal';
+ private $reload = '';
public function __construct($data) {
@@ -82,7 +83,8 @@ class ThreadItem {
$dropping = false;
$star = false;
$isstarred = "unstarred fa-star-o";
- $indent = '';
+ $is_comment = false;
+ $is_item = false;
$osparkle = '';
$total_children = $this->count_descendants();
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
@@ -100,10 +102,13 @@ class ThreadItem {
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
+
$mode = $conv->get_mode();
+ $edlink = (($item['item_type'] == ITEM_TYPE_CARD) ? 'card_edit' : 'editpost');
+
if(local_channel() && $observer['xchan_hash'] === $item['author_xchan'])
- $edpost = array(z_root()."/editpost/".$item['id'], t("Edit"));
+ $edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit'));
else
$edpost = false;
@@ -136,7 +141,7 @@ class ThreadItem {
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
$profile_avatar = $item['author']['xchan_photo_m'];
- $profile_link = chanlink_url($item['author']['xchan_url']);
+ $profile_link = chanlink_hash($item['author_xchan']);
$profile_name = $item['author']['xchan_name'];
$location = format_location($item);
@@ -152,7 +157,7 @@ class ThreadItem {
$response_verbs[] = 'attendyes';
$response_verbs[] = 'attendno';
$response_verbs[] = 'attendmaybe';
- if($this->is_commentable()) {
+ if($this->is_commentable() && $observer) {
$isevent = true;
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
}
@@ -163,7 +168,7 @@ class ThreadItem {
$response_verbs[] = 'agree';
$response_verbs[] = 'disagree';
$response_verbs[] = 'abstain';
- if($this->is_commentable()) {
+ if($this->is_commentable() && $observer) {
$conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
$canvote = true;
}
@@ -183,7 +188,7 @@ class ThreadItem {
$like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : '');
if (count($like_list) > MAX_LIKERS) {
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
- array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
+ array_push($like_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$like_list_part = '';
}
@@ -195,7 +200,7 @@ class ThreadItem {
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
if (count($dislike_list) > MAX_LIKERS) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
- array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
+ array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$dislike_list_part = '';
}
@@ -232,7 +237,7 @@ class ThreadItem {
}
}
else {
- $indent = 'comment';
+ $is_comment = true;
}
@@ -250,8 +255,6 @@ class ThreadItem {
);
}
- $server_role = get_config('system','server_role');
-
$has_bookmarks = false;
if(is_array($item['term'])) {
foreach($item['term'] as $t) {
@@ -264,7 +267,7 @@ class ThreadItem {
if(($item['obj_type'] === ACTIVITY_OBJ_EVENT) && $conv->get_profile_owner() == local_channel())
$has_event = true;
- if($this->is_commentable()) {
+ if($this->is_commentable() && $observer) {
$like = array( t("I like this \x28toggle\x29"), t("like"));
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
}
@@ -276,13 +279,13 @@ class ThreadItem {
$keep_reports = intval(get_config('system','expire_delivery_reports'));
if($keep_reports === 0)
- $keep_reports = 30;
+ $keep_reports = 10;
if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0)
$dreport = t('Delivery Report');
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
- $indent .= ' shiny';
+ $is_new = true;
localize_item($item);
@@ -310,7 +313,8 @@ class ThreadItem {
$tmp_item = array(
'template' => $this->get_template(),
- 'mode' => $mode,
+ 'mode' => $mode,
+ 'item_type' => intval($item['item_type']),
'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
'body' => $body['html'],
'tags' => $body['tags'],
@@ -337,7 +341,6 @@ class ThreadItem {
'profile_url' => $profile_link,
'thread_action_menu' => thread_action_menu($item,$conv->get_mode()),
'thread_author_menu' => thread_author_menu($item,$conv->get_mode()),
- 'item_photo_menu' => item_photo_menu($item),
'dreport' => $dreport,
'name' => $profile_name,
'thumb' => $profile_avatar,
@@ -361,7 +364,8 @@ class ThreadItem {
'attend_title' => t('Attendance Options'),
'vote_label' => t('Vote'),
'vote_title' => t('Voting Options'),
- 'indent' => $indent,
+ 'is_comment' => $is_comment,
+ 'is_new' => $is_new,
'owner_url' => $this->get_owner_url(),
'owner_photo' => $this->get_owner_photo(),
'owner_name' => $this->get_owner_name(),
@@ -370,7 +374,7 @@ class ThreadItem {
'has_tags' => $has_tags,
'reactions' => $this->reactions,
// Item toolbar buttons
- 'emojis' => (($this->is_toplevel() && $this->is_commentable() && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
+ 'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
'like' => $like,
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
'share' => $share,
@@ -407,9 +411,10 @@ class ThreadItem {
'showlike' => $showlike,
'showdislike' => $showdislike,
'comment' => $this->get_comment_box($indent),
- 'previewing' => ($conv->is_preview() ? ' preview ' : ''),
+ 'previewing' => ($conv->is_preview() ? true : false ),
+ 'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
- 'submid' => str_replace(['+','='], ['',''], base64_encode(substr($item['mid'],0,32))),
+ 'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
'thread_level' => $thread_level
);
@@ -480,6 +485,14 @@ class ThreadItem {
return $this->threaded;
}
+ public function set_reload($val) {
+ $this->reload = $val;
+ }
+
+ public function get_reload() {
+ return $this->reload;
+ }
+
public function set_commentable($val) {
$this->commentable = $val;
foreach($this->get_children() as $child)
@@ -713,11 +726,10 @@ class ThreadItem {
call_hooks('comment_buttons',$arr);
$comment_buttons = $arr['comment_buttons'];
-
$comment_box = replace_macros($template,array(
'$return_path' => '',
'$threaded' => $this->is_threaded(),
- '$jsreload' => '', //(($conv->get_mode() === 'display') ? $_SESSION['return_url'] : ''),
+ '$jsreload' => $conv->reload,
'$type' => (($conv->get_mode() === 'channel') ? 'wall-comment' : 'net-comment'),
'$id' => $this->get_id(),
'$parent' => $this->get_id(),
@@ -735,15 +747,21 @@ class ThreadItem {
'$edquote' => t('Quote'),
'$edcode' => t('Code'),
'$edimg' => t('Image'),
+ '$edatt' => t('Attach File'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
'$indent' => $indent,
+ '$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
'$cipher' => $conv->get_cipher(),
- '$sourceapp' => \App::$sourcename
-
+ '$sourceapp' => \App::$sourcename,
+ '$observer' => get_observer_hash(),
+ '$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
+ '$anonname' => [ 'anonname', t('Your full name (required)') ],
+ '$anonmail' => [ 'anonmail', t('Your email address (required)') ],
+ '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
));
return $comment_box;
@@ -767,7 +785,7 @@ class ThreadItem {
return;
if($this->is_toplevel() && ($this->get_data_value('author_xchan') != $this->get_data_value('owner_xchan'))) {
- $this->owner_url = chanlink_url($this->data['owner']['xchan_url']);
+ $this->owner_url = chanlink_hash($this->data['owner']['xchan_hash']);
$this->owner_photo = $this->data['owner']['xchan_photo_m'];
$this->owner_name = $this->data['owner']['xchan_name'];
$this->wall_to_wall = true;
diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php
index beb626f31..436723f8c 100644
--- a/Zotlabs/Lib/ThreadStream.php
+++ b/Zotlabs/Lib/ThreadStream.php
@@ -18,18 +18,21 @@ class ThreadStream {
private $observer = null;
private $writable = false;
private $commentable = false;
+ private $uploadable = false;
private $profile_owner = 0;
private $preview = false;
private $prepared_item = '';
+ public $reload = '';
private $cipher = 'aes256';
// $prepared_item is for use by alternate conversation structures such as photos
// wherein we've already prepared a top level item which doesn't look anything like
// a normal "post" item
- public function __construct($mode, $preview, $prepared_item = '') {
+ public function __construct($mode, $preview, $uploadable, $prepared_item = '') {
$this->set_mode($mode);
$this->preview = $preview;
+ $this->uploadable = $uploadable;
$this->prepared_item = $prepared_item;
$c = ((local_channel()) ? get_pconfig(local_channel(),'system','default_cipher') : '');
if($c)
@@ -55,11 +58,17 @@ class ThreadStream {
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
+ case 'cards':
+ $this->profile_owner = \App::$profile['profile_uid'];
+ $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
+ $this->reload = $_SESSION['return_url'];
+ break;
case 'display':
// in this mode we set profile_owner after initialisation (from conversation()) and then
// pull some trickery which allows us to re-invoke this function afterward
// it's an ugly hack so @FIXME
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
+ $this->uploadable = perm_is_allowed($this->profile_owner,$ob_hash,'write_storage');
break;
case 'page':
$this->profile_owner = \App::$profile['uid'];
@@ -91,6 +100,11 @@ class ThreadStream {
return $this->commentable;
}
+ public function is_uploadable() {
+ return $this->uploadable;
+ }
+
+
/**
* Check if page is a preview
*/
@@ -158,7 +172,7 @@ class ThreadStream {
if(intval($item->get_data_value('item_nocomment'))) {
$item->set_commentable(false);
}
- elseif(($this->observer) && (! $item->is_commentable())) {
+ elseif(! $item->is_commentable()) {
if((array_key_exists('owner',$item->data)) && intval($item->data['owner']['abook_self']))
$item->set_commentable(perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'));
else
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index 6f5b0ddf9..e164875e8 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -19,9 +19,9 @@ require_once("include/group.php");
class Acl extends \Zotlabs\Web\Controller {
- function init(){
+ function init() {
- // logger('mod_acl: ' . print_r($_REQUEST,true));
+ logger('mod_acl: ' . print_r($_REQUEST,true));
$start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
@@ -33,6 +33,7 @@ class Acl extends \Zotlabs\Web\Controller {
// $type =
// '' => standard ACL request
// 'g' => Groups only ACL request
+ // 'f' => forums only ACL request
// 'c' => Connections only ACL request or editor (textarea) mention request
// $_REQUEST['search'] contains ACL search text.
@@ -49,19 +50,19 @@ class Acl extends \Zotlabs\Web\Controller {
$extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
// The different autocomplete libraries use different names for the search text
- // parameter. Internaly we'll use $search to represent the search text no matter
+ // parameter. Internally we'll use $search to represent the search text no matter
// what request variable it was attached to.
if(array_key_exists('query',$_REQUEST)) {
$search = $_REQUEST['query'];
}
- if( (! local_channel()) && (! ($type == 'x' || $type == 'c')))
+ if( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ])))
killme();
$permitted = [];
- if(in_array($type, [ 'm', 'a', 'c' ])) {
+ if(in_array($type, [ 'm', 'a', 'c', 'f' ])) {
// These queries require permission checking. We'll create a simple array of xchan_hash for those with
// the requisite permissions which we can check against.
@@ -104,6 +105,8 @@ class Acl extends \Zotlabs\Web\Controller {
if($type == '' || $type == 'g') {
+ // virtual groups based on private profile viewing ability
+
$r = q("select id, profile_guid, profile_name from profile where is_default = 0 and uid = %d",
intval(local_channel())
);
@@ -121,6 +124,8 @@ class Acl extends \Zotlabs\Web\Controller {
}
}
+ // Normal privacy groups
+
$r = q("SELECT groups.id, groups.hash, groups.gname
FROM groups, group_member
WHERE groups.deleted = 0 AND groups.uid = %d
@@ -150,26 +155,35 @@ class Acl extends \Zotlabs\Web\Controller {
}
}
- if($type == '' || $type == 'c') {
+ if($type == '' || $type == 'c' || $type === 'f') {
+
$extra_channels_sql = '';
- // Only include channels who allow the observer to view their permissions
- foreach($extra_channels as $channel) {
- if(perm_is_allowed(intval($channel), get_observer_hash(),'view_contacts'))
- $extra_channels_sql .= "," . intval($channel);
+
+ // Only include channels who allow the observer to view their connections
+ if($extra_channels) {
+ foreach($extra_channels as $channel) {
+ if(perm_is_allowed(intval($channel), get_observer_hash(),'view_contacts')) {
+ if($extra_channel_sql)
+ $extra_channels_sql .= ',';
+ $extra_channels_sql .= intval($channel);
+ }
+ }
}
- $extra_channels_sql = substr($extra_channels_sql,1); // Remove initial comma
-
// Getting info from the abook is better for local users because it contains info about permissions
if(local_channel()) {
if($extra_channels_sql != '')
$extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and abook_hidden = 0 ";
+
+ // Add atokens belonging to the local channel @TODO restrict by search
+
$r2 = null;
$r1 = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
+
if($r1) {
require_once('include/security.php');
$r2 = array();
@@ -189,6 +203,7 @@ class Acl extends \Zotlabs\Web\Controller {
}
}
+ // add connections
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, xchan_pubforum, abook_flags, abook_self
FROM abook left join xchan on abook_xchan = xchan_hash
@@ -293,7 +308,7 @@ class Acl extends \Zotlabs\Web\Controller {
$contacts[] = array(
"photo" => $g['photo'],
"name" => $g['name'],
- "nick" => $g['address'],
+ "nick" => $g['address']
);
}
}
@@ -310,18 +325,24 @@ class Acl extends \Zotlabs\Web\Controller {
$r = array();
if($r) {
- foreach($r as $g){
+ foreach($r as $g) {
- // remove RSS feeds from ACLs - they are inaccessible
- if(strpos($g['hash'],'/') && $type != 'a')
+ if(($g['network'] === 'rss') && ($type != 'a'))
continue;
-
- if(in_array($g['hash'],$permitted) && $type == 'c' && (! $noforums)) {
+
+ $g['hash'] = urlencode($g['hash']);
+
+ if(! $g['nick']) {
+ $t = explode(' ',strtolower($g['name']));
+ $g['nick'] = $t[0] . '@';
+ }
+
+ if(in_array($g['hash'],$permitted) && in_array($type, [ 'c', 'f' ]) && (! $noforums)) {
$contacts[] = array(
"type" => "c",
"photo" => "images/twopeople.png",
- "name" => $g['name'] . '+',
- "id" => $g['id'] . '+',
+ "name" => $g['name'] . (($type === 'f') ? '' : '+'),
+ "id" => urlencode($g['id']) . (($type === 'f') ? '' : '+'),
"xid" => $g['hash'],
"link" => $g['nick'],
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
@@ -330,18 +351,20 @@ class Acl extends \Zotlabs\Web\Controller {
"label" => t('network')
);
}
- $contacts[] = array(
- "type" => "c",
- "photo" => $g['micro'],
- "name" => $g['name'],
- "id" => $g['id'],
- "xid" => $g['hash'],
- "link" => $g['nick'],
- "nick" => (($g['nick']) ? substr($g['nick'],0,strpos($g['nick'],'@')) : t('RSS')),
- "self" => (intval($g['abook_self']) ? 'abook-self' : ''),
- "taggable" => '',
- "label" => '',
- );
+ if($type !== 'f') {
+ $contacts[] = array(
+ "type" => "c",
+ "photo" => $g['micro'],
+ "name" => $g['name'],
+ "id" => urlencode($g['id']),
+ "xid" => $g['hash'],
+ "link" => $g['nick'],
+ "nick" => (($g['nick']) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
+ "self" => (intval($g['abook_self']) ? 'abook-self' : ''),
+ "taggable" => '',
+ "label" => '',
+ );
+ }
}
}
@@ -398,10 +421,12 @@ class Acl extends \Zotlabs\Web\Controller {
$directory = find_upstream_directory($dirmode);
$url = $directory['url'] . '/dirsearch';
}
+
+ $token = get_config('system','realm_token');
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
if($url) {
- $query = $url . '?f=' ;
+ $query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : '');
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode($search) : '');
$x = z_fetch_url($query);
diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php
index 536d85dde..30f3dfa48 100644
--- a/Zotlabs/Module/Admin.php
+++ b/Zotlabs/Module/Admin.php
@@ -52,6 +52,8 @@ class Admin extends \Zotlabs\Web\Controller {
* Page content
*/
+ nav_set_selected('Admin');
+
$o = '';
if(argc() > 1) {
@@ -91,10 +93,10 @@ class Admin extends \Zotlabs\Web\Controller {
intval(ACCOUNT_BLOCKED)
);
if ($r) {
- $accounts['total'] = array('label' => t('# Accounts'), 'val' => $r[0]['total']);
- $accounts['blocked'] = array('label' => t('# blocked accounts'), 'val' => $r[0]['blocked']);
- $accounts['expired'] = array('label' => t('# expired accounts'), 'val' => $r[0]['expired']);
- $accounts['expiring'] = array('label' => t('# expiring accounts'), 'val' => $r[0]['expiring']);
+ $accounts['total'] = array('label' => t('Accounts'), 'val' => $r[0]['total']);
+ $accounts['blocked'] = array('label' => t('Blocked accounts'), 'val' => $r[0]['blocked']);
+ $accounts['expired'] = array('label' => t('Expired accounts'), 'val' => $r[0]['expired']);
+ $accounts['expiring'] = array('label' => t('Expiring accounts'), 'val' => $r[0]['expiring']);
}
// pending registrations
@@ -105,9 +107,9 @@ class Admin extends \Zotlabs\Web\Controller {
$channels = array();
$r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0");
if ($r) {
- $channels['total'] = array('label' => t('# Channels'), 'val' => $r[0]['total']);
- $channels['main'] = array('label' => t('# primary'), 'val' => $r[0]['main']);
- $channels['clones'] = array('label' => t('# clones'), 'val' => $r[0]['clones']);
+ $channels['total'] = array('label' => t('Channels'), 'val' => $r[0]['total']);
+ $channels['main'] = array('label' => t('Primary'), 'val' => $r[0]['main']);
+ $channels['clones'] = array('label' => t('Clones'), 'val' => $r[0]['clones']);
}
// We can do better, but this is a quick queue status
@@ -118,14 +120,11 @@ class Admin extends \Zotlabs\Web\Controller {
// If no plugins active return 0, otherwise list of plugin names
$plugins = (count(\App::$plugins) == 0) ? count(\App::$plugins) : \App::$plugins;
+ if(is_array($plugins))
+ sort($plugins);
+
// Could be extended to provide also other alerts to the admin
$alertmsg = '';
- // annoy admin about upcoming unsupported PHP version
- if (version_compare(PHP_VERSION, '5.4', '<')) {
- $alertmsg = 'Your PHP version ' . PHP_VERSION . ' will not be supported with the next major release of $Projectname. You are strongly urged to upgrade to a current version.'
- . '<br>PHP 5.3 has reached its <a href="http://php.net/eol.php" class="alert-link">End of Life (EOL)</a> in August 2014.'
- . ' A list about current PHP versions can be found <a href="http://php.net/supported-versions.php" class="alert-link">here</a>.';
- }
$vmaster = get_repository_version('master');
$vdev = get_repository_version('dev');
diff --git a/Zotlabs/Module/Admin/Plugins.php b/Zotlabs/Module/Admin/Plugins.php
index 527e96496..feb29e9d6 100644
--- a/Zotlabs/Module/Admin/Plugins.php
+++ b/Zotlabs/Module/Admin/Plugins.php
@@ -3,10 +3,14 @@
namespace Zotlabs\Module\Admin;
use \Zotlabs\Storage\GitRepo as GitRepo;
+use \Michelf\MarkdownExtra;
class Plugins {
-
+ /**
+ * @brief
+ *
+ */
function post() {
if(argc() > 2 && is_file("addon/" . argv(2) . "/" . argv(2) . ".php")) {
@@ -15,16 +19,15 @@ class Plugins {
$func = argv(2) . '_plugin_admin_post';
$func($a);
}
-
- goaway(z_root() . '/admin/plugins/' . argv(2) );
+ goaway(z_root() . '/admin/plugins/' . argv(2) );
}
elseif(argc() > 2) {
switch(argv(2)) {
case 'updaterepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
- }
+ }
else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
@@ -101,16 +104,15 @@ class Plugins {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
- // TODO: remove directory and unlink /addon/files
+ /// @TODO remove directory and unlink /addon/files
if (rrmdir($repoDir)) {
json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
}
case 'installrepo':
- require_once('library/markdown.php');
if (array_key_exists('repoURL', $_REQUEST)) {
- require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
+ require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
@@ -170,9 +172,8 @@ class Plugins {
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
}
case 'addrepo':
- require_once('library/markdown.php');
if (array_key_exists('repoURL', $_REQUEST)) {
- require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
+ require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
@@ -225,7 +226,7 @@ class Plugins {
$repo['readme'] = $repo['manifest'] = null;
foreach ($git->git->tree('master') as $object) {
if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
- $repo['readme'] = Markdown($git->git->cat->blob($object['hash']));
+ $repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
} else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
$repo['manifest'] = $git->git->cat->blob($object['hash']);
}
@@ -241,7 +242,11 @@ class Plugins {
}
}
-
+ /**
+ * @brief Plugins admin page.
+ *
+ * @return string with parsed HTML
+ */
function get() {
/*
@@ -254,13 +259,13 @@ class Plugins {
notice( t("Item not found.") );
return '';
}
-
+
$enabled = in_array($plugin,\App::$plugins);
$info = get_plugin_info($plugin);
$x = check_plugin_versions($info);
-
+
// disable plugins which are installed but incompatible versions
-
+
if($enabled && ! $x) {
$enabled = false;
$idz = array_search($plugin, \App::$plugins);
@@ -271,7 +276,7 @@ class Plugins {
}
}
$info['disabled'] = 1-intval($x);
-
+
if (x($_GET,"a") && $_GET['a']=="t"){
check_form_security_token_redirectOnErr('/admin/plugins', 'admin_plugins', 't');
$pinstalled = false;
@@ -297,9 +302,9 @@ class Plugins {
}
goaway(z_root() . '/admin/plugins' );
}
+
// display plugin details
- require_once('library/markdown.php');
-
+
if (in_array($plugin, \App::$plugins)){
$status = 'on';
$action = t('Disable');
@@ -307,21 +312,21 @@ class Plugins {
$status = 'off';
$action = t('Enable');
}
-
+
$readme = null;
if (is_file("addon/$plugin/README.md")){
$readme = file_get_contents("addon/$plugin/README.md");
- $readme = Markdown($readme);
+ $readme = MarkdownExtra::defaultTransform($readme);
} else if (is_file("addon/$plugin/README")){
$readme = "<pre>". file_get_contents("addon/$plugin/README") ."</pre>";
}
-
+
$admin_form = '';
-
+
$r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1",
dbesc($plugin)
);
-
+
if($r) {
@require_once("addon/$plugin/$plugin.php");
if(function_exists($plugin.'_plugin_admin')) {
@@ -329,8 +334,8 @@ class Plugins {
$func($a, $admin_form);
}
}
-
-
+
+
$t = get_markup_template('admin_plugins_details.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -338,7 +343,7 @@ class Plugins {
'$toggle' => t('Toggle'),
'$settings' => t('Settings'),
'$baseurl' => z_root(),
-
+
'$plugin' => $plugin,
'$status' => $status,
'$action' => $action,
@@ -351,17 +356,17 @@ class Plugins {
'$str_serverroles' => t('Compatible Server Roles: '),
'$str_requires' => t('Requires: '),
'$disabled' => t('Disabled - version incompatibility'),
-
+
'$admin_form' => $admin_form,
'$function' => 'plugins',
'$screenshot' => '',
'$readme' => $readme,
-
+
'$form_security_token' => get_form_security_token('admin_plugins'),
));
}
-
-
+
+
/*
* List plugins
*/
@@ -374,9 +379,9 @@ class Plugins {
$info = get_plugin_info($id);
$enabled = in_array($id,\App::$plugins);
$x = check_plugin_versions($info);
-
+
// disable plugins which are installed but incompatible versions
-
+
if($enabled && ! $x) {
$enabled = false;
$idz = array_search($id, \App::$plugins);
@@ -387,19 +392,19 @@ class Plugins {
}
}
$info['disabled'] = 1-intval($x);
-
+
$plugins[] = array( $id, (($enabled)?"on":"off") , $info);
}
}
}
-
+
usort($plugins,'self::plugin_sort');
$allowManageRepos = false;
if(is_writable('extend/addon') && is_writable('store/[data]')) {
$allowManageRepos = true;
- }
-
+ }
+
$admin_plugins_add_repo_form= replace_macros(
get_markup_template('admin_plugins_addrepo.tpl'), array(
'$post' => 'admin/plugins/addrepo',
@@ -418,14 +423,14 @@ class Plugins {
'$cancel' => t('Cancel')
)
);
-
+
$reponames = $this->listAddonRepos();
$addonrepos = [];
foreach($reponames as $repo) {
$addonrepos[] = array('name' => $repo, 'description' => '');
- // TODO: Parse repo info to provide more information about repos
+ /// @TODO Parse repo info to provide more information about repos
}
-
+
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -471,5 +476,4 @@ class Plugins {
return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name'])));
}
-
} \ No newline at end of file
diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php
index 829ca71e4..d3d058c53 100644
--- a/Zotlabs/Module/Admin/Site.php
+++ b/Zotlabs/Module/Admin/Site.php
@@ -17,7 +17,6 @@ class Site {
check_form_security_token_redirectOnErr('/admin/site', 'admin_site');
$sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : '');
- $server_role = ((x($_POST,'server_role')) ? notags(trim($_POST['server_role'])) : 'standard');
$banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false);
@@ -48,6 +47,10 @@ class Site {
$no_community_page = !((x($_POST,'no_community_page')) ? True : False);
$default_expire_days = ((array_key_exists('default_expire_days',$_POST)) ? intval($_POST['default_expire_days']) : 0);
+ $reply_address = ((array_key_exists('reply_address',$_POST) && trim($_POST['reply_address'])) ? trim($_POST['reply_address']) : 'noreply@' . \App::get_hostname());
+ $from_email = ((array_key_exists('from_email',$_POST) && trim($_POST['from_email'])) ? trim($_POST['from_email']) : 'Administrator@' . \App::get_hostname());
+ $from_email_name = ((array_key_exists('from_email_name',$_POST) && trim($_POST['from_email_name'])) ? trim($_POST['from_email_name']) : \Zotlabs\Lib\System::get_site_name());
+
$verifyssl = ((x($_POST,'verifyssl')) ? True : False);
$proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : '');
$proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : '');
@@ -59,12 +62,12 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$techlevel_lock = ((x($_POST,'techlock')) ? intval($_POST['techlock']) : 0);
+ $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$techlevel = null;
if(array_key_exists('techlevel', $_POST))
$techlevel = intval($_POST['techlevel']);
- set_config('system', 'server_role', $server_role);
set_config('system', 'feed_contacts', $feed_contacts);
set_config('system', 'delivery_interval', $delivery_interval);
set_config('system', 'delivery_batch_count', $delivery_batch_count);
@@ -77,8 +80,16 @@ class Site {
set_config('system', 'enable_context_help', $enable_context_help);
set_config('system', 'verify_email', $verify_email);
set_config('system', 'default_expire_days', $default_expire_days);
+ set_config('system', 'reply_address', $reply_address);
+ set_config('system', 'from_email', $from_email);
+ set_config('system', 'from_email_name' , $from_email_name);
+ set_config('system', 'imagick_convert_path' , $imagick_path);
+
+
set_config('system', 'techlevel_lock', $techlevel_lock);
+
+
if(! is_null($techlevel))
set_config('system', 'techlevel', $techlevel);
@@ -163,6 +174,14 @@ class Site {
foreach($files as $file) {
$vars = '';
$f = basename($file);
+
+ $info = get_theme_info($f);
+ $compatible = check_plugin_versions($info);
+ if(!$compatible) {
+ $theme_choices[$f] = $theme_choices_mobile[$f] = sprintf(t('%s - (Incompatible)'), $f);
+ continue;
+ }
+
if (file_exists($file . '/library'))
continue;
if (file_exists($file . '/mobile'))
@@ -189,7 +208,7 @@ class Site {
// directory server should not be set or settable unless we are a directory client
if($dirmode == DIRECTORY_MODE_NORMAL) {
- $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s'",
+ $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s' and site_dead = 0",
intval(DIRECTORY_MODE_SECONDARY),
intval(DIRECTORY_MODE_PRIMARY),
dbesc($realm)
@@ -235,12 +254,6 @@ class Site {
// now invert the logic for the setting.
$discover_tab = (1 - $discover_tab);
- $server_roles = [
- 'basic' => t('Basic/Minimal Social Networking'),
- 'standard' => t('Standard Configuration (default)'),
- 'pro' => t('Professional')
- ];
-
$techlevels = [
'0' => t('Beginner/Basic'),
'1' => t('Novice - not skilled but willing to learn'),
@@ -267,8 +280,6 @@ class Site {
// name, label, value, help string, extra data...
'$sitename' => array('sitename', t("Site name"), htmlspecialchars(get_config('system','sitename'), ENT_QUOTES, 'UTF-8'),''),
- '$server_role' => array('server_role', t("Server Configuration/Role"), get_config('system','server_role'),'',$server_roles),
-
'$techlevel' => [ 'techlevel', t('Site default technical skill level'), get_config('system','techlevel'), t('Used to provide a member experience matched to technical comfort level'), $techlevels ],
'$techlock' => [ 'techlock', t('Lock the technical skill level setting'), get_config('system','techlevel_lock'), t('Members can set their own technical comfort level by default') ],
@@ -296,6 +307,10 @@ class Site {
'$login_on_homepage' => array('login_on_homepage', t("Login on Homepage"),((intval($homelogin) || $homelogin === false) ? 1 : '') , t("Present a login box to visitors on the home page if no other content has been configured.")),
'$enable_context_help' => array('enable_context_help', t("Enable context help"),((intval($enable_context_help) === 1 || $enable_context_help === false) ? 1 : 0) , t("Display contextual help for the current page when the help button is pressed.")),
+ '$reply_address' => [ 'reply_address', t('Reply-to email address for system generated email.'), get_config('system','reply_address','noreply@' . \App::get_hostname()),'' ],
+ '$from_email' => [ 'from_email', t('Sender (From) email address for system generated email.'), get_config('system','from_email','Administrator@' . \App::get_hostname()),'' ],
+ '$from_email_name' => [ 'from_email_name', t('Name of email sender for system generated email.'), get_config('system','from_email_name',\Zotlabs\Lib\System::get_site_name()),'' ],
+
'$directory_server' => (($dir_choices) ? array('directory_server', t("Directory Server URL"), get_config('system','directory_server'), t("Default directory server"), $dir_choices) : null),
'$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""),
@@ -304,10 +319,11 @@ class Site {
'$delivery_interval' => array('delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")),
'$delivery_batch_count' => array('delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):1), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
+ '$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$form_security_token' => get_form_security_token("admin_site"),
));
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Admin/Themes.php b/Zotlabs/Module/Admin/Themes.php
index 63a9a1670..8e72a1318 100644
--- a/Zotlabs/Module/Admin/Themes.php
+++ b/Zotlabs/Module/Admin/Themes.php
@@ -2,38 +2,41 @@
namespace Zotlabs\Module\Admin;
+use \Michelf\MarkdownExtra;
+/**
+ * @brief Admin area theme settings.
+ */
class Themes {
+ /**
+ * @brief
+ *
+ */
function post() {
$theme = argv(2);
if (is_file("view/theme/$theme/php/config.php")){
require_once("view/theme/$theme/php/config.php");
- // fixme add parent theme if derived
- if (function_exists("theme_admin_post")){
+ /// @FIXME add parent theme if derived
+ if (function_exists('theme_admin_post')){
theme_admin_post($a);
}
}
info(t('Theme settings updated.'));
- if(is_ajax())
+ if(is_ajax())
return;
-
+
goaway(z_root() . '/admin/themes/' . $theme );
}
-
-
-
/**
* @brief Themes admin page.
*
- * @return string
+ * @return string with parsed HTML
*/
-
function get(){
-
$allowed_themes_str = get_config('system', 'allowed_themes');
$allowed_themes_raw = explode(',', $allowed_themes_str);
$allowed_themes = array();
@@ -41,7 +44,7 @@ class Themes {
foreach($allowed_themes_raw as $x)
if(strlen(trim($x)))
$allowed_themes[] = trim($x);
-
+
$themes = array();
$files = glob('view/theme/*');
if($files) {
@@ -53,56 +56,55 @@ class Themes {
$themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed);
}
}
-
+
if(! count($themes)) {
notice( t('No themes found.'));
return '';
}
-
+
/*
* Single theme
*/
-
+
if (\App::$argc == 3){
$theme = \App::$argv[2];
if(! is_dir("view/theme/$theme")){
notice( t("Item not found.") );
return '';
}
-
+
if (x($_GET,"a") && $_GET['a']=="t"){
check_form_security_token_redirectOnErr('/admin/themes', 'admin_themes', 't');
-
+
// Toggle theme status
-
+
$this->toggle_theme($themes, $theme, $result);
$s = $this->rebuild_theme_table($themes);
if($result)
info( sprintf('Theme %s enabled.', $theme));
else
info( sprintf('Theme %s disabled.', $theme));
-
+
set_config('system', 'allowed_themes', $s);
goaway(z_root() . '/admin/themes' );
}
-
+
// display theme details
- require_once('library/markdown.php');
-
+
if ($this->theme_status($themes,$theme)) {
$status="on"; $action= t("Disable");
} else {
$status="off"; $action= t("Enable");
}
-
+
$readme=Null;
if (is_file("view/theme/$theme/README.md")){
$readme = file_get_contents("view/theme/$theme/README.md");
- $readme = Markdown($readme);
+ $readme = MarkdownExtra::defaultTransform($readme);
} else if (is_file("view/theme/$theme/README")){
- $readme = "<pre>". file_get_contents("view/theme/$theme/README") ."</pre>";
+ $readme = '<pre>'. file_get_contents("view/theme/$theme/README") .'</pre>';
}
-
+
$admin_form = '';
if (is_file("view/theme/$theme/php/config.php")){
require_once("view/theme/$theme/php/config.php");
@@ -110,11 +112,11 @@ class Themes {
$admin_form = theme_admin($a);
}
}
-
+
$screenshot = array( get_theme_screenshot($theme), t('Screenshot'));
if(! stristr($screenshot[0],$theme))
$screenshot = null;
-
+
$t = get_markup_template('admin_plugins_details.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -122,7 +124,7 @@ class Themes {
'$toggle' => t('Toggle'),
'$settings' => t('Settings'),
'$baseurl' => z_root(),
-
+
'$plugin' => $theme,
'$status' => $status,
'$action' => $action,
@@ -133,22 +135,22 @@ class Themes {
'$str_maintainer' => t('Maintainer: '),
'$screenshot' => $screenshot,
'$readme' => $readme,
-
+
'$form_security_token' => get_form_security_token('admin_themes'),
));
}
-
+
/*
* List themes
*/
-
+
$xthemes = array();
if($themes) {
foreach($themes as $th) {
$xthemes[] = array($th['name'],(($th['allowed']) ? "on" : "off"), get_theme_info($th['name']));
}
}
-
+
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -162,13 +164,14 @@ class Themes {
'$form_security_token' => get_form_security_token('admin_themes'),
));
}
-
/**
- * @param array $themes
- * @param string $th
- * @param int $result
+ * @brief Toggle a theme.
+ *
+ * @param array &$themes
+ * @param[in] string $th
+ * @param[out] int &$result
*/
function toggle_theme(&$themes, $th, &$result) {
for($x = 0; $x < count($themes); $x ++) {
@@ -184,7 +187,7 @@ class Themes {
}
}
}
-
+
/**
* @param array $themes
* @param string $th
@@ -203,8 +206,7 @@ class Themes {
}
return 0;
}
-
-
+
/**
* @param array $themes
* @return string
@@ -222,12 +224,5 @@ class Themes {
}
return $o;
}
-
-
-
-
-
-
-
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Appman.php b/Zotlabs/Module/Appman.php
index 270301d34..5c0667357 100644
--- a/Zotlabs/Module/Appman.php
+++ b/Zotlabs/Module/Appman.php
@@ -36,8 +36,9 @@ class Appman extends \Zotlabs\Web\Controller {
if(Zlib\Apps::app_installed(local_channel(),$arr))
info( t('App installed.') . EOL);
-
- return;
+
+ goaway(z_root() . '/apps');
+ return; //not reached
}
@@ -83,6 +84,20 @@ class Appman extends \Zotlabs\Web\Controller {
}
$channel = \App::get_channel();
+
+ if(argc() > 2) {
+ if(argv(2) === 'moveup') {
+ Zlib\Apps::moveup(local_channel(),argv(1));
+ }
+ if(argv(2) === 'movedown') {
+ Zlib\Apps::movedown(local_channel(),argv(1));
+ }
+ goaway(z_root() . '/apporder');
+ }
+
+
+
+
$app = null;
$embed = null;
if($_REQUEST['appid']) {
diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php
new file mode 100644
index 000000000..956548d1f
--- /dev/null
+++ b/Zotlabs/Module/Apporder.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Zotlabs\Module;
+
+use \Zotlabs\Lib as Zlib;
+
+class Apporder extends \Zotlabs\Web\Controller {
+
+ function post() {
+
+ }
+
+ function get() {
+
+ if(! local_channel())
+ return;
+
+ nav_set_selected('Order Apps');
+
+ $syslist = array();
+ $list = Zlib\Apps::app_list(local_channel(), false, 'nav_featured_app');
+ if($list) {
+ foreach($list as $li) {
+ $syslist[] = Zlib\Apps::app_encode($li);
+ }
+ }
+ Zlib\Apps::translate_system_apps($syslist);
+
+ usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
+
+ $syslist = Zlib\Apps::app_order(local_channel(),$syslist);
+
+ foreach($syslist as $app) {
+ $nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
+ }
+
+ return replace_macros(get_markup_template('apporder.tpl'),
+ [
+ '$header' => t('Change Order of Navigation Apps'),
+ '$desc' => t('Use arrows to move the corresponding app up or down in the display list'),
+ '$nav_apps' => $nav_apps
+ ]
+ );
+ }
+}
diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php
index 2df6d675f..2f61f2932 100644
--- a/Zotlabs/Module/Apps.php
+++ b/Zotlabs/Module/Apps.php
@@ -7,6 +7,8 @@ use \Zotlabs\Lib as Zlib;
class Apps extends \Zotlabs\Web\Controller {
function get() {
+
+ nav_set_selected('Apps');
if(argc() == 2 && argv(1) == 'edit')
$mode = 'edit';
@@ -41,9 +43,12 @@ class Apps extends \Zotlabs\Web\Controller {
return replace_macros(get_markup_template('myapps.tpl'), array(
'$sitename' => get_config('system','sitename'),
- '$cat' => ((array_key_exists('cat',$_GET) && $_GET['cat']) ? ' - ' . escape_tags($_GET['cat']) : ''),
+ '$cat' => ((array_key_exists('cat',$_GET) && $_GET['cat']) ? escape_tags($_GET['cat']) : ''),
'$title' => t('Apps'),
'$apps' => $apps,
+ '$authed' => ((local_channel()) ? true : false),
+ '$manage' => t('Manage apps'),
+ '$create' => (($mode == 'edit') ? t('Create new app') : '')
));
}
diff --git a/Zotlabs/Module/Attach.php b/Zotlabs/Module/Attach.php
index 94f46978a..490d5edd0 100644
--- a/Zotlabs/Module/Attach.php
+++ b/Zotlabs/Module/Attach.php
@@ -31,7 +31,7 @@ class Attach extends \Zotlabs\Web\Controller {
$unsafe_types = array('text/html','text/css','application/javascript');
- if(in_array($r['data']['filetype'],$unsafe_types)) {
+ if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($r['data']['uid']))) {
header('Content-type: text/plain');
}
else {
diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php
new file mode 100644
index 000000000..06f66c456
--- /dev/null
+++ b/Zotlabs/Module/Authorize.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Zotlabs\Module;
+
+
+class Authorize extends \Zotlabs\Web\Controller {
+
+
+ function get() {
+
+
+ // workaround for HTTP-auth in CGI mode
+ if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
+ $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ }
+
+ if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
+ $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ }
+
+
+
+
+ require_once('include/oauth2.php');
+
+ $request = \OAuth2\Request::createFromGlobals();
+ $response = new \OAuth2\Response();
+
+ // validate the authorize request
+ if (! $oauth2_server->validateAuthorizeRequest($request, $response)) {
+ $response->send();
+ killme();
+ }
+
+ // display an authorization form
+ if (empty($_POST)) {
+
+ return '
+<form method="post">
+ <label>Do You Authorize TestClient?</label><br />
+ <input type="submit" name="authorized" value="yes">
+ <input type="submit" name="authorized" value="no">
+</form>';
+ }
+
+ // print the authorization code if the user has authorized your client
+ $is_authorized = ($_POST['authorized'] === 'yes');
+ $oauth2_server->handleAuthorizeRequest($request, $response, $is_authorized);
+ if ($is_authorized) {
+ // this is only here so that you get to see your code in the cURL request. Otherwise,
+ // we'd redirect back to the client
+ $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40);
+ echo("SUCCESS! Authorization Code: $code");
+
+ }
+
+ $response->send();
+ killme();
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Block.php b/Zotlabs/Module/Block.php
index e671730f6..d0fed44fe 100644
--- a/Zotlabs/Module/Block.php
+++ b/Zotlabs/Module/Block.php
@@ -3,8 +3,6 @@ namespace Zotlabs\Module;
require_once('include/items.php');
require_once('include/conversation.php');
-require_once('include/page_widgets.php');
-
class Block extends \Zotlabs\Web\Controller {
diff --git a/Zotlabs/Module/Bookmarks.php b/Zotlabs/Module/Bookmarks.php
index 733bfd4e3..e147ffe6c 100644
--- a/Zotlabs/Module/Bookmarks.php
+++ b/Zotlabs/Module/Bookmarks.php
@@ -7,6 +7,9 @@ class Bookmarks extends \Zotlabs\Web\Controller {
function init() {
if(! local_channel())
return;
+
+ nav_set_selected('View Bookmarks');
+
$item_id = intval($_REQUEST['item']);
$burl = trim($_REQUEST['burl']);
@@ -68,7 +71,8 @@ class Bookmarks extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
- $o = profile_tabs($a,true,$channel['channel_address']);
+ //$o = profile_tabs($a,true,$channel['channel_address']);
+ $o = '';
$o .= '<div class="generic-content-wrapper-styled">';
diff --git a/Zotlabs/Module/Cal.php b/Zotlabs/Module/Cal.php
index b982d19a8..41676ce02 100644
--- a/Zotlabs/Module/Cal.php
+++ b/Zotlabs/Module/Cal.php
@@ -86,7 +86,8 @@ class Cal extends \Zotlabs\Web\Controller {
$o = '';
- $tabs = profile_tabs($a, True, $channel['channel_address']);
+ //$tabs = profile_tabs($a, True, $channel['channel_address']);
+ $tabs = '';
$mode = 'view';
$y = 0;
diff --git a/Zotlabs/Module/Card_edit.php b/Zotlabs/Module/Card_edit.php
new file mode 100644
index 000000000..7cc563fd2
--- /dev/null
+++ b/Zotlabs/Module/Card_edit.php
@@ -0,0 +1,138 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/acl_selectors.php');
+require_once('include/conversation.php');
+
+class Card_edit extends \Zotlabs\Web\Controller {
+
+
+ function get() {
+
+ // Figure out which post we're editing
+ $post_id = ((argc() > 1) ? intval(argv(1)) : 0);
+
+ if(! $post_id) {
+ notice( t('Item not found') . EOL);
+ return;
+ }
+
+ $itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
+ intval($post_id),
+ intval(ITEM_TYPE_CARD)
+ );
+ if($itm) {
+ $item_id = q("select * from iconfig where cat = 'system' and k = 'CARD' and iid = %d limit 1",
+ intval($itm[0]['id'])
+ );
+ if($item_id)
+ $card_title = $item_id[0]['v'];
+ }
+ else {
+ notice( t('Item not found') . EOL);
+ return;
+ }
+
+ $owner = $itm[0]['uid'];
+ $uid = local_channel();
+
+ $observer = \App::get_observer();
+
+ $channel = channelx_by_n($owner);
+ if(! $channel) {
+ notice( t('Channel not found.') . EOL);
+ return;
+ }
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'write_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $is_owner = (($uid && $uid == $owner) ? true : false);
+
+ $o = '';
+
+
+
+ $category = '';
+ $catsenabled = ((feature_enabled($owner,'categories')) ? 'categories' : '');
+
+ if ($catsenabled){
+ $itm = fetch_post_tags($itm);
+
+ $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
+
+ foreach ($cats as $cat) {
+ if (strlen($category))
+ $category .= ', ';
+ $category .= $cat['term'];
+ }
+ }
+
+ if($itm[0]['attach']) {
+ $j = json_decode($itm[0]['attach'],true);
+ if($j) {
+ foreach($j as $jj) {
+ $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
+ }
+ }
+ }
+
+
+ $mimetype = $itm[0]['mimetype'];
+
+ $content = $itm[0]['body'];
+
+
+
+ $rp = 'cards/' . $channel['channel_address'];
+
+ $x = array(
+ 'nickname' => $channel['channel_address'],
+ 'bbco_autocomplete'=> 'bbcode',
+ 'return_path' => $rp,
+ 'webpage' => ITEM_TYPE_CARD,
+ 'button' => t('Edit'),
+ 'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
+ 'weblink' => t('Insert web link'),
+ 'hide_voting' => false,
+ 'hide_future' => false,
+ 'hide_location' => false,
+ 'hide_expire' => false,
+ 'showacl' => true,
+ 'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
+ 'permissions' => $itm[0],
+ 'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
+ 'ptyp' => $itm[0]['type'],
+ 'mimeselect' => false,
+ 'mimetype' => $itm[0]['mimetype'],
+ 'body' => undo_post_tagging($content),
+ 'post_id' => $post_id,
+ 'visitor' => true,
+ 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
+ 'placeholdertitle' => t('Title (optional)'),
+ 'pagetitle' => $card_title,
+ 'profile_uid' => (intval($channel['channel_id'])),
+ 'catsenabled' => $catsenabled,
+ 'category' => $category,
+ 'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
+ );
+
+ $editor = status_editor($a, $x);
+
+ $o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
+ '$title' => t('Edit Card'),
+ '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
+ '$id' => $itm[0]['id'],
+ '$editor' => $editor
+ ));
+
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Cards.php b/Zotlabs/Module/Cards.php
new file mode 100644
index 000000000..22c5d673c
--- /dev/null
+++ b/Zotlabs/Module/Cards.php
@@ -0,0 +1,187 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
+
+
+class Cards extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ if(argc() > 1)
+ $which = argv(1);
+ else
+ return;
+
+ profile_load($which);
+
+ }
+
+ function get($update = 0, $load = false) {
+
+ if(observer_prohibited(true)) {
+ return login();
+ }
+
+ if(! \App::$profile) {
+ notice( t('Requested profile is not available.') . EOL );
+ \App::$error = 404;
+ return;
+ }
+
+ if(! feature_enabled(\App::$profile_uid,'cards')) {
+ return;
+ }
+
+ nav_set_selected(t('Cards'));
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
+
+ $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
+
+ if($category) {
+ $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
+ }
+
+
+ $which = argv(1);
+
+ $selected_card = ((argc() > 2) ? argv(2) : '');
+
+ $_SESSION['return_url'] = \App::$query_string;
+
+ $uid = local_channel();
+ $owner = \App::$profile_uid;
+ $observer = \App::get_observer();
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'view_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $is_owner = ($uid && $uid == $owner);
+
+ $channel = channelx_by_n($owner);
+
+ if($channel) {
+ $channel_acl = array(
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ );
+ }
+ else {
+ $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
+ }
+
+
+
+ if(perm_is_allowed($owner,$ob_hash,'write_pages')) {
+
+ $x = [
+ 'webpage' => ITEM_TYPE_CARD,
+ 'is_owner' => true,
+ 'content_label' => t('Add Card'),
+ 'button' => t('Create'),
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
+ || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+ 'acl' => (($is_owner) ? populate_acl($channel_acl, false,
+ \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')) : ''),
+ 'permissions' => $channel_acl,
+ 'showacl' => (($is_owner) ? true : false),
+ 'visitor' => true,
+ 'hide_location' => false,
+ 'hide_voting' => false,
+ 'profile_uid' => intval($owner),
+ 'mimetype' => 'text/bbcode',
+ 'mimeselect' => false,
+ 'layoutselect' => false,
+ 'expanded' => false,
+ 'novoting' => false,
+ 'catsenabled' => feature_enabled($owner,'categories'),
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true
+ ];
+
+ if($_REQUEST['title'])
+ $x['title'] = $_REQUEST['title'];
+ if($_REQUEST['body'])
+ $x['body'] = $_REQUEST['body'];
+ $editor = status_editor($a,$x);
+
+ }
+ else {
+ $editor = '';
+ }
+
+
+ $sql_extra = item_permissions_sql($owner);
+
+ if($selected_card) {
+ $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1",
+ dbesc($selected_card)
+ );
+ if($r) {
+ $sql_extra .= "and item.id = " . intval($r[0]['iid']) . " ";
+ }
+ }
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_CARD)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ if($r) {
+
+ $parents_str = ids_to_querystr($r,'id');
+
+ $items = q("SELECT item.*, item.id AS item_id
+ FROM item
+ WHERE item.uid = %d $item_normal
+ AND item.parent IN ( %s )
+ $sql_extra $sql_extra2 ",
+ intval(\App::$profile['profile_uid']),
+ dbesc($parents_str)
+ );
+ if($items) {
+ xchan_query($items);
+ $items = fetch_post_tags($items, true);
+ $items = conv_sort($items,'updated');
+ }
+ else
+ $items = [];
+ }
+
+ $mode = 'cards';
+
+ $content = conversation($items,$mode,false,'traditional');
+
+ $o = replace_macros(get_markup_template('cards.tpl'), [
+ '$title' => t('Cards'),
+ '$editor' => $editor,
+ '$content' => $content,
+ '$pager' => alt_pager($a,count($items))
+ ]);
+
+ return $o;
+ }
+
+}
diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php
new file mode 100644
index 000000000..77052f97c
--- /dev/null
+++ b/Zotlabs/Module/Cdav.php
@@ -0,0 +1,1259 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/event.php');
+
+require_once('include/auth.php');
+require_once('include/security.php');
+
+class Cdav extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ $record = null;
+ $channel_login = false;
+
+ if((argv(1) !== 'calendar') && (argv(1) !== 'addressbook')) {
+
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+
+ /* Basic authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') {
+ $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ break;
+ }
+
+ /* Signature authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+ if($keyId) {
+ $r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
+ dbesc($keyId)
+ );
+ if($r) {
+ $c = channelx_by_hash($r[0]['hubloc_hash']);
+ if($c) {
+ $a = q("select * from account where account_id = %d limit 1",
+ intval($c['channel_account_id'])
+ );
+ if($a) {
+ $record = [ 'channel' => $c, 'account' => $a[0] ];
+ $channel_login = $c['channel_id'];
+ }
+ }
+ }
+ if(! $record)
+ continue;
+
+ if($record) {
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
+ if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
+ $record = null;
+ }
+ if($record['account']) {
+ authenticate_success($record['account']);
+ if($channel_login) {
+ change_channel($channel_login);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This server combines both CardDAV and CalDAV functionality into a single
+ * server. It is assumed that the server runs at the root of a HTTP domain (be
+ * that a domainname-based vhost or a specific TCP port.
+ *
+ * This example also assumes that you're using SQLite and the database has
+ * already been setup (along with the database tables).
+ *
+ * You may choose to use MySQL instead, just change the PDO connection
+ * statement.
+ */
+
+ /**
+ * UTC or GMT is easy to work with, and usually recommended for any
+ * application.
+ */
+ date_default_timezone_set('UTC');
+
+ /**
+ * Make sure this setting is turned on and reflect the root url for your WebDAV
+ * server.
+ *
+ * This can be for example the root / or a complete path to your server script.
+ */
+
+ $baseUri = '/cdav/';
+
+ /**
+ * Database
+ *
+ */
+
+ $pdo = \DBA::$dba->db;
+
+ // Autoloader
+ require_once 'vendor/autoload.php';
+
+ /**
+ * The backends. Yes we do really need all of them.
+ *
+ * This allows any developer to subclass just any of them and hook into their
+ * own backend systems.
+ */
+
+ $auth = new \Zotlabs\Storage\BasicAuth();
+ $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'CalDAV/CardDAV');
+
+ if (local_channel()) {
+ logger('loggedin');
+ $channel = \App::get_channel();
+ $auth->setCurrentUser($channel['channel_address']);
+ $auth->channel_id = $channel['channel_id'];
+ $auth->channel_hash = $channel['channel_hash'];
+ $auth->channel_account_id = $channel['channel_account_id'];
+ if($channel['channel_timezone'])
+ $auth->setTimezone($channel['channel_timezone']);
+ $auth->observer = $channel['channel_hash'];
+
+ $principalUri = 'principals/' . $channel['channel_address'];
+ if(!cdav_principal($principalUri)) {
+ $this->activate($pdo, $channel);
+ if(!cdav_principal($principalUri)) {
+ return;
+ }
+ }
+
+ }
+
+
+ $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo);
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+
+ /**
+ * The directory tree
+ *
+ * Basically this is an array which contains the 'top-level' directories in the
+ * WebDAV server.
+ */
+
+ $nodes = [
+ // /principals
+ new \Sabre\CalDAV\Principal\Collection($principalBackend),
+ // /calendars
+ new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend),
+ // /addressbook
+ new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend),
+ ];
+
+ // The object tree needs in turn to be passed to the server class
+
+ $server = new \Sabre\DAV\Server($nodes);
+
+ if(isset($baseUri))
+ $server->setBaseUri($baseUri);
+
+ // Plugins
+ $server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth));
+ //$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
+ $server->addPlugin(new \Sabre\DAV\Sync\Plugin());
+ $server->addPlugin(new \Sabre\DAV\Sharing\Plugin());
+ $server->addPlugin(new \Sabre\DAVACL\Plugin());
+
+ // CalDAV plugins
+ $server->addPlugin(new \Sabre\CalDAV\Plugin());
+ $server->addPlugin(new \Sabre\CalDAV\SharingPlugin());
+ //$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
+ $server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
+
+ // CardDAV plugins
+ $server->addPlugin(new \Sabre\CardDAV\Plugin());
+ $server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin());
+
+ // And off we go!
+ $server->exec();
+
+ killme();
+
+ }
+
+ }
+
+ function post() {
+ if(! local_channel())
+ return;
+
+ $channel = \App::get_channel();
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ if(!cdav_principal($principalUri))
+ return;
+
+ $pdo = \DBA::$dba->db;
+
+ require_once 'vendor/autoload.php';
+
+ if(argc() == 2 && argv(1) === 'calendar') {
+
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+ $calendars = $caldavBackend->getCalendarsForUser($principalUri);
+
+ //create new calendar
+ if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) {
+ do {
+ $duplicate = false;
+ $calendarUri = random_string(40);
+
+ $r = q("SELECT uri FROM calendarinstances WHERE principaluri = '%s' AND uri = '%s' LIMIT 1",
+ dbesc($principalUri),
+ dbesc($calendarUri)
+ );
+
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+
+ $properties = [
+ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
+ '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'],
+ '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name']
+ ];
+
+ $id = $caldavBackend->createCalendar($principalUri, $calendarUri, $properties);
+
+ // set new calendar to be visible
+ set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1);
+ }
+
+ //create new calendar object via ajax request
+ if($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) {
+
+ $id = explode(':', $_REQUEST['target']);
+
+ if(!cdav_perms($id[0],$calendars,true))
+ return;
+
+ $title = $_REQUEST['title'];
+ $dtstart = new \DateTime($_REQUEST['dtstart']);
+ if($_REQUEST['dtend'])
+ $dtend = new \DateTime($_REQUEST['dtend']);
+ $description = $_REQUEST['description'];
+ $location = $_REQUEST['location'];
+
+ do {
+ $duplicate = false;
+ $objectUri = random_string(40) . '.ics';
+
+ $r = q("SELECT uri FROM calendarobjects WHERE calendarid = %s AND uri = '%s' LIMIT 1",
+ intval($id[0]),
+ dbesc($objectUri)
+ );
+
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+
+
+ $vcalendar = new \Sabre\VObject\Component\VCalendar([
+ 'VEVENT' => [
+ 'SUMMARY' => $title,
+ 'DTSTART' => $dtstart
+ ]
+ ]);
+ if($dtend)
+ $vcalendar->VEVENT->add('DTEND', $dtend);
+ if($description)
+ $vcalendar->VEVENT->add('DESCRIPTION', $description);
+ if($location)
+ $vcalendar->VEVENT->add('LOCATION', $location);
+
+ $calendarData = $vcalendar->serialize();
+
+ $caldavBackend->createCalendarObject($id, $objectUri, $calendarData);
+
+ killme();
+ }
+
+ //edit calendar name and color
+ if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) {
+
+ $id = explode(':', $_REQUEST['id']);
+
+ if(! cdav_perms($id[0],$calendars))
+ return;
+
+ $mutations = [
+ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
+ '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color']
+ ];
+
+ $patch = new \Sabre\DAV\PropPatch($mutations);
+
+ $caldavBackend->updateCalendar($id, $patch);
+
+ $patch->commit();
+
+ }
+
+ //edit calendar object via ajax request
+ if($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) {
+
+ $id = explode(':', $_REQUEST['target']);
+
+ if(!cdav_perms($id[0],$calendars,true))
+ return;
+
+ $uri = $_REQUEST['uri'];
+ $title = $_REQUEST['title'];
+ $dtstart = new \DateTime($_REQUEST['dtstart']);
+ $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : '';
+ $description = $_REQUEST['description'];
+ $location = $_REQUEST['location'];
+
+ $object = $caldavBackend->getCalendarObject($id, $uri);
+
+ $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']);
+
+ if($title)
+ $vcalendar->VEVENT->SUMMARY = $title;
+ if($dtstart)
+ $vcalendar->VEVENT->DTSTART = $dtstart;
+ if($dtend)
+ $vcalendar->VEVENT->DTEND = $dtend;
+ else
+ unset($vcalendar->VEVENT->DTEND);
+ if($description)
+ $vcalendar->VEVENT->DESCRIPTION = $description;
+ if($location)
+ $vcalendar->VEVENT->LOCATION = $location;
+
+ $calendarData = $vcalendar->serialize();
+
+ $caldavBackend->updateCalendarObject($id, $uri, $calendarData);
+
+ killme();
+ }
+
+ //delete calendar object via ajax request
+ if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) {
+
+ $id = explode(':', $_REQUEST['target']);
+
+ if(!cdav_perms($id[0],$calendars,true))
+ return;
+
+ $uri = $_REQUEST['uri'];
+
+ $caldavBackend->deleteCalendarObject($id, $uri);
+
+ killme();
+ }
+
+ //edit calendar object date/timeme via ajax request (drag and drop)
+ if($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) {
+
+ $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]];
+
+ if(!cdav_perms($id[0],$calendars,true))
+ return;
+
+ $uri = $_REQUEST['uri'];
+ $dtstart = new \DateTime($_REQUEST['dtstart']);
+ $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : '';
+
+ $object = $caldavBackend->getCalendarObject($id, $uri);
+
+ $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']);
+
+ if($dtstart) {
+ $vcalendar->VEVENT->DTSTART = $dtstart;
+ }
+ if($dtend) {
+ $vcalendar->VEVENT->DTEND = $dtend;
+ }
+ else {
+ unset($vcalendar->VEVENT->DTEND);
+ }
+
+ $calendarData = $vcalendar->serialize();
+
+ $caldavBackend->updateCalendarObject($id, $uri, $calendarData);
+
+ killme();
+ }
+
+ //share a calendar - this only works on local system (with channels on the same server)
+ if($_REQUEST['sharee'] && $_REQUEST['share']) {
+
+ $id = [intval($_REQUEST['calendarid']), intval($_REQUEST['instanceid'])];
+
+ if(! cdav_perms($id[0],$calendars))
+ return;
+
+ $hash = $_REQUEST['sharee'];
+
+ $sharee_arr = channelx_by_hash($hash);
+
+ $sharee = new \Sabre\DAV\Xml\Element\Sharee();
+
+ $sharee->href = 'mailto:' . $sharee_arr['xchan_addr'];
+ $sharee->principal = 'principals/' . $sharee_arr['channel_address'];
+ $sharee->access = intval($_REQUEST['access']);
+ $sharee->properties = ['{DAV:}displayname' => $channel['channel_name']];
+
+ $caldavBackend->updateInvites($id, [$sharee]);
+ }
+ }
+
+ if(argc() >= 2 && argv(1) === 'addressbook') {
+
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri);
+
+ //create new addressbook
+ if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) {
+ do {
+ $duplicate = false;
+ $addressbookUri = random_string(20);
+
+ $r = q("SELECT uri FROM addressbooks WHERE principaluri = '%s' AND uri = '%s' LIMIT 1",
+ dbesc($principalUri),
+ dbesc($addressbookUri)
+ );
+
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+
+ $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']];
+
+ $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties);
+ }
+
+ //edit addressbook
+ if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) {
+
+ $id = $_REQUEST['id'];
+
+ if(! cdav_perms($id,$addressbooks))
+ return;
+
+ $mutations = [
+ '{DAV:}displayname' => $_REQUEST['{DAV:}displayname']
+ ];
+
+ $patch = new \Sabre\DAV\PropPatch($mutations);
+
+ $carddavBackend->updateAddressBook($id, $patch);
+
+ $patch->commit();
+ }
+
+ //create addressbook card
+ if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) {
+ $id = $_REQUEST['target'];
+
+ do {
+ $duplicate = false;
+ $uri = random_string(40) . '.vcf';
+
+ $r = q("SELECT uri FROM cards WHERE addressbookid = %s AND uri = '%s' LIMIT 1",
+ intval($id),
+ dbesc($uri)
+ );
+
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+
+ //TODO: this mostly duplictes the procedure in update addressbook card. should move this part to a function to avoid duplication
+ $fn = $_REQUEST['fn'];
+
+ $vcard = new \Sabre\VObject\Component\VCard([
+ 'FN' => $fn,
+ 'N' => array_reverse(explode(' ', $fn))
+ ]);
+
+ $org = $_REQUEST['org'];
+ if($org) {
+ $vcard->ORG = $org;
+ }
+
+ $title = $_REQUEST['title'];
+ if($title) {
+ $vcard->TITLE = $title;
+ }
+
+ $tel = $_REQUEST['tel'];
+ $tel_type = $_REQUEST['tel_type'];
+ if($tel) {
+ $i = 0;
+ foreach($tel as $item) {
+ if($item) {
+ $vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $email = $_REQUEST['email'];
+ $email_type = $_REQUEST['email_type'];
+ if($email) {
+ $i = 0;
+ foreach($email as $item) {
+ if($item) {
+ $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $impp = $_REQUEST['impp'];
+ $impp_type = $_REQUEST['impp_type'];
+ if($impp) {
+ $i = 0;
+ foreach($impp as $item) {
+ if($item) {
+ $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $url = $_REQUEST['url'];
+ $url_type = $_REQUEST['url_type'];
+ if($url) {
+ $i = 0;
+ foreach($url as $item) {
+ if($item) {
+ $vcard->add('URL', $item, ['type' => $url_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $adr = $_REQUEST['adr'];
+ $adr_type = $_REQUEST['adr_type'];
+
+ if($adr) {
+ $i = 0;
+ foreach($adr as $item) {
+ if($item) {
+ $vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
+ }
+ $i++;
+ }
+ }
+
+ $note = $_REQUEST['note'];
+ if($note) {
+ $vcard->NOTE = $note;
+ }
+
+ $cardData = $vcard->serialize();
+
+ $carddavBackend->createCard($id, $uri, $cardData);
+
+ }
+
+ //edit addressbook card
+ if($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) {
+
+ $id = $_REQUEST['target'];
+
+ if(!cdav_perms($id,$addressbooks))
+ return;
+
+ $uri = $_REQUEST['uri'];
+
+ $object = $carddavBackend->getCard($id, $uri);
+ $vcard = \Sabre\VObject\Reader::read($object['carddata']);
+
+ $fn = $_REQUEST['fn'];
+ if($fn) {
+ $vcard->FN = $fn;
+ $vcard->N = array_reverse(explode(' ', $fn));
+ }
+
+ $org = $_REQUEST['org'];
+ if($org) {
+ $vcard->ORG = $org;
+ }
+ else {
+ unset($vcard->ORG);
+ }
+
+ $title = $_REQUEST['title'];
+ if($title) {
+ $vcard->TITLE = $title;
+ }
+ else {
+ unset($vcard->TITLE);
+ }
+
+ $tel = $_REQUEST['tel'];
+ $tel_type = $_REQUEST['tel_type'];
+ if($tel) {
+ $i = 0;
+ unset($vcard->TEL);
+ foreach($tel as $item) {
+ if($item) {
+ $vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
+ }
+ $i++;
+ }
+ }
+ else {
+ unset($vcard->TEL);
+ }
+
+ $email = $_REQUEST['email'];
+ $email_type = $_REQUEST['email_type'];
+ if($email) {
+ $i = 0;
+ unset($vcard->EMAIL);
+ foreach($email as $item) {
+ if($item) {
+ $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
+ }
+ $i++;
+ }
+ }
+ else {
+ unset($vcard->EMAIL);
+ }
+
+ $impp = $_REQUEST['impp'];
+ $impp_type = $_REQUEST['impp_type'];
+ if($impp) {
+ $i = 0;
+ unset($vcard->IMPP);
+ foreach($impp as $item) {
+ if($item) {
+ $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
+ }
+ $i++;
+ }
+ }
+ else {
+ unset($vcard->IMPP);
+ }
+
+ $url = $_REQUEST['url'];
+ $url_type = $_REQUEST['url_type'];
+ if($url) {
+ $i = 0;
+ unset($vcard->URL);
+ foreach($url as $item) {
+ if($item) {
+ $vcard->add('URL', $item, ['type' => $url_type[$i]]);
+ }
+ $i++;
+ }
+ }
+ else {
+ unset($vcard->URL);
+ }
+
+ $adr = $_REQUEST['adr'];
+ $adr_type = $_REQUEST['adr_type'];
+ if($adr) {
+ $i = 0;
+ unset($vcard->ADR);
+ foreach($adr as $item) {
+ if($item) {
+ $vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
+ }
+ $i++;
+ }
+ }
+ else {
+ unset($vcard->ADR);
+ }
+
+ $note = $_REQUEST['note'];
+ if($note) {
+ $vcard->NOTE = $note;
+ }
+ else {
+ unset($vcard->NOTE);
+ }
+
+ $cardData = $vcard->serialize();
+
+ $carddavBackend->updateCard($id, $uri, $cardData);
+ }
+
+ //delete addressbook card
+ if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) {
+
+ $id = $_REQUEST['target'];
+
+ if(!cdav_perms($id,$addressbooks))
+ return;
+
+ $uri = $_REQUEST['uri'];
+
+ $carddavBackend->deleteCard($id, $uri);
+ }
+ }
+
+ //Import calendar or addressbook
+ if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) {
+
+ $src = @file_get_contents($_FILES['userfile']['tmp_name']);
+
+ if($src) {
+
+ if($_REQUEST['c_upload']) {
+ $id = explode(':', $_REQUEST['target']);
+ $ext = 'ics';
+ $table = 'calendarobjects';
+ $column = 'calendarid';
+ $objects = new \Sabre\VObject\Splitter\ICalendar($src);
+ $profile = \Sabre\VObject\Node::PROFILE_CALDAV;
+ $backend = new \Sabre\CalDAV\Backend\PDO($pdo);
+ }
+
+ if($_REQUEST['a_upload']) {
+ $id[] = intval($_REQUEST['target']);
+ $ext = 'vcf';
+ $table = 'cards';
+ $column = 'addressbookid';
+ $objects = new \Sabre\VObject\Splitter\VCard($src);
+ $profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
+ $backend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ }
+
+ while ($object = $objects->getNext()) {
+
+ if($_REQUEST['a_upload']) {
+ $object = $object->convert(\Sabre\VObject\Document::VCARD40);
+ }
+
+ $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR);
+
+ //level 3 Means that the document is invalid,
+ //level 2 means a warning. A warning means it's valid but it could cause interopability issues,
+ //level 1 means that there was a problem earlier, but the problem was automatically repaired.
+
+ if($ret[0]['level'] < 3) {
+ do {
+ $duplicate = false;
+ $objectUri = random_string(40) . '.' . $ext;
+
+ $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1",
+ dbesc($id[0]),
+ dbesc($objectUri)
+ );
+
+ if (count($r))
+ $duplicate = true;
+ } while ($duplicate == true);
+
+ if($_REQUEST['c_upload']) {
+ $backend->createCalendarObject($id, $objectUri, $object->serialize());
+ }
+
+ if($_REQUEST['a_upload']) {
+ $backend->createCard($id[0], $objectUri, $object->serialize());
+ }
+ }
+ else {
+ if($_REQUEST['c_upload']) {
+ notice( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL .
+ '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL .
+ '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL .
+ '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
+ );
+ }
+
+ if($_REQUEST['a_upload']) {
+ notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL .
+ '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL .
+ '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
+ );
+ }
+ }
+ }
+ }
+ @unlink($src);
+ }
+ }
+
+ function get() {
+
+ if(!local_channel())
+ return;
+
+ $channel = \App::get_channel();
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ $pdo = \DBA::$dba->db;
+
+ require_once 'vendor/autoload.php';
+
+ head_add_css('cdav.css');
+
+ if(!cdav_principal($principalUri)) {
+ $this->activate($pdo, $channel);
+ if(!cdav_principal($principalUri)) {
+ return;
+ }
+ }
+
+ if(argv(1) === 'calendar') {
+ nav_set_selected('CalDAV');
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+ $calendars = $caldavBackend->getCalendarsForUser($principalUri);
+ }
+
+ //Display calendar(s) here
+ if(argc() == 2 && argv(1) === 'calendar') {
+
+ head_add_css('/library/fullcalendar/fullcalendar.css');
+ head_add_css('cdav_calendar.css');
+
+ head_add_js('/library/moment/moment.min.js', 1);
+ head_add_js('/library/fullcalendar/fullcalendar.min.js', 1);
+ head_add_js('/library/fullcalendar/locale-all.js', 1);
+
+ foreach($calendars as $calendar) {
+ $editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript
+ $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad');
+ $sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : '');
+ $switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]);
+ if($switch) {
+ $sources .= '{
+ url: \'/cdav/calendar/json/' . $calendar['id'][0] . '/' . $calendar['id'][1] . '\',
+ color: \'' . $color . '\'
+ }, ';
+ }
+
+ if($calendar['share-access'] != 2) {
+ $writable_calendars[] = [
+ 'displayname' => $calendar['{DAV:}displayname'],
+ 'sharer' => $sharer,
+ 'id' => $calendar['id']
+ ];
+ }
+ }
+
+ $sources = rtrim($sources, ', ');
+
+ $first_day = get_pconfig(local_channel(),'system','cal_first_day');
+ $first_day = (($first_day) ? $first_day : 0);
+
+ $title = ['title', t('Event title')];
+ $dtstart = ['dtstart', t('Start date and time'), '', t('Example: YYYY-MM-DD HH:mm')];
+ $dtend = ['dtend', t('End date and time'), '', t('Example: YYYY-MM-DD HH:mm')];
+ $description = ['description', t('Description')];
+ $location = ['location', t('Location')];
+
+ $o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [
+ '$sources' => $sources,
+ '$color' => $color,
+ '$lang' => \App::$language,
+ '$first_day' => $first_day,
+ '$prev' => t('Previous'),
+ '$next' => t('Next'),
+ '$today' => t('Today'),
+ '$month' => t('Month'),
+ '$week' => t('Week'),
+ '$day' => t('Day'),
+ '$list_month' => t('List month'),
+ '$list_week' => t('List week'),
+ '$list_day' => t('List day'),
+ '$title' => $title,
+ '$writable_calendars' => $writable_calendars,
+ '$dtstart' => $dtstart,
+ '$dtend' => $dtend,
+ '$description' => $description,
+ '$location' => $location,
+ '$more' => t('More'),
+ '$less' => t('Less'),
+ '$calendar_select_label' => t('Select calendar'),
+ '$delete' => t('Delete'),
+ '$delete_all' => t('Delete all'),
+ '$cancel' => t('Cancel'),
+ '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.')
+ ]);
+
+ return $o;
+
+ }
+
+ //Provide json data for calendar
+ if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) {
+
+ $id = [argv(3), argv(4)];
+
+ if(! cdav_perms($id[0],$calendars))
+ killme();
+
+ if (x($_GET,'start'))
+ $start = new \DateTime($_GET['start']);
+ if (x($_GET,'end'))
+ $end = new \DateTime($_GET['end']);
+
+ $filters['name'] = 'VCALENDAR';
+ $filters['prop-filters'][0]['name'] = 'VEVENT';
+ $filters['comp-filters'][0]['name'] = 'VEVENT';
+ $filters['comp-filters'][0]['time-range']['start'] = $start;
+ $filters['comp-filters'][0]['time-range']['end'] = $end;
+
+ $uris = $caldavBackend->calendarQuery($id, $filters);
+ if($uris) {
+
+ $objects = $caldavBackend->getMultipleCalendarObjects($id, $uris);
+
+ foreach($objects as $object) {
+
+ $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']);
+
+ if(isset($vcalendar->VEVENT->RRULE))
+ $vcalendar = $vcalendar->expand($start, $end);
+
+ foreach($vcalendar->VEVENT as $vevent) {
+ $title = (string)$vevent->SUMMARY;
+ $dtstart = (string)$vevent->DTSTART;
+ $dtend = (string)$vevent->DTEND;
+ $description = (string)$vevent->DESCRIPTION;
+ $location = (string)$vevent->LOCATION;
+
+ $rw = ((cdav_perms($id[0],$calendars,true)) ? true : false);
+ $recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false);
+
+ $editable = $rw ? true : false;
+
+ if($recurrent)
+ $editable = false;
+
+ $allDay = false;
+
+ // allDay event rules
+ if(!strpos($dtstart, 'T') && !strpos($dtend, 'T'))
+ $allDay = true;
+ if(strpos($dtstart, 'T000000') && strpos($dtend, 'T000000'))
+ $allDay = true;
+
+ $events[] = [
+ 'calendar_id' => $id,
+ 'uri' => $object['uri'],
+ 'title' => $title,
+ 'start' => $dtstart,
+ 'end' => $dtend,
+ 'description' => $description,
+ 'location' => $location,
+ 'allDay' => $allDay,
+ 'editable' => $editable,
+ 'recurrent' => $recurrent,
+ 'rw' => $rw
+ ];
+ }
+ }
+ json_return_and_die($events);
+ }
+ else {
+ killme();
+ }
+ }
+
+ //enable/disable calendars
+ if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && intval(argv(3)) && (argv(4) == 1 || argv(4) == 0)) {
+ $id = argv(3);
+
+ if(! cdav_perms($id,$calendars))
+ killme();
+
+ set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4));
+ killme();
+ }
+
+ //drop calendar
+ if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) {
+ $id = [argv(3), argv(4)];
+
+ if(! cdav_perms($id[0],$calendars))
+ killme();
+
+ $caldavBackend->deleteCalendar($id);
+ killme();
+ }
+
+ //drop sharee
+ if(argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) {
+
+ $id = [argv(3), argv(4)];
+ $hash = argv(5);
+
+ if(! cdav_perms($id[0],$calendars))
+ killme();
+
+ $sharee_arr = channelx_by_hash($hash);
+
+ $sharee = new \Sabre\DAV\Xml\Element\Sharee();
+
+ $sharee->href = 'mailto:' . $sharee_arr['xchan_addr'];
+ $sharee->principal = 'principals/' . $sharee_arr['channel_address'];
+ $sharee->access = 4;
+ $caldavBackend->updateInvites($id, [$sharee]);
+
+ killme();
+ }
+
+
+ if(argv(1) === 'addressbook') {
+ nav_set_selected('CardDAV');
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri);
+ }
+
+ //Display Adressbook here
+ if(argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) {
+
+ $id = argv(2);
+
+ $displayname = cdav_perms($id,$addressbooks);
+
+ if(!$displayname)
+ return;
+
+ head_add_css('cdav_addressbook.css');
+
+ $o = '';
+
+ $sabrecards = $carddavBackend->getCards($id);
+ foreach($sabrecards as $sabrecard) {
+ $uris[] = $sabrecard['uri'];
+ }
+
+ if($uris) {
+ $objects = $carddavBackend->getMultipleCards($id, $uris);
+
+ foreach($objects as $object) {
+ $vcard = \Sabre\VObject\Reader::read($object['carddata']);
+
+ $photo = '';
+ if($vcard->PHOTO) {
+ $photo_value = strtolower($vcard->PHOTO->getValueType()); // binary or uri
+ if($photo_value === 'binary') {
+ $photo_type = strtolower($vcard->PHOTO['TYPE']); // mime jpeg, png or gif
+ $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vcard->PHOTO);
+ }
+ else {
+ $url = parse_url((string)$vcard->PHOTO);
+ $photo = 'data:' . $url['path'];
+ }
+ }
+
+ $fn = '';
+ if($vcard->FN) {
+ $fn = (string)$vcard->FN;
+ }
+
+ $org = '';
+ if($vcard->ORG) {
+ $org = (string)$vcard->ORG;
+ }
+
+ $title = '';
+ if($vcard->TITLE) {
+ $title = (string)$vcard->TITLE;
+ }
+
+ $tels = [];
+ if($vcard->TEL) {
+ foreach($vcard->TEL as $tel) {
+ $type = (($tel['TYPE']) ? translate_type((string)$tel['TYPE']) : '');
+ $tels[] = [
+ 'type' => $type,
+ 'nr' => (string)$tel
+ ];
+ }
+ }
+
+ $emails = [];
+ if($vcard->EMAIL) {
+ foreach($vcard->EMAIL as $email) {
+ $type = (($email['TYPE']) ? translate_type((string)$email['TYPE']) : '');
+ $emails[] = [
+ 'type' => $type,
+ 'address' => (string)$email
+ ];
+ }
+ }
+
+ $impps = [];
+ if($vcard->IMPP) {
+ foreach($vcard->IMPP as $impp) {
+ $type = (($impp['TYPE']) ? translate_type((string)$impp['TYPE']) : '');
+ $impps[] = [
+ 'type' => $type,
+ 'address' => (string)$impp
+ ];
+ }
+ }
+
+ $urls = [];
+ if($vcard->URL) {
+ foreach($vcard->URL as $url) {
+ $type = (($url['TYPE']) ? translate_type((string)$url['TYPE']) : '');
+ $urls[] = [
+ 'type' => $type,
+ 'address' => (string)$url
+ ];
+ }
+ }
+
+ $adrs = [];
+ if($vcard->ADR) {
+ foreach($vcard->ADR as $adr) {
+ $type = (($adr['TYPE']) ? translate_type((string)$adr['TYPE']) : '');
+ $adrs[] = [
+ 'type' => $type,
+ 'address' => $adr->getParts()
+ ];
+ }
+ }
+
+ $note = '';
+ if($vcard->NOTE) {
+ $note = (string)$vcard->NOTE;
+ }
+
+ $cards[] = [
+ 'id' => $object['id'],
+ 'uri' => $object['uri'],
+
+ 'photo' => $photo,
+ 'fn' => $fn,
+ 'org' => $org,
+ 'title' => $title,
+ 'tels' => $tels,
+ 'emails' => $emails,
+ 'impps' => $impps,
+ 'urls' => $urls,
+ 'adrs' => $adrs,
+ 'note' => $note
+ ];
+ }
+
+ usort($cards, function($a, $b) { return strcasecmp($a['fn'], $b['fn']); });
+ }
+
+ $o .= replace_macros(get_markup_template('cdav_addressbook.tpl'), [
+ '$id' => $id,
+ '$cards' => $cards,
+ '$displayname' => $displayname,
+ '$name_label' => t('Name'),
+ '$org_label' => t('Organisation'),
+ '$title_label' => t('Title'),
+ '$tel_label' => t('Phone'),
+ '$email_label' => t('Email'),
+ '$impp_label' => t('Instant messenger'),
+ '$url_label' => t('Website'),
+ '$adr_label' => t('Address'),
+ '$note_label' => t('Note'),
+ '$mobile' => t('Mobile'),
+ '$home' => t('Home'),
+ '$work' => t('Work'),
+ '$other' => t('Other'),
+ '$add_card' => t('Add Contact'),
+ '$add_field' => t('Add Field'),
+ '$create' => t('Create'),
+ '$update' => t('Update'),
+ '$delete' => t('Delete'),
+ '$cancel' => t('Cancel'),
+ '$po_box' => t('P.O. Box'),
+ '$extra' => t('Additional'),
+ '$street' => t('Street'),
+ '$locality' => t('Locality'),
+ '$region' => t('Region'),
+ '$zip_code' => t('ZIP Code'),
+ '$country' => t('Country')
+ ]);
+
+ return $o;
+ }
+
+ //delete addressbook
+ if(argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) {
+ $id = argv(3);
+
+ if(! cdav_perms($id,$addressbooks))
+ return;
+
+ $carddavBackend->deleteAddressBook($id);
+ killme();
+ }
+
+ }
+
+ function activate($pdo, $channel) {
+
+ if(! $channel)
+ return;
+
+ $uri = 'principals/' . $channel['channel_address'];
+
+
+ $r = q("select * from principals where uri = '%s' limit 1",
+ dbesc($uri)
+ );
+ if($r) {
+ $r = q("update principals set email = '%s', displayname = '%s' where uri = '%s' ",
+ dbesc($channel['xchan_addr']),
+ dbesc($channel['channel_name']),
+ dbesc($uri)
+ );
+ }
+ else {
+ $r = q("insert into principals ( uri, email, displayname ) values('%s','%s','%s') ",
+ dbesc($uri),
+ dbesc($channel['xchan_addr']),
+ dbesc($channel['channel_name'])
+ );
+
+ //create default calendar
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+ $properties = [
+ '{DAV:}displayname' => t('Default Calendar'),
+ '{http://apple.com/ns/ical/}calendar-color' => '#3a87ad',
+ '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name']
+ ];
+
+ $id = $caldavBackend->createCalendar($uri, 'default', $properties);
+ set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1);
+
+ //create default addressbook
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+ $properties = ['{DAV:}displayname' => t('Default Addressbook')];
+ $carddavBackend->createAddressBook($uri, $default, $properties);
+
+ }
+ }
+
+
+}
diff --git a/Zotlabs/Module/Changeaddr.php b/Zotlabs/Module/Changeaddr.php
new file mode 100644
index 000000000..5cd236394
--- /dev/null
+++ b/Zotlabs/Module/Changeaddr.php
@@ -0,0 +1,88 @@
+<?php
+namespace Zotlabs\Module;
+
+
+class Changeaddr extends \Zotlabs\Web\Controller {
+
+ function post() {
+
+ if(! local_channel())
+ return;
+
+ if($_SESSION['delegate'])
+ return;
+
+ if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
+ return;
+
+ if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
+ return;
+
+ if($_POST['verify'] !== $_SESSION['remove_account_verify'])
+ return;
+
+
+ $account = \App::get_account();
+ $channel = \App::get_channel();
+
+ $x = account_verify_password($account['account_email'],$_POST['qxz_password']);
+ if(! ($x && $x['account']))
+ return;
+
+ if($account['account_password_changed'] > NULL_DATE) {
+ $d1 = datetime_convert('UTC','UTC','now - 48 hours');
+ if($account['account_password_changed'] > d1) {
+ notice( t('Channel name changes are not allowed within 48 hours of changing the account password.') . EOL);
+ return;
+ }
+ }
+
+ $new_address = trim($_POST['newname']);
+
+ if($new_address === $channel['channel_address'])
+ return;
+
+ if($new_address === 'sys') {
+ notice( t('Reserved nickname. Please choose another.') . EOL);
+ return;
+ }
+
+ if(check_webbie(array($new_address)) !== $new_address) {
+ notice( t('Nickname has unsupported characters or is already being used on this site.') . EOL);
+ return $ret;
+ }
+
+ channel_change_address($channel,$new_address);
+
+ goaway(z_root() . '/changeaddr');
+
+ }
+
+
+ function get() {
+
+ if(! local_channel())
+ goaway(z_root());
+
+ $channel = \App::get_channel();
+
+ $hash = random_string();
+
+ $_SESSION['remove_account_verify'] = $hash;
+
+ $tpl = get_markup_template('channel_rename.tpl');
+ $o .= replace_macros($tpl, array(
+ '$basedir' => z_root(),
+ '$hash' => $hash,
+ '$title' => t('Change channel nickname/address'),
+ '$desc' => array(t('WARNING: '), t('Any/all connections on other networks will be lost!')),
+ '$passwd' => t('Please enter your password for verification:'),
+ '$newname' => array('newname', t('New channel address'),$channel['channel_address'], ''),
+ '$submit' => t('Rename Channel')
+ ));
+
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index 45da92184..14d02d873 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -41,12 +41,20 @@ class Channel extends \Zotlabs\Web\Controller {
$profile = argv(1);
}
- \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" title="' . t('Posts and comments') . '" href="' . z_root() . '/feed/' . $which . '" />' . "\r\n" ;
- \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" title="' . t('Only posts') . '" href="' . z_root() . '/feed/' . $which . '?top=1" />' . "\r\n" ;
+ head_add_link( [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'title' => t('Posts and comments'),
+ 'href' => z_root() . '/feed/' . $which
+ ]);
+
+ head_add_link( [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'title' => t('Only posts'),
+ 'href' => z_root() . '/feed/' . $which . '?f=&top=1'
+ ]);
- // Not yet ready for prime time
- // \App::$page['htmlhead'] .= '<link rel="openid.server" href="' . z_root() . '/id/' . $which .'?f=" />' . "\r\n" ;
- // \App::$page['htmlhead'] .= '<link rel="openid.delegate" href="' . z_root() . '/channel/' . $which .'" />' . "\r\n" ;
// Run profile_load() here to make sure the theme is set before
// we start loading content
@@ -84,11 +92,6 @@ class Channel extends \Zotlabs\Web\Controller {
// Ensure we've got a profile owner if updating.
\App::$profile['profile_uid'] = \App::$profile_uid = $update;
}
- else {
- if(\App::$profile['profile_uid'] == local_channel()) {
- nav_set_selected('home');
- }
- }
$is_owner = (((local_channel()) && (\App::$profile['profile_uid'] == local_channel())) ? true : false);
@@ -111,11 +114,13 @@ class Channel extends \Zotlabs\Web\Controller {
if(! $update) {
+ nav_set_selected('Channel Home');
+
$static = channel_manual_conv_update(\App::$profile['profile_uid']);
- $o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
+ //$o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
- $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
+ // $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
if($channel && $is_owner) {
$channel_acl = array(
@@ -161,6 +166,7 @@ class Channel extends \Zotlabs\Web\Controller {
*/
$item_normal = item_normal();
+ $item_normal_update = item_normal_update();
$sql_extra = item_permissions_sql(\App::$profile['profile_uid']);
if(get_pconfig(\App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid))
@@ -172,7 +178,12 @@ class Channel extends \Zotlabs\Web\Controller {
$simple_update = (($update) ? " AND item_unseen = 1 " : '');
- \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string) . '" title="oembed" />' . "\r\n";
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
if($update && $_SESSION['loadtime'])
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
@@ -180,12 +191,12 @@ class Channel extends \Zotlabs\Web\Controller {
$simple_update = '';
if($static && $simple_update)
- $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
+ $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
if(($update) && (! $load)) {
if($mid) {
- $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
+ $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update
AND item_wall = 1 $simple_update $sql_extra limit 1",
dbesc($mid . '%'),
intval(\App::$profile['profile_uid'])
@@ -195,7 +206,7 @@ class Channel extends \Zotlabs\Web\Controller {
else {
$r = q("SELECT distinct parent AS item_id, created from item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
- WHERE uid = %d $item_normal
+ WHERE uid = %d $item_normal_update
AND item_wall = 1 $simple_update
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra
@@ -209,10 +220,10 @@ class Channel extends \Zotlabs\Web\Controller {
else {
if(x($category)) {
- $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY));
+ $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
}
if(x($hashtags)) {
- $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
+ $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
}
if($datequery) {
@@ -228,9 +239,9 @@ class Channel extends \Zotlabs\Web\Controller {
if($load || ($checkjs->disabled())) {
if($mid) {
- $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal
+ $r = q("SELECT distinct parent AS item_id from item where mid like '%s' and uid = %d $item_normal
AND item_wall = 1 $sql_extra limit 1",
- dbesc($mid),
+ dbesc($mid . '%'),
intval(\App::$profile['profile_uid'])
);
if (! $r) {
@@ -313,11 +324,12 @@ class Channel extends \Zotlabs\Web\Controller {
'$static' => $static,
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$search' => '',
+ '$xchan' => '',
'$order' => '',
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
'$file' => '',
- '$cats' => (($category) ? $category : ''),
- '$tags' => (($hashtags) ? $hashtags : ''),
+ '$cats' => (($category) ? urlencode($category) : ''),
+ '$tags' => (($hashtags) ? urlencode($hashtags) : ''),
'$mid' => $mid,
'$verb' => '',
'$dend' => $datequery,
@@ -349,17 +361,21 @@ class Channel extends \Zotlabs\Web\Controller {
}
if($is_owner && $update_unseen) {
- $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
- intval(local_channel())
- );
+ $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
+ intval(local_channel())
+ );
+ }
}
if($checkjs->disabled()) {
- $o .= conversation($a,$items,'channel',$update,'traditional');
+ $o .= conversation($items,'channel',$update,'traditional');
}
else {
- $o .= conversation($a,$items,'channel',$update,$page_mode);
+ $o .= conversation($items,'channel',$update,$page_mode);
}
if((! $update) || ($checkjs->disabled())) {
diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php
index 01ee74d5a..24ab9b022 100644
--- a/Zotlabs/Module/Chanview.php
+++ b/Zotlabs/Module/Chanview.php
@@ -102,27 +102,32 @@ class Chanview extends \Zotlabs\Web\Controller {
}
$is_zot = false;
+ $connected = false;
if (\App::$poi) {
$url = \App::$poi['xchan_url'];
if(\App::$poi['xchan_network'] === 'zot') {
$is_zot = true;
}
+ if(local_channel()) {
+ $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
+ intval(local_channel()),
+ dbesc(\App::$poi['xchan_hash'])
+ );
+ if($c)
+ $connected = true;
+ }
}
-
+
// We will load the chanview template if it's a foreign network,
// just so that we can provide a connect button along with a profile
// photo. Chances are we can't load the remote profile into an iframe
// because of cross-domain security headers. So provide a link to
// the remote profile.
-
+ // If we are already connected, just go to the profile.
// Zot channels will usually have a connect link.
- // If it isn't zot, 'pro' members won't be able to use the connect
- // button as it is a foreign network so just send them to the remote
- // profile.
-
- if($is_zot || \Zotlabs\Lib\System::get_server_role() === 'pro') {
+ if($is_zot || $connected) {
if($is_zot && $observer) {
$url = zid($url);
}
diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php
index 2c0e7a155..378c9f4dd 100644
--- a/Zotlabs/Module/Chat.php
+++ b/Zotlabs/Module/Chat.php
@@ -33,9 +33,7 @@ class Chat extends \Zotlabs\Web\Controller {
$which = $channel['channel_address'];
$profile = argv(1);
}
-
- \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which .'" />' . "\r\n" ;
-
+
// Run profile_load() here to make sure the theme is set before
// we start loading content
@@ -91,9 +89,11 @@ class Chat extends \Zotlabs\Web\Controller {
function get() {
- if(local_channel())
+ if(local_channel()) {
$channel = \App::get_channel();
-
+ nav_set_selected('My Chatrooms');
+ }
+
$ob = \App::get_observer();
$observer = get_observer_hash();
if(! $observer) {
@@ -212,7 +212,8 @@ class Chat extends \Zotlabs\Web\Controller {
require_once('include/conversation.php');
- $o = profile_tabs($a,((local_channel() && local_channel() == \App::$profile['profile_uid']) ? true : false),\App::$profile['channel_address']);
+ //$o = profile_tabs($a,((local_channel() && local_channel() == \App::$profile['profile_uid']) ? true : false),\App::$profile['channel_address']);
+ $o = '';
if(! feature_enabled(\App::$profile['profile_uid'],'ajaxchat')) {
notice( t('Feature disabled.') . EOL);
diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php
index 1fda8e32b..75191a279 100644
--- a/Zotlabs/Module/Cloud.php
+++ b/Zotlabs/Module/Cloud.php
@@ -37,8 +37,6 @@ class Cloud extends \Zotlabs\Web\Controller {
$profile = 0;
- \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which . '" />' . "\r\n";
-
if ($which)
profile_load( $which, $profile);
@@ -59,16 +57,12 @@ class Cloud extends \Zotlabs\Web\Controller {
$auth->observer = $ob_hash;
}
- if ($_GET['davguest'])
- $_SESSION['davguest'] = true;
$_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']);
$_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']);
- $_SERVER['QUERY_STRING'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['QUERY_STRING']);
$_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']);
$_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']);
- $_SERVER['REQUEST_URI'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['REQUEST_URI']);
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
@@ -92,12 +86,13 @@ class Cloud extends \Zotlabs\Web\Controller {
// require_once('\Zotlabs\Storage/QuotaPlugin.php');
// $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth));
- ob_start();
+// ob_start();
// All we need to do now, is to fire up the server
$server->exec();
- ob_end_flush();
-
+// ob_end_flush();
+ if($browser->build_page)
+ construct_page();
killme();
}
diff --git a/Zotlabs/Module/Common.php b/Zotlabs/Module/Common.php
index 2f3c57267..eebc56d2b 100644
--- a/Zotlabs/Module/Common.php
+++ b/Zotlabs/Module/Common.php
@@ -25,7 +25,7 @@ class Common extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
$o = '';
@@ -34,38 +34,37 @@ class Common extends \Zotlabs\Web\Controller {
$observer_hash = get_observer_hash();
-
if(! perm_is_allowed(\App::$profile['profile_uid'],$observer_hash,'view_contacts')) {
notice( t('Permission denied.') . EOL);
return;
}
- $o .= '<h2>' . t('Common connections') . '</h2>';
-
$t = count_common_friends(\App::$profile['profile_uid'],$observer_hash);
if(! $t) {
notice( t('No connections in common.') . EOL);
- return $o;
+ return;
}
$r = common_friends(\App::$profile['profile_uid'],$observer_hash);
if($r) {
-
- $tpl = get_markup_template('common_friends.tpl');
-
foreach($r as $rr) {
- $o .= replace_macros($tpl,array(
- '$url' => $rr['xchan_url'],
- '$name' => $rr['xchan_name'],
- '$photo' => $rr['xchan_photo_m'],
- '$tags' => ''
- ));
+ $items[] = [
+ 'url' => $rr['xchan_url'],
+ 'name' => $rr['xchan_name'],
+ 'photo' => $rr['xchan_photo_m'],
+ 'tags' => ''
+ ];
}
-
- $o .= cleardiv();
}
+
+ $tpl = get_markup_template('common_friends.tpl');
+
+ $o = replace_macros($tpl, [
+ '$title' => t('View Common Connections'),
+ '$items' => $items
+ ]);
return $o;
}
diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php
index 950be660d..f42ff9b84 100644
--- a/Zotlabs/Module/Connections.php
+++ b/Zotlabs/Module/Connections.php
@@ -5,10 +5,6 @@ namespace Zotlabs\Module;
require_once('include/socgraph.php');
require_once('include/selectors.php');
require_once('include/group.php');
-require_once('include/contact_widgets.php');
-require_once('include/zot.php');
-require_once('include/widgets.php');
-
class Connections extends \Zotlabs\Web\Controller {
@@ -23,7 +19,7 @@ class Connections extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
$sort_type = 0;
$o = '';
@@ -33,6 +29,8 @@ class Connections extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return login();
}
+
+ nav_set_selected('Connections');
$blocked = false;
$hidden = false;
@@ -67,15 +65,14 @@ class Connections extends \Zotlabs\Web\Controller {
$hidden = true;
break;
case 'archived':
- $search_flags = " and abook_archived = 1 ";
- $head = t('Archived');
+ $search_flags = " and ( abook_archived = 1 OR abook_not_here = 1) ";
+ $head = t('Archived/Unreachable');
$archived = true;
break;
case 'pending':
$search_flags = " and abook_pending = 1 ";
$head = t('New');
$pending = true;
- nav_set_selected('intros');
break;
case 'ifpending':
$r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
@@ -85,7 +82,6 @@ class Connections extends \Zotlabs\Web\Controller {
$search_flags = " and abook_pending = 1 ";
$head = t('New');
$pending = true;
- nav_set_selected('intros');
\App::$argv[1] = 'pending';
}
else {
@@ -95,7 +91,6 @@ class Connections extends \Zotlabs\Web\Controller {
\App::$argc = 1;
unset(\App::$argv[1]);
}
- nav_set_selected('intros');
break;
// case 'unconnected':
// $search_flags = " and abook_unconnected = 1 ";
@@ -172,10 +167,10 @@ class Connections extends \Zotlabs\Web\Controller {
),
'archived' => array(
- 'label' => t('Archived'),
+ 'label' => t('Archived/Unreachable'),
'url' => z_root() . '/connections/archived',
'sel' => ($archived) ? 'active' : '',
- 'title' => t('Only show archived connections'),
+ 'title' => t('Only show archived/unreachable connections'),
),
'hidden' => array(
@@ -247,7 +242,8 @@ class Connections extends \Zotlabs\Web\Controller {
((intval($rr['abook_archived'])) ? t('Archived') : ''),
((intval($rr['abook_hidden'])) ? t('Hidden') : ''),
((intval($rr['abook_ignored'])) ? t('Ignored') : ''),
- ((intval($rr['abook_blocked'])) ? t('Blocked') : '')
+ ((intval($rr['abook_blocked'])) ? t('Blocked') : ''),
+ ((intval($rr['abook_not_here'])) ? t('Not connected at this location') : '')
);
foreach($status as $str) {
@@ -261,15 +257,16 @@ class Connections extends \Zotlabs\Web\Controller {
$contacts[] = array(
'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']),
'edit_hover' => t('Edit connection'),
+ 'edit' => t('Edit'),
'delete_hover' => t('Delete connection'),
'id' => $rr['abook_id'],
'thumb' => $rr['xchan_photo_m'],
'name' => $rr['xchan_name'],
- 'classes' => (intval($rr['abook_archived']) ? 'archived' : ''),
+ 'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''),
'link' => z_root() . '/connedit/' . $rr['abook_id'],
'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop',
'delete' => t('Delete'),
- 'url' => chanlink_url($rr['xchan_url']),
+ 'url' => chanlink_hash($rr['xchan_hash']),
'webbie_label' => t('Channel address'),
'webbie' => $rr['xchan_addr'],
'network_label' => t('Network'),
diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php
index 7a753c286..23c5282e3 100644
--- a/Zotlabs/Module/Connedit.php
+++ b/Zotlabs/Module/Connedit.php
@@ -11,9 +11,6 @@ namespace Zotlabs\Module;
require_once('include/socgraph.php');
require_once('include/selectors.php');
require_once('include/group.php');
-require_once('include/contact_widgets.php');
-require_once('include/zot.php');
-require_once('include/widgets.php');
require_once('include/photos.php');
@@ -251,6 +248,10 @@ class Connedit extends \Zotlabs\Web\Controller {
notice( t('Failed to update connection record.') . EOL);
if(! intval(\App::$poi['abook_self'])) {
+ if($new_friend) {
+ \Zotlabs\Daemon\Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] );
+ }
+
\Zotlabs\Daemon\Master::Summon( [
'Notifier',
(($new_friend) ? 'permission_create' : 'permission_update'),
@@ -391,30 +392,22 @@ class Connedit extends \Zotlabs\Web\Controller {
$section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : '');
$channel = \App::get_channel();
- $my_perms = get_channel_default_perms(local_channel());
- $role = get_pconfig(local_channel(),'system','permissions_role');
- if($role) {
- $x = \Zotlabs\Access\PermissionRoles::role_perms($role);
- if($x['perms_connect'])
- $my_perms = $x['perms_connect'];
- }
$yes_no = array(t('No'),t('Yes'));
- if($my_perms) {
- $o .= "<script>function connectDefaultShare() {
- \$('.abook-edit-me').each(function() {
- if(! $(this).is(':disabled'))
- $(this).prop('checked', false);
- });\n\n";
- $perms = get_perms();
- foreach($perms as $p => $v) {
- if($my_perms & $v[1]) {
- $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n";
- }
+ $connect_perms = \Zotlabs\Access\Permissions::connect_perms(local_channel());
+
+ $o .= "<script>function connectDefaultShare() {
+ \$('.abook-edit-me').each(function() {
+ if(! $(this).is(':disabled'))
+ $(this).prop('checked', false);
+ });\n\n";
+ foreach($connect_perms['perms'] as $p => $v) {
+ if($v) {
+ $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n";
}
- $o .= " }\n</script>\n";
}
+ $o .= " }\n</script>\n";
if(argc() == 3) {
@@ -441,6 +434,34 @@ class Connedit extends \Zotlabs\Web\Controller {
goaway(z_root() . '/connedit/' . $contact_id);
}
+
+ if($cmd === 'fetchvc') {
+ $url = str_replace('/channel/','/profile/',$orig_record[0]['xchan_url']) . '/vcard';
+ $recurse = 0;
+ $x = z_fetch_url(zid($url),false,$recurse,['session' => true]);
+ if($x['success']) {
+ $h = new \Zotlabs\Web\HTTPHeaders($x['header']);
+ $fields = $h->fetch();
+ if($fields) {
+ foreach($fields as $y) {
+ if(array_key_exists('content-type',$y)) {
+ $type = explode(';',trim($y['content-type']));
+ if($type && $type[0] === 'text/vcard' && $x['body']) {
+ $vc = \Sabre\VObject\Reader::read($x['body']);
+ $vcard = $vc->serialize();
+ if($vcard) {
+ set_abconfig(local_channel(),$orig_record[0]['abook_xchan'],'system','vcard',$vcard);
+ $this->connedit_clone($a);
+ }
+ }
+ }
+ }
+ }
+ }
+ goaway(z_root() . '/connedit/' . $contact_id);
+ }
+
+
if($cmd === 'resetphoto') {
q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'",
dbesc($orig_record[0]['xchan_hash'])
@@ -582,6 +603,13 @@ class Connedit extends \Zotlabs\Web\Controller {
'sel' => '',
'title' => t('Fetch updated permissions'),
),
+
+ 'rephoto' => array(
+ 'label' => t('Refresh Photo'),
+ 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/resetphoto',
+ 'sel' => '',
+ 'title' => t('Fetch updated photo'),
+ ),
'recent' => array(
'label' => t('Recent Activity'),
@@ -631,6 +659,17 @@ class Connedit extends \Zotlabs\Web\Controller {
);
+
+ if($contact['xchan_network'] === 'zot') {
+ $tools['fetchvc'] = [
+ 'label' => t('Fetch Vcard'),
+ 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/fetchvc',
+ 'sel' => '',
+ 'title' => t('Fetch electronic calling card for this connection')
+ ];
+ }
+
+
$sections = [];
$sections['perms'] = [
@@ -806,7 +845,23 @@ class Connedit extends \Zotlabs\Web\Controller {
}
}
else
- $locstr = t('none');
+ $locstr = $contact['xchan_url'];
+
+ $clone_warn = '';
+ $clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false);
+ if(! $clonable) {
+ $clone_warn = '<strong>';
+ $clone_warn .= ((intval($contact['abook_not_here']))
+ ? t('This connection is unreachable from this location.')
+ : t('This connection may be unreachable from other channel locations.')
+ );
+ $clone_warn .= '</strong><br>' . t('Location independence is not supported by their network.');
+ }
+
+
+
+ if(intval($contact['abook_not_here']) && $unclonable)
+ $not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.');
$o .= replace_macros($tpl, [
'$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])),
@@ -815,12 +870,14 @@ class Connedit extends \Zotlabs\Web\Controller {
'$permcat_new' => t('Add permission role'),
'$permcat_enable' => feature_enabled(local_channel(),'permcats'),
'$addr' => $contact['xchan_addr'],
+ '$primeurl' => $contact['xchan_url'],
'$section' => $section,
'$sections' => $sections,
'$vcard' => $vcard,
'$addr_text' => t('This connection\'s primary address is'),
'$loc_text' => t('Available locations:'),
'$locstr' => $locstr,
+ '$unclonable' => $clone_warn,
'$notself' => (($self) ? '' : '1'),
'$self' => (($self) ? '1' : ''),
'$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'),
diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php
index 72ec1020d..47bce6c2b 100644
--- a/Zotlabs/Module/Cover_photo.php
+++ b/Zotlabs/Module/Cover_photo.php
@@ -23,19 +23,17 @@ require_once('include/channel.php');
class Cover_photo extends \Zotlabs\Web\Controller {
function init() {
-
if(! local_channel()) {
return;
}
$channel = \App::get_channel();
- profile_load($channel['channel_address']);
-
+ profile_load($channel['channel_address']);
}
- /* @brief Evaluate posted values
+ /**
+ * @brief Evaluate posted values
*
- * @param $a Current application
* @return void
*
*/
@@ -130,8 +128,15 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$aid = get_account_id();
- $p = array('aid' => $aid, 'uid' => local_channel(), 'resource_id' => $base_image['resource_id'],
- 'filename' => $base_image['filename'], 'album' => t('Cover Photos'));
+ $p = [
+ 'aid' => $aid,
+ 'uid' => local_channel(),
+ 'resource_id' => $base_image['resource_id'],
+ 'filename' => $base_image['filename'],
+ 'album' => t('Cover Photos'),
+ 'os_path' => $base_image['os_path'],
+ 'display_path' => $base_image['display_path']
+ ];
$p['imgscale'] = 7;
$p['photo_usage'] = PHOTO_COVER;
@@ -195,11 +200,10 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$os_storage = false;
foreach($i as $ii) {
- $smallest = intval($ii['imgscale']);
+ $smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
- $imagedata = $ii['content'];
- $filetype = $ii['mimetype'];
-
+ $imagedata = $ii['content'];
+ $filetype = $ii['mimetype'];
}
}
@@ -263,10 +267,10 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
- /* @brief Generate content of profile-photo view
+ /**
+ * @brief Generate content of profile-photo view
*
- * @param $a Current application
- * @return void
+ * @return string
*
*/
@@ -350,15 +354,15 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$tpl = get_markup_template('cover_photo.tpl');
$o .= replace_macros($tpl,array(
- '$user' => \App::$channel['channel_address'],
- '$lbl_upfile' => t('Upload File:'),
- '$lbl_profiles' => t('Select a profile:'),
- '$title' => t('Upload Cover Photo'),
- '$submit' => t('Upload'),
- '$profiles' => $profiles,
+ '$user' => \App::$channel['channel_address'],
+ '$lbl_upfile' => t('Upload File:'),
+ '$lbl_profiles' => t('Select a profile:'),
+ '$title' => t('Upload Cover Photo'),
+ '$submit' => t('Upload'),
+ '$profiles' => $profiles,
'$form_security_token' => get_form_security_token("cover_photo"),
- // FIXME - yuk
- '$select' => sprintf('%s %s', t('or'), ($newuser) ? '<a href="' . z_root() . '">' . t('skip this step') . '</a>' : '<a href="'. z_root() . '/photos/' . \App::$channel['channel_address'] . '">' . t('select a photo from your photo albums') . '</a>')
+ /// @FIXME - yuk
+ '$select' => sprintf('%s %s', t('or'), ($newuser) ? '<a href="' . z_root() . '">' . t('skip this step') . '</a>' : '<a href="'. z_root() . '/photos/' . \App::$channel['channel_address'] . '">' . t('select a photo from your photo albums') . '</a>')
));
call_hooks('cover_photo_content_end', $o);
@@ -370,14 +374,14 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$resolution = 3;
$tpl = get_markup_template("cropcover.tpl");
$o .= replace_macros($tpl,array(
- '$filename' => $filename,
- '$profile' => intval($_REQUEST['profile']),
- '$resource' => \App::$data['imagecrop'] . '-3',
- '$image_url' => z_root() . '/photo/' . $filename,
- '$title' => t('Crop Image'),
- '$desc' => t('Please adjust the image cropping for optimum viewing.'),
+ '$filename' => $filename,
+ '$profile' => intval($_REQUEST['profile']),
+ '$resource' => \App::$data['imagecrop'] . '-3',
+ '$image_url' => z_root() . '/photo/' . $filename,
+ '$title' => t('Crop Image'),
+ '$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("cover_photo"),
- '$done' => t('Done Editing')
+ '$done' => t('Done Editing')
));
return $o;
}
@@ -393,8 +397,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
*
*/
-
-
function cover_photo_crop_ui_head(&$a, $ph, $hash, $smallest){
$max_length = get_config('system','max_image_length');
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index 8ae2e8991..d506fe9f5 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -12,6 +12,9 @@ use \Sabre\DAV as SDAV;
use \Zotlabs\Storage;
require_once('include/attach.php');
+require_once('include/auth.php');
+require_once('include/security.php');
+
class Dav extends \Zotlabs\Web\Controller {
@@ -21,22 +24,65 @@ class Dav extends \Zotlabs\Web\Controller {
*/
function init() {
- // workaround for HTTP-auth in CGI mode
- if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
- $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
- if(strlen($userpass)) {
- list($name, $password) = explode(':', $userpass);
- $_SERVER['PHP_AUTH_USER'] = $name;
- $_SERVER['PHP_AUTH_PW'] = $password;
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+
+ /* Basic authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') {
+ $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ break;
}
- }
- if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
- $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ;
- if(strlen($userpass)) {
- list($name, $password) = explode(':', $userpass);
- $_SERVER['PHP_AUTH_USER'] = $name;
- $_SERVER['PHP_AUTH_PW'] = $password;
+ /* Signature authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+ if($keyId) {
+ $r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
+ dbesc($keyId)
+ );
+ if($r) {
+ $c = channelx_by_hash($r[0]['hubloc_hash']);
+ if($c) {
+ $a = q("select * from account where account_id = %d limit 1",
+ intval($c['channel_account_id'])
+ );
+ if($a) {
+ $record = [ 'channel' => $c, 'account' => $a[0] ];
+ $channel_login = $c['channel_id'];
+ }
+ }
+ }
+ if(! $record)
+ continue;
+
+ if($record) {
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
+ if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
+ $record = null;
+ }
+ if($record['account']) {
+ authenticate_success($record['account']);
+ if($channel_login) {
+ change_channel($channel_login);
+ }
+ }
+ break;
+ }
+ }
+ }
}
}
diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php
index 59ae88857..caf0190ae 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -4,7 +4,6 @@ namespace Zotlabs\Module;
require_once('include/socgraph.php');
require_once('include/dir_fns.php');
-require_once('include/widgets.php');
require_once('include/bbcode.php');
@@ -78,7 +77,7 @@ class Directory extends \Zotlabs\Web\Controller {
$pubforums = get_directory_setting($observer, 'pubforums');
$o = '';
- nav_set_selected('directory');
+ nav_set_selected('Directory');
if(x($_POST,'search'))
$search = notags(trim($_POST['search']));
@@ -234,7 +233,7 @@ class Directory extends \Zotlabs\Web\Controller {
$age = '';
if(strlen($rr['birthday'])) {
- if(($years = age($rr['birthday'],'UTC','')) != 0)
+ if(($years = age($rr['birthday'],'UTC','')) > 0)
$age = $years;
}
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index 638aa881a..d5afdd787 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -1,60 +1,53 @@
<?php
namespace Zotlabs\Module;
+require_once("include/bbcode.php");
+require_once('include/security.php');
+require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
+require_once('include/items.php');
class Display extends \Zotlabs\Web\Controller {
function get($update = 0, $load = false) {
-
+
$checkjs = new \Zotlabs\Web\CheckJS(1);
if($load)
$_SESSION['loadtime'] = datetime_convert();
-
if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
- require_once("include/bbcode.php");
- require_once('include/security.php');
- require_once('include/conversation.php');
- require_once('include/acl_selectors.php');
- require_once('include/items.php');
-
-
- \App::$page['htmlhead'] .= replace_macros(get_markup_template('display-head.tpl'), array());
-
if(argc() > 1 && argv(1) !== 'load')
$item_hash = argv(1);
if($_REQUEST['mid'])
$item_hash = $_REQUEST['mid'];
- if(! $item_hash) {
+ if(! $item_hash) {
\App::$error = 404;
notice( t('Item not found.') . EOL);
return;
}
$observer_is_owner = false;
-
-
+ $updateable = false;
+
if(local_channel() && (! $update)) {
$channel = \App::get_channel();
-
-
+
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid']
);
-
-
+
$x = array(
'is_owner' => true,
'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
@@ -78,7 +71,6 @@ class Display extends \Zotlabs\Web\Controller {
$o = '<div id="jot-popup">';
$o .= status_editor($a,$x);
$o .= '</div>';
-
}
// This page can be viewed by anybody so the query could be complicated
@@ -97,14 +89,18 @@ class Display extends \Zotlabs\Web\Controller {
if($decoded)
$item_hash = $decoded;
- $r = q("select id, uid, mid, parent_mid, item_type, item_deleted from item where mid like '%s' limit 1",
- dbesc($item_hash . '%'),
- dbesc($decoded . '%')
+ $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1",
+ dbesc($item_hash . '%')
);
if($r) {
$target_item = $r[0];
}
+
+ //if the item is to be moderated redirect to /moderate
+ if($target_item['item_blocked'] == ITEM_MODERATED) {
+ goaway(z_root() . '/moderate/' . $target_item['id']);
+ }
$r = null;
@@ -140,10 +136,16 @@ class Display extends \Zotlabs\Web\Controller {
$simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
if((! $update) && (! $load)) {
-
- $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0);
-
+ $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
+
+ //if the target item is not a post (eg a like) we want to address its thread parent
+ $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
+
+ //if we got a decoded hash we must encode it again before handing to javascript
+ if($decoded)
+ $mid = 'b64.' . base64url_encode($mid);
+
$o .= '<div id="live-display"></div>' . "\r\n";
$o .= "<script> var profile_uid = " . ((intval(local_channel())) ? local_channel() : (-1))
. "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n";
@@ -167,6 +169,7 @@ class Display extends \Zotlabs\Web\Controller {
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
'$search' => '',
+ '$xchan' => '',
'$order' => '',
'$file' => '',
'$cats' => '',
@@ -174,32 +177,37 @@ class Display extends \Zotlabs\Web\Controller {
'$dend' => '',
'$dbegin' => '',
'$verb' => '',
- '$mid' => $item_hash
+ '$mid' => $mid
));
-
-
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
}
-
+
$observer_hash = get_observer_hash();
$item_normal = item_normal();
-
+ $item_normal_update = item_normal_update();
+
$sql_extra = public_permissions_sql($observer_hash);
-
+
if(($update && $load) || ($checkjs->disabled())) {
-
- $updateable = false;
-
+
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']),intval(\App::$pager['start']));
-
+
if($load || ($checkjs->disabled())) {
$r = null;
-
+
require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
-
+
if(local_channel()) {
- $r = q("SELECT * from item
+ $r = q("SELECT item.id as item_id from item
WHERE uid = %d
and mid = '%s'
$item_normal
@@ -209,24 +217,22 @@ class Display extends \Zotlabs\Web\Controller {
);
if($r) {
$updateable = true;
-
}
-
}
+
if($r === null) {
-
+
// in case somebody turned off public access to sys channel content using permissions
- // make that content unsearchable by ensuring the owner_xchan can't match
-
+ // make that content unsearchable by ensuring the owner uid can't match
+
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
-
-
- $r = q("SELECT * from item
+
+ $r = q("SELECT item.id as item_id from item
WHERE mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND item.deny_gid = '' AND item_private = 0 )
- and owner_xchan in ( " . stream_perms_xchans(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
+ and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d )
$sql_extra )
$item_normal
@@ -234,7 +240,6 @@ class Display extends \Zotlabs\Web\Controller {
dbesc($target_item['parent_mid']),
intval($sysid)
);
-
}
}
}
@@ -245,12 +250,12 @@ class Display extends \Zotlabs\Web\Controller {
require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
-
+
if(local_channel()) {
- $r = q("SELECT * from item
+ $r = q("SELECT item.parent AS item_id from item
WHERE uid = %d
- and mid = '%s'
- $item_normal
+ and parent_mid = '%s'
+ $item_normal_update
$simple_update
limit 1",
intval(local_channel()),
@@ -260,20 +265,21 @@ class Display extends \Zotlabs\Web\Controller {
$updateable = true;
}
}
+
if($r === null) {
// in case somebody turned off public access to sys channel content using permissions
// make that content unsearchable by ensuring the owner_xchan can't match
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
-
- $r = q("SELECT * from item
- WHERE mid = '%s'
+
+ $r = q("SELECT item.parent AS item_id from item
+ WHERE parent_mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND item.deny_gid = '' AND item_private = 0 )
- and owner_xchan in ( " . stream_perms_xchans(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
+ and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d )
$sql_extra )
- $item_normal
+ $item_normal_update
$simple_update
limit 1",
dbesc($target_item['parent_mid']),
@@ -288,10 +294,8 @@ class Display extends \Zotlabs\Web\Controller {
}
if($r) {
-
- $parents_str = ids_to_querystr($r,'id');
+ $parents_str = ids_to_querystr($r,'item_id');
if($parents_str) {
-
$items = q("SELECT item.*, item.id AS item_id
FROM item
WHERE parent in ( %s ) $item_normal ",
@@ -302,39 +306,35 @@ class Display extends \Zotlabs\Web\Controller {
$items = fetch_post_tags($items,true);
$items = conv_sort($items,'created');
}
- } else {
+ }
+ else {
$items = array();
}
-
if ($checkjs->disabled()) {
- $o .= conversation($a, $items, 'display', $update, 'traditional');
+ $o .= conversation($items, 'display', $update, 'traditional');
if ($items[0]['title'])
\App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title'];
}
else {
- $o .= conversation($a, $items, 'display', $update, 'client');
+ $o .= conversation($items, 'display', $update, 'client');
}
if($updateable) {
$x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ",
intval(local_channel()),
- intval($r[0]['parent'])
+ intval($r[0]['item_id'])
);
}
-
+
$o .= '<div id="content-complete"></div>';
-
- return $o;
-
-
- /*
- elseif((! $update) && (! {
+
+ if((($update && $load) || $checkjs->disabled()) && (! $items)) {
- $r = q("SELECT id, item_flags FROM item WHERE id = '%s' OR mid = '%s' LIMIT 1",
- dbesc($item_hash),
+ $r = q("SELECT id, item_deleted FROM item WHERE mid = '%s' LIMIT 1",
dbesc($item_hash)
);
+
if($r) {
if(intval($r[0]['item_deleted'])) {
notice( t('Item has been removed.') . EOL );
@@ -348,8 +348,9 @@ class Display extends \Zotlabs\Web\Controller {
}
}
- */
+
+ return $o;
+
}
-
-
+
}
diff --git a/Zotlabs/Module/Editblock.php b/Zotlabs/Module/Editblock.php
index 654e2251d..8a7e87a09 100644
--- a/Zotlabs/Module/Editblock.php
+++ b/Zotlabs/Module/Editblock.php
@@ -98,6 +98,11 @@ class Editblock extends \Zotlabs\Web\Controller {
$mimetype = $itm[0]['mimetype'];
+ $content = $itm[0]['body'];
+ if($itm[0]['mimetype'] === 'text/markdown')
+ $content = \Zotlabs\Lib\MarkdownSoap::unescape($itm[0]['body']);
+
+
$rp = 'blocks/' . $channel['channel_address'];
$x = array(
@@ -117,7 +122,7 @@ class Editblock extends \Zotlabs\Web\Controller {
'ptyp' => $itm[0]['type'],
'mimeselect' => true,
'mimetype' => $itm[0]['mimetype'],
- 'body' => undo_post_tagging($itm[0]['body']),
+ 'body' => undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
diff --git a/Zotlabs/Module/Editlayout.php b/Zotlabs/Module/Editlayout.php
index ea637fcba..3d6a79507 100644
--- a/Zotlabs/Module/Editlayout.php
+++ b/Zotlabs/Module/Editlayout.php
@@ -119,6 +119,7 @@ class Editlayout extends \Zotlabs\Web\Controller {
'hide_weblink' => true,
'hide_attach' => true,
'hide_preview' => true,
+ 'disable_comments' => true,
'ptyp' => $itm[0]['obj_type'],
'body' => undo_post_tagging($itm[0]['body']),
'post_id' => $post_id,
diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php
index d7612b165..a54c42e7f 100644
--- a/Zotlabs/Module/Editpost.php
+++ b/Zotlabs/Module/Editpost.php
@@ -31,7 +31,15 @@ class Editpost extends \Zotlabs\Web\Controller {
dbesc(get_observer_hash())
);
- if(! count($itm)) {
+ // don't allow web editing of potentially binary content (item_obscured = 1)
+ // @FIXME how do we do it instead?
+
+ if((! $itm) || intval($itm[0]['item_obscured'])) {
+ notice( t('Item is not editable') . EOL);
+ return;
+ }
+
+ if($itm[0]['resource_type'] === 'photo' && $itm[0]['resource_id']) {
notice( t('Item is not editable') . EOL);
return;
}
@@ -44,14 +52,6 @@ class Editpost extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
- if(intval($itm[0]['item_obscured'])) {
- $key = get_config('system','prvkey');
- if($itm[0]['title'])
- $itm[0]['title'] = crypto_unencapsulate(json_decode($itm[0]['title'],true),$key);
- if($itm[0]['body'])
- $itm[0]['body'] = crypto_unencapsulate(json_decode($itm[0]['body'],true),$key);
- }
-
$category = '';
$catsenabled = ((feature_enabled($owner_uid,'categories')) ? 'categories' : '');
diff --git a/Zotlabs/Module/Editwebpage.php b/Zotlabs/Module/Editwebpage.php
index 3d4af107d..da536a729 100644
--- a/Zotlabs/Module/Editwebpage.php
+++ b/Zotlabs/Module/Editwebpage.php
@@ -100,24 +100,19 @@ class Editwebpage extends \Zotlabs\Web\Controller {
intval($owner)
);
- if(! $itm) {
+ // don't allow web editing of potentially binary content (item_obscured = 1)
+ // @FIXME how do we do it instead?
+
+ if((! $itm) || intval($itm[0]['item_obscured'])) {
notice( t('Permission denied.') . EOL);
return;
}
- if(intval($itm[0]['item_obscured'])) {
- $key = get_config('system','prvkey');
- if($itm[0]['title'])
- $itm[0]['title'] = crypto_unencapsulate(json_decode($itm[0]['title'],true),$key);
- if($itm[0]['body'])
- $itm[0]['body'] = crypto_unencapsulate(json_decode($itm[0]['body'],true),$key);
- }
-
$item_id = q("select * from iconfig where cat = 'system' and k = 'WEBPAGE' and iid = %d limit 1",
intval($itm[0]['id'])
);
if($item_id)
- $page_title = $item_id[0]['v'];
+ $page_title = urldecode($item_id[0]['v']);
$mimetype = $itm[0]['mimetype'];
@@ -129,9 +124,11 @@ class Editwebpage extends \Zotlabs\Web\Controller {
}
$layout = $itm[0]['layout_mid'];
-
- $tpl = get_markup_template("jot.tpl");
+ $content = $itm[0]['body'];
+ if($itm[0]['mimetype'] === 'text/markdown')
+ $content = \Zotlabs\Lib\MarkdownSoap::unescape($itm[0]['body']);
+
$rp = 'webpages/' . $which;
$x = array(
@@ -147,7 +144,7 @@ class Editwebpage extends \Zotlabs\Web\Controller {
'hide_location' => true,
'hide_voting' => true,
'ptyp' => $itm[0]['type'],
- 'body' => undo_post_tagging($itm[0]['body']),
+ 'body' => undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => ($is_owner) ? true : false,
'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php
index 48667795c..c92af27d6 100644
--- a/Zotlabs/Module/Embedphotos.php
+++ b/Zotlabs/Module/Embedphotos.php
@@ -92,6 +92,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
* It is a limitation of the photo table using a name for a photo album instead of a folder hash
*/
if($album) {
+ require_once('include/attach.php');
$x = q("select hash from attach where filename = '%s' and uid = %d limit 1",
dbesc($album),
intval($owner_uid)
diff --git a/Zotlabs/Module/Events.php b/Zotlabs/Module/Events.php
index edc6dd3f0..33c8b8249 100644
--- a/Zotlabs/Module/Events.php
+++ b/Zotlabs/Module/Events.php
@@ -272,7 +272,7 @@ class Events extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected('all_events');
+ nav_set_selected('Events');
if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
$r = q("update event set dismissed = 1 where id = %d and uid = %d",
diff --git a/Zotlabs/Module/Feed.php b/Zotlabs/Module/Feed.php
index 47871eafb..06637b6d2 100644
--- a/Zotlabs/Module/Feed.php
+++ b/Zotlabs/Module/Feed.php
@@ -1,40 +1,41 @@
<?php
+
namespace Zotlabs\Module;
require_once('include/items.php');
-
class Feed extends \Zotlabs\Web\Controller {
function init() {
- $params = array();
-
- $params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
- $params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : '');
- $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
- $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
- $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
- $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
- $params['records'] = ((x($params,'records')) ? intval($params['records']) : 40);
- $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
- $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
-
- $channel = '';
+ $params = [];
+
+ $params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
+ $params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : '');
+ $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
+ $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
+ $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
+ $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
+ $params['records'] = ((x($params,'records')) ? intval($params['records']) : 40);
+ $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
+ $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
+ $params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
+
+
if(argc() > 1) {
- $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1",
- dbesc(argv(1))
- );
- if(!($r && count($r)))
+
+ if(observer_prohibited(true)) {
killme();
-
- $channel = $r[0];
-
- if(observer_prohibited(true))
+ }
+
+ $channel = channelx_by_nick(argv(1));
+ if(! $channel) {
killme();
+ }
+
- logger('mod_feed: public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
+ logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
echo get_public_feed($channel,$params);
@@ -43,6 +44,4 @@ class Feed extends \Zotlabs\Web\Controller {
}
-
-
}
diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php
index 769134808..5c4b9a502 100644
--- a/Zotlabs/Module/File_upload.php
+++ b/Zotlabs/Module/File_upload.php
@@ -28,15 +28,32 @@ class File_upload extends \Zotlabs\Web\Controller {
$_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']);
}
+ $_REQUEST['allow_cid'] = perms2str($_REQUEST['contact_allow']);
+ $_REQUEST['allow_gid'] = perms2str($_REQUEST['group_allow']);
+ $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']);
+ $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']);
+
if($_REQUEST['filename']) {
- $_REQUEST['allow_cid'] = perms2str($_REQUEST['contact_allow']);
- $_REQUEST['allow_gid'] = perms2str($_REQUEST['group_allow']);
- $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']);
- $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']);
- $r = attach_mkdir($channel,get_observer_hash(),$_REQUEST);
+ $r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
+ if($r['success']) {
+ $hash = $r['data']['hash'];
+
+ $sync = attach_export_data($channel,$hash);
+ if($sync) {
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ }
+ goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']);
+
+ }
}
else {
- $r = attach_store($channel,get_observer_hash(), '', $_REQUEST);
+ $r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
+ if($r['success']) {
+ $sync = attach_export_data($channel,$r['data']['hash']);
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+
+ }
}
goaway(z_root() . '/' . $_REQUEST['return_url']);
diff --git a/Zotlabs/Module/Filer.php b/Zotlabs/Module/Filer.php
index 6a57cdb2a..af59f28fb 100644
--- a/Zotlabs/Module/Filer.php
+++ b/Zotlabs/Module/Filer.php
@@ -49,8 +49,10 @@ class Filer extends \Zotlabs\Web\Controller {
}
$tpl = get_markup_template("filer_dialog.tpl");
$o = replace_macros($tpl, array(
- '$field' => array('term', t("Save to Folder:"), '', '', $filetags, t('- select -')),
+ '$field' => array('term', t('Enter a folder name'), '', '', $filetags, 'placeholder="' . t('or select an existing folder (doubleclick)') . '"'),
'$submit' => t('Save'),
+ '$title' => t('Save to Folder'),
+ '$cancel' => t('Cancel')
));
echo $o;
diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php
index 874445145..55713027a 100644
--- a/Zotlabs/Module/Filestorage.php
+++ b/Zotlabs/Module/Filestorage.php
@@ -5,14 +5,6 @@ namespace Zotlabs\Module;
*
*/
-require_once('include/attach.php');
-
-
-/**
- *
- * @param object &$a
- */
-
class Filestorage extends \Zotlabs\Web\Controller {
function post() {
@@ -26,7 +18,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
$recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0);
$resource = ((x($_POST, 'filehash')) ? notags($_POST['filehash']) : '');
- $notify = ((x($_POST, 'notify')) ? intval($_POST['notify']) : 0);
+ $notify = ((x($_POST, 'notify_edit')) ? intval($_POST['notify_edit']) : 0);
if(! $resource) {
notice(t('Item not found.') . EOL);
@@ -36,19 +28,19 @@ class Filestorage extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
$acl = new \Zotlabs\Access\AccessList($channel);
- $acl->set_from_array($_REQUEST);
+ $acl->set_from_array($_POST);
$x = $acl->get();
- $cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource);
+ $url = get_cloud_url($channel_id, $channel['channel_address'], $resource);
//get the object before permissions change so we can catch eventual former allowed members
- $object = get_file_activity_object($channel_id, $resource, $cloudPath);
+ $object = get_file_activity_object($channel_id, $resource, $url);
attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
file_activity($channel_id, $object, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], 'post', $notify);
- goaway($cloudPath);
+ goaway(dirname($url));
}
function get() {
@@ -107,11 +99,11 @@ class Filestorage extends \Zotlabs\Web\Controller {
$f = $r[0];
$channel = \App::get_channel();
- $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
+ $url = get_cloud_url($channel['channel_id'], $channel['channel_address'], $f['hash']);
attach_delete($owner, $f['hash']);
- goaway($parentpath);
+ goaway(dirname($url));
}
if(argc() > 3 && argv(3) === 'edit') {
@@ -130,8 +122,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
$f = $r[0];
$channel = \App::get_channel();
- $cloudpath = get_cloudpath($f) . (intval($f['is_dir']) ? '?f=&davguest=1' : '');
- $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
+ $cloudpath = get_cloudpath($f);
$aclselect_e = populate_acl($f, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage'));
$is_a_dir = (intval($f['is_dir']) ? true : false);
@@ -146,7 +137,6 @@ class Filestorage extends \Zotlabs\Web\Controller {
'$header' => t('Edit file permissions'),
'$file' => $f,
'$cloudpath' => z_root() . '/' . $encoded_path,
- '$parentpath' => $parentpath,
'$uid' => $channel['channel_id'],
'$channelnick' => $channel['channel_address'],
'$permissions' => t('Permissions'),
@@ -165,7 +155,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'),
'$attach_btn_title' => t('Share this file'),
'$link_btn_title' => t('Show URL to this file'),
- '$notify' => array('notify', t('Notify your contacts about this file'), 0, '', array(t('No'), t('Yes'))),
+ '$notify' => array('notify_edit', t('Show in your contacts shared folder'), 0, '', array(t('No'), t('Yes'))),
));
echo $o;
diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php
index 3d859d94b..413a68e0c 100644
--- a/Zotlabs/Module/Getfile.php
+++ b/Zotlabs/Module/Getfile.php
@@ -35,6 +35,7 @@ class Getfile extends \Zotlabs\Web\Controller {
$sig = $_POST['signature'];
$resource = $_POST['resource'];
$revision = intval($_POST['revision']);
+ $resolution = (-1);
if(! $hash)
killme();
@@ -46,6 +47,11 @@ class Getfile extends \Zotlabs\Web\Controller {
killme();
}
+ if(substr($resource,-2,1) == '-') {
+ $resolution = intval(substr($resource,-1,1));
+ $resource = substr($resource,0,-2);
+ }
+
$slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop'));
if($slop < 1)
$slop = 3;
@@ -63,6 +69,35 @@ class Getfile extends \Zotlabs\Web\Controller {
killme();
}
+
+ if($resolution > 0) {
+ $r = q("select * from photo where resource_id = '%s' and uid = %d limit 1",
+ dbesc($resource),
+ intval($channel['channel_id'])
+ );
+ if($r) {
+ header('Content-type: ' . $r[0]['mimetype']);
+
+ if(intval($r[0]['os_storage'])) {
+ $fname = dbunescbin($r[0]['content']);
+ if(strpos($fname,'store') !== false)
+ $istream = fopen($fname,'rb');
+ else
+ $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname,'rb');
+ $ostream = fopen('php://output','wb');
+ if($istream && $ostream) {
+ pipe_streams($istream,$ostream);
+ fclose($istream);
+ fclose($ostream);
+ }
+ }
+ else {
+ echo dbunescbin($r[0]['content']);
+ }
+ }
+ killme();
+ }
+
$r = attach_by_hash($resource,$channel['channel_hash'],$revision);
if(! $r['success']) {
@@ -73,7 +108,7 @@ class Getfile extends \Zotlabs\Web\Controller {
$unsafe_types = array('text/html','text/css','application/javascript');
- if(in_array($r['data']['filetype'],$unsafe_types)) {
+ if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($channel['channel_id']))) {
header('Content-type: text/plain');
}
else {
diff --git a/Zotlabs/Module/Group.php b/Zotlabs/Module/Group.php
index 646310356..93a089d02 100644
--- a/Zotlabs/Module/Group.php
+++ b/Zotlabs/Module/Group.php
@@ -56,6 +56,7 @@ class Group extends \Zotlabs\Web\Controller {
);
if($r)
info( t('Privacy group updated.') . EOL );
+ build_sync_packet(local_channel(),null,true);
}
goaway(z_root() . '/group/' . argv(1) . '/' . argv(2));
@@ -63,7 +64,8 @@ class Group extends \Zotlabs\Web\Controller {
return;
}
- function get() {
+ function get() {
+
$change = false;
logger('mod_group: ' . \App::$cmd,LOGGER_DEBUG);
diff --git a/Zotlabs/Module/Hcard.php b/Zotlabs/Module/Hcard.php
index 93c8d3ece..912c84fd2 100644
--- a/Zotlabs/Module/Hcard.php
+++ b/Zotlabs/Module/Hcard.php
@@ -14,6 +14,8 @@ class Hcard extends \Zotlabs\Web\Controller {
return;
}
+ logger('hcard_request: ' . $which, LOGGER_DEBUG);
+
$profile = '';
$channel = \App::get_channel();
@@ -29,7 +31,20 @@ class Hcard extends \Zotlabs\Web\Controller {
$profile = $r[0]['profile_guid'];
}
- \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which .'" />' . "\r\n" ;
+ head_add_link( [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'title' => t('Posts and comments'),
+ 'href' => z_root() . '/feed/' . $which
+ ]);
+
+ head_add_link( [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'title' => t('Only posts'),
+ 'href' => z_root() . '/feed/' . $which . '?f=&top=1'
+ ]);
+
if(! $profile) {
$x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1",
@@ -46,12 +61,10 @@ class Hcard extends \Zotlabs\Web\Controller {
}
- function get() {
-
- require_once('include/widgets.php');
- return widget_profile(array());
-
-
+ function get() {
+
+ $x = new \Zotlabs\Widget\Profile();
+ return $x->widget(array());
}
diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php
index e247416d9..f1b1acaef 100644
--- a/Zotlabs/Module/Help.php
+++ b/Zotlabs/Module/Help.php
@@ -15,7 +15,7 @@ require_once('include/help.php');
class Help extends \Zotlabs\Web\Controller {
function get() {
- nav_set_selected('help');
+ nav_set_selected('Help');
if($_REQUEST['search']) {
$o .= '<div id="help-content" class="generic-content-wrapper">';
@@ -44,42 +44,42 @@ class Help extends \Zotlabs\Web\Controller {
return $o;
}
-
-
- if(argc() > 2 && argv(argc()-2) === 'assets') {
- $path = '';
- for($x = 1; $x < argc(); $x ++) {
- if(strlen($path))
- $path .= '/';
- $path .= argv($x);
- }
- $realpath = 'doc/' . $path;
- //Set the content-type header as appropriate
- $imageInfo = getimagesize($realpath);
- switch ($imageInfo[2]) {
- case IMAGETYPE_JPEG:
- header("Content-Type: image/jpeg");
- break;
- case IMAGETYPE_GIF:
- header("Content-Type: image/gif");
- break;
- case IMAGETYPE_PNG:
- header("Content-Type: image/png");
- break;
- default:
- break;
- }
- header("Content-Length: " . filesize($realpath));
+
+
+ if(argc() > 2 && argv(argc()-2) === 'assets') {
+ $path = '';
+ for($x = 1; $x < argc(); $x ++) {
+ if(strlen($path))
+ $path .= '/';
+ $path .= argv($x);
+ }
+ $realpath = 'doc/' . $path;
+ //Set the content-type header as appropriate
+ $imageInfo = getimagesize($realpath);
+ switch ($imageInfo[2]) {
+ case IMAGETYPE_JPEG:
+ header("Content-Type: image/jpeg");
+ break;
+ case IMAGETYPE_GIF:
+ header("Content-Type: image/gif");
+ break;
+ case IMAGETYPE_PNG:
+ header("Content-Type: image/png");
+ break;
+ default:
+ break;
+ }
+ header("Content-Length: " . filesize($realpath));
- // dump the picture and stop the script
- readfile($realpath);
- killme();
- }
+ // dump the picture and stop the script
+ readfile($realpath);
+ killme();
+ }
$headings = [
- 'about' => t('About'),
- 'member' => t('Members'),
- 'admin' => t('Administrators'),
+ 'about' => t('About'),
+ 'member' => t('Members'),
+ 'admin' => t('Administrators'),
'developer' => t('Developers'),
'tutorials' => t('Tutorials')
];
@@ -87,13 +87,16 @@ class Help extends \Zotlabs\Web\Controller {
if(array_key_exists(argv(1), $headings))
$heading = $headings[argv(1)];
- $content = get_help_content();
+ $content = get_help_content();
+
+ $language = determine_help_language()['language'];
return replace_macros(get_markup_template('help.tpl'), array(
- '$title' => t('$Projectname Documentation'),
+ '$title' => t('$Projectname Documentation'),
'$tocHeading' => t('Contents'),
- '$content' => $content,
- '$heading' => $heading
+ '$content' => $content,
+ '$heading' => $heading,
+ '$language' => $language
));
}
diff --git a/Zotlabs/Module/Impel.php b/Zotlabs/Module/Impel.php
index 197d9f859..77f488d26 100644
--- a/Zotlabs/Module/Impel.php
+++ b/Zotlabs/Module/Impel.php
@@ -144,18 +144,8 @@ class Impel extends \Zotlabs\Web\Controller {
// Verify ability to use html or php!!!
- $execflag = false;
-
- if($arr['mimetype'] === 'application/x-php') {
- $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1",
- intval(local_channel())
- );
-
- if($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) {
- $execflag = true;
- }
- }
-
+ $execflag = ((intval($channel['channel_id']) == intval(local_channel()) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
+
$i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['mid']),
intval(local_channel())
diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php
index 3969f25e0..2b16ff4e1 100644
--- a/Zotlabs/Module/Import.php
+++ b/Zotlabs/Module/Import.php
@@ -2,26 +2,32 @@
namespace Zotlabs\Module;
-// Import a channel, either by direct file upload or via
-// connection to original server.
-
-
require_once('include/zot.php');
require_once('include/channel.php');
require_once('include/import.php');
require_once('include/perm_upgrade.php');
-
+/**
+ * @brief Module for channel import.
+ *
+ * Import a channel, either by direct file upload or via
+ * connection to another server.
+ */
class Import extends \Zotlabs\Web\Controller {
+ /**
+ * @brief Import channel into account.
+ *
+ * @param int $account_id
+ */
function import_account($account_id) {
-
+
if(! $account_id){
- logger("import_account: No account ID supplied");
+ logger('No account ID supplied');
return;
}
-
+
$max_friends = account_service_class_fetch($account_id,'total_channels');
$max_feeds = account_service_class_fetch($account_id,'total_feeds');
$data = null;
@@ -32,35 +38,39 @@ class Import extends \Zotlabs\Web\Controller {
$filename = basename($_FILES['filename']['name']);
$filesize = intval($_FILES['filename']['size']);
$filetype = $_FILES['filename']['type'];
-
+ // import channel from file
if($src) {
-
- // This is OS specific and could also fail if your tmpdir isn't very large
- // mostly used for Diaspora which exports gzipped files.
-
+
+ // This is OS specific and could also fail if your tmpdir isn't very
+ // large mostly used for Diaspora which exports gzipped files.
+
if(strpos($filename,'.gz')){
@rename($src,$src . '.gz');
@system('gunzip ' . escapeshellarg($src . '.gz'));
}
-
+
if($filesize) {
$data = @file_get_contents($src);
}
unlink($src);
}
-
+
+ // import channel from another server
if(! $src) {
$old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : '');
if(! $old_address) {
- logger('mod_import: nothing to import.');
+ logger('Nothing to import.');
notice( t('Nothing to import.') . EOL);
return;
+ } else if(strpos($old_address, 'ï¼ ')) {
+ // if you copy the identity address from your profile page, make it work for convenience
+ $old_address = str_replace('ï¼ ', '@', $old_address);
}
-
+
$email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : '');
$password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : '');
-
+
$channelname = substr($old_address,0,strpos($old_address,'@'));
$servername = substr($old_address,strpos($old_address,'@')+1);
@@ -73,6 +83,7 @@ class Import extends \Zotlabs\Web\Controller {
$api_path .= 'channel/export/basic?f=&channel=' . $channelname;
if($import_posts)
$api_path .= '&posts=1';
+
$binary = false;
$redirects = 0;
$opts = array('http_auth' => $email . ':' . $password);
@@ -85,19 +96,18 @@ class Import extends \Zotlabs\Web\Controller {
return;
}
}
-
+
if(! $data) {
- logger('mod_import: empty file.');
+ logger('Empty import file.');
notice( t('Imported file is empty.') . EOL);
return;
}
-
+
$data = json_decode($data,true);
-
- // logger('import: data: ' . print_r($data,true));
- // print_r($data);
-
-
+
+ //logger('import: data: ' . print_r($data,true));
+ //print_r($data);
+
if(! array_key_exists('compatibility',$data)) {
call_hooks('import_foreign_channel_data',$data);
if($data['handled'])
@@ -108,24 +118,23 @@ class Import extends \Zotlabs\Web\Controller {
$v1 = substr($data['compatibility']['database'],-4);
$v2 = substr(DB_UPDATE_VERSION,-4);
if($v2 > $v1) {
- $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 );
+ $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 );
notice($t);
}
- if(array_key_exists('server_role',$data['compatibility']) && $data['compatibility']['server_role'] == 'basic')
- $moving = true;
+
}
-
+
if($moving)
$seize = 1;
-
+
// import channel
-
+
$relocate = ((array_key_exists('relocate',$data)) ? $data['relocate'] : null);
if(array_key_exists('channel',$data)) {
-
+
$max_identities = account_service_class_fetch($account_id,'total_identities');
-
+
if($max_identities !== false) {
$r = q("select channel_id from channel where channel_account_id = %d",
intval($account_id)
@@ -137,46 +146,40 @@ class Import extends \Zotlabs\Web\Controller {
}
$channel = import_channel($data['channel'], $account_id, $seize);
-
}
else {
$moving = false;
$channel = \App::get_channel();
}
-
+
if(! $channel) {
- logger('mod_import: channel not found. ', print_r($channel,true));
+ logger('Channel not found. ', print_r($channel,true));
notice( t('No channel. Import failed.') . EOL);
return;
}
-
-
if(is_array($data['config'])) {
import_config($channel,$data['config']);
}
-
+
logger('import step 2');
-
-
-
if(array_key_exists('channel',$data)) {
if($data['photo']) {
require_once('include/photo/photo_driver.php');
import_channel_photo(base64url_decode($data['photo']['data']),$data['photo']['type'],$account_id,$channel['channel_id']);
}
-
+
if(is_array($data['profile']))
import_profiles($channel,$data['profile']);
}
-
+
logger('import step 3');
-
+
if(is_array($data['hubloc'])) {
import_hublocs($channel,$data['hubloc'],$seize,$moving);
}
-
+
logger('import step 4');
// create new hubloc for the new channel at this site
@@ -200,7 +203,7 @@ class Import extends \Zotlabs\Web\Controller {
);
// reset the original primary hubloc if it is being seized
-
+
if($seize) {
$r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ",
dbesc($channel['channel_hash']),
@@ -210,20 +213,18 @@ class Import extends \Zotlabs\Web\Controller {
}
logger('import step 5');
-
-
-
+
+
// import xchans and contact photos
-
+
if(array_key_exists('channel',$data) && $seize) {
-
+
// replace any existing xchan we may have on this site if we're seizing control
-
+
$r = q("delete from xchan where xchan_hash = '%s'",
dbesc($channel['channel_hash'])
);
-
$r = xchan_store_lowlevel(
[
'xchan_hash' => $channel['channel_hash'],
@@ -242,23 +243,22 @@ class Import extends \Zotlabs\Web\Controller {
'xchan_photo_date' => datetime_convert(),
'xchan_name_date' => datetime_convert()
]
- );
+ );
}
-
+
logger('import step 6');
-
-
+ // import xchans
$xchans = $data['xchan'];
if($xchans) {
foreach($xchans as $xchan) {
-
+
$hash = make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_guid_sig']);
if($xchan['xchan_network'] === 'zot' && $hash !== $xchan['xchan_hash']) {
logger('forged xchan: ' . print_r($xchan,true));
continue;
}
-
+
if(! array_key_exists('xchan_hidden',$xchan)) {
$xchan['xchan_hidden'] = (($xchan['xchan_flags'] & 0x0001) ? 1 : 0);
$xchan['xchan_orphan'] = (($xchan['xchan_flags'] & 0x0002) ? 1 : 0);
@@ -268,57 +268,67 @@ class Import extends \Zotlabs\Web\Controller {
$xchan['xchan_pubforum'] = (($xchan['xchan_flags'] & 0x0020) ? 1 : 0);
$xchan['xchan_deleted'] = (($xchan['xchan_flags'] & 0x1000) ? 1 : 0);
}
-
+
$r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1",
dbesc($xchan['xchan_hash'])
);
if($r)
continue;
- create_table_from_array('xchan',$xchan);
-
+ create_table_from_array('xchan',$xchan);
+
require_once('include/photo/photo_driver.php');
- $photos = import_xchan_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']);
- if($photos[4])
- $photodate = NULL_DATE;
- else
- $photodate = $xchan['xchan_photo_date'];
-
- $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'",
- dbesc($photos[0]),
- dbesc($photos[1]),
- dbesc($photos[2]),
- dbesc($photos[3]),
- dbesc($photodate),
- dbesc($xchan['xchan_hash'])
- );
-
+
+ if($xchan['xchan_hash'] === $channel['channel_hash']) {
+ $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'",
+ dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']),
+ dbesc($xchan['xchan_hash'])
+ );
+ }
+ else {
+ $photos = import_xchan_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']);
+ if($photos[4])
+ $photodate = NULL_DATE;
+ else
+ $photodate = $xchan['xchan_photo_date'];
+
+ $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'",
+ dbesc($photos[0]),
+ dbesc($photos[1]),
+ dbesc($photos[2]),
+ dbesc($photos[3]),
+ dbesc($photodate),
+ dbesc($xchan['xchan_hash'])
+ );
+ }
}
- logger('import step 7');
+ logger('import step 7');
}
-
$friends = 0;
$feeds = 0;
-
+
// import contacts
$abooks = $data['abook'];
if($abooks) {
foreach($abooks as $abook) {
$abook_copy = $abook;
-
+
$abconfig = null;
if(array_key_exists('abconfig',$abook) && is_array($abook['abconfig']) && count($abook['abconfig']))
$abconfig = $abook['abconfig'];
-
+
unset($abook['abook_id']);
unset($abook['abook_rating']);
unset($abook['abook_rating_text']);
unset($abook['abconfig']);
unset($abook['abook_their_perms']);
unset($abook['abook_my_perms']);
+ unset($abook['abook_not_here']);
$abook['abook_account'] = $account_id;
$abook['abook_channel'] = $channel['channel_id'];
@@ -332,7 +342,11 @@ class Import extends \Zotlabs\Web\Controller {
$abook['abook_self'] = (($abook['abook_flags'] & 0x0080 ) ? 1 : 0);
$abook['abook_feed'] = (($abook['abook_flags'] & 0x0100 ) ? 1 : 0);
}
-
+
+ if(array_key_exists('abook_instance',$abook) && $abook['abook_instance'] && strpos($abook['abook_instance'],z_root()) === false) {
+ $abook['abook_not_here'] = 1;
+ }
+
if($abook['abook_self']) {
$role = get_pconfig($channel['channel_id'],'system','permissions_role');
if(($role === 'forum') || ($abook['abook_my_perms'] & PERMS_W_TAGWALL)) {
@@ -340,24 +354,24 @@ class Import extends \Zotlabs\Web\Controller {
dbesc($abook['abook_xchan'])
);
}
- }
+ }
else {
if($max_friends !== false && $friends > $max_friends)
continue;
if($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds))
continue;
}
-
- create_table_from_array('abook',$abook);
+
+ abook_store_lowlevel($abook);
$friends ++;
if(intval($abook['abook_feed']))
$feeds ++;
translate_abook_perms_inbound($channel,$abook_copy);
-
+
if($abconfig) {
- // @fixme does not handle sync of del_abconfig
+ /// @FIXME does not handle sync of del_abconfig
foreach($abconfig as $abc) {
set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
}
@@ -366,20 +380,21 @@ class Import extends \Zotlabs\Web\Controller {
logger('import step 8');
}
-
+
+ // import groups
$groups = $data['group'];
if($groups) {
$saved = array();
foreach($groups as $group) {
$saved[$group['hash']] = array('old' => $group['id']);
- if(array_key_exists('name',$group)) {
+ if(array_key_exists('name', $group)) {
$group['gname'] = $group['name'];
unset($group['name']);
}
unset($group['id']);
$group['uid'] = $channel['channel_id'];
- create_table_from_array('groups',$group);
+ create_table_from_array('groups', $group);
}
$r = q("select * from groups where uid = %d",
intval($channel['channel_id'])
@@ -388,10 +403,10 @@ class Import extends \Zotlabs\Web\Controller {
foreach($r as $rr) {
$saved[$rr['hash']]['new'] = $rr['id'];
}
- }
+ }
}
-
-
+
+ // import group members
$group_members = $data['group_member'];
if($group_members) {
foreach($group_members as $group_member) {
@@ -401,36 +416,36 @@ class Import extends \Zotlabs\Web\Controller {
if($x['old'] == $group_member['gid'])
$group_member['gid'] = $x['new'];
}
- create_table_from_array('group_member',$group_member);
+ create_table_from_array('group_member', $group_member);
}
}
logger('import step 9');
-
+
if(is_array($data['obj']))
import_objs($channel,$data['obj']);
-
+
if(is_array($data['likes']))
import_likes($channel,$data['likes']);
-
+
if(is_array($data['app']))
import_apps($channel,$data['app']);
-
+
if(is_array($data['chatroom']))
import_chatrooms($channel,$data['chatroom']);
-
+
if(is_array($data['conv']))
import_conv($channel,$data['conv']);
-
+
if(is_array($data['mail']))
import_mail($channel,$data['mail']);
-
+
if(is_array($data['event']))
import_events($channel,$data['event']);
-
+
if(is_array($data['event_item']))
import_items($channel,$data['event_item'],false,$relocate);
-
+
if(is_array($data['menu']))
import_menus($channel,$data['menu']);
@@ -439,56 +454,62 @@ class Import extends \Zotlabs\Web\Controller {
if(is_array($data['webpages']))
import_items($channel,$data['webpages'],false,$relocate);
-
+
$addon = array('channel' => $channel,'data' => $data);
call_hooks('import_channel',$addon);
-
+
$saved_notification_flags = notifications_off($channel['channel_id']);
-
+
if($import_posts && array_key_exists('item',$data) && $data['item'])
import_items($channel,$data['item'],false,$relocate);
-
+
notifications_on($channel['channel_id'],$saved_notification_flags);
-
-
+
if(array_key_exists('item_id',$data) && $data['item_id'])
import_item_ids($channel,$data['item_id']);
-
+
// send out refresh requests
// notify old server that it may no longer be primary.
-
+
\Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
-
+
// This will indirectly perform a refresh_all *and* update the directory
-
+
\Zotlabs\Daemon\Master::Summon(array('Directory', $channel['channel_id']));
-
-
+
+
notice( t('Import completed.') . EOL);
-
+
change_channel($channel['channel_id']);
-
+
goaway(z_root() . '/network' );
-
}
-
-
+
+ /**
+ * @brief Handle POST action on channel import page.
+ */
function post() {
-
$account_id = get_account_id();
if(! $account_id)
return;
-
+
+ check_form_security_token_redirectOnErr('/import', 'channel_import');
+
$this->import_account($account_id);
}
-
+
+ /**
+ * @brief Generate channel import page.
+ *
+ * @return string with parsed HTML.
+ */
function get() {
-
+
if(! get_account_id()) {
- notice( t('You must be logged in to use this feature.'));
+ notice( t('You must be logged in to use this feature.') . EOL);
return '';
}
-
+
$o = replace_macros(get_markup_template('channel_import.tpl'),array(
'$title' => t('Import Channel'),
'$desc' => t('Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file.'),
@@ -501,14 +522,14 @@ class Import extends \Zotlabs\Web\Controller {
'$label_import_primary' => t('Make this hub my primary location'),
'$label_import_moving' => t('Move this channel (disable all previous locations)'),
'$label_import_posts' => t('Import a few months of posts if possible (limited by available memory'),
- '$pleasewait' => t('This process may take several minutes to complete. Please submit the form only once and leave this page open until finished.'),
+ '$pleasewait' => t('This process may take several minutes to complete. Please submit the form only once and leave this page open until finished.'),
'$email' => '',
'$pass' => '',
+ '$form_security_token' => get_form_security_token('channel_import'),
'$submit' => t('Submit')
));
-
+
return $o;
-
}
-
+
}
diff --git a/Zotlabs/Module/Import_items.php b/Zotlabs/Module/Import_items.php
index f20cbfe7e..c2b2506fe 100644
--- a/Zotlabs/Module/Import_items.php
+++ b/Zotlabs/Module/Import_items.php
@@ -3,54 +3,60 @@ namespace Zotlabs\Module;
require_once('include/import.php');
-
+/**
+ * @brief Module for importing items.
+ *
+ * Import existing posts and content from an export file.
+ */
class Import_items extends \Zotlabs\Web\Controller {
function post() {
-
+
if(! local_channel())
return;
-
+
+ check_form_security_token_redirectOnErr('/import_items', 'import_items');
+
$data = null;
-
+
$src = $_FILES['filename']['tmp_name'];
$filename = basename($_FILES['filename']['name']);
$filesize = intval($_FILES['filename']['size']);
$filetype = $_FILES['filename']['type'];
-
+
if($src) {
// This is OS specific and could also fail if your tmpdir isn't very large
// mostly used for Diaspora which exports gzipped files.
-
+
if(strpos($filename,'.gz')){
@rename($src,$src . '.gz');
@system('gunzip ' . escapeshellarg($src . '.gz'));
}
-
+
if($filesize) {
$data = @file_get_contents($src);
}
unlink($src);
}
-
+
if(! $src) {
-
+
$old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : '');
-
+
if(! $old_address) {
- logger('mod_import: nothing to import.');
+ logger('Nothing to import.');
notice( t('Nothing to import.') . EOL);
return;
}
-
+
$email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : '');
$password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : '');
-
+
$year = ((x($_REQUEST,'year')) ? $_REQUEST['year'] : '');
-
+
$channelname = substr($old_address,0,strpos($old_address,'@'));
$servername = substr($old_address,strpos($old_address,'@')+1);
-
+
$scheme = 'https://';
$api_path = '/api/red/channel/export/items?f=&channel=' . $channelname . '&year=' . intval($year);
$binary = false;
@@ -64,68 +70,66 @@ class Import_items extends \Zotlabs\Web\Controller {
$data = $ret['body'];
else
notice( t('Unable to download data from old server') . EOL);
-
}
-
+
if(! $data) {
- logger('mod_import: empty file.');
+ logger('Empty file.');
notice( t('Imported file is empty.') . EOL);
return;
}
-
- $data = json_decode($data,true);
-
- // logger('import: data: ' . print_r($data,true));
- // print_r($data);
-
+
+ $data = json_decode($data, true);
+
+ //logger('import: data: ' . print_r($data,true));
+ //print_r($data);
+
if(! is_array($data))
return;
-
+
if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) {
$v1 = substr($data['compatibility']['database'],-4);
$v2 = substr(DB_UPDATE_VERSION,-4);
if($v2 > $v1) {
- $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 );
- notice($t);
+ $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 );
+ notice($t . EOL);
}
}
-
+
$channel = \App::get_channel();
-
-
+
if(array_key_exists('item',$data) && $data['item']) {
import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null));
}
-
+
if(array_key_exists('item_id',$data) && $data['item_id']) {
import_item_ids($channel,$data['item_id']);
}
-
+
info( t('Import completed') . EOL);
- return;
}
-
-
-
-
+
+
+ /**
+ * @brief Generate item import page.
+ *
+ * @return string with parsed HTML.
+ */
function get() {
-
+
if(! local_channel()) {
notice( t('Permission denied') . EOL);
return login();
}
-
- $o = replace_macros(get_markup_template('item_import.tpl'),array(
+
+ $o = replace_macros(get_markup_template('item_import.tpl'), array(
'$title' => t('Import Items'),
'$desc' => t('Use this form to import existing posts and content from an export file.'),
'$label_filename' => t('File to Upload'),
+ '$form_security_token' => get_form_security_token('import_items'),
'$submit' => t('Submit')
));
-
+
return $o;
-
}
-
-
-
+
}
diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php
index 6b6f80a31..0bcd1c1fa 100644
--- a/Zotlabs/Module/Invite.php
+++ b/Zotlabs/Module/Invite.php
@@ -49,7 +49,7 @@ class Invite extends \Zotlabs\Web\Controller {
if(! $recip)
continue;
- if(! valid_email($recip)) {
+ if(! validate_email($recip)) {
notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL);
continue;
}
@@ -88,12 +88,14 @@ class Invite extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
+
+ nav_set_selected('Invite');
$tpl = get_markup_template('invite.tpl');
$invonly = false;
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 4725ecb38..9e5dcfaff 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -33,7 +33,7 @@ class Item extends \Zotlabs\Web\Controller {
// This will change. Figure out who the observer is and whether or not
// they have permission to post here. Else ignore the post.
- if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'commenter')))
+ if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'anonname')))
return;
$uid = local_channel();
@@ -77,7 +77,7 @@ class Item extends \Zotlabs\Web\Controller {
call_hooks('post_local_start', $_REQUEST);
- // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
+ // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
$api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false);
@@ -110,6 +110,7 @@ class Item extends \Zotlabs\Web\Controller {
$preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0);
$categories = ((x($_REQUEST,'category')) ? escape_tags($_REQUEST['category']) : '');
$webpage = ((x($_REQUEST,'webpage')) ? intval($_REQUEST['webpage']) : 0);
+ $item_obscured = ((x($_REQUEST,'obscured')) ? intval($_REQUEST['obscured']) : 0);
$pagetitle = ((x($_REQUEST,'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : '');
$layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): '');
$plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
@@ -204,10 +205,29 @@ class Item extends \Zotlabs\Web\Controller {
$route = $parent_item['route'];
}
+
+ $moderated = false;
- if(! $observer)
+ if(! $observer) {
$observer = \App::get_observer();
+ if(! $observer) {
+ $observer = anon_identity_init($_REQUEST);
+ if($observer) {
+ $moderated = true;
+ $remote_xchan = $remote_observer = $observer;
+ }
+ }
+ }
+ if(! $observer) {
+ notice( t('Permission denied.') . EOL) ;
+ if($api_source)
+ return ( [ 'success' => false, 'message' => 'permission denied' ] );
+ if(x($_REQUEST,'return'))
+ goaway(z_root() . "/" . $return_path );
+ killme();
+ }
+
if($parent) {
logger('mod_item: item_post parent=' . $parent);
$can_comment = false;
@@ -311,7 +331,7 @@ class Item extends \Zotlabs\Web\Controller {
$walltowall = false;
$walltowall_comment = false;
- if($remote_xchan)
+ if($remote_xchan && ! $moderated)
$observer = $remote_observer;
if($observer) {
@@ -471,34 +491,16 @@ class Item extends \Zotlabs\Web\Controller {
if(! $mimetype)
$mimetype = 'text/bbcode';
+
+ $execflag = ((intval($uid) == intval($profile_uid)
+ && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
+
if($preview) {
- $body = z_input_filter($profile_uid,$body,$mimetype);
+ $body = z_input_filter($body,$mimetype,$execflag);
}
-
// Verify ability to use html or php!!!
- $execflag = false;
-
- if($mimetype !== 'text/bbcode') {
- $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1",
- intval($profile_uid)
- );
- if($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) {
- if($uid && (get_account_id() == $z[0]['account_id'])) {
- $execflag = true;
- }
- else {
- notice( t('Executable content type not permitted to this channel.') . EOL);
- if($api_source)
- return ( [ 'success' => false, 'message' => 'forbidden content type' ] );
- if(x($_REQUEST,'return'))
- goaway(z_root() . "/" . $return_path );
- killme();
- }
- }
- }
-
$gacl = $acl->get();
$str_contact_allow = $gacl['allow_cid'];
$str_group_allow = $gacl['allow_gid'];
@@ -632,7 +634,7 @@ class Item extends \Zotlabs\Web\Controller {
$attach_link = '';
$hash = substr($mtch,0,strpos($mtch,','));
$rev = intval(substr($mtch,strpos($mtch,',')));
- $r = attach_by_hash_nodata($hash,$rev);
+ $r = attach_by_hash_nodata($hash, $observer['xchan_hash'], $rev);
if($r['success']) {
$attachments[] = array(
'href' => z_root() . '/attach/' . $r['data']['hash'],
@@ -657,14 +659,23 @@ class Item extends \Zotlabs\Web\Controller {
// BBCODE end alert
if(strlen($categories)) {
+
$cats = explode(',',$categories);
foreach($cats as $cat) {
+
+ if($webpage == ITEM_TYPE_CARD) {
+ $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat));
+ }
+ else {
+ $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat));
+ }
+
$post_tags[] = array(
'uid' => $profile_uid,
'ttype' => TERM_CATEGORY,
'otype' => TERM_OBJ_POST,
'term' => trim($cat),
- 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
+ 'url' => $catlink
);
}
}
@@ -683,7 +694,7 @@ class Item extends \Zotlabs\Web\Controller {
foreach($t as $t1) {
$post_tags[] = array(
'uid' => $profile_uid,
- 'ttype' => $t1['type'],
+ 'ttype' => $t1['ttype'],
'otype' => TERM_OBJ_POST,
'term' => $t1['term'],
'url' => $t1['url'],
@@ -732,7 +743,9 @@ class Item extends \Zotlabs\Web\Controller {
if($parent_item)
$parent_mid = $parent_item['mid'];
-
+
+
+
// Fallback so that we alway have a thr_parent
if(!$thr_parent)
@@ -742,6 +755,21 @@ class Item extends \Zotlabs\Web\Controller {
$item_thread_top = ((! $parent) ? 1 : 0);
+
+ // fix permalinks for cards
+
+ if($webpage == ITEM_TYPE_CARD) {
+ $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : substr($mid,0,16));
+ }
+ if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) {
+ $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.iid = %d limit 1",
+ intval($parent_item['id'])
+ );
+ if($r) {
+ $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . $r[0]['v'];
+ }
+ }
+
if ((! $plink) && ($item_thread_top)) {
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
}
@@ -816,7 +844,7 @@ class Item extends \Zotlabs\Web\Controller {
$datarray['owner'] = $owner_xchan;
$datarray['author'] = $observer;
$datarray['attach'] = json_encode($datarray['attach']);
- $o = conversation($a,array($datarray),'search',false,'preview');
+ $o = conversation(array($datarray),'search',false,'preview');
// logger('preview: ' . $o, LOGGER_DEBUG);
echo json_encode(array('preview' => $o));
killme();
@@ -859,20 +887,8 @@ class Item extends \Zotlabs\Web\Controller {
}
- if(mb_strlen($datarray['title']) > 255)
- $datarray['title'] = mb_substr($datarray['title'],0,255);
-
- if(array_key_exists('item_private',$datarray) && $datarray['item_private']) {
-
- $datarray['body'] = trim(z_input_filter($datarray['uid'],$datarray['body'],$datarray['mimetype']));
-
- if($uid) {
- if($channel['channel_hash'] === $datarray['author_xchan']) {
- $datarray['sig'] = base64url_encode(rsa_sign($datarray['body'],$channel['channel_prvkey']));
- $datarray['item_verified'] = 1;
- }
- }
- }
+ if(mb_strlen($datarray['title']) > 191)
+ $datarray['title'] = mb_substr($datarray['title'],0,191);
if($webpage) {
Zlib\IConfig::Set($datarray,'system', webpage_to_namespace($webpage),
@@ -889,7 +905,17 @@ class Item extends \Zotlabs\Web\Controller {
$x = item_store_update($datarray,$execflag);
- item_create_edit_activity($x);
+ // We only need edit activities for other federated protocols
+ // which do not support edits natively. While this does federate
+ // edits, it presents a number of issues locally - such as #757 and #758.
+ // The SQL check for an edit activity would not perform that well so to fix these issues
+ // requires an additional item flag (perhaps 'item_edit_activity') that we can add to the
+ // query for searches and notifications.
+
+ // For now we'll just forget about trying to make edits work on network protocols that
+ // don't support them.
+
+ // item_create_edit_activity($x);
if(! $parent) {
$r = q("select * from item where id = %d",
@@ -928,6 +954,11 @@ class Item extends \Zotlabs\Web\Controller {
if($parent) {
+ // prevent conversations which you are involved from being expired
+
+ if(local_channel())
+ retain_item($parent);
+
// only send comment notification if this is a wall-to-wall comment,
// otherwise it will happen during delivery
@@ -1015,6 +1046,10 @@ class Item extends \Zotlabs\Web\Controller {
\Zotlabs\Daemon\Master::Summon(array('Notifier', $notify_type, $post_id));
logger('post_complete');
+
+ if($moderated) {
+ info(t('Your comment is awaiting approval.') . EOL);
+ }
// figure out how to return, depending on from whence we came
@@ -1070,21 +1105,28 @@ class Item extends \Zotlabs\Web\Controller {
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion
-
+
+ $complex = false;
+
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
drop_item($i[0]['id']);
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
- $r = q("select * from item where id = %d",
- intval($i[0]['id'])
- );
- if($r) {
- xchan_query($r);
- $sync_item = fetch_post_tags($r);
- build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
- }
+ $complex = true;
+ }
+
+ $r = q("select * from item where id = %d",
+ intval($i[0]['id'])
+ );
+ if($r) {
+ xchan_query($r);
+ $sync_item = fetch_post_tags($r);
+ build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
+ }
+
+ if($complex) {
tag_deliver($i[0]['uid'],$i[0]['id']);
}
}
diff --git a/Zotlabs/Module/Lang.php b/Zotlabs/Module/Lang.php
index 69f10fe6d..0e5d85d05 100644
--- a/Zotlabs/Module/Lang.php
+++ b/Zotlabs/Module/Lang.php
@@ -5,6 +5,7 @@ namespace Zotlabs\Module;
class Lang extends \Zotlabs\Web\Controller {
function get() {
+ nav_set_selected('Language');
return lang_selector();
}
diff --git a/Zotlabs/Module/Layouts.php b/Zotlabs/Module/Layouts.php
index c07f65ce1..34d754029 100644
--- a/Zotlabs/Module/Layouts.php
+++ b/Zotlabs/Module/Layouts.php
@@ -125,6 +125,7 @@ class Layouts extends \Zotlabs\Web\Controller {
'hide_weblink' => true,
'hide_attach' => true,
'hide_preview' => true,
+ 'disable_comments' => true,
'ptlabel' => t('Layout Name'),
'profile_uid' => intval($owner),
'expanded' => true,
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index 5ce8ec7f0..b104a5f5f 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -255,7 +255,7 @@ class Like extends \Zotlabs\Web\Controller {
// get the item. Allow linked photos (which are normally hidden) to be liked
$r = q("SELECT * FROM item WHERE id = %d
- and item_type = 0 and item_deleted = 0 and item_unpublished = 0
+ and (item_type = 0 or item_type = 6) and item_deleted = 0 and item_unpublished = 0
and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1",
intval($item_id)
);
@@ -373,6 +373,10 @@ class Like extends \Zotlabs\Web\Controller {
$links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink']));
$objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
+
+ if($objtype === ACTIVITY_OBJ_NOTE && (! intval($item['item_thread_top'])))
+ $objtype = ACTIVITY_OBJ_COMMENT;
+
$body = $item['body'];
@@ -500,6 +504,11 @@ class Like extends \Zotlabs\Web\Controller {
$post = item_store($arr);
$post_id = $post['item_id'];
+
+ // save the conversation from expiration
+
+ if(local_channel() && array_key_exists('item',$post) && (intval($post['item']['id']) != intval($post['item']['parent'])))
+ retain_item($post['item']['parent']);
$arr['id'] = $post_id;
diff --git a/Zotlabs/Module/Linkinfo.php b/Zotlabs/Module/Linkinfo.php
index 8f8231c49..78c34583e 100644
--- a/Zotlabs/Module/Linkinfo.php
+++ b/Zotlabs/Module/Linkinfo.php
@@ -95,7 +95,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
echo $arr['text'];
killme();
}
-
+
if($process_oembed) {
$x = oembed_process($url);
if($x) {
diff --git a/Zotlabs/Module/Lockview.php b/Zotlabs/Module/Lockview.php
index fc7d5c7c8..466d16997 100644
--- a/Zotlabs/Module/Lockview.php
+++ b/Zotlabs/Module/Lockview.php
@@ -72,7 +72,7 @@ class Lockview extends \Zotlabs\Web\Controller {
}
if($uid != local_channel()) {
- echo '<li>' . t('Remote privacy information not available.') . '</li>';
+ echo '<div class="dropdown-item">' . t('Remote privacy information not available.') . '</div>';
killme();
}
@@ -84,7 +84,7 @@ class Lockview extends \Zotlabs\Web\Controller {
// as unknown specific recipients. The sender will have the visibility list and will fall through to the
// next section.
- echo '<li>' . translate_scope((! $item['public_policy']) ? 'specific' : $item['public_policy']) . '</li>';
+ echo '<div class="dropdown-item">' . translate_scope((! $item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>';
killme();
}
@@ -93,7 +93,7 @@ class Lockview extends \Zotlabs\Web\Controller {
$deny_users = expand_acl($item['deny_cid']);
$deny_groups = expand_acl($item['deny_gid']);
- $o = '<li>' . t('Visible to:') . '</li>';
+ $o = '<div class="dropdown-item">' . t('Visible to:') . '</div>';
$l = array();
stringify_array_elms($allowed_groups,true);
@@ -114,24 +114,24 @@ class Lockview extends \Zotlabs\Web\Controller {
$r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )");
if($r)
foreach($r as $rr)
- $l[] = '<li><b>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</b></li>';
+ $l[] = '<div class="dropdown-item"><b>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</b></div>';
}
if(count($allowed_groups)) {
$r = q("SELECT gname FROM groups WHERE hash IN ( " . implode(', ', $allowed_groups) . " )");
if($r)
foreach($r as $rr)
- $l[] = '<li><b>' . $rr['gname'] . '</b></li>';
+ $l[] = '<div class="dropdown-item"><b>' . $rr['gname'] . '</b></div>';
}
if(count($allowed_users)) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )");
if($r)
foreach($r as $rr)
- $l[] = '<li>' . $rr['xchan_name'] . '</li>';
+ $l[] = '<div class="dropdown-item">' . $rr['xchan_name'] . '</div>';
if($atokens) {
foreach($atokens as $at) {
if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) {
- $l[] = '<li>' . $at['xchan_name'] . '</li>';
+ $l[] = '<div class="dropdown-item">' . $at['xchan_name'] . '</div>';
}
}
}
@@ -150,7 +150,7 @@ class Lockview extends \Zotlabs\Web\Controller {
$r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )");
if($r)
foreach($r as $rr)
- $l[] = '<li><b><strike>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</strike></b></li>';
+ $l[] = '<div class="dropdown-item"><b><strike>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</strike></b></div>';
}
@@ -159,18 +159,18 @@ class Lockview extends \Zotlabs\Web\Controller {
$r = q("SELECT gname FROM groups WHERE hash IN ( " . implode(', ', $deny_groups) . " )");
if($r)
foreach($r as $rr)
- $l[] = '<li><b><strike>' . $rr['gname'] . '</strike></b></li>';
+ $l[] = '<div class="dropdown-item"><b><strike>' . $rr['gname'] . '</strike></b></div>';
}
if(count($deny_users)) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )");
if($r)
foreach($r as $rr)
- $l[] = '<li><strike>' . $rr['xchan_name'] . '</strike></li>';
+ $l[] = '<div class="dropdown-item"><strike>' . $rr['xchan_name'] . '</strike></div>';
if($atokens) {
foreach($atokens as $at) {
if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) {
- $l[] = '<li><strike>' . $at['xchan_name'] . '</strike></li>';
+ $l[] = '<div class="dropdown-item"><strike>' . $at['xchan_name'] . '</strike></div>';
}
}
}
diff --git a/Zotlabs/Module/Logout.php b/Zotlabs/Module/Logout.php
new file mode 100644
index 000000000..6aa11d110
--- /dev/null
+++ b/Zotlabs/Module/Logout.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Zotlabs\Module;
+
+class Logout extends \Zotlabs\Web\Controller {
+
+ function init() {
+ \App::$session->nuke();
+ goaway(z_root());
+
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php
index 9ee5f9324..879085f96 100644
--- a/Zotlabs/Module/Magic.php
+++ b/Zotlabs/Module/Magic.php
@@ -17,6 +17,7 @@ class Magic extends \Zotlabs\Web\Controller {
$dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : '');
$test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0);
$rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0);
+ $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0);
$delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : '');
$parsed = parse_url($dest);
@@ -132,12 +133,32 @@ class Magic extends \Zotlabs\Web\Controller {
if(local_channel()) {
$channel = \App::get_channel();
+ // OpenWebAuth
+
+ if($owa) {
+
+ $headers = [];
+ $headers['Accept'] = 'application/x-zot+json' ;
+ $headers['X-Open-Web-Auth'] = random_string();
+ $headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
+ 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
+ $x = z_fetch_url($basepath . '/owa',false,$redirects,[ 'headers' => $headers ]);
+
+ if($x['success']) {
+ $j = json_decode($x['body'],true);
+ if($j['success'] && $j['token']) {
+ $x = strpbrk($dest,'?&');
+ $args = (($x) ? '&owt=' . $j['token'] : '?f=&owt=' . $j['token']) . (($delegate) ? '&delegate=1' : '');
+
+ goaway($dest . $args);
+ }
+ }
+ goaway($dest);
+ }
+
+
$token = random_string();
- $token_sig = base64url_encode(rsa_sign($token,$channel['channel_prvkey']));
-
- $channel['token'] = $token;
- $channel['token_sig'] = $token_sig;
-
+
\Zotlabs\Zot\Verify::create('auth',$channel['channel_id'],$token,$x[0]['hubloc_url']);
$target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode(channel_reddress($channel))
diff --git a/Zotlabs/Module/Mail.php b/Zotlabs/Module/Mail.php
index 459ce5acf..12f3b8152 100644
--- a/Zotlabs/Module/Mail.php
+++ b/Zotlabs/Module/Mail.php
@@ -22,32 +22,40 @@ class Mail extends \Zotlabs\Web\Controller {
$recipient = ((x($_REQUEST,'messageto')) ? notags(trim($_REQUEST['messageto'])) : '');
$rstr = ((x($_REQUEST,'messagerecip')) ? notags(trim($_REQUEST['messagerecip'])) : '');
$preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0);
- $expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
+ $expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
+ $raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
+ $mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
if($preview) {
- $body = cleanup_bbcode($body);
- $results = linkify_tags($a, $body, local_channel());
+ if($raw) {
+ $body = mail_prepare_binary(['id' => 'M0']);
+ echo json_encode(['preview' => $body]);
+ }
+ else {
+ $body = cleanup_bbcode($body);
+ $results = linkify_tags($a, $body, local_channel());
- if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
- $attachments = array();
- foreach($match[2] as $mtch) {
- $hash = substr($mtch,0,strpos($mtch,','));
- $rev = intval(substr($mtch,strpos($mtch,',')));
- $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
- if($r['success']) {
- $attachments[] = array(
- 'href' => z_root() . '/attach/' . $r['data']['hash'],
- 'length' => $r['data']['filesize'],
- 'type' => $r['data']['filetype'],
- 'title' => urlencode($r['data']['filename']),
- 'revision' => $r['data']['revision']
- );
+ if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
+ $attachments = array();
+ foreach($match[2] as $mtch) {
+ $hash = substr($mtch,0,strpos($mtch,','));
+ $rev = intval(substr($mtch,strpos($mtch,',')));
+ $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
+ if($r['success']) {
+ $attachments[] = array(
+ 'href' => z_root() . '/attach/' . $r['data']['hash'],
+ 'length' => $r['data']['filesize'],
+ 'type' => $r['data']['filetype'],
+ 'title' => urlencode($r['data']['filename']),
+ 'revision' => $r['data']['revision']
+ );
+ }
+ $body = trim(str_replace($match[1],'',$body));
}
- $body = trim(str_replace($match[1],'',$body));
}
+ echo json_encode(['preview' => zidify_links(smilies(bbcode($body)))]);
}
- echo json_encode(['preview' => zidify_links(smilies(bbcode($body)))]);
killme();
}
@@ -102,36 +110,10 @@ class Mail extends \Zotlabs\Web\Controller {
}
}
- // if(feature_enabled(local_channel(),'richtext')) {
- // $body = fix_mce_lf($body);
- // }
-
require_once('include/text.php');
linkify_tags($a, $body, local_channel());
- // I don't think this is used any more.
-
- if($preview) {
- $mail = [
- 'mailbox' => 'outbox',
- 'id' => 0,
- 'mid' => 'M0',
- 'from_name' => $channel['xchan_name'],
- 'from_url' => $channel['xchan_url'],
- 'from_photo' => $channel['xchan_photo_s'],
- 'subject' => zidify_links(smilies(bbcode($subject))),
- 'body' => zidify_links(smilies(bbcode($body))),
- 'attachments' => '',
- 'can_recall' => false,
- 'is_recalled' => '',
- 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c')
- ];
-
- echo replace_macros(get_markup_template('mail_conv.tpl'), [ '$mail' => $mail ] );
- killme();
- }
-
if(! $recipient) {
notice('No recipient found.');
\App::$argc = 2;
@@ -141,7 +123,7 @@ class Mail extends \Zotlabs\Web\Controller {
// We have a local_channel, let send_message use the session channel and save a lookup
- $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires);
+ $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw);
if($ret['success']) {
xchan_mail_query($ret['mail']);
@@ -158,7 +140,7 @@ class Mail extends \Zotlabs\Web\Controller {
function get() {
$o = '';
- nav_set_selected('messages');
+ nav_set_selected('Mail');
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
@@ -178,6 +160,25 @@ class Mail extends \Zotlabs\Web\Controller {
'$header' => t('Messages'),
));
+ if(argc() == 3 && intval(argv(1)) && argv(2) === 'download') {
+
+ $r = q("select * from mail where id = %d and channel_id = %d",
+ intval(argv(1)),
+ intval(local_channel())
+ );
+
+ if($r) {
+
+ header('Content-type: ' . $r[0]['mail_mimetype']);
+ header('Content-disposition: attachment; filename="' . t('message') . '-' . $r[0]['id'] . '"' );
+ $body = (($r[0]['mail_obscured']) ? base64url_decode(str_rot47($r[0]['body'])) : $r[0]['body']);
+ echo $body;
+ killme();
+ }
+
+ }
+
+
if((argc() == 4) && (argv(2) === 'drop')) {
if(! intval(argv(3)))
return;
@@ -296,7 +297,9 @@ class Mail extends \Zotlabs\Web\Controller {
return $o;
}
-
+
+ $direct_mid = 0;
+
switch(argv(1)) {
case 'combined':
$mailbox = 'combined';
@@ -309,12 +312,22 @@ class Mail extends \Zotlabs\Web\Controller {
break;
default:
$mailbox = 'combined';
+
+ // notifications direct to mail/nn
+
+ if(intval(argv(1)))
+ $direct_mid = intval(argv(1));
break;
}
+
$last_message = private_messages_list(local_channel(), $mailbox, 0, 1);
-
+
$mid = ((argc() > 2) && (intval(argv(2)))) ? argv(2) : $last_message[0]['id'];
+
+ if($direct_mid)
+ $mid = $direct_mid;
+
$plaintext = true;
@@ -358,6 +371,11 @@ class Mail extends \Zotlabs\Web\Controller {
foreach($messages as $message) {
$s = theme_attachments($message);
+
+ if($message['mail_raw'])
+ $message['body'] = mail_prepare_binary([ 'id' => $message['id'] ]);
+ else
+ $message['body'] = zidify_links(smilies(bbcode($message['body'])));
$mails[] = array(
'mailbox' => $mailbox,
@@ -370,7 +388,7 @@ class Mail extends \Zotlabs\Web\Controller {
'to_url' => chanlink_hash($message['to_xchan']),
'to_photo' => $message['to']['xchan_photo_s'],
'subject' => $message['title'],
- 'body' => zidify_links(smilies(bbcode($message['body']))),
+ 'body' => $message['body'],
'attachments' => $s,
'delete' => t('Delete message'),
'dreport' => t('Delivery report'),
diff --git a/Zotlabs/Module/Manage.php b/Zotlabs/Module/Manage.php
index 3b7b3c3dd..9c5c32294 100644
--- a/Zotlabs/Module/Manage.php
+++ b/Zotlabs/Module/Manage.php
@@ -10,6 +10,8 @@ class Manage extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
+
+ nav_set_selected('Channel Manager');
require_once('include/security.php');
@@ -46,107 +48,111 @@ class Manage extends \Zotlabs\Web\Controller {
$channels = null;
- if(local_channel()) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ",
- intval(get_account_id())
- );
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ",
+ intval(get_account_id())
+ );
- $account = \App::get_account();
+ $account = \App::get_account();
- if($r && count($r)) {
- $channels = $r;
- for($x = 0; $x < count($channels); $x ++) {
- $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']);
- $channels[$x]['default'] = (($channels[$x]['channel_id'] == $account['account_default_channel']) ? "1" : '');
- $channels[$x]['default_links'] = '1';
+ if($r && count($r)) {
+ $channels = $r;
+ for($x = 0; $x < count($channels); $x ++) {
+ $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']);
+ $channels[$x]['default'] = (($channels[$x]['channel_id'] == $account['account_default_channel']) ? "1" : '');
+ $channels[$x]['default_links'] = '1';
- $c = q("SELECT id, item_wall FROM item
- WHERE item_unseen = 1 and uid = %d " . item_normal(),
- intval($channels[$x]['channel_id'])
- );
+ $c = q("SELECT id, item_wall FROM item
+ WHERE item_unseen = 1 and uid = %d " . item_normal(),
+ intval($channels[$x]['channel_id'])
+ );
- if($c) {
- foreach ($c as $it) {
- if(intval($it['item_wall']))
- $channels[$x]['home'] ++;
- else
- $channels[$x]['network'] ++;
- }
+ if($c) {
+ foreach ($c as $it) {
+ if(intval($it['item_wall']))
+ $channels[$x]['home'] ++;
+ else
+ $channels[$x]['network'] ++;
}
+ }
- $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
- intval($channels[$x]['channel_id'])
- );
+ $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
+ intval($channels[$x]['channel_id'])
+ );
- if($intr)
- $channels[$x]['intros'] = intval($intr[0]['total']);
+ if($intr)
+ $channels[$x]['intros'] = intval($intr[0]['total']);
- $mails = q("SELECT count(id) as total from mail WHERE channel_id = %d AND mail_seen = 0 and from_xchan != '%s' ",
- intval($channels[$x]['channel_id']),
- dbesc($channels[$x]['channel_hash'])
- );
+ $mails = q("SELECT count(id) as total from mail WHERE channel_id = %d AND mail_seen = 0 and from_xchan != '%s' ",
+ intval($channels[$x]['channel_id']),
+ dbesc($channels[$x]['channel_hash'])
+ );
- if($mails)
- $channels[$x]['mail'] = intval($mails[0]['total']);
+ if($mails)
+ $channels[$x]['mail'] = intval($mails[0]['total']);
- $events = q("SELECT etype, dtstart, adjust FROM event
- WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0
- ORDER BY dtstart ASC ",
- intval($channels[$x]['channel_id']),
- dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')),
- dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
- );
-
- if($events) {
- $channels[$x]['all_events'] = count($events);
-
- if($channels[$x]['all_events']) {
- $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d');
- foreach($events as $e) {
- $bd = false;
- if($e['etype'] === 'birthday') {
- $channels[$x]['birthdays'] ++;
- $bd = true;
- }
- else {
- $channels[$x]['events'] ++;
- }
- if(datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['dtstart'], 'Y-m-d') === $str_now) {
- $channels[$x]['all_events_today'] ++;
- if($bd)
- $channels[$x]['birthdays_today'] ++;
- else
- $channels[$x]['events_today'] ++;
- }
+ $events = q("SELECT etype, dtstart, adjust FROM event
+ WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0
+ ORDER BY dtstart ASC ",
+ intval($channels[$x]['channel_id']),
+ dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')),
+ dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
+ );
+
+ if($events) {
+ $channels[$x]['all_events'] = count($events);
+
+ if($channels[$x]['all_events']) {
+ $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d');
+ foreach($events as $e) {
+ $bd = false;
+ if($e['etype'] === 'birthday') {
+ $channels[$x]['birthdays'] ++;
+ $bd = true;
+ }
+ else {
+ $channels[$x]['events'] ++;
+ }
+ if(datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['dtstart'], 'Y-m-d') === $str_now) {
+ $channels[$x]['all_events_today'] ++;
+ if($bd)
+ $channels[$x]['birthdays_today'] ++;
+ else
+ $channels[$x]['events_today'] ++;
}
}
}
}
}
-
- $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0",
- intval(get_account_id())
- );
- $limit = account_service_class_fetch(get_account_id(),'total_identities');
- if($limit !== false) {
- $channel_usage_message = sprintf( t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit);
- }
- else {
- $channel_usage_message = '';
- }
+
+ }
+
+ $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0",
+ intval(get_account_id())
+ );
+ $limit = account_service_class_fetch(get_account_id(),'total_identities');
+ if($limit !== false) {
+ $channel_usage_message = sprintf( t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit);
}
+ else {
+ $channel_usage_message = '';
+ }
+
$create = array( 'new_channel', t('Create a new channel'), t('Create New'));
- $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where
- abook_channel = %d and abook_xchan in ( select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'delegate' and v = '1' )",
- intval(local_channel()),
- intval(local_channel())
- );
+ $delegates = null;
+
+ if(local_channel()) {
+ $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where
+ abook_channel = %d and abook_xchan in ( select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'delegate' and v = '1' )",
+ intval(local_channel()),
+ intval(local_channel())
+ );
+ }
if($delegates) {
for($x = 0; $x < count($delegates); $x ++) {
diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php
new file mode 100644
index 000000000..cf1625a6b
--- /dev/null
+++ b/Zotlabs/Module/Moderate.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Zotlabs\Module;
+
+require_once('include/conversation.php');
+
+
+class Moderate extends \Zotlabs\Web\Controller {
+
+
+ function get() {
+ if(! local_channel()) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ //show all items
+ if(argc() == 1) {
+ $r = q("select item.id as item_id, item.* from item where item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc limit 60",
+ intval(local_channel()),
+ intval(ITEM_MODERATED)
+ );
+ }
+
+ //show a single item
+ if(argc() == 2) {
+ $post_id = intval(argv(1));
+
+ $r = q("select item.id as item_id, item.* from item where item.id = %d and item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc limit 60",
+ intval($post_id),
+ intval(local_channel()),
+ intval(ITEM_MODERATED)
+ );
+ }
+
+ if(argc() > 2) {
+ $post_id = intval(argv(1));
+ if(! $post_id)
+ goaway(z_root() . '/moderate');
+
+ $action = argv(2);
+
+ $r = q("select * from item where uid = %d and id = %d and item_blocked = %d limit 1",
+ intval(local_channel()),
+ intval($post_id),
+ intval(ITEM_MODERATED)
+ );
+
+ if($r) {
+ if($action === 'approve') {
+ q("update item set item_blocked = 0 where uid = %d and id = %d",
+ intval(local_channel()),
+ intval($post_id)
+ );
+ notice( t('Comment approved') . EOL);
+ }
+ elseif($action === 'drop') {
+ drop_item($post_id,false);
+ notice( t('Comment deleted') . EOL);
+ }
+
+ $r = q("select * from item where id = %d",
+ intval($post_id)
+ );
+ if($r) {
+ xchan_query($r);
+ $sync_item = fetch_post_tags($r);
+ build_sync_packet(local_channel(),array('item' => array(encode_item($sync_item[0],true))));
+ }
+ if($action === 'approve') {
+ \Zotlabs\Daemon\Master::Summon(array('Notifier', 'comment-new', $post_id));
+ }
+ goaway(z_root() . '/moderate');
+ }
+ }
+
+ if($r) {
+ xchan_query($r);
+ $items = fetch_post_tags($r,true);
+ }
+ else {
+ $items = array();
+ }
+
+ $o = conversation($items,'moderate',false,'traditional');
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Mood.php b/Zotlabs/Module/Mood.php
index eeb050040..ad29ec7e8 100644
--- a/Zotlabs/Module/Mood.php
+++ b/Zotlabs/Module/Mood.php
@@ -110,17 +110,17 @@ class Mood extends \Zotlabs\Web\Controller {
- function get() {
+ function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
-
+
+ nav_set_selected('Mood');
+
$parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0');
-
-
$verbs = get_mood_verbs();
$shortlist = array();
diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php
index 8263420b6..ee736ff42 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -44,6 +44,7 @@ class Network extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
$item_normal = item_normal();
+ $item_normal_update = item_normal_update();
$datequery = $datequery2 = '';
@@ -116,10 +117,9 @@ class Network extends \Zotlabs\Web\Controller {
$spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0);
$cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0);
$cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99);
- $firehose = ((x($_GET,'fh')) ? intval($_GET['fh']) : 0);
$file = ((x($_GET,'file')) ? $_GET['file'] : '');
-
-
+ $xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : '');
+
$deftag = '';
if(x($_GET,'search') || x($_GET,'file'))
@@ -154,7 +154,7 @@ class Network extends \Zotlabs\Web\Controller {
));
}
- nav_set_selected('network');
+ nav_set_selected('Grid');
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
@@ -257,6 +257,26 @@ class Network extends \Zotlabs\Web\Controller {
goaway(z_root() . '/network');
}
}
+ elseif($xchan) {
+ $r = q("select * from xchan where xchan_hash = '%s'",
+ dbesc($xchan)
+ );
+ if($r) {
+ $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($xchan) . "' or owner_xchan = '" . dbesc($xchan) . "' ) $item_normal ) ";
+ $title = replace_macros(get_markup_template("section_title.tpl"),array(
+ '$title' => '<a href="' . zid($r[0]['xchan_url']) . '" ><img src="' . zid($r[0]['xchan_photo_s']) . '" alt="' . urlencode($r[0]['xchan_name']) . '" /></a> <a href="' . zid($r[0]['xchan_url']) . '" >' . $r[0]['xchan_name'] . '</a>'
+ ));
+ $o = $tabs;
+ $o .= $title;
+ $o .= $status_editor;
+
+ }
+ else {
+ notice( t('Invalid channel.') . EOL);
+ goaway(z_root() . '/network');
+ }
+
+ }
if(x($category)) {
$sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY));
@@ -270,9 +290,6 @@ class Network extends \Zotlabs\Web\Controller {
// We only launch liveUpdate if you aren't filtering in some incompatible
// way and also you aren't writing a comment (discovered in javascript).
- if($gid || $cid || $cmin || ($cmax != 99) || $star || $liked || $conv || $spam || $nouveau || $list)
- $firehose = 0;
-
$maxheight = get_pconfig(local_channel(),'system','network_divmore_height');
if(! $maxheight)
$maxheight = 400;
@@ -295,17 +312,18 @@ class Network extends \Zotlabs\Web\Controller {
'$liked' => (($liked) ? $liked : '0'),
'$conv' => (($conv) ? $conv : '0'),
'$spam' => (($spam) ? $spam : '0'),
- '$fh' => (($firehose) ? $firehose : '0'),
+ '$fh' => '0',
'$nouveau' => (($nouveau) ? $nouveau : '0'),
'$wall' => '0',
'$static' => $static,
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$search' => (($search) ? $search : ''),
+ '$xchan' => $xchan,
'$order' => $order,
'$file' => $file,
- '$cats' => $category,
- '$tags' => $hashtags,
+ '$cats' => urlencode($category),
+ '$tags' => urlencode($hashtags),
'$dend' => $datequery,
'$mid' => '',
'$verb' => $verb,
@@ -388,16 +406,7 @@ class Network extends \Zotlabs\Web\Controller {
}
$abook_uids = " and abook.abook_channel = " . local_channel() . " ";
-
- if($firehose && (! get_config('system','disable_discover_tab'))) {
- require_once('include/channel.php');
- $sys = get_sys_channel();
- $uids = " and item.uid = " . intval($sys['channel_id']) . " ";
- \App::$data['firehose'] = intval($sys['channel_id']);
- }
- else {
- $uids = " and item.uid = " . local_channel() . " ";
- }
+ $uids = " and item.uid = " . local_channel() . " ";
if(get_pconfig(local_channel(),'system','network_list_mode'))
$page_mode = 'list';
@@ -469,10 +478,11 @@ class Network extends \Zotlabs\Web\Controller {
}
else {
+
// this is an update
$r = q("SELECT item.parent AS item_id FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
- WHERE true $uids $item_normal $simple_update
+ WHERE true $uids $item_normal_update $simple_update
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra3 $sql_extra $sql_nets "
);
@@ -494,14 +504,14 @@ class Network extends \Zotlabs\Web\Controller {
dbesc($parents_str)
);
- xchan_query($items,true,(($firehose) ? local_channel() : 0));
+ xchan_query($items,true);
$items = fetch_post_tags($items,true);
$items = conv_sort($items,$ordering);
}
else {
$items = array();
}
-
+
if($page_mode === 'list') {
/**
@@ -513,24 +523,30 @@ class Network extends \Zotlabs\Web\Controller {
if($parents_str) {
$update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
+ $update_unseen .= " AND obj_type != '" . dbesc(ACTIVITY_OBJ_FILE) . "'";
$update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
}
}
else {
if($parents_str) {
- $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
+ $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " ) AND obj_type != '" . dbesc(ACTIVITY_OBJ_FILE) . "'";
}
}
}
- if(($update_unseen) && (! $firehose))
- $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ",
- intval(local_channel())
- );
+ if($update_unseen) {
+ $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ",
+ intval(local_channel())
+ );
+ }
+ }
$mode = (($nouveau) ? 'network-new' : 'network');
- $o .= conversation($a,$items,$mode,$update,$page_mode);
+ $o .= conversation($items,$mode,$update,$page_mode);
if(($items) && (! $update))
$o .= alt_pager($a,count($items));
diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php
index 8e6fd1d37..2b73fa191 100644
--- a/Zotlabs/Module/New_channel.php
+++ b/Zotlabs/Module/New_channel.php
@@ -9,7 +9,7 @@ require_once('include/permissions.php');
class New_channel extends \Zotlabs\Web\Controller {
function init() {
-
+
$cmd = ((argc() > 1) ? argv(1) : '');
if($cmd === 'autofill.json') {
@@ -134,7 +134,7 @@ class New_channel extends \Zotlabs\Web\Controller {
$name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'), "*");
$nickhub = '@' . \App::get_hostname();
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub), "*");
- $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles);
+ $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles);
$o = replace_macros(get_markup_template('new_channel.tpl'), array(
'$title' => t('Create Channel'),
diff --git a/Zotlabs/Module/Notifications.php b/Zotlabs/Module/Notifications.php
index e0313dd8b..dfa007548 100644
--- a/Zotlabs/Module/Notifications.php
+++ b/Zotlabs/Module/Notifications.php
@@ -12,25 +12,44 @@ class Notifications extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected('notifications');
+ nav_set_selected('Notifications');
$o = '';
-
- $r = q("SELECT * from notify where uid = %d and seen = 0 order by created desc",
+
+ $r = q("select count(*) as total from notify where uid = %d and seen = 0",
intval(local_channel())
);
+ if($r && intval($t[0]['total']) > 49) {
+ $r = q("select * from notify where uid = %d
+ and seen = 0 order by created desc limit 50",
+ intval(local_channel())
+ );
+ } else {
+ $r1 = q("select * from notify where uid = %d
+ and seen = 0 order by created desc limit 50",
+ intval(local_channel())
+ );
+ $r2 = q("select * from notify where uid = %d
+ and seen = 1 order by created desc limit %d",
+ intval(local_channel()),
+ intval(50 - intval($t[0]['total']))
+ );
+ $r = array_merge($r1,$r2);
+ }
if($r) {
$notifications_available = 1;
- foreach ($r as $it) {
- $x = strip_tags(bbcode($it['msg']));
+ foreach ($r as $rr) {
+ $x = strip_tags(bbcode($rr['msg']));
if(strpos($x,','))
$x = substr($x,strpos($x,',')+1);
$notif_content .= replace_macros(get_markup_template('notify.tpl'),array(
- '$item_link' => z_root().'/notify/view/'. $it['id'],
- '$item_image' => $it['photo'],
+ '$item_link' => z_root().'/notify/view/'. $rr['id'],
+ '$item_image' => $rr['photo'],
'$item_text' => $x,
- '$item_when' => relative_date($it['created'])
+ '$item_when' => relative_date($rr['created']),
+ '$item_seen' => (($rr['seen']) ? true : false),
+ '$new' => t('New')
));
}
}
@@ -40,7 +59,7 @@ class Notifications extends \Zotlabs\Web\Controller {
$o .= replace_macros(get_markup_template('notifications.tpl'),array(
'$notif_header' => t('System Notifications'),
- '$notif_link_mark_seen' => t('Mark all system notifications seen'),
+ '$notif_link_mark_seen' => t('Mark all seen'),
'$notif_content' => $notif_content,
'$notifications_available' => $notifications_available,
));
diff --git a/Zotlabs/Module/Notify.php b/Zotlabs/Module/Notify.php
index f592f6f37..3d6e1c2e7 100644
--- a/Zotlabs/Module/Notify.php
+++ b/Zotlabs/Module/Notify.php
@@ -15,12 +15,16 @@ class Notify extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($r) {
- q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d",
- dbesc($r[0]['parent']),
- dbesc($r[0]['otype']),
- dbesc($r[0]['link']),
- intval(local_channel())
- );
+ $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d",
+ dbesc($r[0]['parent']),
+ dbesc($r[0]['otype']),
+ dbesc($r[0]['link']),
+ intval(local_channel())
+ );
+ }
goaway($r[0]['link']);
}
goaway(z_root());
diff --git a/Zotlabs/Module/Oembed.php b/Zotlabs/Module/Oembed.php
index 9394e5942..aee5ea079 100644
--- a/Zotlabs/Module/Oembed.php
+++ b/Zotlabs/Module/Oembed.php
@@ -22,7 +22,7 @@ class Oembed extends \Zotlabs\Web\Controller {
}
else {
- echo "<html><head><base target=\"_blank\" /></head><body>";
+ echo "<html><head><base target=\"_blank\" rel=\"nofollow noopener\" /></head><body>";
$src = base64url_decode(argv(1));
$j = oembed_fetch_url($src);
echo $j['html'];
diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php
index dc0547a42..5e06d3540 100644
--- a/Zotlabs/Module/Oep.php
+++ b/Zotlabs/Module/Oep.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+require_once('include/security.php');
+
// oembed provider
@@ -41,6 +43,8 @@ class Oep extends \Zotlabs\Web\Controller {
$arr = $this->oep_profile_reply($_REQUEST);
elseif(fnmatch('*/profile/*',$url))
$arr = $this->oep_profile_reply($_REQUEST);
+ elseif(fnmatch('*/cards/*',$url))
+ $arr = $this->oep_cards_reply($_REQUEST);
if($arr) {
if($html) {
@@ -66,49 +70,158 @@ class Oep extends \Zotlabs\Web\Controller {
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
-
- if(preg_match('#//(.*?)/(.*?)/(.*?)/(.*?)mid\=(.*?)(&|$)#',$url,$matches)) {
- $chn = $matches[3];
- $res = $matches[5];
+ logger('processing display');
+ if(preg_match('#//(.*?)/display/(.*?)(&|\?|$)#',$url,$matches)) {
+ $res = $matches[2];
}
-
- if(! ($chn && $res))
- return;
- $c = q("select * from channel where channel_address = '%s' limit 1",
- dbesc($chn)
+
+ if(strpos($res,'b64.') === 0) {
+ $res = base64url_decode(substr($res,4));
+ }
+
+ $item_normal = item_normal();
+
+ $p = q("select * from item where mid like '%s' limit 1",
+ dbesc($res . '%')
);
-
- if(! $c)
+
+ if(! $p)
return;
+
+ $c = channelx_by_n($p[0]['uid']);
+
- $sql_extra = item_permissions_sql($c[0]['channel_id']);
+ if(! ($c && $res))
+ return;
+
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream'))
+ return;
+
+ $sql_extra = item_permissions_sql($c['channel_id']);
- $p = q("select * from item where mid = '%s' and uid = %d $sql_extra limit 1",
- dbesc($res),
- intval($c[0]['channel_id'])
+ $p = q("select * from item where mid like '%s' and uid = %d $sql_extra $item_normal limit 1",
+ dbesc($res . '%'),
+ intval($c['channel_id'])
);
+
if(! $p)
return;
xchan_query($p,true);
$p = fetch_post_tags($p,true);
+
+ // This function can get tripped up if the item is already a reshare
+ // (the multiple share declarations do not parse cleanly if nested)
+ // So build a template with a known nonsense string as the content, and then
+ // replace that known string with the actual rendered content, sending
+ // each content layer through bbcode() separately.
+
+ $x = '2eGriplW^*Jmf4';
+
+
+ $o = "[share author='".urlencode($p[0]['author']['xchan_name']).
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
+ if($p[0]['title'])
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+
+ $o .= $x;
+ $o .= "[/share]";
+ $o = bbcode($o);
+
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
+ $ret['type'] = 'rich';
+
+ $w = (($maxwidth) ? $maxwidth : 640);
+ $h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
+
+ $ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
+
+ $ret['width'] = $w;
+ $ret['height'] = $h;
+
+ return $ret;
+
+ }
+
+
+ function oep_cards_reply($args) {
+
+ $ret = [];
+ $url = $args['url'];
+ $maxwidth = intval($args['maxwidth']);
+ $maxheight = intval($args['maxheight']);
+
+ if(preg_match('#//(.*?)/cards/(.*?)/(.*?)(&|\?|$)#',$url,$matches)) {
+ $nick = $matches[2];
+ $res = $matches[3];
+ }
+ if(! ($nick && $res))
+ return $ret;
+
+ $channel = channelx_by_nick($nick);
+
+ if(! $channel)
+ return $ret;
+
+
+ if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_pages'))
+ return $ret;
+
+ $sql_extra = item_permissions_sql($channel['channel_id'],get_observer_hash());
+
+ $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1",
+ dbesc($res)
+ );
+ if($r) {
+ $sql_extra = "and item.id = " . intval($r[0]['iid']) . " ";
+ }
+ else {
+ return $ret;
+ }
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($channel['channel_id']),
+ intval(ITEM_TYPE_CARD)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ if($r) {
+ xchan_query($r);
+ $p = fetch_post_tags($r, true);
+ }
+
+ $x = '2eGriplW^*Jmf4';
+
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
- "' profile='".$p[0]['author']['xchan_url'] .
- "' avatar='".$p[0]['author']['xchan_photo_s'].
- "' link='".$p[0]['plink'].
- "' posted='".$p[0]['created'].
- "' message_id='".$p[0]['mid']."']";
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
- $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
- $o .= $p[0]['body'];
- $o .= "[/share]";
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+
+ $o .= $x;
+ $o .= "[/share]";
$o = bbcode($o);
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
- $h = (($maxheight) ? $maxheight : $w * 2 / 3);
+ $h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
$ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
@@ -118,6 +231,7 @@ class Oep extends \Zotlabs\Web\Controller {
return $ret;
}
+
function oep_mid_reply($args) {
@@ -139,6 +253,9 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
+
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream'))
+ return;
$sql_extra = item_permissions_sql($c[0]['channel_id']);
@@ -151,23 +268,33 @@ class Oep extends \Zotlabs\Web\Controller {
xchan_query($p,true);
$p = fetch_post_tags($p,true);
-
+
+ // This function can get tripped up if the item is already a reshare
+ // (the multiple share declarations do not parse cleanly if nested)
+ // So build a template with a known nonsense string as the content, and then
+ // replace that known string with the actual rendered content, sending
+ // each content layer through bbcode() separately.
+
+ $x = '2eGriplW^*Jmf4';
+
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
- "' profile='".$p[0]['author']['xchan_url'] .
- "' avatar='".$p[0]['author']['xchan_photo_s'].
- "' link='".$p[0]['plink'].
- "' posted='".$p[0]['created'].
- "' message_id='".$p[0]['mid']."']";
- if($p[0]['title'])
- $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
- $o .= $p[0]['body'];
- $o .= "[/share]";
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
+ if($p[0]['title'])
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+ $o .= $x;
+ $o .= "[/share]";
$o = bbcode($o);
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
- $h = (($maxheight) ? $maxheight : $w * 2 / 3);
+ $h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
$ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
@@ -247,6 +374,9 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
+ return;
+
$sql_extra = permissions_sql($c[0]['channel_id']);
$p = q("select resource_id from photo where album = '%s' and uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
@@ -308,6 +438,9 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
+ return;
+
$sql_extra = permissions_sql($c[0]['channel_id']);
$p = q("select resource_id from photo where uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
@@ -368,7 +501,10 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
-
+
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
+ return;
+
$sql_extra = permissions_sql($c[0]['channel_id']);
diff --git a/Zotlabs/Module/Ofeed.php b/Zotlabs/Module/Ofeed.php
new file mode 100644
index 000000000..58488d4af
--- /dev/null
+++ b/Zotlabs/Module/Ofeed.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Zotlabs\Module;
+
+/* Ofeed: Broken feed for software which requires broken feeds */
+
+require_once('include/items.php');
+
+class Ofeed extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ $params = [];
+
+ $params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
+ $params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : '');
+ $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
+ $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
+ $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
+ $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
+ $params['records'] = ((x($params,'records')) ? intval($params['records']) : 10);
+ $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
+ $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
+ $params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1);
+
+
+ if(argc() > 1) {
+
+ if(observer_prohibited(true)) {
+ killme();
+ }
+
+ $channel = channelx_by_nick(argv(1));
+ if(! $channel) {
+ killme();
+ }
+
+
+ logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
+
+ echo get_public_feed($channel,$params);
+
+ killme();
+ }
+
+ }
+
+}
diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php
new file mode 100644
index 000000000..4b0d855c5
--- /dev/null
+++ b/Zotlabs/Module/Owa.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Zotlabs\Module;
+
+/**
+ * OpenWebAuth verifier and token generator
+ * See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
+ * Requests to this endpoint should be signed using HTTP Signatures
+ * using the 'Authorization: Signature' authentication method
+ * If the signature verifies a token is returned.
+ *
+ * This token may be exchanged for an authenticated cookie.
+ */
+
+class Owa extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ $ret = [ 'success' => false ];
+
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+
+ if($keyId) {
+ $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
+ where hubloc_addr = '%s' limit 1",
+ dbesc(str_replace('acct:','',$keyId))
+ );
+ if($r) {
+ $hubloc = $r[0];
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
+ if($verified && $verified['header_signed'] && $verified['header_valid']) {
+ $ret['success'] = true;
+ $token = random_string(32);
+ \Zotlabs\Zot\Verify::create('owt',0,$token,$r[0]['hubloc_addr']);
+ $ret['token'] = $token;
+ }
+ }
+ }
+ }
+ }
+ }
+ json_return_and_die($ret,'application/x-zot+json');
+ }
+}
diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php
index 6ef285dd0..c142afe77 100644
--- a/Zotlabs/Module/Page.php
+++ b/Zotlabs/Module/Page.php
@@ -3,7 +3,6 @@ namespace Zotlabs\Module;
require_once('include/items.php');
require_once('include/conversation.php');
-require_once('include/page_widgets.php');
class Page extends \Zotlabs\Web\Controller {
@@ -43,11 +42,31 @@ class Page extends \Zotlabs\Web\Controller {
$channel_address = argv(1);
+ // Always look first for the page name prefixed by the observer language; for instance page/nickname/de/foo
+ // followed by page/nickname/foo if that is not found.
+ // If your browser language is de and you want to access the default in this case,
+ // use page/nickname/-/foo to over-ride the language and access only the page with pagelink of 'foo'
+
+ $page_name = '';
+ $ignore_language = false;
+
+ for($x = 2; $x < argc(); $x ++) {
+ if($page_name === '' && argv($x) === '-') {
+ $ignore_language = true;
+ continue;
+ }
+ if($page_name)
+ $page_name .= '/';
+ $page_name .= argv($x);
+ }
+
+
// The page link title was stored in a urlencoded format
// php or the browser may/will have decoded it, so re-encode it for our search
- $page_id = urlencode(argv(2));
-
+ $page_id = urlencode($page_name);
+ $lang_page_id = urlencode(\App::$language . '/' . $page_name);
+
$u = q("select channel_id from channel where channel_address = '%s' limit 1",
dbesc($channel_address)
);
@@ -64,16 +83,31 @@ class Page extends \Zotlabs\Web\Controller {
require_once('include/security.php');
$sql_options = item_permissions_sql($u[0]['channel_id']);
-
- $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 item.item_delayed = 0
- and (( iconfig.k = 'WEBPAGE' and item_type = %d )
- OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1",
- intval($u[0]['channel_id']),
- dbesc($page_id),
- intval(ITEM_TYPE_WEBPAGE),
- intval(ITEM_TYPE_PDL)
- );
+
+ $r = null;
+
+ if(! $ignore_language) {
+ $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 item.item_delayed = 0
+ and (( iconfig.k = 'WEBPAGE' and item_type = %d )
+ OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1",
+ intval($u[0]['channel_id']),
+ dbesc($lang_page_id),
+ intval(ITEM_TYPE_WEBPAGE),
+ intval(ITEM_TYPE_PDL)
+ );
+ }
+ if(! $r) {
+ $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 item.item_delayed = 0
+ and (( iconfig.k = 'WEBPAGE' and item_type = %d )
+ OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1",
+ intval($u[0]['channel_id']),
+ dbesc($page_id),
+ intval(ITEM_TYPE_WEBPAGE),
+ intval(ITEM_TYPE_PDL)
+ );
+ }
if(! $r) {
// Check again with no permissions clause to see if it is a permissions issue
diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php
index 618444480..f8af470ac 100644
--- a/Zotlabs/Module/Pdledit.php
+++ b/Zotlabs/Module/Pdledit.php
@@ -14,7 +14,7 @@ class Pdledit extends \Zotlabs\Web\Controller {
if(! trim($_REQUEST['content'])) {
del_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl');
- goaway(z_root() . '/pdledit/' . $_REQUEST['module']);
+ goaway(z_root() . '/pdledit');
}
set_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl',escape_tags($_REQUEST['content']));
build_sync_packet();
@@ -34,19 +34,38 @@ class Pdledit extends \Zotlabs\Web\Controller {
notice( t('Feature disabled.') . EOL);
return;
}
-
+
+ if(argc() > 2 && argv(2) === 'reset') {
+ del_pconfig(local_channel(),'system','mod_' . argv(1) . '.pdl');
+ goaway(z_root() . '/pdledit');
+ }
+
if(argc() > 1)
$module = 'mod_' . argv(1) . '.pdl';
else {
$o .= '<div class="generic-content-wrapper-styled">';
$o .= '<h1>' . t('Edit System Page Description') . '</h1>';
+
+ $edited = [];
+
+ $r = q("select k from pconfig where uid = %d and cat = 'system' and k like '%s' ",
+ intval(local_channel()),
+ dbesc('mod_%.pdl')
+ );
+
+ if($r) {
+ foreach($r as $rv) {
+ $edited[] = substr(str_replace('.pdl','',$rv['k']),4);
+ }
+ }
+
$files = glob('Zotlabs/Module/*.php');
if($files) {
foreach($files as $f) {
$name = lcfirst(basename($f,'.php'));
$x = theme_include('mod_' . $name . '.pdl');
if($x) {
- $o .= '<a href="pdledit/' . $name . '" >' . $name . '</a><br />';
+ $o .= '<a href="pdledit/' . $name . '" >' . $name . '</a>' . ((in_array($name,$edited)) ? ' ' . t('(modified)') . ' <a href="pdledit/' . $name . '/reset" >' . t('Reset') . '</a>': '' ) . '<br />';
}
}
}
@@ -69,6 +88,7 @@ class Pdledit extends \Zotlabs\Web\Controller {
'$header' => t('Edit System Page Description'),
'$mname' => t('Module Name:'),
'$help' => t('Layout Help'),
+ '$another' => t('Edit another layout'),
'$module' => argv(1),
'$content' => htmlspecialchars($t,ENT_COMPAT,'UTF-8'),
'$submit' => t('Submit')
diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php
index 256a51e71..8a110f925 100644
--- a/Zotlabs/Module/Photo.php
+++ b/Zotlabs/Module/Photo.php
@@ -127,7 +127,6 @@ class Photo extends \Zotlabs\Web\Controller {
}
}
-
$r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo),
intval($resolution)
@@ -150,12 +149,16 @@ class Photo extends \Zotlabs\Web\Controller {
$channel = channelx_by_n($r[0]['uid']);
// Now we'll see if we can access the photo
-
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1",
dbesc($photo),
intval($resolution)
);
-
+
+ // viewing cover photos is allowed unless a plugin chooses to block it.
+
+ if($r && intval($r[0]['photo_usage']) === PHOTO_COVER && $resolution >= PHOTO_RES_COVER_1200)
+ $allowed = 1;
+
$d = [ 'imgscale' => $resolution, 'resource_id' => $photo, 'photo' => $r, 'allowed' => $allowed ];
call_hooks('get_photo',$d);
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 582174d0e..caef45d98 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -15,13 +15,10 @@ class Photos extends \Zotlabs\Web\Controller {
function init() {
-
if(observer_prohibited()) {
return;
}
- $o = '';
-
if(argc() > 1) {
$nick = argv(1);
@@ -54,7 +51,6 @@ class Photos extends \Zotlabs\Web\Controller {
logger('mod-photos: photos_post: begin' , LOGGER_DEBUG);
-
logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA);
logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA);
@@ -92,14 +88,9 @@ class Photos extends \Zotlabs\Web\Controller {
if((argc() > 3) && (argv(2) === 'album')) {
- $album = hex2bin(argv(3));
-
- if($album === t('Profile Photos')) {
- // not allowed
- goaway(z_root() . '/' . $_SESSION['photo_return']);
- }
-
- if(! photos_album_exists($page_owner_uid,$album)) {
+ $album = argv(3);
+
+ if(! photos_album_exists($page_owner_uid, get_observer_hash(), $album)) {
notice( t('Album not found.') . EOL);
goaway(z_root() . '/' . $_SESSION['photo_return']);
}
@@ -121,7 +112,7 @@ class Photos extends \Zotlabs\Web\Controller {
$folder_hash = '';
- $r = q("select * from attach where is_dir = 1 and uid = %d and filename = '%s'",
+ $r = q("select * from attach where is_dir = 1 and uid = %d and hash = '%s'",
intval($page_owner_uid),
dbesc($album)
);
@@ -129,14 +120,7 @@ class Photos extends \Zotlabs\Web\Controller {
notice( t('Album not found.') . EOL);
return;
}
- if(count($r) > 1) {
- notice( t('Multiple storage folders exist with this album name, but within different directories. Please remove the desired folder or folders using the Files manager') . EOL);
- return;
- }
- else {
- $folder_hash = $r[0]['hash'];
- }
-
+ $folder_hash = $r[0]['hash'];
$res = array();
@@ -468,7 +452,7 @@ class Photos extends \Zotlabs\Web\Controller {
* default post action - upload a photo
*/
- $channel = \App::$data['channel'];
+ $channel = \App::$data['channel'];
$observer = \App::$data['observer'];
$_REQUEST['source'] = 'photos';
@@ -485,12 +469,10 @@ class Photos extends \Zotlabs\Web\Controller {
if(! $r['success']) {
notice($r['message'] . EOL);
+ goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']);
}
-
- if($_REQUEST['newalbum'])
- goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($_REQUEST['newalbum']));
- else
- goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex(datetime_convert('UTC',date_default_timezone_get(),'now', 'Y')));
+
+ goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $r['data']['folder']);
}
@@ -569,7 +551,11 @@ class Photos extends \Zotlabs\Web\Controller {
return;
}
- $sql_extra = permissions_sql($owner_uid);
+ $sql_item = item_permissions_sql($owner_uid,get_observer_hash());
+ $sql_extra = permissions_sql($owner_uid,get_observer_hash(),'photo');
+ $sql_attach = permissions_sql($owner_uid,get_observer_hash(),'attach');
+
+ nav_set_selected('Photos');
$o = "";
@@ -579,7 +565,7 @@ class Photos extends \Zotlabs\Web\Controller {
// tabs
$_is_owner = (local_channel() && (local_channel() == $owner_uid));
- $o .= profile_tabs($a,$_is_owner, \App::$data['channel']['channel_address']);
+ //$o .= profile_tabs($a,$_is_owner, \App::$data['channel']['channel_address']);
/**
* Display upload form
@@ -628,8 +614,14 @@ class Photos extends \Zotlabs\Web\Controller {
if(! $aclselect) {
$aclselect = '<input id="group_allow" type="hidden" name="allow_gid[]" value="" /><input id="contact_allow" type="hidden" name="allow_cid[]" value="" /><input id="group_deny" type="hidden" name="deny_gid[]" value="" /><input id="contact_deny" type="hidden" name="deny_cid[]" value="" />';
}
-
- $selname = (($datum) ? hex2bin($datum) : '');
+
+ $selname = '';
+
+ if($datum) {
+ $h = attach_by_hash_nodata($datum,get_observer_hash());
+ $selname = $h['data']['display_path'];
+ }
+
$albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer']));
@@ -679,30 +671,19 @@ class Photos extends \Zotlabs\Web\Controller {
*/
if($datatype === 'album') {
-
- if(strlen($datum)) {
- if((strlen($datum) & 1) || (! ctype_xdigit($datum))) {
- notice( t('Album name could not be decoded') . EOL);
- logger('mod_photos: illegal album encoding: ' . $datum);
- $datum = '';
- goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']);
- }
- }
-
- $album = (($datum) ? hex2bin($datum) : '');
-
- \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
- //check if the album exists and if we have perms
- $r = q("SELECT album FROM photo WHERE uid = %d AND album = '%s' and is_nsfw = %d $sql_extra LIMIT 1",
- intval($owner_uid),
- dbesc($album),
- intval($unsafe)
- );
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
- if($r) {
+ if($x = photos_album_exists($owner_uid, get_observer_hash(), $datum)) {
\App::set_pager_itemspage(60);
- } else {
+ $album = $x['display_path'];
+ }
+ else {
goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']);
}
@@ -712,26 +693,26 @@ class Photos extends \Zotlabs\Web\Controller {
$order = 'DESC';
$r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
- (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph
+ (SELECT resource_id, max(imgscale) imgscale FROM photo left join attach on folder = '%s' and photo.resource_id = attach.hash WHERE attach.uid = %d AND imgscale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph
ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
ORDER BY created $order LIMIT %d OFFSET %d",
+ dbesc($x['hash']),
intval($owner_uid),
- dbesc($album),
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval($unsafe),
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
);
-
- //edit album name
+
+ // edit album name
$album_edit = null;
- if(($album !== t('Profile Photos')) && ($album !== 'Profile Photos') && ($album !== 'Contact Photos') && ($album !== t('Contact Photos'))) {
- if($can_post) {
- $album_e = $album;
- $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer']));
+
+ if($can_post) {
+ $album_e = $album;
+ $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer']));
- // @fixme - syncronise actions with DAV
+ // @fixme - syncronise actions with DAV
// $edit_tpl = get_markup_template('album_edit.tpl');
// $album_edit = replace_macros($edit_tpl,array(
@@ -745,13 +726,12 @@ class Photos extends \Zotlabs\Web\Controller {
// '$dropsubmit' => t('Delete Album')
// ));
- }
}
if($_GET['order'] === 'posted')
- $order = array(t('Show Newest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($album));
+ $order = array(t('Show Newest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $datum);
else
- $order = array(t('Show Oldest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($album) . '?f=&order=posted');
+ $order = array(t('Show Oldest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $datum . '?f=&order=posted');
$photos = array();
if(count($r)) {
@@ -790,7 +770,7 @@ class Photos extends \Zotlabs\Web\Controller {
if($photos) {
$o = replace_macros(get_markup_template('photosajax.tpl'),array(
'$photos' => $photos,
- '$album_id' => bin2hex($album)
+ '$album_id' => $datum
));
}
else {
@@ -805,10 +785,10 @@ class Photos extends \Zotlabs\Web\Controller {
$o .= replace_macros($tpl, array(
'$photos' => $photos,
'$album' => $album,
- '$album_id' => bin2hex($album),
+ '$album_id' => $datum,
'$album_edit' => array(t('Edit Album'), $album_edit),
'$can_post' => $can_post,
- '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/upload/' . bin2hex($album)),
+ '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/upload/' . $datum),
'$order' => $order,
'$upload_form' => $upload_form,
'$usage' => $usage_message
@@ -822,8 +802,6 @@ class Photos extends \Zotlabs\Web\Controller {
killme();
}
- // $o .= paginate($a);
-
return $o;
}
@@ -836,6 +814,11 @@ class Photos extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
+ $x = q("select folder from attach where hash = '%s' and uid = %d $sql_attach limit 1",
+ dbesc($datum),
+ intval($owner_uid)
+ );
+
// fetch image, item containing image, then comments
$ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM photo WHERE uid = %d AND resource_id = '%s'
@@ -844,7 +827,7 @@ class Photos extends \Zotlabs\Web\Controller {
dbesc($datum)
);
- if(! $ph) {
+ if(! ($ph && $x)) {
/* Check again - this time without specifying permissions */
@@ -869,16 +852,16 @@ class Photos extends \Zotlabs\Web\Controller {
else
$order = 'DESC';
-
- $prvnxt = q("SELECT resource_id FROM photo WHERE album = '%s' AND uid = %d AND imgscale = 0
- $sql_extra ORDER BY created $order ",
- dbesc($ph[0]['album']),
+
+ $prvnxt = q("SELECT hash FROM attach WHERE folder = '%s' AND uid = %d AND is_photo = 1
+ $sql_attach ORDER BY created $order ",
+ dbesc($x[0]['folder']),
intval($owner_uid)
);
-
+
if(count($prvnxt)) {
for($z = 0; $z < count($prvnxt); $z++) {
- if($prvnxt[$z]['resource_id'] == $ph[0]['resource_id']) {
+ if($prvnxt[$z]['hash'] == $ph[0]['resource_id']) {
$prv = $z - 1;
$nxt = $z + 1;
if($prv < 0)
@@ -889,8 +872,8 @@ class Photos extends \Zotlabs\Web\Controller {
}
}
- $prevlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '');
- $nextlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '');
+ $prevlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['hash'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '');
+ $nextlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['hash'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '');
}
@@ -907,7 +890,7 @@ class Photos extends \Zotlabs\Web\Controller {
}
}
- $album_link = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($ph[0]['album']);
+ $album_link = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $x[0]['folder'];
$tools = Null;
$lock = Null;
@@ -947,7 +930,7 @@ class Photos extends \Zotlabs\Web\Controller {
// Do we have an item for this photo?
$linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo'
- $sql_extra LIMIT 1",
+ $sql_item LIMIT 1",
dbesc($datum)
);
@@ -962,7 +945,7 @@ class Photos extends \Zotlabs\Web\Controller {
$item_normal = item_normal();
$r = q("select * from item where parent_mid = '%s'
- $item_normal and uid = %d $sql_extra ",
+ $item_normal and uid = %d $sql_item ",
dbesc($link_item['mid']),
intval($link_item['uid'])
@@ -1008,13 +991,6 @@ class Photos extends \Zotlabs\Web\Controller {
$edit = null;
if($can_post) {
- $m = q("select folder from attach where hash = '%s' and uid = %d limit 1",
- dbesc($ph[0]['resource_id']),
- intval($ph[0]['uid'])
- );
- if($m)
- $album_hash = $m[0]['folder'];
-
$album_e = $ph[0]['album'];
$caption_e = $ph[0]['description'];
$aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : '');
@@ -1024,35 +1000,35 @@ class Photos extends \Zotlabs\Web\Controller {
$folder_list = attach_folder_select_list($ph[0]['uid']);
- $edit = array(
+ $edit = [
'edit' => t('Edit photo'),
'id' => $link_item['id'],
- 'rotatecw' => t('Rotate CW (right)'),
- 'rotateccw' => t('Rotate CCW (left)'),
- 'albums' => $albums['albums'],
- 'album' => $album_e,
- 'album_select' => [ 'move_to_album', t('Move photo to album'), $album_hash, '', $folder_list ],
- 'newalbum_label' => t('Enter a new album name'),
+ 'rotatecw' => t('Rotate CW (right)'),
+ 'rotateccw' => t('Rotate CCW (left)'),
+ 'albums' => $albums['albums'],
+ 'album' => $album_e,
+ 'album_select' => [ 'move_to_album', t('Move photo to album'), $x[0]['folder'], '', $folder_list ],
+ 'newalbum_label' => t('Enter a new album name'),
'newalbum_placeholder' => t('or select an existing one (doubleclick)'),
- 'nickname' => \App::$data['channel']['channel_address'],
- 'resource_id' => $ph[0]['resource_id'],
- 'capt_label' => t('Caption'),
- 'caption' => $caption_e,
- 'tag_label' => t('Add a Tag'),
- 'permissions' => t('Permissions'),
- 'aclselect' => $aclselect_e,
- 'allow_cid' => acl2json($ph[0]['allow_cid']),
- 'allow_gid' => acl2json($ph[0]['allow_gid']),
- 'deny_cid' => acl2json($ph[0]['deny_cid']),
- 'deny_gid' => acl2json($ph[0]['deny_gid']),
- 'lockstate' => $lockstate[0],
- 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com'),
- 'item_id' => ((count($linked_items)) ? $link_item['id'] : 0),
- 'adult_enabled' => feature_enabled($owner_uid,'adult_photo_flagging'),
- 'adult' => array('adult',t('Flag as adult in album view'), intval($ph[0]['is_nsfw']),''),
- 'submit' => t('Submit'),
- 'delete' => t('Delete Photo')
- );
+ 'nickname' => \App::$data['channel']['channel_address'],
+ 'resource_id' => $ph[0]['resource_id'],
+ 'capt_label' => t('Caption'),
+ 'caption' => $caption_e,
+ 'tag_label' => t('Add a Tag'),
+ 'permissions' => t('Permissions'),
+ 'aclselect' => $aclselect_e,
+ 'allow_cid' => acl2json($ph[0]['allow_cid']),
+ 'allow_gid' => acl2json($ph[0]['allow_gid']),
+ 'deny_cid' => acl2json($ph[0]['deny_cid']),
+ 'deny_gid' => acl2json($ph[0]['deny_gid']),
+ 'lockstate' => $lockstate[0],
+ 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com'),
+ 'item_id' => ((count($linked_items)) ? $link_item['id'] : 0),
+ 'adult_enabled' => feature_enabled($owner_uid,'adult_photo_flagging'),
+ 'adult' => array('adult',t('Flag as adult in album view'), intval($ph[0]['is_nsfw']),''),
+ 'submit' => t('Submit'),
+ 'delete' => t('Delete Photo')
+ ];
}
if(count($linked_items)) {
@@ -1065,19 +1041,19 @@ class Photos extends \Zotlabs\Web\Controller {
$likebuttons = '';
- if($can_post || $can_comment) {
- $likebuttons = array(
- 'id' => $link_item['id'],
+ if($observer && ($can_post || $can_comment)) {
+ $likebuttons = [
+ 'id' => $link_item['id'],
'likethis' => t("I like this \x28toggle\x29"),
- 'nolike' => t("I don't like this \x28toggle\x29"),
- 'share' => t('Share'),
- 'wait' => t('Please wait')
- );
+ 'nolike' => t("I don't like this \x28toggle\x29"),
+ 'share' => t('Share'),
+ 'wait' => t('Please wait')
+ ];
}
$comments = '';
if(! count($r)) {
- if($can_post || $can_comment) {
+ if($observer && ($can_post || $can_comment)) {
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
'$mode' => 'photos',
@@ -1196,7 +1172,7 @@ class Photos extends \Zotlabs\Web\Controller {
}
- if($can_post || $can_comment) {
+ if($observer && ($can_post || $can_comment)) {
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
'$jsreload' => $return_url,
@@ -1277,25 +1253,13 @@ class Photos extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
- /*
- $r = q("SELECT resource_id, max(imgscale) AS imgscale FROM photo WHERE uid = %d
- and photo_usage in ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id",
- intval(\App::$data['channel']['channel_id']),
- intval(PHOTO_NORMAL),
- intval(PHOTO_PROFILE),
- intval($unsafe)
- );
- if($r) {
- \App::set_pager_total(count($r));
- \App::set_pager_itemspage(60);
- }
- */
\App::set_pager_itemspage(60);
- $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created FROM photo p
+ $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created, p.display_path
+ FROM photo p
INNER JOIN ( SELECT resource_id, max(imgscale) imgscale FROM photo
- WHERE uid = %d AND photo_usage IN ( %d, %d )
+ WHERE photo.uid = %d AND photo_usage IN ( %d, %d )
AND is_nsfw = %d $sql_extra group by resource_id ) ph
ON (p.resource_id = ph.resource_id and p.imgscale = ph.imgscale)
ORDER by p.created DESC LIMIT %d OFFSET %d",
@@ -1313,21 +1277,19 @@ class Photos extends \Zotlabs\Web\Controller {
if($r) {
$twist = 'rotright';
foreach($r as $rr) {
+
+ if(! attach_can_view_folder(\App::$data['channel']['channel_id'],get_observer_hash(),$rr['resource_id']))
+ continue;
+
if($twist == 'rotright')
$twist = 'rotleft';
else
$twist = 'rotright';
$ext = $phototypes[$rr['mimetype']];
- if(\App::get_template_engine() === 'internal') {
- $alt_e = template_escape($rr['filename']);
- $name_e = template_escape($rr['album']);
- }
- else {
- $alt_e = $rr['filename'];
- $name_e = $rr['album'];
- }
-
+ $alt_e = $rr['filename'];
+ $name_e = dirname($rr['display_path']);
+
$photos[] = array(
'id' => $rr['id'],
'twist' => ' ' . $twist . rand(2,4),
@@ -1336,9 +1298,7 @@ class Photos extends \Zotlabs\Web\Controller {
'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['imgscale']) == 6) ? 4 : $rr['imgscale']) . '.' . $ext,
'alt' => $alt_e,
'album' => array(
- 'link' => z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($rr['album']),
'name' => $name_e,
- 'alt' => t('View Album'),
),
);
diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php
index bf2fa5cc9..c91659f2f 100644
--- a/Zotlabs/Module/Ping.php
+++ b/Zotlabs/Module/Ping.php
@@ -19,6 +19,7 @@ class Ping extends \Zotlabs\Web\Controller {
* @result JSON
*/
function init() {
+
$result = array();
$notifs = array();
@@ -36,6 +37,11 @@ class Ping extends \Zotlabs\Web\Controller {
$result['all_events_today'] = 0;
$result['notice'] = array();
$result['info'] = array();
+ $result['pubs'] = 0;
+ $result['files'] = 0;
+
+ if(! $_SESSION['static_loadtime'])
+ $_SESSION['static_loadtime'] = datetime_convert();
$t0 = dba_timer();
@@ -134,6 +140,61 @@ class Ping extends \Zotlabs\Web\Controller {
db_utcnow(), db_quoteinterval('3 MINUTE')
);
+ $discover_tab_on = ((get_config('system','disable_discover_tab') != 1) ? true : false);
+ $notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on);
+
+ if($notify_pubs) {
+ $sys = get_sys_channel();
+
+ $pubs = q("SELECT count(id) as total from item
+ WHERE uid = %d
+ AND author_xchan != '%s'
+ AND obj_type != '%s'
+ AND item_unseen = 1
+ AND created > '" . datetime_convert('UTC','UTC',$_SESSION['static_loadtime']) . "'
+ $item_normal",
+ intval($sys['channel_id']),
+ dbesc(get_observer_hash()),
+ dbesc(ACTIVITY_OBJ_FILE)
+ );
+
+ if($pubs)
+ $result['pubs'] = intval($pubs[0]['total']);
+ }
+
+ if((argc() > 1) && (argv(1) === 'pubs') && ($notify_pubs)) {
+ $sys = get_sys_channel();
+ $result = array();
+
+ $r = q("SELECT * FROM item
+ WHERE uid = %d
+ AND author_xchan != '%s'
+ AND obj_type != '%s'
+ AND item_unseen = 1
+ AND created > '" . datetime_convert('UTC','UTC',$_SESSION['static_loadtime']) . "'
+ $item_normal
+ ORDER BY created DESC
+ LIMIT 300",
+ intval($sys['channel_id']),
+ dbesc(get_observer_hash()),
+ dbesc(ACTIVITY_OBJ_FILE)
+ );
+
+ if($r) {
+ xchan_query($r);
+ foreach($r as $rr) {
+ $rr['llink'] = str_replace('display/', 'pubstream/?f=&mid=', $rr['llink']);
+ $result[] = \Zotlabs\Lib\Enotify::format($rr);
+ }
+ }
+
+// logger('ping (network||home): ' . print_r($result, true), LOGGER_DATA);
+ echo json_encode(array('notify' => $result));
+ killme();
+ }
+
+ $t1 = dba_timer();
+
if((! local_channel()) || ($result['invalid'])) {
echo json_encode($result);
killme();
@@ -177,6 +238,9 @@ class Ping extends \Zotlabs\Web\Controller {
intval(local_channel())
);
break;
+ case 'pubs':
+ unset($_SESSION['static_loadtime']);
+ break;
default:
break;
}
@@ -194,37 +258,20 @@ class Ping extends \Zotlabs\Web\Controller {
* dropdown menu.
*/
if(argc() > 1 && argv(1) === 'notify') {
- $t = q("select count(*) as total from notify where uid = %d and seen = 0",
+ $t = q("select * from notify where uid = %d and seen = 0 order by created desc",
intval(local_channel())
);
- if($t && intval($t[0]['total']) > 49) {
- $z = q("select * from notify where uid = %d
- and seen = 0 order by created desc limit 50",
- intval(local_channel())
- );
- } else {
- $z1 = q("select * from notify where uid = %d
- and seen = 0 order by created desc limit 50",
- intval(local_channel())
- );
- $z2 = q("select * from notify where uid = %d
- and seen = 1 order by created desc limit %d",
- intval(local_channel()),
- intval(50 - intval($t[0]['total']))
- );
- $z = array_merge($z1,$z2);
- }
- if(count($z)) {
- foreach($z as $zz) {
+ if($t) {
+ foreach($t as $tt) {
$notifs[] = array(
- 'notify_link' => z_root() . '/notify/view/' . $zz['id'],
- 'name' => $zz['xname'],
- 'url' => $zz['url'],
- 'photo' => $zz['photo'],
- 'when' => relative_date($zz['created']),
- 'hclass' => (($zz['seen']) ? 'notify-seen' : 'notify-unseen'),
- 'message' => strip_tags(bbcode($zz['msg']))
+ 'notify_link' => z_root() . '/notify/view/' . $tt['id'],
+ 'name' => $tt['xname'],
+ 'url' => $tt['url'],
+ 'photo' => $tt['photo'],
+ 'when' => relative_date($tt['created']),
+ 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
+ 'message' => strip_tags(bbcode($tt['msg']))
);
}
}
@@ -233,7 +280,7 @@ class Ping extends \Zotlabs\Web\Controller {
killme();
}
- if(argc() > 1 && argv(1) === 'messages') {
+ if(argc() > 1 && argv(1) === 'mail') {
$channel = \App::get_channel();
$t = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan
where channel_id = %d and mail_seen = 0 and mail_deleted = 0
@@ -265,9 +312,12 @@ class Ping extends \Zotlabs\Web\Controller {
$r = q("SELECT * FROM item
WHERE item_unseen = 1 and uid = %d $item_normal
- and author_xchan != '%s' ORDER BY created DESC limit 300",
+ AND author_xchan != '%s'
+ AND obj_type != '%s'
+ ORDER BY created DESC limit 300",
intval(local_channel()),
- dbesc($ob_hash)
+ dbesc($ob_hash),
+ dbesc(ACTIVITY_OBJ_FILE)
);
if($r) {
@@ -308,6 +358,30 @@ class Ping extends \Zotlabs\Web\Controller {
killme();
}
+ if((argc() > 1 && (argv(1) === 'register')) && is_site_admin()) {
+ $result = array();
+
+ $r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0",
+ intval(ACCOUNT_PENDING)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $result[] = array(
+ 'notify_link' => z_root() . '/admin/accounts',
+ 'name' => $rr['account_email'],
+ 'url' => '',
+ 'photo' => get_default_profile_photo(48),
+ 'when' => relative_date($rr['account_created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('requires approval')
+ );
+ }
+ }
+ logger('ping (register): ' . print_r($result, true), LOGGER_DATA);
+ echo json_encode(array('notify' => $result));
+ killme();
+ }
+
if(argc() > 1 && (argv(1) === 'all_events')) {
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
@@ -345,6 +419,39 @@ class Ping extends \Zotlabs\Web\Controller {
killme();
}
+ if(argc() > 1 && (argv(1) === 'files')) {
+ $result = array();
+
+ $r = q("SELECT item.created, xchan.xchan_name, xchan.xchan_url, xchan.xchan_photo_s FROM item
+ LEFT JOIN xchan on author_xchan = xchan_hash
+ WHERE item.verb = '%s'
+ AND item.obj_type = '%s'
+ AND item.uid = %d
+ AND item.owner_xchan != '%s'
+ AND item.item_unseen = 1",
+ dbesc(ACTIVITY_POST),
+ dbesc(ACTIVITY_OBJ_FILE),
+ intval(local_channel()),
+ dbesc($ob_hash)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $result[] = array(
+ 'notify_link' => z_root() . '/sharedwithme',
+ 'name' => $rr['xchan_name'],
+ 'url' => $rr['xchan_url'],
+ 'photo' => $rr['xchan_photo_s'],
+ 'when' => relative_date($rr['created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('shared a file with you')
+ );
+ }
+ }
+ logger('ping (files): ' . print_r($result, true), LOGGER_DATA);
+ echo json_encode(array('notify' => $result));
+ killme();
+ }
+
/**
* Normal ping - just the counts, no detail
*/
@@ -356,15 +463,35 @@ class Ping extends \Zotlabs\Web\Controller {
$result['notify'] = intval($t[0]['total']);
}
- $t1 = dba_timer();
+ $t2 = dba_timer();
+
+ if($vnotify & VNOTIFY_FILES) {
+ $files = q("SELECT count(id) as total FROM item
+ WHERE verb = '%s'
+ AND obj_type = '%s'
+ AND uid = %d
+ AND owner_xchan != '%s'
+ AND item_unseen = 1",
+ dbesc(ACTIVITY_POST),
+ dbesc(ACTIVITY_OBJ_FILE),
+ intval(local_channel()),
+ dbesc($ob_hash)
+ );
+ if($files)
+ $result['files'] = intval($files[0]['total']);
+ }
+
+ $t3 = dba_timer();
if($vnotify & (VNOTIFY_NETWORK|VNOTIFY_CHANNEL)) {
$r = q("SELECT id, item_wall FROM item
WHERE item_unseen = 1 and uid = %d
$item_normal
- and author_xchan != '%s'",
+ AND author_xchan != '%s'
+ AND obj_type != '%s'",
intval(local_channel()),
- dbesc($ob_hash)
+ dbesc($ob_hash),
+ dbesc(ACTIVITY_OBJ_FILE)
);
if($r) {
@@ -384,20 +511,20 @@ class Ping extends \Zotlabs\Web\Controller {
if(! ($vnotify & VNOTIFY_CHANNEL))
$result['home'] = 0;
- $t2 = dba_timer();
+ $t4 = dba_timer();
if($vnotify & VNOTIFY_INTRO) {
$intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
intval(local_channel())
);
- $t3 = dba_timer();
+ $t5 = dba_timer();
if($intr)
$result['intros'] = intval($intr[0]['total']);
}
- $t4 = dba_timer();
+ $t6 = dba_timer();
$channel = \App::get_channel();
if($vnotify & VNOTIFY_MAIL) {
@@ -420,7 +547,7 @@ class Ping extends \Zotlabs\Web\Controller {
}
}
- $t5 = dba_timer();
+ $t7 = dba_timer();
if($vnotify & (VNOTIFY_EVENT|VNOTIFY_EVENTTODAY|VNOTIFY_BIRTHDAY)) {
$events = q("SELECT etype, dtstart, adjust FROM event
@@ -466,9 +593,9 @@ class Ping extends \Zotlabs\Web\Controller {
$x = json_encode($result);
- $t6 = dba_timer();
+ $t8 = dba_timer();
-// logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0));
+// logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t8 - $t7, $t7 - $t6, $t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0));
echo $x;
killme();
diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php
index cf8d83023..d13ec5ced 100644
--- a/Zotlabs/Module/Poke.php
+++ b/Zotlabs/Module/Poke.php
@@ -41,7 +41,10 @@ class Poke extends \Zotlabs\Web\Controller {
$activity = ACTIVITY_POKE . '#' . urlencode($verbs[$verb][0]);
$contact_id = intval($_REQUEST['cid']);
- if(! $contact_id)
+
+ $xchan = trim($_REQUEST['xchan']);
+
+ if(! ($contact_id || $xchan))
return;
$parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
@@ -49,13 +52,20 @@ class Poke extends \Zotlabs\Web\Controller {
logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG);
- $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1",
- intval($contact_id),
- intval($uid)
- );
-
+ if($contact_id) {
+ $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1",
+ intval($contact_id),
+ intval($uid)
+ );
+ }
+ if($xchan) {
+ $r = q("SELECT * FROM xchan where xchan_hash like ( '%s' ) LIMIT 1",
+ dbesc($xchan . '%')
+ );
+ }
+
if(! $r) {
- logger('poke: no target ' . $contact_id);
+ logger('poke: no target.');
return;
}
@@ -79,7 +89,7 @@ class Poke extends \Zotlabs\Web\Controller {
$deny_gid = $r[0]['deny_gid'];
}
}
- else {
+ elseif($contact_id) {
$item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0);
@@ -92,9 +102,11 @@ class Poke extends \Zotlabs\Web\Controller {
$arr = array();
+
+
$arr['item_wall'] = 1;
$arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']);
- $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid);
+ $arr['parent_mid'] = (($parent_mid) ? $parent_mid : '');
$arr['title'] = '';
$arr['allow_cid'] = $allow_cid;
$arr['allow_gid'] = $allow_gid;
@@ -131,12 +143,14 @@ class Poke extends \Zotlabs\Web\Controller {
- function get() {
+ function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
+
+ nav_set_selected('Poke');
$name = '';
$id = '';
diff --git a/Zotlabs/Module/Post.php b/Zotlabs/Module/Post.php
index c78484a45..f67cbf020 100644
--- a/Zotlabs/Module/Post.php
+++ b/Zotlabs/Module/Post.php
@@ -19,16 +19,16 @@ class Post extends \Zotlabs\Web\Controller {
function init() {
if(array_key_exists('auth', $_REQUEST)) {
$x = new \Zotlabs\Zot\Auth($_REQUEST);
-
exit;
}
}
function post() {
- $z = new \Zotlabs\Zot\Receiver($_REQUEST['data'], get_config('system', 'prvkey'), new \Zotlabs\Zot\ZotHandler());
+ if(array_key_exists('data',$_REQUEST)) {
+ $z = new \Zotlabs\Zot\Receiver($_REQUEST['data'], get_config('system', 'prvkey'), new \Zotlabs\Zot\ZotHandler());
+ exit;
+ }
- // notreached;
- exit;
}
}
diff --git a/Zotlabs/Module/Probe.php b/Zotlabs/Module/Probe.php
index 7fc0e8ff5..2e65f107c 100644
--- a/Zotlabs/Module/Probe.php
+++ b/Zotlabs/Module/Probe.php
@@ -7,7 +7,9 @@ require_once('include/zot.php');
class Probe extends \Zotlabs\Web\Controller {
function get() {
-
+
+ nav_set_selected('Remote Diagnostics');
+
$o .= '<h3>Probe Diagnostic</h3>';
$o .= '<form action="probe" method="get">';
diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php
index 0bc23952b..43106e3af 100644
--- a/Zotlabs/Module/Profile.php
+++ b/Zotlabs/Module/Profile.php
@@ -21,6 +21,8 @@ class Profile extends \Zotlabs\Web\Controller {
\App::$error = 404;
return;
}
+
+ nav_set_selected('Profile');
$profile = '';
$channel = \App::get_channel();
@@ -37,8 +39,21 @@ class Profile extends \Zotlabs\Web\Controller {
$profile = $r[0]['profile_guid'];
}
- \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which .'" />' . "\r\n" ;
-
+ head_add_link( [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'title' => t('Posts and comments'),
+ 'href' => z_root() . '/feed/' . $which
+ ]);
+
+ head_add_link( [
+ 'rel' => 'alternate',
+ 'type' => 'application/atom+xml',
+ 'title' => t('Only posts'),
+ 'href' => z_root() . '/feed/' . $which . '?f=&top=1'
+ ]);
+
+
if(! $profile) {
$x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1",
dbesc(argv(1))
@@ -79,7 +94,6 @@ class Profile extends \Zotlabs\Web\Controller {
echo \App::$profile['profile_vcard'];
killme();
}
-
$is_owner = ((local_channel()) && (local_channel() == \App::$profile['profile_uid']) ? true : false);
@@ -87,11 +101,14 @@ class Profile extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
-
- $o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
-
- \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string) . '" title="oembed" />' . "\r\n";
-
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
$o .= advanced_profile($a);
call_hooks('profile_advanced',$o);
return $o;
diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php
index 29a239f4d..27e6bc445 100644
--- a/Zotlabs/Module/Profile_photo.php
+++ b/Zotlabs/Module/Profile_photo.php
@@ -108,11 +108,13 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$aid = get_account_id();
$p = [
- 'aid' => $aid,
- 'uid' => local_channel(),
- 'resource_id' => $base_image['resource_id'],
- 'filename' => $base_image['filename'],
- 'album' => t('Profile Photos')
+ 'aid' => $aid,
+ 'uid' => local_channel(),
+ 'resource_id' => $base_image['resource_id'],
+ 'filename' => $base_image['filename'],
+ 'album' => t('Profile Photos'),
+ 'os_path' => $base_image['os_path'],
+ 'display_path' => $base_image['display_path']
];
$p['imgscale'] = PHOTO_RES_PROFILE_300;
@@ -156,6 +158,9 @@ class Profile_photo extends \Zotlabs\Web\Controller {
intval(local_channel())
);
+
+
+
send_profile_photo_activity($channel,$base_image,$profile);
}
@@ -172,19 +177,28 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// We'll set the updated profile-photo timestamp even if it isn't the default profile,
// so that browsers will do a cache update unconditionally
+ // Also set links back to site-specific profile photo url in case it was
+ // changed to a generic URL by a clone operation. Otherwise the new photo may
+ // not get pushed to other sites correctly.
-
- $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s'
+ $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s'
where xchan_hash = '%s'",
dbesc($im->getType()),
dbesc(datetime_convert()),
+ dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']),
dbesc($channel['xchan_hash'])
);
photo_profile_setperms(local_channel(),$base_image['resource_id'],$_REQUEST['profile']);
+ $sync = attach_export_data($channel,$base_image['resource_id']);
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
- // Similarly, tell the nav bar to bypass the cache and update the avater image.
+
+ // Similarly, tell the nav bar to bypass the cache and update the avatar image.
$_SESSION['reload_avatar'] = true;
info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
@@ -341,6 +355,11 @@ class Profile_photo extends \Zotlabs\Web\Controller {
photo_profile_setperms(local_channel(),$resource_id,$_REQUEST['profile']);
+ $sync = attach_export_data($channel,$resource_id);
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+
+
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
goaway(z_root() . '/profiles');
}
diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php
index 32e888f14..b1cf9596c 100644
--- a/Zotlabs/Module/Profiles.php
+++ b/Zotlabs/Module/Profiles.php
@@ -9,7 +9,7 @@ class Profiles extends \Zotlabs\Web\Controller {
function init() {
- nav_set_selected('profiles');
+ nav_set_selected('Profiles');
if(! local_channel()) {
return;
@@ -317,8 +317,10 @@ class Profiles extends \Zotlabs\Web\Controller {
$hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0);
+// start fresh and create a new vcard. TODO: preserve the original guid or whatever else needs saving
+// $orig_vcard = (($orig[0]['profile_vcard']) ? \Sabre\VObject\Reader::read($orig[0]['profile_vcard']) : null);
- $orig_vcard = (($orig[0]['profile_vcard']) ? \Sabre\VObject\Reader::read($orig[0]['profile_vcard']) : null);
+ $orig_vcard = null;
$channel = \App::get_channel();
@@ -330,13 +332,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'photo' => $channel['xchan_photo_l'],
'adr' => [],
'adr_type' => [ $default_vcard_cat ],
- 'tel' => [],
- 'tel_type' => [ $default_vcard_cat ],
- 'email' => [],
- 'email_type' => [ $default_vcard_cat ],
- 'impp' => [],
- 'impp_type' => [ $default_vcard_cat ],
- 'url' => [],
+ 'url' => [ $homepage ],
'url_type' => [ $default_vcard_cat ]
];
@@ -350,9 +346,12 @@ class Profiles extends \Zotlabs\Web\Controller {
6 => $country_name
];
-
$profile_vcard = update_vcard($defcard,$orig_vcard);
+ $orig_vcard = \Sabre\VObject\Reader::read($profile_vcard);
+
+ $profile_vcard = update_vcard($_REQUEST,$orig_vcard);
+
require_once('include/text.php');
linkify_tags($a, $likes, local_channel());
@@ -700,6 +699,10 @@ class Profiles extends \Zotlabs\Web\Controller {
}
//logger('extra_fields: ' . print_r($extra_fields,true));
+
+ $vc = $r[0]['profile_vcard'];
+ $vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null);
+ $vcard = (($vctmp) ? get_vcard_array($vctmp,$r[0]['id']) : [] );
$f = get_config('system','birthday_input_format');
if(! $f)
@@ -717,6 +720,7 @@ class Profiles extends \Zotlabs\Web\Controller {
. get_form_security_token("profile_drop"),
'$fields' => $fields,
+ '$vcard' => $vcard,
'$guid' => $r[0]['profile_guid'],
'$banner' => t('Edit Profile Details'),
'$submit' => t('Submit'),
@@ -776,11 +780,28 @@ class Profiles extends \Zotlabs\Web\Controller {
'$film' => array('film', t('Film/Dance/Culture/Entertainment'), $r[0]['film']),
'$interest' => array('interest', t('Hobbies/Interests'), $r[0]['interest']),
'$romance' => array('romance',t('Love/Romance'), $r[0]['romance']),
- '$work' => array('work', t('Work/Employment'), $r[0]['employment']),
+ '$employ' => array('work', t('Work/Employment'), $r[0]['employment']),
'$education' => array('education', t('School/Education'), $r[0]['education']),
'$contact' => array('contact', t('Contact information and social networks'), $r[0]['contact']),
'$channels' => array('channels', t('My other channels'), $r[0]['channels']),
'$extra_fields' => $extra_fields,
+ '$comms' => t('Communications'),
+ '$tel_label' => t('Phone'),
+ '$email_label' => t('Email'),
+ '$impp_label' => t('Instant messenger'),
+ '$url_label' => t('Website'),
+ '$adr_label' => t('Address'),
+ '$note_label' => t('Note'),
+ '$mobile' => t('Mobile'),
+ '$home' => t('Home'),
+ '$work' => t('Work'),
+ '$other' => t('Other'),
+ '$add_card' => t('Add Contact'),
+ '$add_field' => t('Add Field'),
+ '$create' => t('Create'),
+ '$update' => t('Update'),
+ '$delete' => t('Delete'),
+ '$cancel' => t('Cancel'),
));
$arr = array('profile' => $r[0], 'entry' => $o);
diff --git a/Zotlabs/Module/Pubsites.php b/Zotlabs/Module/Pubsites.php
index d87967189..ef02cf099 100644
--- a/Zotlabs/Module/Pubsites.php
+++ b/Zotlabs/Module/Pubsites.php
@@ -36,7 +36,8 @@ class Pubsites extends \Zotlabs\Web\Controller {
$o .= '</tr>';
if($j['sites']) {
foreach($j['sites'] as $jj) {
- if(! \Zotlabs\Lib\System::compatible_project($jj['project']))
+ $projectname = explode(' ',$jj['project']);
+ if(! \Zotlabs\Lib\System::compatible_project($projectname[0]))
continue;
if(strpos($jj['version'],' ')) {
$x = explode(' ', $jj['version']);
diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php
index 6c4d479d4..15e2d8a74 100644
--- a/Zotlabs/Module/Pubstream.php
+++ b/Zotlabs/Module/Pubstream.php
@@ -7,27 +7,40 @@ require_once('include/conversation.php');
class Pubstream extends \Zotlabs\Web\Controller {
function get($update = 0, $load = false) {
-
+
if($load)
$_SESSION['loadtime'] = datetime_convert();
-
+
if(observer_prohibited(true)) {
return login();
}
-
- if(get_config('system','disable_discover_tab'))
+ $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
+ if($disable_discover_tab)
return;
-
+
+ $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
+
+ if(strpos($mid,'b64.') === 0)
+ $decoded = @base64url_decode(substr($mid,4));
+ if($decoded)
+ $mid = $decoded;
+
$item_normal = item_normal();
+ $item_normal_update = item_normal_update();
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
- if(! $update) {
+ if(! $update && !$load) {
+
+ nav_set_selected(t('Public Stream'));
+
+ if(!$mid)
+ $_SESSION['static_loadtime'] = datetime_convert();
- $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0);
+ $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
$maxheight = get_config('system','home_divmore_height');
if(! $maxheight)
@@ -38,6 +51,10 @@ class Pubstream extends \Zotlabs\Web\Controller {
. "; var profile_page = " . \App::$pager['page']
. "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
+ //if we got a decoded hash we must encode it again before handing to javascript
+ if($decoded)
+ $mid = 'b64.' . base64url_encode($mid);
+
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
'$baseurl' => z_root(),
'$pgtype' => 'pubstream',
@@ -57,12 +74,13 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$static' => $static,
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$search' => '',
+ '$xchan' => '',
'$order' => 'comment',
'$file' => '',
'$cats' => '',
'$tags' => '',
'$dend' => '',
- '$mid' => '',
+ '$mid' => $mid,
'$verb' => '',
'$dbegin' => ''
));
@@ -104,7 +122,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$simple_update = '';
if($static && $simple_update)
- $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
+ $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
//logger('update: ' . $update . ' load: ' . $load);
@@ -113,29 +131,46 @@ class Pubstream extends \Zotlabs\Web\Controller {
$ordering = "commented";
if($load) {
-
- // Fetch a page full of parent items for this page
-
- $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE true $uids $item_normal
- AND item.parent = item.id
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets
- ORDER BY $ordering DESC $pager_sql "
- );
-
-
+ if($mid) {
+ $r = q("SELECT parent AS item_id FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE mid like '%s' $uids $item_normal
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets LIMIT 1",
+ dbesc($mid . '%')
+ );
+ }
+ else {
+ // Fetch a page full of parent items for this page
+ $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE true $uids $item_normal
+ AND item.parent = item.id
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets
+ ORDER BY $ordering DESC $pager_sql "
+ );
+ }
}
elseif($update) {
-
- $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE true $uids $item_normal
- AND item.parent = item.id $simple_update
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets"
- );
+ if($mid) {
+ $r = q("SELECT parent AS item_id FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE mid like '%s' $uids $item_normal_update $simple_update
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets LIMIT 1",
+ dbesc($mid . '%')
+ );
+ }
+ else {
+ $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE true $uids $item_normal_update
+ AND item.parent = item.id $simple_update
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets"
+ );
+ }
$_SESSION['loadtime'] = datetime_convert();
}
// Then fetch all the children of the parents that are on this page
@@ -166,7 +201,10 @@ class Pubstream extends \Zotlabs\Web\Controller {
// fake it
$mode = ('network');
- $o .= conversation($a,$items,$mode,$update,$page_mode);
+ $o .= conversation($items,$mode,$update,$page_mode);
+
+ if($mid)
+ $o .= '<div id="content-complete"></div>';
if(($items) && (! $update))
$o .= alt_pager($a,count($items));
diff --git a/Zotlabs/Module/Randprof.php b/Zotlabs/Module/Randprof.php
index dc2e925fe..94ec095cb 100644
--- a/Zotlabs/Module/Randprof.php
+++ b/Zotlabs/Module/Randprof.php
@@ -8,7 +8,7 @@ class Randprof extends \Zotlabs\Web\Controller {
function init() {
$x = random_profile();
if($x)
- goaway(chanlink_url($x));
+ goaway(chanlink_hash($x));
/** FIXME this doesn't work at the moment as a fallback */
goaway(z_root() . '/profile');
diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php
index ed4f87e7e..6cd79c952 100644
--- a/Zotlabs/Module/React.php
+++ b/Zotlabs/Module/React.php
@@ -39,6 +39,10 @@ class React extends \Zotlabs\Web\Controller {
$n['author_xchan'] = $channel['channel_hash'];
$x = item_store($n);
+
+ if(local_channel())
+ retain_item($postid);
+
if($x['success']) {
$nid = $x['item_id'];
\Zotlabs\Daemon\Master::Summon(array('Notifier','like',$nid));
diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php
index 1d8944d8e..95e3ca96f 100644
--- a/Zotlabs/Module/Register.php
+++ b/Zotlabs/Module/Register.php
@@ -27,7 +27,7 @@ class Register extends \Zotlabs\Web\Controller {
$result = check_account_email($_REQUEST['email']);
break;
case 'password_check.json':
- $result = check_account_password($_REQUEST['password']);
+ $result = check_account_password($_REQUEST['password1']);
break;
default:
break;
@@ -123,12 +123,19 @@ class Register extends \Zotlabs\Web\Controller {
if($policy == REGISTER_OPEN ) {
if($email_verify) {
$res = verify_email_address($result);
+ if($res) {
+ info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ }
}
else {
$res = send_register_success_email($result['email'],$result['password']);
}
if($res) {
- info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ if($invite_code) {
+ info( t('Registration successful. Continue to create your first channel...') . EOL ) ;
+ } else {
+ info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ }
}
}
elseif($policy == REGISTER_APPROVE) {
@@ -151,7 +158,7 @@ class Register extends \Zotlabs\Web\Controller {
$new_channel = false;
$next_page = 'new_channel';
- if(get_config('system','auto_channel_create') || get_config('system','server_role') == 'basic') {
+ if(get_config('system','auto_channel_create')) {
$new_channel = auto_channel_create($result['account']['account_id']);
if($new_channel['success']) {
$channel_id = $new_channel['channel']['channel_id'];
@@ -167,7 +174,8 @@ class Register extends \Zotlabs\Web\Controller {
$next_page = $x;
$_SESSION['workflow'] = true;
}
-
+
+ unset($_SESSION['login_return_url']);
goaway(z_root() . '/' . $next_page);
}
@@ -231,20 +239,18 @@ class Register extends \Zotlabs\Web\Controller {
$enable_tos = 1 - intval(get_config('system','no_termsofservice'));
$email = array('email', t('Your email address'), ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : ""));
- $password = array('password', t('Choose a password'), ((x($_REQUEST,'password')) ? trim($_REQUEST['password']) : ""));
- $password2 = array('password2', t('Please re-enter your password'), ((x($_REQUEST,'password2')) ? trim($_REQUEST['password2']) : ""));
+ $password = array('password', t('Choose a password'), '');
+ $password2 = array('password2', t('Please re-enter your password'), '');
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
$name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'));
$nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl'));
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub));
- $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles);
+ $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles);
$tos = array('tos', $label_tos, '', '', array(t('no'),t('yes')));
- $server_role = get_config('system','server_role');
-
- $auto_create = (($server_role == 'basic') || (get_config('system','auto_channel_create')) ? true : false);
- $default_role = (($server_role == 'basic') ? 'social' : get_config('system','default_permissions_role'));
+ $auto_create = (get_config('system','auto_channel_create') ? true : false);
+ $default_role = get_config('system','default_permissions_role');
require_once('include/bbcode.php');
diff --git a/Zotlabs/Module/Rmagic.php b/Zotlabs/Module/Rmagic.php
index 9fcc72441..bfc03f6ec 100644
--- a/Zotlabs/Module/Rmagic.php
+++ b/Zotlabs/Module/Rmagic.php
@@ -17,8 +17,8 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($r) {
if($r[0]['hubloc_url'] === z_root())
goaway(z_root() . '/login');
- $dest = z_root() . '/' . str_replace('zid=','zid_=',\App::$query_string);
- goaway($r[0]['hubloc_url'] . '/magic' . '?f=&dest=' . $dest);
+ $dest = z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string);
+ goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&dest=' . $dest);
}
}
}
@@ -61,9 +61,9 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($_SESSION['return_url'])
$dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',$_SESSION['return_url']));
else
- $dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',\App::$query_string));
+ $dest = urlencode(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],\App::$query_string));
- goaway($url . '/magic' . '?f=&dest=' . $dest);
+ goaway($url . '/magic' . '?f=&owa=1&dest=' . $dest);
}
}
}
diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php
index 1349cd1c5..5d2f0d7e8 100644
--- a/Zotlabs/Module/Rpost.php
+++ b/Zotlabs/Module/Rpost.php
@@ -20,6 +20,7 @@ require_once('include/zot.php');
* body= Body of post
* url= URL which will be parsed and the results appended to the body
* source= Source application
+ * post_id= post_id of post to 'share' (local use only)
* remote_return= absolute URL to return after posting is finished
* type= choices are 'html' or 'bbcode', default is 'bbcode'
*
@@ -59,6 +60,8 @@ class Rpost extends \Zotlabs\Web\Controller {
}
return login();
}
+
+ nav_set_selected('Post');
// If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables
@@ -88,8 +91,6 @@ class Rpost extends \Zotlabs\Web\Controller {
}
$plaintext = true;
- // if(feature_enabled(local_channel(),'richtext'))
- // $plaintext = false;
if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') {
require_once('include/html2bbcode.php');
@@ -108,28 +109,67 @@ class Rpost extends \Zotlabs\Web\Controller {
if($x['success'])
$_REQUEST['body'] = $_REQUEST['body'] . $x['body'];
}
+
+ if($_REQUEST['post_id']) {
+ $r = q("SELECT * from item WHERE id = %d LIMIT 1",
+ intval($_REQUEST['post_id'])
+ );
+ if(($r) && (! intval($r[0]['item_private']))) {
+ $sql_extra = item_permissions_sql($r[0]['uid']);
+
+ $r = q("select * from item where id = %d $sql_extra",
+ intval($_REQUEST['post_id'])
+ );
+ if($r && $r[0]['mimetype'] === 'text/bbcode') {
+
+ xchan_query($r);
+
+ $is_photo = (($r[0]['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
+ if($is_photo) {
+ $object = json_decode($r[0]['obj'],true);
+ $photo_bb = $object['body'];
+ }
+
+ if (strpos($r[0]['body'], "[/share]") !== false) {
+ $pos = strpos($r[0]['body'], "[share");
+ $i = substr($r[0]['body'], $pos);
+ } else {
+ $i = "[share author='".urlencode($r[0]['author']['xchan_name']).
+ "' profile='".$r[0]['author']['xchan_url'] .
+ "' avatar='".$r[0]['author']['xchan_photo_s'].
+ "' link='".$r[0]['plink'].
+ "' posted='".$r[0]['created'].
+ "' message_id='".$r[0]['mid']."']";
+ if($r[0]['title'])
+ $i .= '[b]'.$r[0]['title'].'[/b]'."\r\n";
+ $i .= (($is_photo) ? $photo_bb . "\r\n" . $r[0]['body'] : $r[0]['body']);
+ $i .= "[/share]";
+ }
+ }
+ }
+ $_REQUEST['body'] = $_REQUEST['body'] . $i;
+ }
$x = array(
- 'is_owner' => true,
- 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
- 'default_location' => $channel['channel_location'],
- 'nickname' => $channel['channel_address'],
- 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'),
- 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
- 'permissions' => $channel_acl,
- 'bang' => '',
- 'visitor' => true,
- 'profile_uid' => local_channel(),
- 'title' => $_REQUEST['title'],
- 'body' => $_REQUEST['body'],
- 'attachment' => $_REQUEST['attachment'],
- 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''),
- 'return_path' => 'rpost/return',
- 'bbco_autocomplete' => 'bbcode',
- 'editor_autocomplete'=> true,
- 'bbcode' => true,
- 'jotnets' => true
-
+ 'is_owner' => true,
+ 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
+ 'default_location' => $channel['channel_location'],
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'),
+ 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
+ 'permissions' => $channel_acl,
+ 'bang' => '',
+ 'visitor' => true,
+ 'profile_uid' => local_channel(),
+ 'title' => $_REQUEST['title'],
+ 'body' => $_REQUEST['body'],
+ 'attachment' => $_REQUEST['attachment'],
+ 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''),
+ 'return_path' => 'rpost/return',
+ 'bbco_autocomplete' => 'bbcode',
+ 'editor_autocomplete' => true,
+ 'bbcode' => true,
+ 'jotnets' => true
);
$editor = status_editor($a,$x);
diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php
index 89eaa4ffa..37e9a336f 100644
--- a/Zotlabs/Module/Search.php
+++ b/Zotlabs/Module/Search.php
@@ -15,14 +15,14 @@ class Search extends \Zotlabs\Web\Controller {
if((get_config('system','block_public')) || (get_config('system','block_public_search'))) {
if ((! local_channel()) && (! remote_channel())) {
notice( t('Public access denied.') . EOL);
- return;
+ return;
}
}
if($load)
$_SESSION['loadtime'] = datetime_convert();
- nav_set_selected('search');
+ nav_set_selected('Search');
require_once("include/bbcode.php");
require_once('include/security.php');
@@ -81,11 +81,12 @@ class Search extends \Zotlabs\Web\Controller {
return $o;
if($tag) {
- $sql_extra = sprintf(" AND item.id IN (select oid from term where otype = %d and ttype in ( %d , %d) and term = '%s') ",
+ $wildtag = str_replace('*','%',$search);
+ $sql_extra = sprintf(" AND item.id IN (select oid from term where otype = %d and ttype in ( %d , %d) and term like '%s') ",
intval(TERM_OBJ_POST),
intval(TERM_HASHTAG),
intval(TERM_COMMUNITYTAG),
- dbesc(protect_sprintf($search))
+ dbesc(protect_sprintf($wildtag))
);
}
else {
@@ -130,6 +131,7 @@ class Search extends \Zotlabs\Web\Controller {
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$search' => (($tag) ? urlencode('#') : '') . $search,
+ '$xchan' => '',
'$order' => '',
'$file' => '',
'$cats' => '',
@@ -143,7 +145,7 @@ class Search extends \Zotlabs\Web\Controller {
}
- $item_normal = item_normal();
+ $item_normal = item_normal_search();
$pub_sql = public_permissions_sql($observer_hash);
require_once('include/channel.php');
@@ -224,7 +226,7 @@ class Search extends \Zotlabs\Web\Controller {
else
$o .= '<h2>' . sprintf( t('Search results for: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '</h2>';
- $o .= conversation($a,$items,'search',$update,'client');
+ $o .= conversation($items,'search',$update,'client');
$o .= '</div>';
diff --git a/Zotlabs/Module/Settings.php b/Zotlabs/Module/Settings.php
index 76794e21c..79031c98f 100644
--- a/Zotlabs/Module/Settings.php
+++ b/Zotlabs/Module/Settings.php
@@ -53,7 +53,7 @@ class Settings extends \Zotlabs\Web\Controller {
function get() {
- nav_set_selected('settings');
+ nav_set_selected('Settings');
if((! local_channel()) || ($_SESSION['delegate'])) {
notice( t('Permission denied.') . EOL );
diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php
index ec176797d..18890e89f 100644
--- a/Zotlabs/Module/Settings/Account.php
+++ b/Zotlabs/Module/Settings/Account.php
@@ -16,7 +16,7 @@ class Account {
$account = \App::get_account();
if($email != $account['account_email']) {
- if(! valid_email($email))
+ if(! validate_email($email))
$errs[] = t('Not valid email.');
$adm = trim(get_config('system','admin_email'));
if(($adm) && (strcasecmp($email,$adm) == 0)) {
diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php
index 5b9cfdaca..41e23b717 100644
--- a/Zotlabs/Module/Settings/Channel.php
+++ b/Zotlabs/Module/Settings/Channel.php
@@ -199,6 +199,10 @@ class Channel {
$vnotify += intval($_POST['vnotify10']);
if(x($_POST,'vnotify11'))
$vnotify += intval($_POST['vnotify11']);
+ if(x($_POST,'vnotify12'))
+ $vnotify += intval($_POST['vnotify12']);
+ if(x($_POST,'vnotify13') && (get_config('system', 'disable_discover_tab') != 1))
+ $vnotify += intval($_POST['vnotify13']);
$always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0;
@@ -277,8 +281,8 @@ class Channel {
if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) {
// FIXME - set to un-verified, blocked and redirect to logout
- // Why? Are we verifying people or email addresses?
-
+ // Q: Why? Are we verifying people or email addresses?
+ // A: the policy is to verify email addresses
}
goaway(z_root() . '/settings' );
@@ -324,7 +328,7 @@ class Channel {
foreach($global_perms as $k => $perm) {
$options = array();
foreach($perm_opts as $opt) {
- if((! strstr($k,'view')) && $opt[1] == PERMS_PUBLIC)
+ if(((! strstr($k,'view')) && $k !== 'post_comments') && $opt[1] == PERMS_PUBLIC)
continue;
$options[$opt[1]] = $opt[0];
}
@@ -489,7 +493,6 @@ class Channel {
'$h_prv' => t('Security and Privacy Settings'),
'$permissions_set' => $permissions_set,
- '$server_role' => \Zotlabs\Lib\System::get_server_role(),
'$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'),
'$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no),
@@ -506,7 +509,7 @@ class Channel {
'$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')),
'$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')),
- '$permissions' => t('Default Access Control List (ACL)'),
+ '$permissions' => t('Default Privacy Group'),
'$permdesc' => t("\x28click to open/close\x29"),
'$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
'$allow_cid' => acl2json($perm_defaults['allow_cid']),
@@ -556,6 +559,8 @@ class Channel {
'$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no),
'$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no),
'$vnotify11' => array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no),
+ '$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no),
+ '$vnotify13' => ((get_config('system', 'disable_discover_tab') != 1) ? array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no) : array()),
'$always_show_in_notices' => array('always_show_in_notices', t('Also show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no),
'$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')),
@@ -575,7 +580,7 @@ class Channel {
'$removeme' => t('Remove Channel'),
'$removechannel' => t('Remove this channel.'),
'$firefoxshare' => t('Firefox Share $Projectname provider'),
- '$cal_first_day' => array('first_day', t('Start calendar week on monday'), ((get_pconfig(local_channel(),'system','cal_first_day')) ? 1 : ''), '', $yes_no),
+ '$cal_first_day' => array('first_day', t('Start calendar week on Monday'), ((get_pconfig(local_channel(),'system','cal_first_day')) ? 1 : ''), '', $yes_no),
));
call_hooks('settings_form',$o);
diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php
index 67cecf1f5..a444d28a2 100644
--- a/Zotlabs/Module/Settings/Display.php
+++ b/Zotlabs/Module/Settings/Display.php
@@ -24,34 +24,34 @@ class Display {
$mobile_theme = ((x($_POST,'mobile_theme')) ? notags(trim($_POST['mobile_theme'])) : '');
$preload_images = ((x($_POST,'preload_images')) ? intval($_POST['preload_images']) : 0);
$user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0);
- $nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0);
- $title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0);
+ $nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0);
+ $title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0);
$channel_list_mode = ((x($_POST,'channel_list_mode')) ? intval($_POST['channel_list_mode']) : 0);
$network_list_mode = ((x($_POST,'network_list_mode')) ? intval($_POST['network_list_mode']) : 0);
$manual_update = ((array_key_exists('manual_update',$_POST)) ? intval($_POST['manual_update']) : 0);
-
+
$channel_divmore_height = ((x($_POST,'channel_divmore_height')) ? intval($_POST['channel_divmore_height']) : 400);
if($channel_divmore_height < 50)
$channel_divmore_height = 50;
$network_divmore_height = ((x($_POST,'network_divmore_height')) ? intval($_POST['network_divmore_height']) : 400);
if($network_divmore_height < 50)
$network_divmore_height = 50;
-
+
$browser_update = ((x($_POST,'browser_update')) ? intval($_POST['browser_update']) : 0);
$browser_update = $browser_update * 1000;
if($browser_update < 10000)
$browser_update = 10000;
-
+
$itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 20);
if($itemspage > 100)
$itemspage = 100;
-
- if ($mobile_theme == "---")
+
+ if ($mobile_theme == "---")
del_pconfig(local_channel(),'system','mobile_theme');
else {
set_pconfig(local_channel(),'system','mobile_theme',$mobile_theme);
}
-
+
set_pconfig(local_channel(),'system','preload_images',$preload_images);
set_pconfig(local_channel(),'system','user_scalable',$user_scalable);
set_pconfig(local_channel(),'system','update_interval', $browser_update);
@@ -63,9 +63,9 @@ class Display {
set_pconfig(local_channel(),'system','channel_divmore_height', $channel_divmore_height);
set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height);
set_pconfig(local_channel(),'system','manual_conversation_update', $manual_update);
-
+
$newschema = '';
- if($theme == $existing_theme){
+ if($theme){
// call theme_post only if theme has not been changed
if( ($themeconfigfile = $this->get_theme_config_file($theme)) != null){
require_once($themeconfigfile);
@@ -76,7 +76,7 @@ class Display {
if(array_key_exists($_POST['schema'],$schemas))
$newschema = $_POST['schema'];
if($newschema === '---')
- $newschema = '';
+ $newschema = '';
$theme_config->post();
}
}
@@ -85,18 +85,18 @@ class Display {
logger('theme: ' . $theme . (($newschema) ? ':' . $newschema : ''));
$_SESSION['theme'] = $theme . (($newschema) ? ':' . $newschema : '');
-
+
$r = q("UPDATE channel SET channel_theme = '%s' WHERE channel_id = %d",
dbesc($theme . (($newschema) ? ':' . $newschema : '')),
intval(local_channel())
);
-
+
call_hooks('display_settings_post', $_POST);
build_sync_packet();
goaway(z_root() . '/settings/display' );
return; // NOTREACHED
}
-
+
function get() {
@@ -115,28 +115,36 @@ class Display {
$default_mobile_theme = get_config('system','mobile_theme');
if(! $mobile_default_theme)
$mobile_default_theme = 'none';
-
+
$allowed_themes_str = get_config('system','allowed_themes');
$allowed_themes_raw = explode(',',$allowed_themes_str);
$allowed_themes = array();
if(count($allowed_themes_raw))
- foreach($allowed_themes_raw as $x)
+ foreach($allowed_themes_raw as $x)
if(strlen(trim($x)) && is_dir("view/theme/$x"))
$allowed_themes[] = trim($x);
-
+
$themes = array();
$files = glob('view/theme/*');
if($allowed_themes) {
foreach($allowed_themes as $th) {
$f = $th;
+
+ $info = get_theme_info($th);
+ $compatible = check_plugin_versions($info);
+ if(!$compatible) {
+ $mobile_themes[$f] = $themes[$f] = sprintf(t('%s - (Incompatible)'), $f);
+ continue;
+ }
+
$is_experimental = file_exists('view/theme/' . $th . '/experimental');
$unsupported = file_exists('view/theme/' . $th . '/unsupported');
$is_mobile = file_exists('view/theme/' . $th . '/mobile');
$is_library = file_exists('view/theme/'. $th . '/library');
- $mobile_themes["---"] = t("No special theme for mobile devices");
-
- if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){
+ $mobile_themes['---'] = t("No special theme for mobile devices");
+
+ if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){
$theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f);
if (! $is_library) {
if($is_mobile) {
@@ -147,32 +155,35 @@ class Display {
}
}
}
-
}
}
$theme_selected = ((array_key_exists('theme',$_SESSION) && $_SESSION['theme']) ? $_SESSION['theme'] : $theme);
+ if (strpos($theme_selected, ':')) {
+ $theme_selected = explode(':', $theme_selected)[0];
+ }
+
$mobile_theme_selected = (!x($_SESSION,'mobile_theme')? $default_mobile_theme : $_SESSION['mobile_theme']);
-
+
$preload_images = get_pconfig(local_channel(),'system','preload_images');
$preload_images = (($preload_images===false)? '0': $preload_images); // default if not set: 0
-
+
$user_scalable = get_pconfig(local_channel(),'system','user_scalable');
$user_scalable = (($user_scalable===false)? '0': $user_scalable); // default if not set: 0
-
+
$browser_update = intval(get_pconfig(local_channel(), 'system','update_interval'));
$browser_update = (($browser_update == 0) ? 80 : $browser_update / 1000); // default if not set: 40 seconds
-
+
$itemspage = intval(get_pconfig(local_channel(), 'system','itemspage'));
$itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items
-
+
$nosmile = get_pconfig(local_channel(),'system','no_smilies');
$nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0
-
+
$title_tosource = get_pconfig(local_channel(),'system','title_tosource');
$title_tosource = (($title_tosource===false)? '0': $title_tosource); // default if not set: 0
-
+
$theme_config = "";
if(($themeconfigfile = $this->get_theme_config_file($theme)) != null){
require_once($themeconfigfile);
@@ -185,18 +196,18 @@ class Display {
}
// logger('schemas: ' . print_r($schemas,true));
-
+
$tpl = get_markup_template("settings_display.tpl");
$o = replace_macros($tpl, array(
'$ptitle' => t('Display Settings'),
- '$d_tset' => t('Theme Settings'),
- '$d_ctset' => t('Custom Theme Settings'),
+ '$d_tset' => t('Theme Settings'),
+ '$d_ctset' => t('Custom Theme Settings'),
'$d_cset' => t('Content Settings'),
'$form_security_token' => get_form_security_token("settings_display"),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$uid' => local_channel(),
-
+
'$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false),
'$schema' => array('schema', t('Select scheme'), $existing_schema, '' , $schemas),
@@ -215,11 +226,11 @@ class Display {
'$network_list_mode' => array('network_list_mode', t('Use blog/list mode on grid page'), get_pconfig(local_channel(),'system','network_list_mode'), t('(comments displayed separately)'), $yes_no),
'$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','channel_divmore_height')) ? get_pconfig(local_channel(),'system','channel_divmore_height') : 400), t('click to expand content exceeding this height')),
'$network_divmore_height' => array('network_divmore_height', t('Grid page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','network_divmore_height')) ? get_pconfig(local_channel(),'system','network_divmore_height') : 400) , t('click to expand content exceeding this height')),
-
-
+
+
));
- call_hooks('display_settings',$o);
+ call_hooks('display_settings',$o);
return $o;
}
@@ -227,10 +238,10 @@ class Display {
function get_theme_config_file($theme){
$base_theme = \App::$theme_info['extends'];
-
+
if (file_exists("view/theme/$theme/php/config.php")){
return "view/theme/$theme/php/config.php";
- }
+ }
if (file_exists("view/theme/$base_theme/php/config.php")){
return "view/theme/$base_theme/php/config.php";
}
@@ -239,5 +250,5 @@ class Display {
-
+
}
diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php
index 4885abd1d..ebe2996d3 100644
--- a/Zotlabs/Module/Settings/Featured.php
+++ b/Zotlabs/Module/Settings/Featured.php
@@ -10,14 +10,16 @@ class Featured {
call_hooks('feature_settings_post', $_POST);
- if(intval($_POST['affinity_cmax'])) {
- set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax']));
- }
- if(intval($_POST['affinity_cmin'])) {
- set_pconfig(local_channel(),'affinity','cmin',intval($_POST['affinity_cmin']));
- }
- if(intval($_POST['affinity_cmax']) || intval($_POST['affinity_cmin'])) {
- info( t('Affinity Slider settings updated.') . EOL);
+ if($_POST['affinity_slider-submit']) {
+ if(intval($_POST['affinity_cmax'])) {
+ set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax']));
+ }
+ if(intval($_POST['affinity_cmin'])) {
+ set_pconfig(local_channel(),'affinity','cmin',intval($_POST['affinity_cmin']));
+ }
+ if(intval($_POST['affinity_cmax']) || intval($_POST['affinity_cmin'])) {
+ info( t('Affinity Slider settings updated.') . EOL);
+ }
}
build_sync_packet();
diff --git a/Zotlabs/Module/Settings/Permcats.php b/Zotlabs/Module/Settings/Permcats.php
index 35d533196..336f69653 100644
--- a/Zotlabs/Module/Settings/Permcats.php
+++ b/Zotlabs/Module/Settings/Permcats.php
@@ -42,8 +42,6 @@ class Permcats {
function get() {
-logger('cmd: ' . \App::$cmd);
-
if(! local_channel())
return;
@@ -85,7 +83,7 @@ logger('cmd: ' . \App::$cmd);
if($existing[$k])
$thisperm = "1";
- $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
+ $perms[] = array('perms_' . $k, $v, '',$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
}
@@ -114,4 +112,4 @@ logger('cmd: ' . \App::$cmd);
return $o;
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php
index 9c688af01..8e7fbbddf 100644
--- a/Zotlabs/Module/Setup.php
+++ b/Zotlabs/Module/Setup.php
@@ -38,7 +38,7 @@ class Setup extends \Zotlabs\Web\Controller {
ini_set('log_errors', '0');
ini_set('display_errors', '1');
- // $baseurl/setup/testrwrite to test if rewite in .htaccess is working
+ // $baseurl/setup/testrewrite to test if rewrite in .htaccess is working
if (argc() == 2 && argv(1) == "testrewrite") {
echo 'ok';
killme();
@@ -73,9 +73,6 @@ class Setup extends \Zotlabs\Web\Controller {
$phpath = trim($_POST['phpath']);
$adminmail = trim($_POST['adminmail']);
$siteurl = trim($_POST['siteurl']);
- $server_role = trim($_POST['server_role']);
- if(! $server_role)
- $server_role = 'standard';
// $siteurl should not have a trailing slash
@@ -103,9 +100,6 @@ class Setup extends \Zotlabs\Web\Controller {
$timezone = trim($_POST['timezone']);
$adminmail = trim($_POST['adminmail']);
$siteurl = trim($_POST['siteurl']);
- $server_role = trim($_POST['server_role']);
- if(! $server_role)
- $server_role = 'standard';
if($siteurl != z_root()) {
$test = z_fetch_url($siteurl."/setup/testrewrite");
@@ -134,7 +128,7 @@ class Setup extends \Zotlabs\Web\Controller {
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$dbtype' => $dbtype,
- '$server_role' => $server_role,
+ '$server_role' => 'pro',
'$timezone' => $timezone,
'$siteurl' => $siteurl,
'$site_id' => random_string(),
@@ -192,14 +186,17 @@ class Setup extends \Zotlabs\Web\Controller {
}
$db_return_text = '';
if(x(\App::$data, 'db_installed')) {
- $txt = '<p style="font-size: 130%;">';
- $txt .= t('Your site database has been installed.') . EOL;
+ $pass = 'Installation succeeded!';
+ $icon = 'check';
+ $txt = t('Your site database has been installed.') . EOL;
$db_return_text .= $txt;
}
if(x(\App::$data, 'db_failed')) {
+ $pass = 'Database install failed!';
+ $icon = 'exclamation-triangle';
$txt = t('You may need to import the file "install/schema_xxx.sql" manually using a database client.') . EOL;
$txt .= t('Please see the file "install/INSTALL.txt".') . EOL ."<hr>" ;
- $txt .= "<pre>".\App::$data['db_failed'] . "</pre>". EOL ;
+ $txt .= "<pre>" . \App::$data['db_failed'] . "</pre>". EOL ;
$db_return_text .= $txt;
}
if(\DBA::$dba && \DBA::$dba->connected) {
@@ -223,8 +220,10 @@ class Setup extends \Zotlabs\Web\Controller {
$tpl = get_markup_template('install.tpl');
return replace_macros($tpl, array(
'$title' => $install_title,
- '$pass' => '',
- '$text' => $db_return_text . $this->what_next(),
+ '$icon' => $icon,
+ '$pass' => $pass,
+ '$text' => $db_return_text,
+ '$what_next' => $this->what_next()
));
}
@@ -324,11 +323,6 @@ class Setup extends \Zotlabs\Web\Controller {
$siteurl = trim($_POST['siteurl']);
$timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles');
- $server_roles = [
- 'basic' => t('Basic/Minimal Social Networking'),
- 'standard' => t('Standard Configuration (default)'),
- 'pro' => t('Professional')
- ];
$tpl = get_markup_template('install_settings.tpl');
$o .= replace_macros($tpl, array(
@@ -348,8 +342,6 @@ class Setup extends \Zotlabs\Web\Controller {
'$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')),
- '$server_role' => array('server_role', t("Server Configuration/Role"), 'standard','',$server_roles),
-
'$timezone' => array('timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()),
'$baseurl' => z_root(),
@@ -408,7 +400,7 @@ class Setup extends \Zotlabs\Web\Controller {
if(!$passed) {
$help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL;
$help .= t('If you don\'t have a command line version of PHP installed on server, you will not be able to run background polling via cron.') . EOL;
- $help .= EOL . EOL ;
+ $help .= EOL;
$tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, array(
'$field' => array('phpath', t('PHP executable path'), $phpath, t('Enter full path to php executable. You can leave this blank to continue the installation.')),
@@ -456,7 +448,7 @@ class Setup extends \Zotlabs\Web\Controller {
userReadableSize($result['max_upload_filesize']),
$result['max_file_uploads']
);
- $help .= '<br>' . t('You can adjust these settings in the server php.ini file.');
+ $help .= '<br><br>' . t('You can adjust these settings in the server php.ini file.');
$this->check_add($checks, t('PHP upload limits'), true, false, $help);
}
@@ -508,6 +500,7 @@ class Setup extends \Zotlabs\Web\Controller {
$this->check_add($ck_funcs, t('PDO database PHP module'), true, true);
$this->check_add($ck_funcs, t('mb_string PHP module'), true, true);
$this->check_add($ck_funcs, t('xml PHP module'), true, true);
+ $this->check_add($ck_funcs, t('zip PHP module'), true, true);
if(function_exists('apache_get_modules')){
if (! in_array('mod_rewrite', apache_get_modules())) {
@@ -550,8 +543,12 @@ class Setup extends \Zotlabs\Web\Controller {
$ck_funcs[4]['help'] = t('Error: mb_string PHP module required but not installed.');
}
if(! extension_loaded('xml')) {
+ $ck_funcs[5]['status'] = false;
+ $ck_funcs[5]['help'] = t('Error: xml PHP module required for DAV but not installed.');
+ }
+ if(! extension_loaded('zip')) {
$ck_funcs[6]['status'] = false;
- $ck_funcs[6]['help'] = t('Error: xml PHP module required for DAV but not installed.');
+ $ck_funcs[6]['help'] = t('Error: zip PHP module required but not installed.');
}
$checks = array_merge($checks, $ck_funcs);
@@ -624,7 +621,6 @@ class Setup extends \Zotlabs\Web\Controller {
* @param[out] array &$checks
*/
function check_htaccess(&$checks) {
- $a = get_app();
$status = true;
$help = '';
$ssl_error = false;
@@ -718,7 +714,6 @@ class Setup extends \Zotlabs\Web\Controller {
* @return string with parsed HTML
*/
function what_next() {
- $a = get_app();
// install the standard theme
set_config('system', 'allowed_themes', 'redbasic');
@@ -745,12 +740,12 @@ class Setup extends \Zotlabs\Web\Controller {
$baseurl = z_root();
return
- t('<h1>What next</h1>')
- ."<p>".t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.')
+ t('<h1>What next?</h1>')
+ ."<div class=\"alert alert-info\">".t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.').EOL
.t('Please see the file "install/INSTALL.txt".')
- ."</p><p>"
+ ."</div><div>"
.t("Go to your new hub <a href='$baseurl/register'>registration page</a> and register as new member. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.")
- ."</p>";
+ ."</div>";
}
/**
diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php
index fcc2486ba..5c4811c59 100644
--- a/Zotlabs/Module/Share.php
+++ b/Zotlabs/Module/Share.php
@@ -76,7 +76,7 @@ class Share extends \Zotlabs\Web\Controller {
$observer = \App::get_observer();
$parsed = $observer['xchan_url'];
if($parsed) {
- $post_url = $parsed['scheme'] . ':' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '')
+ $post_url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '')
. '/rpost';
/**
diff --git a/Zotlabs/Module/Sharedwithme.php b/Zotlabs/Module/Sharedwithme.php
index 25bc7dba3..2c97e9726 100644
--- a/Zotlabs/Module/Sharedwithme.php
+++ b/Zotlabs/Module/Sharedwithme.php
@@ -4,6 +4,11 @@ require_once('include/conversation.php');
require_once('include/text.php');
+/**
+ * @file Zotlabs/Module/Sharedwithme.php
+ *
+ */
+
class Sharedwithme extends \Zotlabs\Web\Controller {
function get() {
@@ -92,7 +97,8 @@ class Sharedwithme extends \Zotlabs\Web\Controller {
}
- $o = profile_tabs($a, $is_owner, $channel['channel_address']);
+ //$o = profile_tabs($a, $is_owner, $channel['channel_address']);
+ $o = '';
$o .= replace_macros(get_markup_template('sharedwithme.tpl'), array(
'$header' => t('Files: shared with me'),
diff --git a/Zotlabs/Module/Siteinfo.php b/Zotlabs/Module/Siteinfo.php
index 7c3918425..fafd51f65 100644
--- a/Zotlabs/Module/Siteinfo.php
+++ b/Zotlabs/Module/Siteinfo.php
@@ -5,14 +5,13 @@ namespace Zotlabs\Module;
class Siteinfo extends \Zotlabs\Web\Controller {
function init() {
- if (argv(1) === 'json') {
+logger(print_r($_REQUEST,true));
+ if (argv(1) === 'json' || $_REQUEST['module_format'] === 'json') {
$data = get_site_info();
json_return_and_die($data);
}
}
-
-
-
+
function get() {
$siteinfo = replace_macros(get_markup_template('siteinfo.tpl'),
diff --git a/Zotlabs/Module/Siteinfo_json.php b/Zotlabs/Module/Siteinfo_json.php
deleted file mode 100644
index 99c22610f..000000000
--- a/Zotlabs/Module/Siteinfo_json.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-
-class Siteinfo_json extends \Zotlabs\Web\Controller {
-
- function init() {
-
- $data = get_site_info();
- json_return_and_die($data);
-
- }
-
-}
diff --git a/Zotlabs/Module/Suggest.php b/Zotlabs/Module/Suggest.php
index 367308d90..f79e4e245 100644
--- a/Zotlabs/Module/Suggest.php
+++ b/Zotlabs/Module/Suggest.php
@@ -3,8 +3,6 @@ namespace Zotlabs\Module;
require_once('include/socgraph.php');
require_once('include/contact_widgets.php');
-require_once('include/widgets.php');
-
class Suggest extends \Zotlabs\Web\Controller {
@@ -23,13 +21,15 @@ class Suggest extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
$o = '';
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
+
+ nav_set_selected('Suggest Channels');
$_SESSION['return_url'] = z_root() . '/' . \App::$cmd;
diff --git a/Zotlabs/Module/Tasks.php b/Zotlabs/Module/Tasks.php
index c8deb11bf..0709f31f6 100644
--- a/Zotlabs/Module/Tasks.php
+++ b/Zotlabs/Module/Tasks.php
@@ -19,8 +19,8 @@ class Tasks extends \Zotlabs\Web\Controller {
$arr['all'] = 1;
$x = tasks_fetch($arr);
+ $x['html'] = '';
if($x['tasks']) {
- $x['html'] = '';
foreach($x['tasks'] as $y) {
$x['html'] .= '<div class="tasklist-item"><input type="checkbox" onchange="taskComplete(' . $y['id'] . '); return false;" /> ' . $y['summary'] . '</div>';
}
@@ -69,6 +69,7 @@ class Tasks extends \Zotlabs\Web\Controller {
if($x)
$ret['success'] = true;
}
+
json_return_and_die($ret);
}
diff --git a/Zotlabs/Module/Thing.php b/Zotlabs/Module/Thing.php
index 95c6c5636..f816632ab 100644
--- a/Zotlabs/Module/Thing.php
+++ b/Zotlabs/Module/Thing.php
@@ -91,6 +91,7 @@ class Thing extends \Zotlabs\Web\Controller {
}
$orig_record = $t[0];
if($photo != $orig_record['obj_imgurl']) {
+ delete_thing_photo($orig_record['obj_imgurl'],get_observer_hash());
$arr = import_xchan_photo($photo,get_observer_hash(),true);
$local_photo = $arr[0];
$local_photo_type = $arr[3];
@@ -336,6 +337,9 @@ class Thing extends \Zotlabs\Web\Controller {
return '';
}
+
+ delete_thing_photo($r[0]['obj_imgurl'],get_observer_hash());
+
$x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d",
dbesc($thing_hash),
intval(TERM_OBJ_THING),
diff --git a/Zotlabs/Module/Token.php b/Zotlabs/Module/Token.php
new file mode 100644
index 000000000..e0d9d74d7
--- /dev/null
+++ b/Zotlabs/Module/Token.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Zotlabs\Module;
+
+
+class Token extends \Zotlabs\Web\Controller {
+
+
+ function get() {
+
+
+ // workaround for HTTP-auth in CGI mode
+ if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
+ $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ }
+
+ if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
+ $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ }
+
+
+
+
+ require_once('include/oauth2.php');
+ $oauth2_server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send();
+
+ killme();
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Update_cards.php b/Zotlabs/Module/Update_cards.php
new file mode 100644
index 000000000..bb87357e8
--- /dev/null
+++ b/Zotlabs/Module/Update_cards.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Zotlabs\Module;
+
+/**
+ * Module: update_profile
+ * Purpose: AJAX synchronisation of profile page
+ *
+ */
+
+
+class Update_cards extends \Zotlabs\Web\Controller {
+
+function get() {
+
+ $profile_uid = intval($_GET['p']);
+ $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
+
+ header("Content-type: text/html");
+ echo "<!DOCTYPE html><html><body><section></section></body></html>\r\n";
+
+ killme();
+
+
+ $mod = new Cards();
+
+ $text = $mod->get($profile_uid,$load);
+
+ /**
+ * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well
+ */
+
+ echo str_replace("\t",' ',$text);
+ echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
+ echo "</body></html>\r\n";
+ killme();
+
+}
+}
diff --git a/Zotlabs/Module/Update_display.php b/Zotlabs/Module/Update_display.php
index 13b04204d..b2c6a56f5 100644
--- a/Zotlabs/Module/Update_display.php
+++ b/Zotlabs/Module/Update_display.php
@@ -21,26 +21,10 @@ class Update_display extends \Zotlabs\Web\Controller {
$mod = new Display();
$text = $mod->get($profile_uid, $load);
- $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
- $replace = "<img\${1} dst=\"\${2}\"";
- // $text = preg_replace($pattern, $replace, $text);
- /*
- if(! $load) {
- $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />';
- $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i";
- $text = preg_replace($pattern, $replace, $text);
- }
- */
echo str_replace("\t",' ',$text);
echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
echo "</body></html>\r\n";
- // logger('update_display: ' . $text);
+
killme();
}
diff --git a/Zotlabs/Module/Viewconnections.php b/Zotlabs/Module/Viewconnections.php
index 4364d482a..1f9c03751 100644
--- a/Zotlabs/Module/Viewconnections.php
+++ b/Zotlabs/Module/Viewconnections.php
@@ -70,7 +70,7 @@ class Viewconnections extends \Zotlabs\Web\Controller {
foreach($r as $rr) {
- $url = chanlink_url($rr['xchan_url']);
+ $url = chanlink_hash($rr['xchan_hash']);
if($url) {
$contacts[] = array(
'id' => $rr['abook_id'],
diff --git a/Zotlabs/Module/Viewsrc.php b/Zotlabs/Module/Viewsrc.php
index fa755a3ec..54ab89e81 100644
--- a/Zotlabs/Module/Viewsrc.php
+++ b/Zotlabs/Module/Viewsrc.php
@@ -13,6 +13,7 @@ class Viewsrc extends \Zotlabs\Web\Controller {
$item_id = ((argc() > 1) ? intval(argv(1)) : 0);
$json = ((argc() > 2 && argv(2) === 'json') ? true : false);
+ $dload = ((argc() > 2 && argv(2) === 'download') ? true : false);
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
@@ -27,7 +28,7 @@ class Viewsrc extends \Zotlabs\Web\Controller {
$item_normal = item_normal();
if(local_channel() && $item_id) {
- $r = q("select id, item_flags, item_obscured, body from item where uid in (%d , %d) and id = %d $item_normal limit 1",
+ $r = q("select id, item_flags, mimetype, item_obscured, body from item where uid in (%d , %d) and id = %d $item_normal limit 1",
intval(local_channel()),
intval($sys['channel_id']),
intval($item_id)
@@ -35,8 +36,18 @@ class Viewsrc extends \Zotlabs\Web\Controller {
if($r) {
if(intval($r[0]['item_obscured']))
- $r[0]['body'] = crypto_unencapsulate(json_decode($r[0]['body'],true),get_config('system','prvkey'));
- $o = (($json) ? json_encode($r[0]['body']) : str_replace("\n",'<br />',$r[0]['body']));
+ $dload = true;
+
+ if($dload) {
+ header('Content-type: ' . $r[0]['mimetype']);
+ header('Content-disposition: attachment; filename="' . t('item') . '-' . $item_id . '"' );
+ echo $r[0]['body'];
+ killme();
+ }
+
+
+ $content = escape_tags($r[0]['body']);
+ $o = (($json) ? json_encode($content) : str_replace("\n",'<br />',$content));
}
}
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index c6fe7518e..e001ad929 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -2,16 +2,25 @@
namespace Zotlabs\Module;
require_once('include/attach.php');
-require_once('include/channel.php');
require_once('include/photos.php');
-
class Wall_attach extends \Zotlabs\Web\Controller {
+ function init() {
+ logger('request_method: ' . $_SERVER['REQUEST_METHOD'],LOGGER_DATA,LOG_INFO);
+ logger('wall_attach: ' . print_r($_REQUEST,true),LOGGER_DEBUG,LOG_INFO);
+ logger('wall_attach files: ' . print_r($_FILES,true),LOGGER_DEBUG,LOG_INFO);
+ // for testing without actually storing anything
+ // http_status_exit(200,'OK');
+ }
+
+
function post() {
$using_api = false;
-
+
+ $result = [];
+
if($_REQUEST['api_source'] && array_key_exists('media',$_FILES)) {
$using_api = true;
}
@@ -28,7 +37,46 @@ class Wall_attach extends \Zotlabs\Web\Controller {
if(! $channel)
killme();
-
+
+ $matches = [];
+ $partial = false;
+
+ $x = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
+ if($x) {
+ // logger('Content-Range: ' . print_r($matches,true));
+ $partial = true;
+ }
+
+ if($partial) {
+ $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]);
+ if($x['partial']) {
+ header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
+ json_return_and_die($result);
+ }
+ else {
+ header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0));
+
+ $_FILES['userfile'] = [
+ 'name' => $x['name'],
+ 'type' => $x['type'],
+ 'tmp_name' => $x['tmp_name'],
+ 'error' => $x['error'],
+ 'size' => $x['size']
+ ];
+ }
+ }
+ else {
+ if(! array_key_exists('userfile',$_FILES)) {
+ $_FILES['userfile'] = [
+ 'name' => $_FILES['files']['name'],
+ 'type' => $_FILES['files']['type'],
+ 'tmp_name' => $_FILES['files']['tmp_name'],
+ 'error' => $_FILES['files']['error'],
+ 'size' => $_FILES['files']['size']
+ ];
+ }
+ }
+
$observer = \App::get_observer();
@@ -49,12 +97,19 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$s = "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
}
+
+ $sync = attach_export_data($channel,$r['data']['hash']);
+ if($sync) {
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ }
+
if($using_api)
return $s;
-
- echo $s;
- killme();
-
+
+ $result['message'] = $s;
+ json_return_and_die($result);
+
}
+
}
diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php
index 46b94f091..97ec55ba3 100644
--- a/Zotlabs/Module/Webpages.php
+++ b/Zotlabs/Module/Webpages.php
@@ -34,7 +34,9 @@ class Webpages extends \Zotlabs\Web\Controller {
\App::$error = 404;
return;
}
-
+
+ nav_set_selected('Webpages');
+
$which = argv(1);
$_SESSION['return_url'] = \App::$query_string;
@@ -142,7 +144,8 @@ class Webpages extends \Zotlabs\Web\Controller {
$is_owner = ($uid && $uid == $owner);
- $o = profile_tabs($a, $is_owner, \App::$profile['channel_address']);
+ //$o = profile_tabs($a, $is_owner, \App::$profile['channel_address']);
+ $o = '';
$x = array(
'webpage' => ITEM_TYPE_WEBPAGE,
@@ -178,11 +181,8 @@ class Webpages extends \Zotlabs\Web\Controller {
// so just list titles and an edit link.
- /** @TODO - this should be replaced with pagelist_widget */
-
$sql_extra = item_permissions_sql($owner);
-
$r = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d
$sql_extra order by item.created desc",
@@ -190,12 +190,6 @@ class Webpages extends \Zotlabs\Web\Controller {
intval(ITEM_TYPE_WEBPAGE)
);
-// $r = q("select * from item_id left join item on item_id.iid = item.id
-// where item_id.uid = %d and service = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc",
-// intval($owner),
-// intval(ITEM_TYPE_WEBPAGE)
-// );
-
if(! $r)
$x['pagetitle'] = 'home';
@@ -217,13 +211,15 @@ class Webpages extends \Zotlabs\Web\Controller {
'created' => $rr['created'],
'edited' => $rr['edited'],
'mimetype' => $rr['mimetype'],
- 'pagetitle' => $rr['v'],
+ 'pageurl' => str_replace('%2f','/',$rr['v']),
+ 'pagetitle' => urldecode($rr['v']),
'mid' => $rr['mid'],
'layout_mid' => $rr['layout_mid']
);
$pages[$rr['iid']][] = array(
'url' => $rr['iid'],
- 'pagetitle' => $rr['v'],
+ 'pageurl' => str_replace('%2f','/',$rr['v']),
+ 'pagetitle' => urldecode($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']),
@@ -693,7 +689,8 @@ class Webpages extends \Zotlabs\Web\Controller {
}
rrmdir($zip_folderpath); rrmdir($tmp_folderpath); // delete temporary files
-
+ killme();
+
break;
default :
break;
diff --git a/Zotlabs/Module/Wfinger.php b/Zotlabs/Module/Wfinger.php
index 04eed47c3..9db95f181 100644
--- a/Zotlabs/Module/Wfinger.php
+++ b/Zotlabs/Module/Wfinger.php
@@ -30,14 +30,24 @@ class Wfinger extends \Zotlabs\Web\Controller {
$resource = $_REQUEST['resource'];
logger('webfinger: ' . $resource,LOGGER_DEBUG);
+
+ $root_resource = false;
+ $pchan = false;
+
+ if(strcasecmp(rtrim($resource,'/'),z_root()) === 0)
+ $root_resource = true;
+
$r = null;
- if($resource) {
+ if(($resource) && (! $root_resource)) {
if(strpos($resource,'acct:') === 0) {
$channel = str_replace('acct:','',$resource);
if(strpos($channel,'@') !== false) {
$host = substr($channel,strpos($channel,'@')+1);
+
+ // If the webfinger address points off site, redirect to the correct site
+
if(strcasecmp($host,\App::get_hostname())) {
goaway('https://' . $host . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=' . $zot : ''));
}
@@ -48,16 +58,47 @@ class Wfinger extends \Zotlabs\Web\Controller {
$channel = str_replace('~','',basename($resource));
}
- $r = q("select * from channel left join xchan on channel_hash = xchan_hash
- where channel_address = '%s' limit 1",
- dbesc($channel)
- );
-
+ if(substr($channel,0,1) === '[' ) {
+ $channel = substr($channel,1);
+ $channel = substr($channel,0,-1);
+ $pchan = true;
+ $r = q("select * from pchan left join xchan on pchan_hash = xchan_hash
+ where pchan_guid = '%s' limit 1",
+ dbesc($channel)
+ );
+ if($r) {
+ $r[0] = pchan_to_chan($r[0]);
+ }
+ }
+ else {
+ $r = q("select * from channel left join xchan on channel_hash = xchan_hash
+ where channel_address = '%s' limit 1",
+ dbesc($channel)
+ );
+ }
}
header('Access-Control-Allow-Origin: *');
+
+ if($root_resource) {
+ $result['subject'] = $resource;
+ $result['properties'] = [
+ 'https://w3id.org/security/v1#publicKeyPem' => get_config('system','pubkey')
+ ];
+ $result['links'] = [
+ [
+ 'rel' => 'http://purl.org/openwebauth/v1',
+ 'type' => 'application/x-zot+json',
+ 'href' => z_root() . '/owa',
+ ],
+ ];
+
+
+
+ }
+
if($resource && $r) {
$h = q("select hubloc_addr from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
@@ -67,7 +108,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
$result['subject'] = $resource;
$aliases = array(
- z_root() . '/channel/' . $r[0]['channel_address'],
+ z_root() . (($pchan) ? '/pchan/' : '/channel/') . $r[0]['channel_address'],
z_root() . '/~' . $r[0]['channel_address']
);
@@ -77,64 +118,107 @@ class Wfinger extends \Zotlabs\Web\Controller {
}
}
- $result['aliases'] = array();
+ $result['aliases'] = [];
- $result['properties'] = array(
- 'http://webfinger.net/ns/name' => $r[0]['channel_name'],
- 'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name']
- );
+ $result['properties'] = [
+ 'http://webfinger.net/ns/name' => $r[0]['channel_name'],
+ 'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name'],
+ 'https://w3id.org/security/v1#publicKeyPem' => $r[0]['xchan_pubkey']
+ ];
foreach($aliases as $alias)
if($alias != $resource)
$result['aliases'][] = $alias;
- $result['links'] = array(
-
- array(
- 'rel' => 'http://webfinger.net/rel/avatar',
- 'type' => $r[0]['xchan_photo_mimetype'],
- 'href' => $r[0]['xchan_photo_l']
- ),
-
- array(
- 'rel' => 'http://webfinger.net/rel/profile-page',
- 'href' => z_root() . '/profile/' . $r[0]['channel_address'],
- ),
-
- array(
- 'rel' => 'http://webfinger.net/rel/blog',
- 'href' => z_root() . '/channel/' . $r[0]['channel_address'],
- ),
-
- array(
- 'rel' => 'http://ostatus.org/schema/1.0/subscribe',
- 'template' => z_root() . '/follow/url={uri}',
- ),
-
- array(
- 'rel' => 'http://purl.org/zot/protocol',
- 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
- ),
-
- array(
- 'rel' => 'magic-public-key',
- 'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
- )
- );
+
+ if($pchan) {
+ $result['links'] = [
+
+ [
+ 'rel' => 'http://webfinger.net/rel/avatar',
+ 'type' => $r[0]['xchan_photo_mimetype'],
+ 'href' => $r[0]['xchan_photo_l']
+ ],
+
+ [
+ 'rel' => 'http://webfinger.net/rel/profile-page',
+ 'href' => $r[0]['xchan_url'],
+ ],
+
+ [
+ 'rel' => 'magic-public-key',
+ 'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
+ ]
+
+ ];
+
+
+ }
+ else {
+
+ $result['links'] = [
+
+ [
+ 'rel' => 'http://webfinger.net/rel/avatar',
+ 'type' => $r[0]['xchan_photo_mimetype'],
+ 'href' => $r[0]['xchan_photo_l']
+ ],
+
+ [
+ 'rel' => 'http://webfinger.net/rel/profile-page',
+ 'href' => z_root() . '/profile/' . $r[0]['channel_address'],
+ ],
+
+ [
+ 'rel' => 'http://schemas.google.com/g/2010#updates-from',
+ 'type' => 'application/atom+xml',
+ 'href' => z_root() . '/ofeed/' . $r[0]['channel_address']
+ ],
+
+ [
+ 'rel' => 'http://webfinger.net/rel/blog',
+ 'href' => z_root() . '/channel/' . $r[0]['channel_address'],
+ ],
+
+ [
+ 'rel' => 'http://ostatus.org/schema/1.0/subscribe',
+ 'template' => z_root() . '/follow?f=&url={uri}',
+ ],
+
+ [
+ 'rel' => 'http://purl.org/zot/protocol',
+ 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
+ ],
+
+ [
+ 'rel' => 'http://purl.org/openwebauth/v1',
+ 'type' => 'application/x-zot+json',
+ 'href' => z_root() . '/owa',
+ ],
+
+ [
+ 'rel' => 'magic-public-key',
+ 'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
+ ]
+ ];
+ }
+
if($zot) {
// get a zotinfo packet and return it with webfinger
- $result['zot'] = zotinfo(array('address' => $r[0]['xchan_addr']));
+ $result['zot'] = zotinfo( [ 'address' => $r[0]['xchan_addr'] ]);
}
}
- else {
+
+ if(! $result) {
header($_SERVER["SERVER_PROTOCOL"] . ' ' . 400 . ' ' . 'Bad Request');
killme();
}
- $arr = array('channel' => $r[0], 'request' => $_REQUEST, 'result' => $result);
+ $arr = [ 'channel' => $r[0], 'pchan' => $pchan, 'request' => $_REQUEST, 'result' => $result ];
call_hooks('webfinger',$arr);
-
+
+
json_return_and_die($arr['result'],'application/jrd+json');
}
diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php
index d42c26681..d6a01af11 100644
--- a/Zotlabs/Module/Wiki.php
+++ b/Zotlabs/Module/Wiki.php
@@ -3,6 +3,7 @@
namespace Zotlabs\Module;
use \Zotlabs\Lib as Zlib;
+use \Michelf\MarkdownExtra;
require_once('include/acl_selectors.php');
require_once('include/conversation.php');
@@ -41,7 +42,7 @@ class Wiki extends \Zotlabs\Web\Controller {
if(! feature_enabled(\App::$profile_uid,'wiki')) {
notice( t('Not found') . EOL);
- return;
+ return;
}
@@ -75,6 +76,8 @@ class Wiki extends \Zotlabs\Web\Controller {
$wiki_owner = true;
+ nav_set_selected('Wiki');
+
// Obtain the default permission settings of the channel
$owner_acl = array(
'allow_cid' => $owner['channel_allow_cid'],
@@ -106,15 +109,17 @@ class Wiki extends \Zotlabs\Web\Controller {
}
$is_owner = ((local_channel()) && (local_channel() == \App::$profile['profile_uid']) ? true : false);
- $o = profile_tabs($a, $is_owner, \App::$profile['channel_address']);
+ //$o = profile_tabs($a, $is_owner, \App::$profile['channel_address']);
+ $o = '';
// Download a wiki
-/*
+
if((argc() > 3) && (argv(2) === 'download') && (argv(3) === 'wiki')) {
$resource_id = argv(4);
+ $w = Zlib\NativeWiki::get_wiki($owner['channel_id'],$observer_hash,$resource_id);
- $w = Zlib\NativeWiki::get_wiki($owner,$observer_hash,$resource_id);
+// $w = Zlib\NativeWiki::get_wiki($owner,$observer_hash,$resource_id);
if(! $w['htmlName']) {
notice(t('Error retrieving wiki') . EOL);
}
@@ -129,8 +134,41 @@ class Wiki extends \Zotlabs\Web\Controller {
$zip_filename = $w['urlName'];
$zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename;
+
// Generate the zip file
- ZLib\ExtendedZip::zipTree($w['path'], $zip_filepath, \ZipArchive::CREATE);
+
+ $zip = new \ZipArchive;
+ $r = $zip->open($zip_filepath, \ZipArchive::CREATE);
+ if($r === true) {
+ $pages = [];
+ $i = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' order by revision desc",
+ dbesc($resource_id)
+ );
+
+ if($i) {
+ foreach($i as $iv) {
+ if(in_array($iv['mid'],$pages))
+ continue;
+
+ if($iv['mimetype'] === 'text/plain') {
+ $content = html_entity_decode($iv['body'],ENT_COMPAT,'UTF-8');
+ }
+ elseif($iv['mimetype'] === 'text/bbcode') {
+ $content = html_entity_decode($iv['body'],ENT_COMPAT,'UTF-8');
+ }
+ elseif($iv['mimetype'] === 'text/markdown') {
+ $content = html_entity_decode(Zlib\MarkdownSoap::unescape($iv['body']),ENT_COMPAT,'UTF-8');
+ }
+ $fname = get_iconfig($iv['id'],'nwikipage','pagetitle') . Zlib\NativeWikiPage::get_file_ext($iv);
+ $zip->addFromString($fname,$content);
+ $pages[] = $iv['mid'];
+ }
+
+
+ }
+
+ }
+ $zip->close();
// Output the file for download
@@ -149,10 +187,11 @@ class Wiki extends \Zotlabs\Web\Controller {
killme();
}
-*/
+
switch(argc()) {
case 2:
$wikis = Zlib\NativeWiki::listwikis($owner, get_observer_hash());
+
if($wikis) {
$o .= replace_macros(get_markup_template('wikilist.tpl'), array(
'$header' => t('Wikis'),
@@ -166,16 +205,19 @@ class Wiki extends \Zotlabs\Web\Controller {
'$create' => t('Create New'),
'$submit' => t('Submit'),
'$wikiName' => array('wikiName', t('Wiki name')),
- '$mimeType' => array('mimeType', t('Content type'), '', '', ['text/markdown' => 'Markdown', 'text/bbcode' => 'BB Code']),
+ '$mimeType' => array('mimeType', t('Content type'), '', '', ['text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]),
'$name' => t('Name'),
'$type' => t('Type'),
+ '$unlocked' => t('Any&nbsp;type'),
'$lockstate' => $x['lockstate'],
'$acl' => $x['acl'],
'$allow_cid' => $x['allow_cid'],
'$allow_gid' => $x['allow_gid'],
'$deny_cid' => $x['deny_cid'],
'$deny_gid' => $x['deny_gid'],
- '$notify' => array('postVisible', t('Create a status post for this wiki'), '', '', array(t('No'), t('Yes')))
+ '$typelock' => array('typelock', t('Lock content type'), '', '', array(t('No'), t('Yes'))),
+ '$notify' => array('postVisible', t('Create a status post for this wiki'), '', '', array(t('No'), t('Yes'))),
+ '$edit_wiki_name' => t('Edit Wiki Name')
));
return $o;
@@ -190,12 +232,29 @@ class Wiki extends \Zotlabs\Web\Controller {
goaway(z_root() . '/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/Home');
case 4:
+ default:
// GET /wiki/channel/wiki/page
// Fetch the wiki info and determine observer permissions
$wikiUrlName = urldecode(argv(2));
- $pageUrlName = urldecode(argv(3));
+
+ $page_name = '';
+ $ignore_language = false;
+
+ for($x = 3; $x < argc(); $x ++) {
+ if($page_name === '' && argv($x) === '-') {
+ $ignore_language = true;
+ continue;
+ }
+ if($page_name) {
+ $page_name .= '/';
+ }
+ $page_name .= argv($x);
+ }
+
+ $pageUrlName = urldecode($page_name);
+ $langPageUrlName = urldecode(\App::$language . '/' . $page_name);
$w = Zlib\NativeWiki::exists_by_name($owner['channel_id'], $wikiUrlName);
@@ -225,35 +284,46 @@ class Wiki extends \Zotlabs\Web\Controller {
$wikiheaderPage = urldecode($pageUrlName);
$renamePage = (($wikiheaderPage === 'Home') ? '' : t('Rename page'));
+ $p = [];
- $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
- if(! $p['success']) {
+ if(! $ignore_language) {
+ $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $langPageUrlName));
+ }
+ if(! ($p && $p['success'])) {
+ $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
+ }
+ if(! ($p && $p['success'])) {
notice( t('Error retrieving page content') . EOL);
goaway(z_root() . '/' . argv(0) . '/' . argv(1) );
}
- $mimeType = $p['mimeType'];
+ $mimeType = $p['pageMimeType'];
+
+ $sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page'));
+ if($mimeType === 'text/plain')
+ $sampleContent = t('New page');
+
+ $content = (($p['content'] == '') ? $sampleContent : $p['content']);
- $rawContent = (($p['mimeType'] == 'text/bbcode')
- ? htmlspecialchars_decode(json_decode($p['content']),ENT_COMPAT)
- : htmlspecialchars_decode($p['content'],ENT_COMPAT)
- );
- $content = ($p['content'] !== '' ? $rawContent : '"# New page\n"');
// Render the Markdown-formatted page content in HTML
if($mimeType == 'text/bbcode') {
$renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
}
- else {
- require_once('library/markdown.php');
- $html = Zlib\NativeWikiPage::generate_toc(zidify_text(purify_html(Markdown(Zlib\NativeWikiPage::bbcode(json_decode($content))))));
+ elseif($mimeType === 'text/plain') {
+ $renderedContent = str_replace(["\n",' ',"\t"],[EOL,'&nbsp;','&nbsp;&nbsp;&nbsp;&nbsp;'],htmlentities($content,ENT_COMPAT,'UTF-8',false));
+ }
+ elseif($mimeType === 'text/markdown') {
+ $content = Zlib\MarkdownSoap::unescape($content);
+ $html = Zlib\NativeWikiPage::generate_toc(zidify_text(MarkdownExtra::defaultTransform(Zlib\NativeWikiPage::bbcode($content))));
$renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
}
$showPageControls = $wiki_editor;
break;
- default: // Strip the extraneous URL components
- goaway('/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/' . $pageUrlName);
+// default: // Strip the extraneous URL components
+// goaway('/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/' . $pageUrlName);
}
+
$wikiModalID = random_string(3);
$wikiModal = replace_macros(get_markup_template('generic_modal.tpl'), array(
@@ -263,6 +333,9 @@ class Wiki extends \Zotlabs\Web\Controller {
'$cancel' => t('Cancel')
));
+ $types = [ 'text/bbcode' => t('BBcode'), 'text/markdown' => t('Markdown'), 'text/plain' => 'Text' ];
+ $currenttype = $types[$mimeType];
+
$placeholder = t('Short description of your changes (optional)');
$o .= replace_macros(get_markup_template('wiki.tpl'),array(
@@ -272,10 +345,12 @@ class Wiki extends \Zotlabs\Web\Controller {
'$showPageControls' => $showPageControls,
'$editOrSourceLabel' => (($showPageControls) ? t('Edit') : t('Source')),
'$tools_label' => 'Page Tools',
- '$channel' => $owner['channel_address'],
+ '$channel_address' => $owner['channel_address'],
+ '$channel_id' => $owner['channel_id'],
'$resource_id' => $resource_id,
'$page' => $pageUrlName,
'$mimeType' => $mimeType,
+ '$typename' => $currenttype,
'$content' => $content,
'$renderedContent' => $renderedContent,
'$pageRename' => array('pageRename', t('New page name'), '', ''),
@@ -295,8 +370,8 @@ class Wiki extends \Zotlabs\Web\Controller {
'$modalerroralbum' => t('Error getting album'),
));
- if($p['mimeType'] != 'text/bbcode')
- head_add_js('library/ace/ace.js'); // Ace Code Editor
+ if($p['pageMimeType'] === 'text/markdown')
+ head_add_js('/library/ace/ace.js'); // Ace Code Editor
return $o;
}
@@ -314,31 +389,33 @@ class Wiki extends \Zotlabs\Web\Controller {
return;
}
- if(! perm_is_allowed(\App::$profile_uid,get_observer_hash(),'write_wiki')) {
- notice( t('Permission denied.') . EOL);
- return;
- }
-
// /wiki/channel/preview
// Render mardown-formatted text in HTML for preview
if((argc() > 2) && (argv(2) === 'preview')) {
$content = $_POST['content'];
$resource_id = $_POST['resource_id'];
+
$w = Zlib\NativeWiki::get_wiki($owner['channel_id'],$observer_hash,$resource_id);
$wikiURL = argv(0) . '/' . argv(1) . '/' . $w['urlName'];
- $mimeType = $w['mimeType'];
+ $mimeType = $_POST['mimetype'];
- if($mimeType == 'text/bbcode') {
+ if($mimeType === 'text/bbcode') {
$html = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))),$wikiURL);
}
- else {
- require_once('library/markdown.php');
- $content = Zlib\NativeWikiPage::bbcode($content);
- $html = Zlib\NativeWikiPage::generate_toc(zidify_text(purify_html(Markdown($content))));
+ elseif($mimeType === 'text/markdown') {
+ $bb = Zlib\NativeWikiPage::bbcode($content);
+ $x = new ZLib\MarkdownSoap($bb);
+ $md = $x->clean();
+ $md = ZLib\MarkdownSoap::unescape($md);
+ $html = MarkdownExtra::defaultTransform($md);
+ $html = Zlib\NativeWikiPage::generate_toc(zidify_text($html));
$html = Zlib\NativeWikiPage::convert_links($html,$wikiURL);
}
+ elseif($mimeType === 'text/plain') {
+ $html = str_replace(["\n",' ',"\t"],[EOL,'&nbsp;','&nbsp;&nbsp;&nbsp;&nbsp;'],htmlentities($content,ENT_COMPAT,'UTF-8',false));
+ }
json_return_and_die(array('html' => $html, 'success' => true));
}
@@ -359,10 +436,19 @@ class Wiki extends \Zotlabs\Web\Controller {
$wiki['htmlName'] = escape_tags($_POST['wikiName']);
$wiki['urlName'] = urlencode(urlencode($_POST['wikiName']));
$wiki['mimeType'] = $_POST['mimeType'];
+ $wiki['typelock'] = $_POST['typelock'];
if($wiki['urlName'] === '') {
notice( t('Error creating wiki. Invalid name.') . EOL);
goaway('/wiki');
+ return; //not reached
+ }
+
+ $exists = Zlib\NativeWiki::exists_by_name($owner['channel_id'], $wiki['urlName']);
+ if($exists['id']) {
+ notice( t('A wiki with this name already exists.') . EOL);
+ goaway('/wiki');
+ return; //not reached
}
// Get ACL for permissions
@@ -371,7 +457,7 @@ class Wiki extends \Zotlabs\Web\Controller {
$r = Zlib\NativeWiki::create_wiki($owner, $observer_hash, $wiki, $acl);
if($r['success']) {
Zlib\NativeWiki::sync_a_wiki_item($owner['channel_id'],$r['item_id'],$r['item']['resource_id']);
- $homePage = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash,'Home', $r['item']['resource_id']);
+ $homePage = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash,'Home', $r['item']['resource_id'], $wiki['mimeType']);
if(! $homePage['success']) {
notice( t('Wiki created, but error creating Home page.'));
goaway(z_root() . '/wiki/' . $nick . '/' . $wiki['urlName']);
@@ -385,6 +471,52 @@ class Wiki extends \Zotlabs\Web\Controller {
}
}
+ // Update a wiki
+ // /wiki/channel/update/wiki
+ if ((argc() > 3) && (argv(2) === 'update') && (argv(3) === 'wiki')) {
+ // Only the channel owner can update a wiki, at least until we create a
+ // more detail permissions framework
+
+ if (local_channel() !== intval($owner['channel_id'])) {
+ goaway('/' . argv(0) . '/' . $nick . '/');
+ }
+
+ $arr = [];
+
+ $arr['urlName'] = urlencode(urlencode($_POST['origRawName']));
+
+ if($_POST['updateRawName'])
+ $arr['updateRawName'] = $_POST['updateRawName'];
+
+ if(($arr['urlName'] || $arr['updateRawName']) === '') {
+ notice( t('Error updating wiki. Invalid name.') . EOL);
+ goaway('/wiki');
+ return; //not reached
+ }
+
+ $wiki = Zlib\NativeWiki::exists_by_name($owner['channel_id'], $arr['urlName']);
+
+ if($wiki['resource_id']) {
+
+ $arr['resource_id'] = $wiki['resource_id'];
+
+ $acl = new \Zotlabs\Access\AccessList($owner);
+ $acl->set_from_array($_POST);
+
+ $r = Zlib\NativeWiki::update_wiki($owner['channel_id'], $observer_hash, $arr, $acl);
+ if($r['success']) {
+ Zlib\NativeWiki::sync_a_wiki_item($owner['channel_id'],$r['item_id'],$r['item']['resource_id']);
+ goaway(z_root() . '/wiki/' . $nick);
+ }
+ else {
+ notice( t('Error updating wiki'));
+ goaway(z_root() . '/wiki');
+ }
+
+ }
+ goaway(z_root() . '/wiki');
+ }
+
// Delete a wiki
if ((argc() > 3) && (argv(2) === 'delete') && (argv(3) === 'wiki')) {
@@ -410,11 +542,13 @@ class Wiki extends \Zotlabs\Web\Controller {
// Create a page
if ((argc() === 4) && (argv(2) === 'create') && (argv(3) === 'page')) {
+ $mimetype = $_POST['mimetype'];
+
$resource_id = $_POST['resource_id'];
// Determine if observer has permission to create a page
+
-
- $perms = Zlib\NativeWiki::get_permissions($resource_id, intval($owner['channel_id']), $observer_hash);
+ $perms = Zlib\NativeWiki::get_permissions($resource_id, intval($owner['channel_id']), $observer_hash, $mimetype);
if(! $perms['write']) {
logger('Wiki write permission denied. ' . EOL);
json_return_and_die(array('success' => false));
@@ -424,7 +558,7 @@ class Wiki extends \Zotlabs\Web\Controller {
if(urlencode(escape_tags($_POST['pageName'])) === '') {
json_return_and_die(array('message' => 'Error creating page. Invalid name.', 'success' => false));
}
- $page = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id);
+ $page = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id, $mimetype);
if($page['item_id']) {
$commit = Zlib\NativeWikiPage::commit(array(
@@ -461,10 +595,16 @@ class Wiki extends \Zotlabs\Web\Controller {
json_return_and_die(array('pages' => null, 'message' => 'Permission denied.', 'success' => false));
}
- $page_list_html = widget_wiki_pages(array(
- 'resource_id' => $resource_id,
- 'refresh' => true,
- 'channel' => argv(1)));
+ // @FIXME - we shouldn't invoke this if it isn't in the PDL or has been over-ridden
+
+ $x = new \Zotlabs\Widget\Wiki_pages();
+
+ $page_list_html = $x->widget([
+ 'resource_id' => $resource_id,
+ 'channel_id' => $owner['channel_id'],
+ 'channel_address' => $owner['channel_address'],
+ 'refresh' => true
+ ]);
json_return_and_die(array('pages' => $page_list_html, 'message' => '', 'success' => true));
}
@@ -519,7 +659,6 @@ class Wiki extends \Zotlabs\Web\Controller {
$resource_id = $_POST['resource_id'];
$pageUrlName = $_POST['name'];
-
// Determine if observer has permission to read content
$perms = Zlib\NativeWiki::get_permissions($resource_id, intval($owner['channel_id']), $observer_hash);
@@ -528,11 +667,12 @@ class Wiki extends \Zotlabs\Web\Controller {
json_return_and_die(array('historyHTML' => '', 'message' => 'Permission denied.', 'success' => false));
}
- $historyHTML = widget_wiki_page_history(array(
+ $historyHTML = \Zotlabs\Lib\NativeWikiPage::render_page_history(array(
'resource_id' => $resource_id,
'pageUrlName' => $pageUrlName,
'permsWrite' => $perms['write']
));
+
json_return_and_die(array('historyHTML' => $historyHTML, 'message' => '', 'success' => true));
}
diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php
index 3ed19962b..959e31cbe 100644
--- a/Zotlabs/Module/Xrd.php
+++ b/Zotlabs/Module/Xrd.php
@@ -9,6 +9,7 @@ class Xrd extends \Zotlabs\Web\Controller {
function init() {
$uri = urldecode(notags(trim($_GET['uri'])));
+ $subject = $uri;
logger('xrd: ' . $uri,LOGGER_DEBUG);
$resource = $uri;
@@ -30,13 +31,7 @@ class Xrd extends \Zotlabs\Web\Controller {
);
if(! $r)
killme();
-
- $dspr = replace_macros(get_markup_template('xrd_diaspora.tpl'),array(
- '$baseurl' => z_root(),
- '$dspr_guid' => $r[0]['channel_guid'] . str_replace('.','',\App::get_hostname()),
- '$dspr_key' => base64_encode(pemtorsa($r[0]['channel_pubkey']))
- ));
-
+
$salmon_key = salmon_key($r[0]['channel_pubkey']);
header('Access-Control-Allow-Origin: *');
@@ -49,24 +44,21 @@ class Xrd extends \Zotlabs\Web\Controller {
if($aliases[$x] === $resource)
unset($aliases[$x]);
}
-
-
+
$o = replace_macros(get_markup_template('xrd_person.tpl'), array(
'$nick' => $r[0]['channel_address'],
'$accturi' => $resource,
+ '$subject' => $subject,
'$aliases' => $aliases,
+ '$channel_url' => z_root() . '/channel/' . $r[0]['channel_address'],
'$profile_url' => z_root() . '/channel/' . $r[0]['channel_address'],
'$hcard_url' => z_root() . '/hcard/' . $r[0]['channel_address'],
- '$atom' => z_root() . '/feed/' . $r[0]['channel_address'],
+ '$atom' => z_root() . '/ofeed/' . $r[0]['channel_address'],
'$zot_post' => z_root() . '/post/' . $r[0]['channel_address'],
'$poco_url' => z_root() . '/poco/' . $r[0]['channel_address'],
'$photo' => z_root() . '/photo/profile/l/' . $r[0]['channel_id'],
- '$dspr' => $dspr,
- // '$salmon' => z_root() . '/salmon/' . $r[0]['channel_address'],
- // '$salmen' => z_root() . '/salmon/' . $r[0]['channel_address'] . '/mention',
'$modexp' => 'data:application/magic-public-key,' . $salmon_key,
- '$subscribe' => z_root() . '/follow?url={uri}',
- '$bigkey' => salmon_key($r[0]['channel_pubkey'])
+ '$subscribe' => z_root() . '/follow?f=&amp;url={uri}',
));
diff --git a/Zotlabs/Module/Zfinger.php b/Zotlabs/Module/Zfinger.php
index 2ff605fc9..0f7f6a64b 100644
--- a/Zotlabs/Module/Zfinger.php
+++ b/Zotlabs/Module/Zfinger.php
@@ -9,8 +9,36 @@ class Zfinger extends \Zotlabs\Web\Controller {
require_once('include/zot.php');
require_once('include/crypto.php');
-
$x = zotinfo($_REQUEST);
+
+ if($x && $x['guid'] && $x['guid_sig']) {
+ $chan_hash = make_xchan_hash($x['guid'],$x['guid_sig']);
+ if($chan_hash) {
+ $chan = channelx_by_hash($chan_hash);
+ }
+ }
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/json' ;
+ $ret = json_encode($x);
+
+ if($chan) {
+ $hash = \Zotlabs\Web\HTTPSig::generate_digest($ret,false);
+ $headers['Digest'] = 'SHA-256=' . $hash;
+ \Zotlabs\Web\HTTPSig::create_sig('',$headers,$chan['channel_prvkey'],
+ 'acct:' . $chan['channel_address'] . '@' . \App::get_hostname(),true);
+ }
+ else {
+ foreach($headers as $k => $v) {
+ header($k . ': ' . $v);
+ }
+ }
+
+ echo $ret;
+ killme();
+
+
+
json_return_and_die($x);
}
diff --git a/Zotlabs/Module/Zotfeed.php b/Zotlabs/Module/Zotfeed.php
index 6b505c890..381e3acb2 100644
--- a/Zotlabs/Module/Zotfeed.php
+++ b/Zotlabs/Module/Zotfeed.php
@@ -22,7 +22,8 @@ class Zotfeed extends \Zotlabs\Web\Controller {
$observer = \App::get_observer();
-
+ logger('observer: ' . get_observer_hash(), LOGGER_DEBUG);
+
$channel_address = ((argc() > 1) ? argv(1) : '');
if($channel_address) {
$r = q("select channel_id, channel_name from channel where channel_address = '%s' and channel_removed = 0 limit 1",
diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php
index 5826063fd..8831bd117 100644
--- a/Zotlabs/Render/Comanche.php
+++ b/Zotlabs/Render/Comanche.php
@@ -4,8 +4,6 @@ namespace Zotlabs\Render;
require_once('include/security.php');
require_once('include/menu.php');
-require_once('include/widgets.php');
-
class Comanche {
@@ -20,7 +18,49 @@ class Comanche {
$s = str_replace($mtch[0], '', $s);
}
}
-
+
+ /*
+ * This section supports the "switch" statement of the form given by the following
+ * example. The [default][/default] block must be the last in the arbitrary
+ * list of cases. The first case that matches the switch variable is used
+ * and the rest are not evaluated.
+ *
+ * [switch observer.language]
+ * [case de]
+ * [block]german-content[/block]
+ * [/case]
+ * [case es]
+ * [block]spanish-content[/block]
+ * [/case]
+ * [default]
+ * [block]english-content[/block]
+ * [/default]
+ * [/switch]
+ */
+
+ $cnt = preg_match_all("/\[switch (.*?)\](.*?)\[default\](.*?)\[\/default\]\s*\[\/switch\]/ism", $s, $matches, PREG_SET_ORDER);
+ if($cnt) {
+ foreach($matches as $mtch) {
+ $switch_done = 0;
+ $switch_var = $this->get_condition_var($mtch[1]);
+ $default = $mtch[3];
+ $cases = array();
+ $cntt = preg_match_all("/\[case (.*?)\](.*?)\[\/case\]/ism", $mtch[2], $cases, PREG_SET_ORDER);
+ if($cntt) {
+ foreach($cases as $case) {
+ if($case[1] === $switch_var) {
+ $switch_done = 1;
+ $s = str_replace($mtch[0], $case[2], $s);
+ break;
+ }
+ }
+ if($switch_done === 0) {
+ $s = str_replace($mtch[0], $default, $s);
+ }
+ }
+ }
+ }
+
$cnt = preg_match_all("/\[if (.*?)\](.*?)\[else\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
@@ -81,6 +121,11 @@ class Comanche {
if($cnt)
\App::$layout['theme'] = trim($matches[1]);
+ $cnt = preg_match("/\[navbar\](.*?)\[\/navbar\]/ism", $s, $matches);
+ if($cnt)
+ \App::$layout['navbar'] = trim($matches[1]);
+
+
$cnt = preg_match_all("/\[webpage\](.*?)\[\/webpage\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
// only the last webpage definition is used if there is more than one
@@ -108,6 +153,7 @@ class Comanche {
* $observer.address - xchan_addr or false
* $observer.name - xchan_name or false
* $observer - xchan_hash of observer or empty string
+ * $local_channel - logged in channel_id or false
*/
function get_condition_var($v) {
@@ -117,6 +163,9 @@ class Comanche {
return get_config($x[1],$x[2]);
elseif($x[0] === 'request')
return $_SERVER['REQUEST_URI'];
+ elseif($x[0] === 'local_channel') {
+ return local_channel();
+ }
elseif($x[0] === 'observer') {
if(count($x) > 1) {
if($x[1] == 'language')
@@ -128,6 +177,8 @@ class Comanche {
return $y['xchan_addr'];
elseif($x[1] == 'name')
return $y['xchan_name'];
+ elseif($x[1] == 'webname')
+ return substr($y['xchan_addr'],0,strpos($y['xchan_addr'],'@'));
return false;
}
return get_observer_hash();
@@ -410,6 +461,24 @@ class Comanche {
}
}
+ if(! purify_filename($name))
+ return '';
+
+ $clsname = ucfirst($name);
+ $nsname = "\\Zotlabs\\Widget\\" . $clsname;
+
+ if(file_exists('Zotlabs/SiteWidget/' . $clsname . '.php'))
+ require_once('Zotlabs/SiteWidget/' . $clsname . '.php');
+ elseif(file_exists('Zotlabs/Widget/' . $clsname . '.php'))
+ require_once('Zotlabs/Widget/' . $clsname . '.php');
+ if(class_exists($nsname)) {
+ $x = new $nsname;
+ $f = 'widget';
+ if(method_exists($x,$f)) {
+ return $x->$f($vars);
+ }
+ }
+
$func = 'widget_' . trim($name);
if(! function_exists($func)) {
diff --git a/Zotlabs/Render/Theme.php b/Zotlabs/Render/Theme.php
index 9f9009d72..3a0116abe 100644
--- a/Zotlabs/Render/Theme.php
+++ b/Zotlabs/Render/Theme.php
@@ -70,9 +70,15 @@ class Theme {
$chosen_theme = $_GET['theme_preview'];
// Allow theme selection of the form 'theme_name:schema_name'
-
$themepair = explode(':', $chosen_theme);
+ // Check if $chosen_theme is compatible with core. If not fall back to default
+ $info = get_theme_info($themepair[0]);
+ $compatible = check_plugin_versions($info);
+ if(!$compatible) {
+ $chosen_theme = '';
+ }
+
if($chosen_theme && (file_exists('view/theme/' . $themepair[0] . '/css/style.css') || file_exists('view/theme/' . $themepair[0] . '/php/style.php'))) {
return($themepair);
}
@@ -125,9 +131,9 @@ class Theme {
$opts .= $schema_str;
if(file_exists('view/theme/' . $t . '/php/style.php'))
- return('view/theme/' . $t . '/php/style.pcss' . $opts);
+ return('/view/theme/' . $t . '/php/style.pcss' . $opts);
- return('view/theme/' . $t . '/css/style.css');
+ return('/view/theme/' . $t . '/css/style.css');
}
function debug() {
diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php
index 0ff9fad13..d8af03703 100644
--- a/Zotlabs/Storage/BasicAuth.php
+++ b/Zotlabs/Storage/BasicAuth.php
@@ -187,14 +187,11 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
}
protected function check_module_access($channel_id) {
- if($channel_id && \App::$module === 'cdav') {
- $x = get_pconfig($channel_id,'cdav','enabled');
- if(! $x) {
- $this->module_disabled = true;
- return false;
- }
+ if($channel_id && in_array(\App::$module,[ 'dav', 'cdav', 'snap'] )) {
+ return true;
}
- return true;
+ $this->module_disabled = true;
+ return false;
}
/**
diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php
index a30eedba5..6f6f4a292 100644
--- a/Zotlabs/Storage/Browser.php
+++ b/Zotlabs/Storage/Browser.php
@@ -17,6 +17,7 @@ use Sabre\DAV;
*/
class Browser extends DAV\Browser\Plugin {
+ public $build_page = false;
/**
* @see set_writeable()
* @see \\Sabre\\DAV\\Auth\\Backend\\BackendInterface
@@ -84,7 +85,7 @@ class Browser extends DAV\Browser\Plugin {
require_once('include/conversation.php');
require_once('include/text.php');
if ($this->auth->owner_nick) {
- $html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick);
+ $html = '';
}
$files = $this->server->getPropertiesForPath($path, array(
@@ -240,9 +241,13 @@ class Browser extends DAV\Browser\Plugin {
'$nick' => $this->auth->getCurrentUser()
));
- $a = get_app();
+
+ $a = false;
+
+ nav_set_selected('Files');
+
\App::$page['content'] = $html;
- load_pdl($a);
+ load_pdl();
$current_theme = \Zotlabs\Render\Theme::current();
@@ -255,7 +260,7 @@ class Browser extends DAV\Browser\Plugin {
}
}
$this->server->httpResponse->setHeader('Content-Security-Policy', "script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'");
- construct_page($a);
+ $this->build_page = true;
}
/**
@@ -314,7 +319,16 @@ class Browser extends DAV\Browser\Plugin {
$quota['desc'] = $quotaDesc;
$quota['warning'] = ((($limit) && ((round($used / $limit, 1) * 100) >= 90)) ? t('WARNING:') : ''); // 10485760 bytes = 100MB
- $path = trim(str_replace('cloud/' . $this->auth->owner_nick, '', $path), '/');
+ // strip 'cloud/nickname', but only at the beginning of the path
+
+ $special = 'cloud/' . $this->auth->owner_nick;
+ $count = strlen($special);
+
+ if(strpos($path,$special) === 0)
+ $path = trim(substr($path,$count),'/');
+
+ $info = t('Please use DAV to upload large (video, audio) files.<br>See <a class="zrl" href="help/member/member_guide#Cloud_Desktop_Clients">Cloud Desktop Clients</a>');
+
$output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array(
'$folder_header' => t('Create new folder'),
@@ -322,6 +336,7 @@ class Browser extends DAV\Browser\Plugin {
'$upload_header' => t('Upload file'),
'$upload_submit' => t('Upload'),
'$quota' => $quota,
+ '$info' => $info,
'$channick' => $this->auth->owner_nick,
'$aclselect' => $aclselect,
'$allow_cid' => acl2json($channel_acl['allow_cid']),
@@ -332,7 +347,8 @@ class Browser extends DAV\Browser\Plugin {
'$return_url' => \App::$cmd,
'$path' => $path,
'$folder' => find_folder_hash_by_path($this->auth->owner_id, $path),
- '$dragdroptext' => t('Drop files here to immediately upload')
+ '$dragdroptext' => t('Drop files here to immediately upload'),
+ '$notify' => ['notify', t('Show in your contacts shared folder'), 0, '', [t('No'), t('Yes')]]
));
}
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index 5d078b04e..0ed7a3c68 100644
--- a/Zotlabs/Storage/Directory.php
+++ b/Zotlabs/Storage/Directory.php
@@ -49,7 +49,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
* @param BasicAuth &$auth_plugin
*/
public function __construct($ext_path, &$auth_plugin) {
-// $ext_path = urldecode($ext_path);
+ // $ext_path = urldecode($ext_path);
logger('directory ' . $ext_path, LOGGER_DATA);
$this->ext_path = $ext_path;
// remove "/cloud" from the beginning of the path
@@ -167,6 +167,14 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
intval($this->auth->owner_id)
);
+ $x = attach_syspaths($this->auth->owner_id,$this->folder_hash);
+
+ $y = q("update attach set display_path = '%s where hash = '%s' and uid = %d",
+ dbesc($x['path']),
+ dbesc($this->folder_hash),
+ intval($this->auth->owner_id)
+ );
+
$ch = channelx_by_n($this->auth->owner_id);
if ($ch) {
$sync = attach_export_data($ch, $this->folder_hash);
@@ -260,14 +268,18 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
dbesc($f),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
- '', //TODO: use os_path
- '', //TODO: use display_path
+ '',
+ '',
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
dbesc($deny_gid)
);
+ // fetch the actual storage paths
+
+ $xpath = attach_syspaths($this->auth->owner_id, $hash);
+
// returns the number of bytes that were written to the file, or FALSE on failure
$size = file_put_contents($f, $data);
// delete attach entry if file_put_contents() failed
@@ -281,15 +293,17 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$edited = datetime_convert();
$is_photo = 0;
- $x = @getimagesize($f);
- logger('getimagesize: ' . print_r($x,true), LOGGER_DATA);
- if (($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) {
+ $gis = @getimagesize($f);
+ logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA);
+ if (($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
$is_photo = 1;
}
// updates entry with filesize and timestamp
- $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
+ $d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc($size),
+ dbesc($xpath['os_path']),
+ dbesc($xpath['display_path']),
intval($is_photo),
dbesc($edited),
dbesc($hash),
@@ -312,29 +326,29 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
// check against service class quota
$limit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'));
if ($limit !== false) {
- $x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ",
+ $z = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ",
intval($c[0]['channel_account_id'])
);
- if (($x) && ($x[0]['total'] + $size > $limit)) {
- logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . userReadableSize($limit));
+ if (($z) && ($z[0]['total'] + $size > $limit)) {
+ logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $z[0]['total'] . ' limit is ' . userReadableSize($limit));
attach_delete($c[0]['channel_id'], $hash);
return;
}
}
- if ($is_photo) {
+ if($is_photo) {
$album = '';
if ($this->folder_hash) {
- $f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d",
+ $f1 = q("select filename, display_path from attach WHERE hash = '%s' AND uid = %d",
dbesc($this->folder_hash),
intval($c[0]['channel_id'])
);
if ($f1)
- $album = $f1[0]['filename'];
+ $album = (($f1[0]['display_path']) ? $f1[0]['display_path'] : $f1[0]['filename']);
}
require_once('include/photos.php');
- $args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct);
+ $args = array( 'resource_id' => $hash, 'album' => $album, 'os_syspath' => $f, 'os_path' => $xpath['os_path'], 'display_path' => $xpath['path'], 'filename' => $name, 'getimagesize' => $gis, 'directory' => $direct);
$p = photo_upload($c[0], \App::get_observer(), $args);
}
@@ -646,20 +660,24 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
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';
- }
+
+ $prefix = '';
+ $suffix = '';
+
$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) {
+
+ // @FIXME I don't think we use revisions currently in attach structures.
+ // In case we see any in the wild provide a unique filename. This
+ // name may or may not be accessible
+
+ if($rr['revision'])
+ $rr['filename'] .= '-' . $rr['revision'];
+
//logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
if (intval($rr['is_dir'])) {
$ret[] = new Directory($path . '/' . $rr['filename'], $auth);
@@ -687,7 +705,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$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",
+ AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN)
);
diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php
index d2bca3964..332bf6896 100644
--- a/Zotlabs/Storage/File.php
+++ b/Zotlabs/Storage/File.php
@@ -85,13 +85,23 @@ class File extends DAV\Node implements DAV\IFile {
intval($this->data['id'])
);
+ $x = attach_syspaths($this->auth->owner_id,$this->data['hash']);
+
+ $y = q("update attach set display_path = '%s where hash = '%s' and uid = %d",
+ dbesc($x['path']),
+ dbesc($this->data['hash']),
+ intval($this->auth->owner_id)
+ );
+
if($this->data->is_photo) {
- $r = q("update photo set filename = '%s' where resource_id = '%s' and uid = %d",
+ $r = q("update photo set filename = '%s', display_path = '%s' where resource_id = '%s' and uid = %d",
dbesc($newName),
+ dbesc($x['path']),
dbesc($this->data['hash']),
intval($this->auth->owner_id)
);
}
+
$ch = channelx_by_n($this->auth->owner_id);
if($ch) {
$sync = attach_export_data($ch,$this->data['hash']);
@@ -244,7 +254,7 @@ class File extends DAV\Node implements DAV\IFile {
// @todo this should be a global definition
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
- if (in_array($r[0]['filetype'], $unsafe_types)) {
+ if (in_array($r[0]['filetype'], $unsafe_types) && (! channel_codeallowed($this->data['uid']))) {
header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"');
header('Content-type: text/plain');
}
@@ -255,7 +265,7 @@ class File extends DAV\Node implements DAV\IFile {
$f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x;
else
$f = $x;
- return fopen($f, 'rb');
+ return @fopen($f, 'rb');
}
return dbunescbin($r[0]['content']);
}
@@ -290,7 +300,7 @@ class File extends DAV\Node implements DAV\IFile {
public function getContentType() {
// @todo this should be a global definition.
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
- if (in_array($this->data['filetype'], $unsafe_types)) {
+ if (in_array($this->data['filetype'], $unsafe_types) && (! channel_codeallowed($this->data['uid']))) {
return 'text/plain';
}
return $this->data['filetype'];
diff --git a/Zotlabs/Web/CheckJS.php b/Zotlabs/Web/CheckJS.php
index 109790fa5..8179ceb15 100644
--- a/Zotlabs/Web/CheckJS.php
+++ b/Zotlabs/Web/CheckJS.php
@@ -21,9 +21,9 @@ class CheckJS {
$page = urlencode(\App::$query_string);
if($test) {
- self::$jsdisabled = 1;
+ $this->jsdisabled = 1;
if(array_key_exists('jsdisabled',$_COOKIE))
- self::$jsdisabled = $_COOKIE['jsdisabled'];
+ $this->jsdisabled = $_COOKIE['jsdisabled'];
if(! array_key_exists('jsdisabled',$_COOKIE)) {
\App::$page['htmlhead'] .= "\r\n" . '<script>document.cookie="jsdisabled=0; path=/"; var jsMatch = /\&jsdisabled=0/; if (!jsMatch.exec(location.href)) { location.href = "' . z_root() . '/nojs/0?f=&redir=' . $page . '" ; }</script>' . "\r\n";
@@ -41,7 +41,7 @@ class CheckJS {
}
function disabled() {
- return self::$jsdisabled;
+ return $this->jsdisabled;
}
diff --git a/Zotlabs/Web/HTTPHeaders.php b/Zotlabs/Web/HTTPHeaders.php
new file mode 100644
index 000000000..4be51a8f3
--- /dev/null
+++ b/Zotlabs/Web/HTTPHeaders.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Zotlabs\Web;
+
+class HTTPHeaders {
+
+ private $in_progress = [];
+ private $parsed = [];
+
+
+ function __construct($headers) {
+
+ $lines = explode("\n",str_replace("\r",'',$headers));
+ if($lines) {
+ foreach($lines as $line) {
+ if(preg_match('/^\s+/',$line,$matches) && trim($line)) {
+ if($this->in_progress['k']) {
+ $this->in_progress['v'] .= ' ' . ltrim($line);
+ continue;
+ }
+ }
+ else {
+ if($this->in_progress['k']) {
+ $this->parsed[] = [ $this->in_progress['k'] => $this->in_progress['v'] ];
+ $this->in_progress = [];
+ }
+
+ $this->in_progress['k'] = strtolower(substr($line,0,strpos($line,':')));
+ $this->in_progress['v'] = ltrim(substr($line,strpos($line,':') + 1));
+ }
+
+ }
+ if($this->in_progress['k']) {
+ $this->parsed[] = [ $this->in_progress['k'] => $this->in_progress['v'] ];
+ $this->in_progress = [];
+ }
+ }
+ }
+
+ function fetch() {
+ return $this->parsed;
+ }
+
+ function fetcharr() {
+ $ret = [];
+ if($this->parsed) {
+ foreach($this->parsed as $x) {
+ foreach($x as $y => $z) {
+ $ret[$y] = $z;
+ }
+ }
+ }
+ return $ret;
+ }
+
+
+}
+
+
+
diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php
new file mode 100644
index 000000000..1c66b8cf4
--- /dev/null
+++ b/Zotlabs/Web/HTTPSig.php
@@ -0,0 +1,313 @@
+<?php
+
+namespace Zotlabs\Web;
+
+/**
+ * Implements HTTP Signatures per draft-cavage-http-signatures-07
+ */
+
+
+class HTTPSig {
+
+ // See RFC5843
+
+ static function generate_digest($body,$set = true) {
+ $digest = base64_encode(hash('sha256',$body,true));
+
+ if($set) {
+ header('Digest: SHA-256=' . $digest);
+ }
+ return $digest;
+ }
+
+ // See draft-cavage-http-signatures-08
+
+ static function verify($data,$key = '') {
+
+ $body = $data;
+ $headers = null;
+ $spoofable = false;
+
+ $result = [
+ 'signer' => '',
+ 'header_signed' => false,
+ 'header_valid' => false,
+ 'content_signed' => false,
+ 'content_valid' => false
+ ];
+
+ // decide if $data arrived via controller submission or curl
+ if(is_array($data) && $data['header']) {
+ if(! $data['success'])
+ return $result;
+ $h = new \Zotlabs\Web\HTTPHeaders($data['header']);
+ $headers = $h->fetcharr();
+ $body = $data['body'];
+ }
+
+ else {
+ $headers = [];
+ $headers['(request-target)'] =
+ strtolower($_SERVER['REQUEST_METHOD']) . ' ' .
+ $_SERVER['REQUEST_URI'];
+ foreach($_SERVER as $k => $v) {
+ if(strpos($k,'HTTP_') === 0) {
+ $field = str_replace('_','-',strtolower(substr($k,5)));
+ $headers[$field] = $v;
+ }
+ }
+ }
+
+ $sig_block = null;
+
+ if(array_key_exists('signature',$headers)) {
+ $sig_block = self::parse_sigheader($headers['signature']);
+ }
+ elseif(array_key_exists('authorization',$headers)) {
+ $sig_block = self::parse_sigheader($headers['authorization']);
+ }
+
+ if(! $sig_block) {
+ logger('no signature provided.');
+ return $result;
+ }
+
+ // Warning: This log statement includes binary data
+ // logger('sig_block: ' . print_r($sig_block,true), LOGGER_DATA);
+
+ $result['header_signed'] = true;
+
+ $signed_headers = $sig_block['headers'];
+ if(! $signed_headers)
+ $signed_headers = [ 'date' ];
+
+ $signed_data = '';
+ foreach($signed_headers as $h) {
+ if(array_key_exists($h,$headers)) {
+ $signed_data .= $h . ': ' . $headers[$h] . "\n";
+ }
+ if(strpos($h,'.')) {
+ $spoofable = true;
+ }
+ }
+ $signed_data = rtrim($signed_data,"\n");
+
+ $algorithm = null;
+ if($sig_block['algorithm'] === 'rsa-sha256') {
+ $algorithm = 'sha256';
+ }
+ if($sig_block['algorithm'] === 'rsa-sha512') {
+ $algorithm = 'sha512';
+ }
+
+ if($key && function_exists($key)) {
+ $result['signer'] = $sig_block['keyId'];
+ $key = $key($sig_block['keyId']);
+ }
+
+ if(! $key) {
+ $result['signer'] = $sig_block['keyId'];
+ $key = self::get_activitypub_key($sig_block['keyId']);
+ }
+
+ if(! $key)
+ return $result;
+
+ $x = rsa_verify($signed_data,$sig_block['signature'],$key,$algorithm);
+
+ logger('verified: ' . $x, LOGGER_DEBUG);
+
+ if($x === false)
+ return $result;
+
+ if(! $spoofable)
+ $result['header_valid'] = true;
+
+ if(in_array('digest',$signed_headers)) {
+ $result['content_signed'] = true;
+ $digest = explode('=', $headers['digest']);
+ if($digest[0] === 'SHA-256')
+ $hashalg = 'sha256';
+ if($digest[0] === 'SHA-512')
+ $hashalg = 'sha512';
+
+ // The explode operation will have stripped the '=' padding, so compare against unpadded base64
+ if(rtrim(base64_encode(hash($hashalg,$body,true)),'=') === $digest[1]) {
+ $result['content_valid'] = true;
+ }
+ }
+
+ logger('Content_Valid: ' . $result['content_valid']);
+
+ return $result;
+
+ }
+
+ function get_activitypub_key($id) {
+
+ if(strpos($id,'acct:') === 0) {
+ $x = q("select xchan_pubkey from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1",
+ dbesc(str_replace('acct:','',$id))
+ );
+ }
+ else {
+ $x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
+ dbesc($id)
+ );
+ }
+
+ if($x && $x[0]['xchan_pubkey']) {
+ return ($x[0]['xchan_pubkey']);
+ }
+ $r = as_fetch($id);
+
+ if($r) {
+ $j = json_decode($r,true);
+
+ if($j['id'] !== $id)
+ return false;
+ if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey'])) {
+ return($j['publicKey']['publicKeyPem']);
+ }
+ }
+ return false;
+ }
+
+
+
+
+ static function create_sig($request,$head,$prvkey,$keyid = 'Key',$send_headers = false,$auth = false,$alg = 'sha256',
+ $crypt_key = null, $crypt_algo = 'aes256ctr') {
+
+ $return_headers = [];
+
+ if($alg === 'sha256') {
+ $algorithm = 'rsa-sha256';
+ }
+ if($alg === 'sha512') {
+ $algorithm = 'rsa-sha512';
+ }
+
+ $x = self::sign($request,$head,$prvkey,$alg);
+
+ $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm
+ . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
+
+ if($crypt_key) {
+ $x = crypto_encapsulate($headerval,$crypt_key,$crypt_alg);
+ $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'];
+ }
+
+ if($auth) {
+ $sighead = 'Authorization: Signature ' . $headerval;
+ }
+ else {
+ $sighead = 'Signature: ' . $headerval;
+ }
+
+ if($head) {
+ foreach($head as $k => $v) {
+ if($send_headers) {
+ header($k . ': ' . $v);
+ }
+ else {
+ $return_headers[] = $k . ': ' . $v;
+ }
+ }
+ }
+ if($send_headers) {
+ header($sighead);
+ }
+ else {
+ $return_headers[] = $sighead;
+ }
+ return $return_headers;
+ }
+
+
+
+ static function sign($request,$head,$prvkey,$alg = 'sha256') {
+
+ $ret = [];
+
+ $headers = '';
+ $fields = '';
+ if($request) {
+ $headers = '(request-target)' . ': ' . trim($request) . "\n";
+ $fields = '(request-target)';
+ }
+
+ if(head) {
+ foreach($head as $k => $v) {
+ $headers .= strtolower($k) . ': ' . trim($v) . "\n";
+ if($fields)
+ $fields .= ' ';
+ $fields .= strtolower($k);
+ }
+ // strip the trailing linefeed
+ $headers = rtrim($headers,"\n");
+ }
+
+ $sig = base64_encode(rsa_sign($headers,$prvkey,$alg));
+
+ $ret['headers'] = $fields;
+ $ret['signature'] = $sig;
+
+ return $ret;
+ }
+
+ static function parse_sigheader($header) {
+
+ $ret = [];
+ $matches = [];
+
+ // if the header is encrypted, decrypt with (default) site private key and continue
+
+ if(preg_match('/iv="(.*?)"/ism',$header,$matches))
+ $header = self::decrypt_sigheader($header);
+
+ if(preg_match('/keyId="(.*?)"/ism',$header,$matches))
+ $ret['keyId'] = $matches[1];
+ if(preg_match('/algorithm="(.*?)"/ism',$header,$matches))
+ $ret['algorithm'] = $matches[1];
+ if(preg_match('/headers="(.*?)"/ism',$header,$matches))
+ $ret['headers'] = explode(' ', $matches[1]);
+ if(preg_match('/signature="(.*?)"/ism',$header,$matches))
+ $ret['signature'] = base64_decode(preg_replace('/\s+/','',$matches[1]));
+
+ if(($ret['signature']) && ($ret['algorithm']) && (! $ret['headers']))
+ $ret['headers'] = [ 'date' ];
+
+ return $ret;
+ }
+
+
+ static function decrypt_sigheader($header,$prvkey = null) {
+
+ $iv = $key = $alg = $data = null;
+
+ if(! $prvkey) {
+ $prvkey = get_config('system','prvkey');
+ }
+
+ $matches = [];
+
+ if(preg_match('/iv="(.*?)"/ism',$header,$matches))
+ $iv = $matches[1];
+ if(preg_match('/key="(.*?)"/ism',$header,$matches))
+ $key = $matches[1];
+ if(preg_match('/alg="(.*?)"/ism',$header,$matches))
+ $alg = $matches[1];
+ if(preg_match('/data="(.*?)"/ism',$header,$matches))
+ $data = $matches[1];
+
+ if($iv && $key && $alg && $data) {
+ return crypto_unencapsulate([ 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey);
+ }
+ return '';
+
+ }
+
+}
+
+
diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php
index ba2e78b25..9486130cb 100644
--- a/Zotlabs/Web/Router.php
+++ b/Zotlabs/Web/Router.php
@@ -62,12 +62,6 @@ class Router {
}
}
- if((strpos($module,'admin') === 0) && (! is_site_admin())) {
- \App::$module_loaded = false;
- notice( t('Permission denied.') . EOL);
- goaway(z_root());
- }
-
/*
* If the site has a custom module to over-ride the standard module, use it.
* Otherwise, look for the standard program module
@@ -125,6 +119,18 @@ class Router {
if(! (\App::$module_loaded)) {
+ // undo the setting of a letsencrypt acme-challenge rewrite rule
+ // which blocks access to our .well-known routes.
+ // Also provide a config setting for sites that have a legitimate need
+ // for a custom .htaccess in the .well-known directory; but they should
+ // make the file read-only so letsencrypt doesn't modify it
+
+ if(strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) {
+ if(file_exists('.well-known/.htaccess') && get_config('system','fix_apache_acme',true)) {
+ rename('.well-known/.htaccess','.well-known/.htaccess.old');
+ }
+ }
+
$x = [
'module' => $module,
'installed' => \App::$module_loaded,
@@ -172,6 +178,7 @@ class Router {
*/
if(\App::$module_loaded) {
+
\App::$page['page_title'] = \App::$module;
$placeholder = '';
@@ -208,7 +215,7 @@ class Router {
* The member may have also created a customised PDL that's stored in the config
*/
- load_pdl($a);
+ load_pdl();
/*
* load current theme info
diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php
index 5bb0e08e8..9e6af8c4c 100644
--- a/Zotlabs/Web/WebServer.php
+++ b/Zotlabs/Web/WebServer.php
@@ -58,7 +58,11 @@ class WebServer {
if((x($_GET,'zid')) && (! \App::$install)) {
\App::$query_string = strip_zids(\App::$query_string);
if(! local_channel()) {
- $_SESSION['my_address'] = $_GET['zid'];
+ if ($_SESSION['my_address']!=$_GET['zid'])
+ {
+ $_SESSION['my_address'] = $_GET['zid'];
+ $_SESSION['authenticated'] = 0;
+ }
zid_init();
}
}
@@ -70,6 +74,12 @@ class WebServer {
}
}
+ if((x($_REQUEST,'owt')) && (! \App::$install)) {
+ $token = $_REQUEST['owt'];
+ \App::$query_string = strip_query_param(\App::$query_string,'owt');
+ owt_init($token);
+ }
+
if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
require('include/auth.php');
@@ -79,11 +89,6 @@ class WebServer {
if(! x($_SESSION, 'sysmsg_info'))
$_SESSION['sysmsg_info'] = array();
- /*
- * check_config() is responsible for running update scripts. These automatically
- * update the DB schema whenever we push a new one out. It also checks to see if
- * any plugins have been added or removed and reacts accordingly.
- */
if(\App::$install) {
@@ -91,13 +96,49 @@ class WebServer {
if(\App::$module != 'view')
\App::$module = 'setup';
}
- else
- check_config($a);
+ else {
+
+ /*
+ * check_config() is responsible for running update scripts. These automatically
+ * update the DB schema whenever we push a new one out. It also checks to see if
+ * any plugins have been added or removed and reacts accordingly.
+ */
+
+ check_config();
+ }
- nav_set_selected('nothing');
+ //nav_set_selected('nothing');
$Router = new Router($a);
+ /* Initialise the Link: response header if this is a channel page.
+ * This cannot be done inside the channel module because some protocol
+ * addons over-ride the module functions and these links are common
+ * to all protocol drivers; thus doing it here avoids duplication.
+ */
+
+ if (( \App::$module === 'channel' ) && argc() > 1) {
+ \App::$channel_links = [
+ [
+ 'rel' => 'lrdd',
+ 'type' => 'application/xrd+xml',
+ 'url' => z_root() . '/xrd?f=&uri=acct%3A' . argv(1) . '%40' . \App::get_hostname()
+ ],
+ [
+ 'rel' => 'jrd',
+ 'type' => 'application/jrd+json',
+ 'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . \App::get_hostname()
+ ],
+ ];
+ $x = [ 'channel_address' => argv(1), 'channel_links' => \App::$channel_links ];
+ call_hooks('channel_links', $x );
+ \App::$channel_links = $x['channel_links'];
+ header('Link: ' . \App::get_channel_links());
+ }
+
+
+
+
/* initialise content region */
if(! x(\App::$page, 'content'))
@@ -130,8 +171,8 @@ class WebServer {
call_hooks('page_end', \App::$page['content']);
- construct_page($a);
+ construct_page();
killme();
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Widget/Activity.php b/Zotlabs/Widget/Activity.php
new file mode 100644
index 000000000..04e9fc4b1
--- /dev/null
+++ b/Zotlabs/Widget/Activity.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Activity {
+
+ function widget($arr) {
+
+ if(! local_channel())
+ return '';
+
+ $o = '';
+
+ if(is_array($arr) && array_key_exists('limit',$arr))
+ $limit = " limit " . intval($limit) . " ";
+ else
+ $limit = '';
+
+ $perms_sql = item_permissions_sql(local_channel()) . item_normal();
+
+ $r = q("select author_xchan from item where item_unseen = 1 and uid = %d $perms_sql",
+ intval(local_channel())
+ );
+
+ $contributors = [];
+ $arr = [];
+
+ if($r) {
+ foreach($r as $rv) {
+ if(array_key_exists($rv['author_xchan'],$contributors)) {
+ $contributors[$rv['author_xchan']] ++;
+ }
+ else {
+ $contributors[$rv['author_xchan']] = 1;
+ }
+ }
+ foreach($contributors as $k => $v) {
+ $arr[] = [ 'author_xchan' => $k, 'total' => $v ];
+ }
+ usort($arr,'total_sort');
+ xchan_query($arr);
+ }
+
+ $x = [ 'entries' => $arr ];
+ call_hooks('activity_widget',$x);
+ $arr = $x['entries'];
+
+ if($arr) {
+ $o .= '<div class="widget">';
+ $o .= '<h3>' . t('Activity','widget') . '</h3><ul class="nav nav-pills flex-column">';
+
+ foreach($arr as $rv) {
+ $o .= '<li class="nav-item"><a class="nav-link" href="network?f=&xchan=' . urlencode($rv['author_xchan']) . '" ><span class="badge badge-secondary float-right">' . ((intval($rv['total'])) ? intval($rv['total']) : '') . '</span><img src="' . $rv['author']['xchan_photo_s'] . '" class="menu-img-1" /> ' . $rv['author']['xchan_name'] . '</a></li>';
+ }
+ $o .= '</ul></div>';
+ }
+ return $o;
+ }
+
+}
+
diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php
new file mode 100644
index 000000000..a761eebe3
--- /dev/null
+++ b/Zotlabs/Widget/Admin.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Admin {
+
+ function widget($arr) {
+
+ /*
+ * Side bar links
+ */
+
+ if(! is_site_admin()) {
+ return '';
+ }
+
+ $o = '';
+
+ // array( url, name, extra css classes )
+
+ $aside = [
+ 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'),
+ 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')),
+ 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'),
+ 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'),
+ 'features' => array(z_root() . '/admin/features/', t('Features'), 'features'),
+ 'plugins' => array(z_root() . '/admin/plugins/', t('Plugins'), 'plugins'),
+ 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'),
+ 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'),
+ 'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'),
+ 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync')
+ ];
+
+ /* get plugins admin page */
+
+ $r = q("SELECT * FROM addon WHERE plugin_admin = 1");
+
+ $plugins = array();
+ if($r) {
+ foreach ($r as $h){
+ $plugin = $h['aname'];
+ $plugins[] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin');
+ // temp plugins with admin
+ \App::$plugins_admin[] = $plugin;
+ }
+ }
+
+ $logs = array(z_root() . '/admin/logs/', t('Logs'), 'logs');
+
+ $arr = array('links' => $aside,'plugins' => $plugins,'logs' => $logs);
+ call_hooks('admin_aside',$arr);
+
+ $o .= replace_macros(get_markup_template('admin_aside.tpl'), array(
+ '$admin' => $aside,
+ '$admtxt' => t('Admin'),
+ '$plugadmtxt' => t('Plugin Features'),
+ '$plugins' => $plugins,
+ '$logtxt' => t('Logs'),
+ '$logs' => $logs,
+ '$h_pending' => t('Member registrations waiting for confirmation'),
+ '$admurl'=> z_root() . '/admin/'
+ ));
+
+ return $o;
+
+ }
+}
+
diff --git a/Zotlabs/Widget/Affinity.php b/Zotlabs/Widget/Affinity.php
new file mode 100644
index 000000000..439ba1f33
--- /dev/null
+++ b/Zotlabs/Widget/Affinity.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Affinity {
+
+ function widget($arr) {
+
+ if(! local_channel())
+ return '';
+
+ // Get default cmin value from pconfig, but allow GET parameter to override
+ $cmin = intval(get_pconfig(local_channel(),'affinity','cmin'));
+ $cmin = (($cmin) ? $cmin : 0);
+ $cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $cmin);
+
+ // Get default cmax value from pconfig, but allow GET parameter to override
+ $cmax = intval(get_pconfig(local_channel(),'affinity','cmax'));
+ $cmax = (($cmax) ? $cmax : 99);
+ $cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $cmax);
+
+
+ if(feature_enabled(local_channel(),'affinity')) {
+
+ $labels = array(
+ t('Me'),
+ t('Family'),
+ t('Friends'),
+ t('Acquaintances'),
+ t('All')
+ );
+ call_hooks('affinity_labels',$labels);
+ $label_str = '';
+
+ if($labels) {
+ foreach($labels as $l) {
+ if($label_str) {
+ $label_str .= ", '|'";
+ $label_str .= ", '" . $l . "'";
+ }
+ else
+ $label_str .= "'" . $l . "'";
+ }
+ }
+
+ $tpl = get_markup_template('main_slider.tpl');
+ $x = replace_macros($tpl,array(
+ '$val' => $cmin . ',' . $cmax,
+ '$refresh' => t('Refresh'),
+ '$labels' => $label_str,
+ ));
+
+ $arr = array('html' => $x);
+ call_hooks('main_slider',$arr);
+ return $arr['html'];
+ }
+ return '';
+ }
+}
+ \ No newline at end of file
diff --git a/Zotlabs/Widget/Album.php b/Zotlabs/Widget/Album.php
new file mode 100644
index 000000000..f359e6d0f
--- /dev/null
+++ b/Zotlabs/Widget/Album.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/attach.php');
+
+class Album {
+
+ function widget($args) {
+
+
+ $owner_uid = \App::$profile_uid;
+ $sql_extra = permissions_sql($owner_uid);
+
+
+ if(! perm_is_allowed($owner_uid,get_observer_hash(),'view_storage'))
+ return '';
+
+ if($args['album'])
+ $album = $args['album'];
+ if($args['title'])
+ $title = $args['title'];
+
+ /**
+ * This may return incorrect permissions if you have multiple directories of the same name.
+ * It is a limitation of the photo table using a name for a photo album instead of a folder hash
+ */
+
+ if($album) {
+ $x = q("select hash from attach where filename = '%s' and uid = %d limit 1",
+ dbesc($album),
+ intval($owner_uid)
+ );
+ if($x) {
+ $y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']);
+ if(! $y)
+ return '';
+ }
+ }
+
+ $order = 'DESC';
+
+ $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
+ (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
+ ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
+ ORDER BY created $order ",
+ intval($owner_uid),
+ dbesc($album),
+ intval(PHOTO_NORMAL),
+ intval(PHOTO_PROFILE)
+ );
+
+ //edit album name
+ $album_edit = null;
+
+ $photos = array();
+ if($r) {
+ $twist = 'rotright';
+ foreach($r as $rr) {
+
+ if($twist == 'rotright')
+ $twist = 'rotleft';
+ else
+ $twist = 'rotright';
+
+ $ext = $phototypes[$rr['mimetype']];
+
+ $imgalt_e = $rr['filename'];
+ $desc_e = $rr['description'];
+
+ $imagelink = (z_root() . '/photos/' . \App::$profile['channel_address'] . '/image/' . $rr['resource_id']);
+
+
+ $photos[] = array(
+ 'id' => $rr['id'],
+ 'twist' => ' ' . $twist . rand(2,4),
+ 'link' => $imagelink,
+ 'title' => t('View Photo'),
+ 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
+ 'alt' => $imgalt_e,
+ 'desc'=> $desc_e,
+ 'ext' => $ext,
+ 'hash'=> $rr['resource_id'],
+ 'unknown' => t('Unknown')
+ );
+ }
+ }
+
+
+ $tpl = get_markup_template('photo_album.tpl');
+ $o .= replace_macros($tpl, array(
+ '$photos' => $photos,
+ '$album' => (($title) ? $title : $album),
+ '$album_id' => rand(),
+ '$album_edit' => array(t('Edit Album'), $album_edit),
+ '$can_post' => false,
+ '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
+ '$order' => false,
+ '$upload_form' => $upload_form,
+ '$usage' => $usage_message
+ ));
+
+ return $o;
+ }
+}
+
diff --git a/Zotlabs/Widget/Appcategories.php b/Zotlabs/Widget/Appcategories.php
new file mode 100644
index 000000000..490ec1abc
--- /dev/null
+++ b/Zotlabs/Widget/Appcategories.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Appcategories {
+
+ function widget($arr) {
+
+ if(! local_channel())
+ return '';
+
+ $selected = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : '');
+
+ // @FIXME ??? $srchurl undefined here - commented out until is reviewed
+ //$srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ //$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
+
+ // Leaving this line which negates the effect of the two invalid lines prior
+ $srchurl = z_root() . '/apps';
+
+ $terms = array();
+
+ $r = q("select distinct(term.term)
+ from term join app on term.oid = app.id
+ where app_channel = %d
+ and term.uid = app_channel
+ and term.otype = %d
+ and term.term != 'nav_featured_app'
+ order by term.term asc",
+ intval(local_channel()),
+ intval(TERM_OBJ_APP)
+ );
+
+ if($r) {
+ foreach($r as $rr)
+ $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : ''));
+
+ return replace_macros(get_markup_template('categories_widget.tpl'),array(
+ '$title' => t('Categories'),
+ '$desc' => '',
+ '$sel_all' => (($selected == '') ? 'selected' : ''),
+ '$all' => t('Everything'),
+ '$terms' => $terms,
+ '$base' => $srchurl,
+
+ ));
+ }
+ }
+}
diff --git a/Zotlabs/Widget/Appcloud.php b/Zotlabs/Widget/Appcloud.php
new file mode 100644
index 000000000..2a4671eee
--- /dev/null
+++ b/Zotlabs/Widget/Appcloud.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Appcloud {
+
+ function widget($arr) {
+ if(! local_channel())
+ return '';
+ return app_tagblock(z_root() . '/apps');
+ }
+}
+
diff --git a/Zotlabs/Widget/Archive.php b/Zotlabs/Widget/Archive.php
new file mode 100644
index 000000000..c151ca563
--- /dev/null
+++ b/Zotlabs/Widget/Archive.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Archive {
+
+ function widget($arr) {
+
+ $o = '';
+
+ if(! \App::$profile_uid) {
+ return '';
+ }
+
+ $uid = \App::$profile_uid;
+
+ if(! feature_enabled($uid,'archives'))
+ return '';
+
+ if(! perm_is_allowed($uid,get_observer_hash(),'view_stream'))
+ return '';
+
+ $wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0);
+ $style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select');
+ $showend = ((get_pconfig($uid,'system','archive_show_end_date')) ? true : false);
+ $mindate = get_pconfig($uid,'system','archive_mindate');
+ $visible_years = get_pconfig($uid,'system','archive_visible_years');
+ if(! $visible_years)
+ $visible_years = 5;
+
+ $url = z_root() . '/' . \App::$cmd;
+
+ $ret = list_post_dates($uid,$wall,$mindate);
+
+ if(! count($ret))
+ return '';
+
+ $cutoff_year = intval(datetime_convert('',date_default_timezone_get(),'now','Y')) - $visible_years;
+ $cutoff = ((array_key_exists($cutoff_year,$ret))? true : false);
+
+ $o = replace_macros(get_markup_template('posted_date_widget.tpl'),array(
+ '$title' => t('Archives'),
+ '$size' => $visible_years,
+ '$cutoff_year' => $cutoff_year,
+ '$cutoff' => $cutoff,
+ '$url' => $url,
+ '$style' => $style,
+ '$showend' => $showend,
+ '$dates' => $ret
+ ));
+ return $o;
+ }
+}
+
diff --git a/Zotlabs/Widget/Bookmarkedchats.php b/Zotlabs/Widget/Bookmarkedchats.php
new file mode 100644
index 000000000..d64bbdb4b
--- /dev/null
+++ b/Zotlabs/Widget/Bookmarkedchats.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Bookmarkedchats {
+
+ function widget($arr) {
+
+ if(! feature_enabled(\App::$profile['profile_uid'],'ajaxchat'))
+ return '';
+
+ $h = get_observer_hash();
+ if(! $h)
+ return;
+ $r = q("select xchat_url, xchat_desc from xchat where xchat_xchan = '%s' order by xchat_desc",
+ dbesc($h)
+ );
+ if($r) {
+ for($x = 0; $x < count($r); $x ++) {
+ $r[$x]['xchat_url'] = zid($r[$x]['xchat_url']);
+ }
+ }
+ return replace_macros(get_markup_template('bookmarkedchats.tpl'),array(
+ '$header' => t('Bookmarked Chatrooms'),
+ '$rooms' => $r
+ ));
+ }
+}
diff --git a/Zotlabs/Widget/Catcloud_wall.php b/Zotlabs/Widget/Catcloud_wall.php
new file mode 100644
index 000000000..3795987cc
--- /dev/null
+++ b/Zotlabs/Widget/Catcloud_wall.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Catcloud_wall {
+
+ function widget($arr) {
+
+ if((! \App::$profile['profile_uid']) || (! \App::$profile['channel_hash']))
+ return '';
+ if(! perm_is_allowed(\App::$profile['profile_uid'], get_observer_hash(), 'view_stream'))
+ return '';
+
+ $limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50);
+
+ return catblock(\App::$profile['profile_uid'], $limit, '', \App::$profile['channel_hash'], 'wall');
+ }
+
+}
diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php
new file mode 100644
index 000000000..305869706
--- /dev/null
+++ b/Zotlabs/Widget/Categories.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/contact_widgets.php');
+
+class Categories {
+
+ function widget($arr) {
+
+ $cards = ((array_key_exists('cards',$arr) && $arr['cards']) ? true : false);
+
+ if(($cards) && (! feature_enabled(\App::$profile['profile_uid'],'cards')))
+ return '';
+
+ if((! \App::$profile['profile_uid'])
+ || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards) ? 'view_pages' : 'view_stream')))) {
+ return '';
+ }
+
+ $cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : '');
+ $srchurl = (($cards) ? \App::$argv[0] . '/' . \App::$argv[1] : \App::$query_string);
+ $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
+
+ if($cards)
+ return cardcategories_widget($srchurl, $cat);
+ else
+ return categories_widget($srchurl, $cat);
+
+ }
+}
diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php
new file mode 100644
index 000000000..60a860f93
--- /dev/null
+++ b/Zotlabs/Widget/Cdav.php
@@ -0,0 +1,176 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+
+class Cdav {
+
+ function widget() {
+ if(!local_channel())
+ return;
+
+ $channel = \App::get_channel();
+ $principalUri = 'principals/' . $channel['channel_address'];
+
+ if(!cdav_principal($principalUri))
+ return;
+
+ $pdo = \DBA::$dba->db;
+
+ require_once 'vendor/autoload.php';
+
+ $o = '';
+
+ if(argc() == 2 && argv(1) === 'calendar') {
+
+ $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+
+ $sabrecals = $caldavBackend->getCalendarsForUser($principalUri);
+
+ //TODO: we should probably also check for permission to send stream here
+ $local_channels = q("SELECT * FROM channel LEFT JOIN abook ON abook_xchan = channel_hash WHERE channel_system = 0 AND channel_removed = 0 AND channel_hash != '%s' AND abook_channel = %d",
+ dbesc($channel['channel_hash']),
+ intval($channel['channel_id'])
+ );
+
+ $sharee_options .= '<option value="">' . t('Select Channel') . '</option>' . "\r\n";
+ foreach($local_channels as $local_channel) {
+ $sharee_options .= '<option value="' . $local_channel['channel_hash'] . '">' . $local_channel['channel_name'] . '</option>' . "\r\n";
+ }
+
+ $access_options = '<option value="3">' . t('Read-write') . '</option>' . "\r\n";
+ $access_options .= '<option value="2">' . t('Read-only') . '</option>' . "\r\n";
+
+ //list calendars
+ foreach($sabrecals as $sabrecal) {
+ if($sabrecal['share-access'] == 1)
+ $access = '';
+ if($sabrecal['share-access'] == 2)
+ $access = 'read';
+ if($sabrecal['share-access'] == 3)
+ $access = 'read-write';
+
+ $invites = $caldavBackend->getInvites($sabrecal['id']);
+
+ $json_source = '/cdav/calendar/json/' . $sabrecal['id'][0] . '/' . $sabrecal['id'][1];
+
+ $switch = get_pconfig(local_channel(), 'cdav_calendar', $sabrecal['id'][0]);
+
+ $color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad');
+
+ $editable = (($sabrecal['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript
+
+ $sharees = [];
+ $share_displayname = [];
+ foreach($invites as $invite) {
+ if(strpos($invite->href, 'mailto:') !== false) {
+ $sharee = channelx_by_hash(substr($invite->href, 7));
+ $sharees[] = [
+ 'name' => $sharee['channel_name'],
+ 'access' => (($invite->access == 3) ? ' (RW)' : ' (R)'),
+ 'hash' => $sharee['channel_hash']
+ ];
+ }
+ }
+
+ if(!$access) {
+ $my_calendars[] = [
+ 'ownernick' => $channel['channel_address'],
+ 'uri' => $sabrecal['uri'],
+ 'displayname' => $sabrecal['{DAV:}displayname'],
+ 'calendarid' => $sabrecal['id'][0],
+ 'instanceid' => $sabrecal['id'][1],
+ 'json_source' => $json_source,
+ 'color' => $color,
+ 'editable' => $editable,
+ 'switch' => $switch,
+ 'sharees' => $sharees
+ ];
+ }
+ else {
+ $shared_calendars[] = [
+ 'ownernick' => $channel['channel_address'],
+ 'uri' => $sabrecal['uri'],
+ 'displayname' => $sabrecal['{DAV:}displayname'],
+ 'calendarid' => $sabrecal['id'][0],
+ 'instanceid' => $sabrecal['id'][1],
+ 'json_source' => $json_source,
+ 'color' => $color,
+ 'editable' => $editable,
+ 'switch' => $switch,
+ 'sharer' => $sabrecal['{urn:ietf:params:xml:ns:caldav}calendar-description'],
+ 'access' => $access
+ ];
+ }
+
+ if(!$access || $access === 'read-write') {
+ $writable_calendars[] = [
+ 'displayname' => ((!$access) ? $sabrecal['{DAV:}displayname'] : $share_displayname[0]),
+ 'id' => $sabrecal['id']
+ ];
+ }
+ }
+
+ $o .= replace_macros(get_markup_template('cdav_widget_calendar.tpl'), [
+ '$my_calendars_label' => t('My Calendars'),
+ '$my_calendars' => $my_calendars,
+ '$shared_calendars_label' => t('Shared Calendars'),
+ '$shared_calendars' => $shared_calendars,
+ '$sharee_options' => $sharee_options,
+ '$access_options' => $access_options,
+ '$share_label' => t('Share this calendar'),
+ '$share' => t('Share'),
+ '$edit_label' => t('Calendar name and color'),
+ '$edit' => t('Edit'),
+ '$create_label' => t('Create new calendar'),
+ '$create' => t('Create'),
+ '$create_placeholder' => t('Calendar Name'),
+ '$tools_label' => t('Calendar Tools'),
+ '$import_label' => t('Import calendar'),
+ '$import_placeholder' => t('Select a calendar to import to'),
+ '$upload' => t('Upload'),
+ '$writable_calendars' => $writable_calendars
+ ]);
+
+ return $o;
+
+ }
+
+ if(argc() >= 2 && argv(1) === 'addressbook') {
+
+ $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+
+ $sabreabooks = $carddavBackend->getAddressBooksForUser($principalUri);
+
+ //list addressbooks
+ foreach($sabreabooks as $sabreabook) {
+ $addressbooks[] = [
+ 'ownernick' => $channel['channel_address'],
+ 'uri' => $sabreabook['uri'],
+ 'displayname' => $sabreabook['{DAV:}displayname'],
+ 'id' => $sabreabook['id']
+
+ ];
+ }
+
+ $o .= replace_macros(get_markup_template('cdav_widget_addressbook.tpl'), [
+ '$addressbooks_label' => t('Addressbooks'),
+ '$addressbooks' => $addressbooks,
+ '$edit_label' => t('Addressbook name'),
+ '$edit' => t('Edit'),
+ '$create_label' => t('Create new addressbook'),
+ '$create_placeholder' => t('Addressbook Name'),
+ '$create' => t('Create'),
+ '$tools_label' => t('Addressbook Tools'),
+ '$import_label' => t('Import addressbook'),
+ '$import_placeholder' => t('Select an addressbook to import to'),
+ '$upload' => t('Upload')
+ ]);
+
+ return $o;
+
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Widget/Chatroom_list.php b/Zotlabs/Widget/Chatroom_list.php
new file mode 100644
index 000000000..e2aad0e05
--- /dev/null
+++ b/Zotlabs/Widget/Chatroom_list.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Chatroom_list {
+
+ function widget($arr) {
+
+ if(! \App::$profile)
+ return '';
+
+ $r = \Zotlabs\Lib\Chatroom::roomlist(\App::$profile['profile_uid']);
+
+ if($r) {
+ return replace_macros(get_markup_template('chatroomlist.tpl'), array(
+ '$header' => t('Chatrooms'),
+ '$baseurl' => z_root(),
+ '$nickname' => \App::$profile['channel_address'],
+ '$items' => $r,
+ '$overview' => t('Overview')
+ ));
+ }
+ }
+}
diff --git a/Zotlabs/Widget/Chatroom_members.php b/Zotlabs/Widget/Chatroom_members.php
new file mode 100644
index 000000000..8ed77fb3c
--- /dev/null
+++ b/Zotlabs/Widget/Chatroom_members.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Chatroom_members {
+
+ // The actual contents are filled in via AJAX
+
+ function widget() {
+ return replace_macros(get_markup_template('chatroom_members.tpl'), array(
+ '$header' => t('Chat Members')
+ ));
+ }
+
+}
diff --git a/Zotlabs/Widget/Clock.php b/Zotlabs/Widget/Clock.php
new file mode 100644
index 000000000..b63b5f748
--- /dev/null
+++ b/Zotlabs/Widget/Clock.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Clock {
+
+ function widget($arr) {
+
+ $miltime = 0;
+ if(isset($arr['military']) && $arr['military'])
+ $miltime = 1;
+
+ $o = <<< EOT
+<div class="widget">
+<h3 class="clockface"></h3>
+<script>
+
+var timerID = null
+var timerRunning = false
+
+function stopclock(){
+ if(timerRunning)
+ clearTimeout(timerID)
+ timerRunning = false
+}
+
+function startclock(){
+ stopclock()
+ showtime()
+}
+
+function showtime(){
+ var now = new Date()
+ var hours = now.getHours()
+ var minutes = now.getMinutes()
+ var seconds = now.getSeconds()
+ var military = $miltime
+ var timeValue = ""
+ if(military)
+ timeValue = hours
+ else
+ timeValue = ((hours > 12) ? hours - 12 : hours)
+ timeValue += ((minutes < 10) ? ":0" : ":") + minutes
+// timeValue += ((seconds < 10) ? ":0" : ":") + seconds
+ if(! military)
+ timeValue += (hours >= 12) ? " P.M." : " A.M."
+ $('.clockface').html(timeValue)
+ timerID = setTimeout("showtime()",1000)
+ timerRunning = true
+}
+
+$(document).ready(function() {
+ startclock();
+});
+
+</script>
+</div>
+EOT;
+
+ return $o;
+ }
+}
+
diff --git a/Zotlabs/Widget/Collections.php b/Zotlabs/Widget/Collections.php
new file mode 100644
index 000000000..d2b29679a
--- /dev/null
+++ b/Zotlabs/Widget/Collections.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/group.php');
+
+class Collections {
+
+ function widget($args) {
+
+ $mode = ((array_key_exists('mode',$args)) ? $args['mode'] : 'conversation');
+ switch($mode) {
+ case 'conversation':
+ $every = argv(0);
+ $each = argv(0);
+ $edit = true;
+ $current = $_REQUEST['gid'];
+ $abook_id = 0;
+ $wmode = 0;
+ break;
+ case 'connections':
+ $every = 'connections';
+ $each = 'group';
+ $edit = true;
+ $current = $_REQUEST['gid'];
+ $abook_id = 0;
+ $wmode = 0;
+ case 'groups':
+ $every = 'connections';
+ $each = argv(0);
+ $edit = false;
+ $current = intval(argv(1));
+ $abook_id = 0;
+ $wmode = 1;
+ break;
+ case 'abook':
+ $every = 'connections';
+ $each = 'group';
+ $edit = false;
+ $current = 0;
+ $abook_id = \App::$poi['abook_xchan'];
+ $wmode = 1;
+ break;
+ default:
+ return '';
+ break;
+ }
+
+ return group_side($every, $each, $edit, $current, $abook_id, $wmode);
+ }
+}
diff --git a/Zotlabs/Widget/Common_friends.php b/Zotlabs/Widget/Common_friends.php
new file mode 100644
index 000000000..a67b9312c
--- /dev/null
+++ b/Zotlabs/Widget/Common_friends.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/contact_widgets.php');
+
+class Common_friends {
+
+ function widget($arr) {
+
+ if((! \App::$profile['profile_uid'])
+ || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'view_contacts'))) {
+ return '';
+ }
+
+ return common_friends_visitor_widget(\App::$profile['profile_uid']);
+
+ }
+}
diff --git a/Zotlabs/Widget/Conversations.php b/Zotlabs/Widget/Conversations.php
new file mode 100644
index 000000000..56510750f
--- /dev/null
+++ b/Zotlabs/Widget/Conversations.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Conversations {
+
+ function widget($arr) {
+
+ if (! local_channel())
+ return;
+
+ if(argc() > 1) {
+
+ switch(argv(1)) {
+ case 'inbox':
+ $mailbox = 'inbox';
+ $header = t('Received Messages');
+ break;
+ case 'outbox':
+ $mailbox = 'outbox';
+ $header = t('Sent Messages');
+ break;
+ default:
+ $mailbox = 'combined';
+ $header = t('Conversations');
+ break;
+ }
+
+ require_once('include/message.php');
+
+ // private_messages_list() can do other more complicated stuff, for now keep it simple
+ $r = private_messages_list(local_channel(), $mailbox, \App::$pager['start'], \App::$pager['itemspage']);
+
+ if(! $r) {
+ info( t('No messages.') . EOL);
+ return $o;
+ }
+
+ $messages = array();
+
+ foreach($r as $rr) {
+
+ $selected = ((argc() == 3) ? intval(argv(2)) == intval($rr['id']) : $r[0]['id'] == $rr['id']);
+
+ $messages[] = array(
+ 'mailbox' => $mailbox,
+ 'id' => $rr['id'],
+ 'from_name' => $rr['from']['xchan_name'],
+ 'from_url' => chanlink_hash($rr['from_xchan']),
+ 'from_photo' => $rr['from']['xchan_photo_s'],
+ 'to_name' => $rr['to']['xchan_name'],
+ 'to_url' => chanlink_hash($rr['to_xchan']),
+ 'to_photo' => $rr['to']['xchan_photo_s'],
+ 'subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'),
+ 'delete' => t('Delete conversation'),
+ 'body' => $rr['body'],
+ 'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], 'c'),
+ 'seen' => $rr['seen'],
+ 'selected' => ((argv(1) != 'new') ? $selected : '')
+ );
+ }
+
+ $tpl = get_markup_template('mail_head.tpl');
+ $o .= replace_macros($tpl, array(
+ '$header' => $header,
+ '$messages' => $messages
+ ));
+
+ }
+ return $o;
+ }
+
+}
+
diff --git a/Zotlabs/Widget/Cover_photo.php b/Zotlabs/Widget/Cover_photo.php
new file mode 100644
index 000000000..d2eb1be92
--- /dev/null
+++ b/Zotlabs/Widget/Cover_photo.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Cover_photo {
+
+ function widget($arr) {
+
+ require_once('include/channel.php');
+ $o = '';
+
+ if(\App::$module == 'channel' && $_REQUEST['mid'])
+ return '';
+
+ $channel_id = 0;
+ if(array_key_exists('channel_id', $arr) && intval($arr['channel_id']))
+ $channel_id = intval($arr['channel_id']);
+ if(! $channel_id)
+ $channel_id = \App::$profile_uid;
+ if(! $channel_id)
+ return '';
+
+ $channel = channelx_by_n($channel_id);
+
+ if(array_key_exists('style', $arr) && isset($arr['style']))
+ $style = $arr['style'];
+ else
+ $style = 'width:100%; height: auto;';
+
+ // ensure they can't sneak in an eval(js) function
+
+ if(strpbrk($style,'(\'"<>') !== false)
+ $style = '';
+
+ if(array_key_exists('title', $arr) && isset($arr['title']))
+ $title = $arr['title'];
+ else
+ $title = $channel['channel_name'];
+
+ if(array_key_exists('subtitle', $arr) && isset($arr['subtitle']))
+ $subtitle = $arr['subtitle'];
+ else
+ $subtitle = str_replace('@','&#x40;',$channel['xchan_addr']);
+
+ $c = get_cover_photo($channel_id,'html');
+
+ if($c) {
+ $photo_html = (($style) ? str_replace('alt=',' style="' . $style . '" alt=',$c) : $c);
+
+ $o = replace_macros(get_markup_template('cover_photo_widget.tpl'),array(
+ '$photo_html' => $photo_html,
+ '$title' => $title,
+ '$subtitle' => $subtitle,
+ '$hovertitle' => t('Click to show more'),
+ ));
+ }
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Design_tools.php b/Zotlabs/Widget/Design_tools.php
new file mode 100644
index 000000000..8ab6a235d
--- /dev/null
+++ b/Zotlabs/Widget/Design_tools.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Design_tools {
+
+ function widget($arr) {
+
+ // mod menu doesn't load a profile. For any modules which load a profile, check it.
+ // otherwise local_channel() is sufficient for permissions.
+
+ if(\App::$profile['profile_uid'])
+ if((\App::$profile['profile_uid'] != local_channel()) && (! \App::$is_sys))
+ return '';
+
+ if(! local_channel())
+ return '';
+
+ return design_tools();
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Widget/Dirsort.php b/Zotlabs/Widget/Dirsort.php
new file mode 100644
index 000000000..e75a00e50
--- /dev/null
+++ b/Zotlabs/Widget/Dirsort.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/dir_fns.php');
+
+class Dirsort {
+ function widget($arr) {
+ return dir_sort_links();
+ }
+}
diff --git a/Zotlabs/Widget/Dirtags.php b/Zotlabs/Widget/Dirtags.php
new file mode 100644
index 000000000..f211d5942
--- /dev/null
+++ b/Zotlabs/Widget/Dirtags.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/dir_fns.php');
+
+class Dirtags {
+
+ function widget($arr) {
+ return dir_tagblock(z_root() . '/directory', null);
+ }
+
+}
diff --git a/Zotlabs/Widget/Eventstools.php b/Zotlabs/Widget/Eventstools.php
new file mode 100644
index 000000000..7efd3f72e
--- /dev/null
+++ b/Zotlabs/Widget/Eventstools.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Eventstools {
+
+ function widget($arr) {
+
+ if(! local_channel())
+ return;
+
+ return replace_macros(get_markup_template('events_tools_side.tpl'), array(
+ '$title' => t('Events Tools'),
+ '$export' => t('Export Calendar'),
+ '$import' => t('Import Calendar'),
+ '$submit' => t('Submit')
+ ));
+ }
+}
diff --git a/Zotlabs/Widget/Filer.php b/Zotlabs/Widget/Filer.php
new file mode 100644
index 000000000..5d6f96a87
--- /dev/null
+++ b/Zotlabs/Widget/Filer.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/contact_widgets.php');
+
+class Filer {
+
+ function widget($arr) {
+ if(! local_channel())
+ return '';
+
+
+ $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",
+ intval(local_channel()),
+ intval(TERM_FILE)
+ );
+ if(! $r)
+ return;
+
+ foreach($r as $rr)
+ $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : ''));
+
+ return replace_macros(get_markup_template('fileas_widget.tpl'),array(
+ '$title' => t('Saved Folders'),
+ '$desc' => '',
+ '$sel_all' => (($selected == '') ? 'selected' : ''),
+ '$all' => t('Everything'),
+ '$terms' => $terms,
+ '$base' => z_root() . '/' . \App::$cmd
+ ));
+ }
+}
diff --git a/Zotlabs/Widget/Findpeople.php b/Zotlabs/Widget/Findpeople.php
new file mode 100644
index 000000000..f450b96ae
--- /dev/null
+++ b/Zotlabs/Widget/Findpeople.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/contact_widgets.php');
+
+class Findpeople {
+ function widget($arr) {
+ return findpeople_widget();
+ }
+}
+
diff --git a/Zotlabs/Widget/Follow.php b/Zotlabs/Widget/Follow.php
new file mode 100644
index 000000000..c4aecc8e1
--- /dev/null
+++ b/Zotlabs/Widget/Follow.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Follow {
+
+ function widget($args) {
+ if(! local_channel())
+ return '';
+
+ $uid = \App::$channel['channel_id'];
+ $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ",
+ intval($uid)
+ );
+
+ if($r)
+ $total_channels = $r[0]['total'];
+
+ $limit = service_class_fetch($uid,'total_channels');
+ if($limit !== false) {
+ $abook_usage_message = sprintf( t("You have %1$.0f of %2$.0f allowed connections."), $total_channels, $limit);
+ }
+ else {
+ $abook_usage_message = '';
+ }
+
+ return replace_macros(get_markup_template('follow.tpl'),array(
+ '$connect' => t('Add New Connection'),
+ '$desc' => t('Enter channel address'),
+ '$hint' => t('Examples: bob@example.com, https://example.com/barbara'),
+ '$follow' => t('Connect'),
+ '$abook_usage_message' => $abook_usage_message
+ ));
+ }
+}
+
diff --git a/Zotlabs/Widget/Forums.php b/Zotlabs/Widget/Forums.php
new file mode 100644
index 000000000..002c0ee21
--- /dev/null
+++ b/Zotlabs/Widget/Forums.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Forums {
+
+ function widget($arr) {
+
+ if(! local_channel())
+ return '';
+
+ $o = '';
+
+ if(is_array($arr) && array_key_exists('limit',$arr))
+ $limit = " limit " . intval($limit) . " ";
+ else
+ $limit = '';
+
+ $unseen = 0;
+ if(is_array($arr) && array_key_exists('unseen',$arr) && intval($arr['unseen']))
+ $unseen = 1;
+
+ $perms_sql = item_permissions_sql(local_channel()) . item_normal();
+
+ $xf = false;
+
+ $x1 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'send_stream' and v = '0'",
+ intval(local_channel())
+ );
+ if($x1) {
+ $xc = ids_to_querystr($x1,'xchan',true);
+ $x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . $xc . ") ",
+ intval(local_channel())
+ );
+ if($x2)
+ $xf = ids_to_querystr($x2,'xchan',true);
+ }
+
+ $sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
+
+ $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_deleted = 0 and abook_channel = %d $sql_extra order by xchan_name $limit ",
+ intval(local_channel())
+ );
+ if(! $r1)
+ return $o;
+
+ $str = '';
+
+ // Trying to cram all this into a single query with joins and the proper group by's is tough.
+ // 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 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) {
+ $o .= '<div class="widget">';
+ $o .= '<h3>' . t('Forums') . '</h3><ul class="nav nav-pills flex-column">';
+
+ foreach($r1 as $rr) {
+ if($unseen && (! intval($rr['unseen'])))
+ continue;
+ $o .= '<li class="nav-item"><a class="nav-link" href="network?f=&pf=1&cid=' . $rr['abook_id'] . '" ><span class="badge badge-secondary float-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><img class ="menu-img-1" src="' . $rr['xchan_photo_s'] . '" /> ' . $rr['xchan_name'] . '</a></li>';
+ }
+ $o .= '</ul></div>';
+ }
+ return $o;
+
+ }
+}
diff --git a/Zotlabs/Widget/Fullprofile.php b/Zotlabs/Widget/Fullprofile.php
new file mode 100644
index 000000000..d7340ef40
--- /dev/null
+++ b/Zotlabs/Widget/Fullprofile.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Fullprofile {
+
+ function widget($arr) {
+
+ if(! \App::$profile['profile_uid'])
+ return;
+
+ $block = observer_prohibited();
+
+ return profile_sidebar(\App::$profile, $block);
+ }
+}
diff --git a/Zotlabs/Widget/Helpindex.php b/Zotlabs/Widget/Helpindex.php
new file mode 100644
index 000000000..6c8748194
--- /dev/null
+++ b/Zotlabs/Widget/Helpindex.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Helpindex {
+
+ function widget($arr) {
+
+ $o .= '<div class="widget">';
+
+ $level_0 = get_help_content('sitetoc');
+ if(! $level_0) {
+ $path = 'toc';
+ $x = determine_help_language();
+ $lang = $x['language'];
+ if($lang !== 'en') {
+ $path = $lang . '/toc';
+ }
+ $level_0 = get_help_content($path);
+ }
+
+ $level_0 = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills flex-column">',$level_0);
+
+ $levels = array();
+
+
+ // TODO: Implement support for translations in hierarchical table of content files
+ /*
+ if(argc() > 2) {
+ $path = '';
+ for($x = 1; $x < argc(); $x ++) {
+ $path .= argv($x) . '/';
+ $y = get_help_content($path . 'sitetoc');
+ if(! $y)
+ $y = get_help_content($path . 'toc');
+ if($y)
+ $levels[] = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills flex-column">',$y);
+ }
+ }
+ */
+
+ if($level_0)
+ $o .= $level_0;
+ if($levels) {
+ foreach($levels as $l) {
+ $o .= '<br /><br />';
+ $o .= $l;
+ }
+ }
+
+ $o .= '</div>';
+
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Item.php b/Zotlabs/Widget/Item.php
new file mode 100644
index 000000000..273d5649c
--- /dev/null
+++ b/Zotlabs/Widget/Item.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/security.php');
+
+class Item {
+
+ function widget($arr) {
+
+ $channel_id = 0;
+ if(array_key_exists('channel_id',$arr) && intval($arr['channel_id']))
+ $channel_id = intval($arr['channel_id']);
+ if(! $channel_id)
+ $channel_id = \App::$profile_uid;
+ if(! $channel_id)
+ return '';
+
+
+ if((! $arr['mid']) && (! $arr['title']))
+ return '';
+
+ if(! perm_is_allowed($channel_id, get_observer_hash(), 'view_pages'))
+ return '';
+
+ $sql_extra = item_permissions_sql($channel_id);
+
+ if($arr['title']) {
+ $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)
+ );
+ }
+ else {
+ $r = q("select * from item where mid = '%s' and uid = %d and item_type = "
+ . intval(ITEM_TYPE_WEBPAGE) . " $sql_extra limit 1",
+ dbesc($arr['mid']),
+ intval($channel_id)
+ );
+ }
+
+ if(! $r)
+ return '';
+
+ xchan_query($r);
+ $r = fetch_post_tags($r, true);
+
+ $o = prepare_page($r[0]);
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Mailmenu.php b/Zotlabs/Widget/Mailmenu.php
new file mode 100644
index 000000000..512f7d9c0
--- /dev/null
+++ b/Zotlabs/Widget/Mailmenu.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Mailmenu {
+
+ function widget($arr) {
+
+ if (! local_channel())
+ return;
+
+ return replace_macros(get_markup_template('message_side.tpl'), array(
+ '$title' => t('Private Mail Menu'),
+ '$combined' => array(
+ 'label' => t('Combined View'),
+ 'url' => z_root() . '/mail/combined',
+ 'sel' => (argv(1) == 'combined'),
+ ),
+ '$inbox' => array(
+ 'label' => t('Inbox'),
+ 'url' => z_root() . '/mail/inbox',
+ 'sel' => (argv(1) == 'inbox'),
+ ),
+ '$outbox' => array(
+ 'label' => t('Outbox'),
+ 'url' => z_root() . '/mail/outbox',
+ 'sel' => (argv(1) == 'outbox'),
+ ),
+ '$new' => array(
+ 'label' => t('New Message'),
+ 'url' => z_root() . '/mail/new',
+ 'sel'=> (argv(1) == 'new'),
+ )
+ ));
+ }
+}
diff --git a/Zotlabs/Widget/Menu_preview.php b/Zotlabs/Widget/Menu_preview.php
new file mode 100644
index 000000000..51218f6cf
--- /dev/null
+++ b/Zotlabs/Widget/Menu_preview.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/menu.php');
+
+class Menu_preview {
+
+ function widget($arr) {
+ if(! \App::$data['menu_item'])
+ return;
+
+ return menu_render(\App::$data['menu_item']);
+ }
+
+}
diff --git a/Zotlabs/Widget/Notes.php b/Zotlabs/Widget/Notes.php
new file mode 100644
index 000000000..5c83a550f
--- /dev/null
+++ b/Zotlabs/Widget/Notes.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Notes {
+
+ function widget($arr) {
+ if(! local_channel())
+ return '';
+ if(! feature_enabled(local_channel(),'private_notes'))
+ return '';
+
+ $text = get_pconfig(local_channel(),'notes','text');
+
+ $o = replace_macros(get_markup_template('notes.tpl'), array(
+ '$banner' => t('Notes'),
+ '$text' => $text,
+ '$save' => t('Save'),
+ ));
+
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php
new file mode 100644
index 000000000..a857f1ad9
--- /dev/null
+++ b/Zotlabs/Widget/Notifications.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Notifications {
+
+ function widget($arr) {
+
+ $channel = \App::get_channel();
+
+ if(local_channel()) {
+ $notifications[] = [
+ 'type' => 'network',
+ 'icon' => 'th',
+ 'severity' => 'secondary',
+ 'label' => t('New Network Activity'),
+ 'title' => t('New Network Activity Notifications'),
+ 'viewall' => [
+ 'url' => 'network',
+ 'label' => t('View your network activity')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notifications read')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'home',
+ 'icon' => 'home',
+ 'severity' => 'danger',
+ 'label' => t('New Home Activity'),
+ 'title' => t('New Home Activity Notifications'),
+ 'viewall' => [
+ 'url' => 'channel/' . $channel['channel_address'],
+ 'label' => t('View your home activity')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notifications seen')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'mail',
+ 'icon' => 'envelope',
+ 'severity' => 'danger',
+ 'label' => t('New Mails'),
+ 'title' => t('New Mails Notifications'),
+ 'viewall' => [
+ 'url' => 'mail/combined',
+ 'label' => t('View your private mails')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all messages seen')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'all_events',
+ 'icon' => 'calendar',
+ 'severity' => 'secondary',
+ 'label' => t('New Events'),
+ 'title' => t('New Events Notifications'),
+ 'viewall' => [
+ 'url' => 'mail/combined',
+ 'label' => t('View events')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all events seen')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'intros',
+ 'icon' => 'users',
+ 'severity' => 'danger',
+ 'label' => t('New Connections'),
+ 'title' => t('New Connections Notifications'),
+ 'viewall' => [
+ 'url' => 'connections',
+ 'label' => t('View all connections')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'files',
+ 'icon' => 'folder',
+ 'severity' => 'danger',
+ 'label' => t('New Files'),
+ 'title' => t('New Files Notifications'),
+ ];
+
+ $notifications[] = [
+ 'type' => 'notify',
+ 'icon' => 'exclamation',
+ 'severity' => 'danger',
+ 'label' => t('Notices'),
+ 'title' => t('Notices'),
+ 'viewall' => [
+ 'url' => 'notifications/system',
+ 'label' => t('View all notices')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notices seen')
+ ]
+ ];
+ }
+
+ if(local_channel() && is_site_admin()) {
+ $notifications[] = [
+ 'type' => 'register',
+ 'icon' => 'user-o',
+ 'severity' => 'danger',
+ 'label' => t('New Registrations'),
+ 'title' => t('New Registrations Notifications'),
+ ];
+ }
+
+ if(get_config('system', 'disable_discover_tab') != 1) {
+ $notifications[] = [
+ 'type' => 'pubs',
+ 'icon' => 'globe',
+ 'severity' => 'secondary',
+ 'label' => t('Public Stream'),
+ 'title' => t('Public Stream Notifications'),
+ 'viewall' => [
+ 'url' => 'pubstream',
+ 'label' => t('View the public stream')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notifications seen')
+ ]
+ ];
+ }
+
+ $o = replace_macros(get_markup_template('notifications_widget.tpl'), array(
+ '$notifications' => $notifications,
+ '$loading' => t('Loading...')
+ ));
+
+ return $o;
+
+ }
+}
+
diff --git a/Zotlabs/Widget/Photo.php b/Zotlabs/Widget/Photo.php
new file mode 100644
index 000000000..10031f028
--- /dev/null
+++ b/Zotlabs/Widget/Photo.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Photo {
+
+
+ /**
+ * @brief Widget to display a single photo.
+ *
+ * @param array $arr associative array with
+ * * \e string \b src URL of photo; URL must be an http or https URL
+ * * \e boolean \b zrl use zid in URL
+ * * \e string \b style CSS string
+ *
+ * @return string with parsed HTML
+ */
+
+ function widget($arr) {
+
+ $style = $zrl = false;
+
+ if(array_key_exists('src', $arr) && isset($arr['src']))
+ $url = $arr['src'];
+
+ if(strpos($url, 'http') !== 0)
+ return '';
+
+ if(array_key_exists('style', $arr) && isset($arr['style']))
+ $style = $arr['style'];
+
+ // ensure they can't sneak in an eval(js) function
+
+ if(strpbrk($style, '(\'"<>' ) !== false)
+ $style = '';
+
+ if(array_key_exists('zrl', $arr) && isset($arr['zrl']))
+ $zrl = (($arr['zrl']) ? true : false);
+
+ if($zrl)
+ $url = zid($url);
+
+ $o = '<div class="widget">';
+
+ $o .= '<img ' . (($zrl) ? ' class="zrl" ' : '')
+ . (($style) ? ' style="' . $style . '"' : '')
+ . ' src="' . $url . '" alt="' . t('photo/image') . '">';
+
+ $o .= '</div>';
+
+ return $o;
+ }
+}
+
diff --git a/Zotlabs/Widget/Photo_albums.php b/Zotlabs/Widget/Photo_albums.php
new file mode 100644
index 000000000..6df8ddf3c
--- /dev/null
+++ b/Zotlabs/Widget/Photo_albums.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/photos.php');
+
+class Photo_albums {
+
+ function widget($arr) {
+
+ if(! \App::$profile['profile_uid'])
+ return '';
+
+ $channelx = channelx_by_n(\App::$profile['profile_uid']);
+
+ if((! $channelx) || (! perm_is_allowed(\App::$profile['profile_uid'], get_observer_hash(), 'view_storage')))
+ return '';
+
+ $sortkey = ((array_key_exists('sortkey',$arr)) ? $arr['sortkey'] : 'display_path');
+ $direction = ((array_key_exists('direction',$arr)) ? $arr['direction'] : 'asc');
+
+ return photos_album_widget($channelx, \App::get_observer(),$sortkey,$direction);
+ }
+}
+
diff --git a/Zotlabs/Widget/Photo_rand.php b/Zotlabs/Widget/Photo_rand.php
new file mode 100644
index 000000000..af80a3b9f
--- /dev/null
+++ b/Zotlabs/Widget/Photo_rand.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/photos.php');
+
+class Photo_rand {
+
+ function widget($arr) {
+
+ $style = false;
+
+ if(array_key_exists('album', $arr) && isset($arr['album']))
+ $album = $arr['album'];
+ else
+ $album = '';
+
+ $channel_id = 0;
+ if(array_key_exists('channel_id', $arr) && intval($arr['channel_id']))
+ $channel_id = intval($arr['channel_id']);
+ if(! $channel_id)
+ $channel_id = \App::$profile_uid;
+ if(! $channel_id)
+ return '';
+
+ $scale = ((array_key_exists('scale',$arr)) ? intval($arr['scale']) : 0);
+
+ $ret = photos_list_photos(array('channel_id' => $channel_id),\App::get_observer(),$album);
+
+ $filtered = array();
+ if($ret['success'] && $ret['photos'])
+ foreach($ret['photos'] as $p)
+ if($p['imgscale'] == $scale)
+ $filtered[] = $p['src'];
+
+ if($filtered) {
+ $e = mt_rand(0, count($filtered) - 1);
+ $url = $filtered[$e];
+ }
+
+ if(strpos($url, 'http') !== 0)
+ return '';
+
+ if(array_key_exists('style', $arr) && isset($arr['style']))
+ $style = $arr['style'];
+
+ // ensure they can't sneak in an eval(js) function
+
+ if(strpos($style,'(') !== false)
+ return '';
+
+ $url = zid($url);
+
+ $o = '<div class="widget">';
+
+ $o .= '<img class="zrl" '
+ . (($style) ? ' style="' . $style . '"' : '')
+ . ' src="' . $url . '" alt="' . t('photo/image') . '">';
+
+ $o .= '</div>';
+
+ return $o;
+ }
+}
+
+
diff --git a/Zotlabs/Widget/Portfolio.php b/Zotlabs/Widget/Portfolio.php
new file mode 100644
index 000000000..216ca952c
--- /dev/null
+++ b/Zotlabs/Widget/Portfolio.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/attach.php');
+
+class Portfolio {
+
+ function widget($args) {
+
+
+ $owner_uid = \App::$profile_uid;
+ $sql_extra = permissions_sql($owner_uid);
+
+
+ if(! perm_is_allowed($owner_uid,get_observer_hash(),'view_storage'))
+ return '';
+
+ if($args['album'])
+ $album = $args['album'];
+ if($args['title'])
+ $title = $args['title'];
+
+ /**
+ * This may return incorrect permissions if you have multiple directories of the same name.
+ * It is a limitation of the photo table using a name for a photo album instead of a folder hash
+ */
+
+ if($album) {
+ $x = q("select hash from attach where filename = '%s' and uid = %d limit 1",
+ dbesc($album),
+ intval($owner_uid)
+ );
+ if($x) {
+ $y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']);
+ if(! $y)
+ return '';
+ }
+ }
+
+ $order = 'DESC';
+
+ $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
+ (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
+ ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
+ ORDER BY created $order ",
+ intval($owner_uid),
+ dbesc($album),
+ intval(PHOTO_NORMAL),
+ intval(PHOTO_PROFILE)
+ );
+
+ //edit album name
+ $album_edit = null;
+
+ $photos = array();
+ if($r) {
+ $twist = 'rotright';
+ foreach($r as $rr) {
+
+ if($twist == 'rotright')
+ $twist = 'rotleft';
+ else
+ $twist = 'rotright';
+
+ $ext = $phototypes[$rr['mimetype']];
+
+ $imgalt_e = $rr['filename'];
+ $desc_e = $rr['description'];
+
+ $imagelink = (z_root() . '/photos/' . \App::$profile['channel_address'] . '/image/' . $rr['resource_id']);
+
+
+ $photos[] = array(
+ 'id' => $rr['id'],
+ 'twist' => ' ' . $twist . rand(2,4),
+ 'link' => $imagelink,
+ 'title' => t('View Photo'),
+ 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
+ 'fullsrc' => z_root() . '/photo/' . $rr['resource_id'] . '-' . '1' . '.' .$ext,
+ 'resource_id' => $rr['resource_id'],
+ 'alt' => $imgalt_e,
+ 'desc'=> $desc_e,
+ 'ext' => $ext,
+ 'hash'=> $rr['resource_id'],
+ 'unknown' => t('Unknown')
+ );
+ }
+ }
+
+
+ $tpl = get_markup_template('photo_album_portfolio.tpl');
+ $o .= replace_macros($tpl, array(
+ '$photos' => $photos,
+ '$album' => (($title) ? $title : $album),
+ '$album_id' => rand(),
+ '$album_edit' => array(t('Edit Album'), $album_edit),
+ '$can_post' => false,
+ '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
+ '$order' => false,
+ '$upload_form' => $upload_form,
+ '$usage' => $usage_message
+ ));
+
+ return $o;
+ }
+}
+
diff --git a/Zotlabs/Widget/Profile.php b/Zotlabs/Widget/Profile.php
new file mode 100644
index 000000000..bffd910b6
--- /dev/null
+++ b/Zotlabs/Widget/Profile.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Profile {
+
+ function widget($args) {
+ $block = observer_prohibited();
+ return profile_sidebar(\App::$profile, $block, true);
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Widget/Pubsites.php b/Zotlabs/Widget/Pubsites.php
new file mode 100644
index 000000000..958ba68c2
--- /dev/null
+++ b/Zotlabs/Widget/Pubsites.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Pubsites {
+
+ // used by site ratings pages to provide a return link
+
+ function widget($arr) {
+ if(\App::$poi)
+ return;
+ return '<div class="widget"><ul class="nav nav-pills"><li><a href="pubsites">' . t('Public Hubs') . '</a></li></ul></div>';
+ }
+}
+
+
diff --git a/Zotlabs/Widget/Random_block.php b/Zotlabs/Widget/Random_block.php
new file mode 100644
index 000000000..465a51f97
--- /dev/null
+++ b/Zotlabs/Widget/Random_block.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Random_block {
+
+ function widget($arr) {
+
+ $channel_id = 0;
+ if(array_key_exists('channel_id',$arr) && intval($arr['channel_id']))
+ $channel_id = intval($arr['channel_id']);
+ if(! $channel_id)
+ $channel_id = \App::$profile_uid;
+ if(! $channel_id)
+ return '';
+
+ if(array_key_exists('contains',$arr))
+ $contains = $arr['contains'];
+
+ $o = '';
+
+ require_once('include/security.php');
+ $sql_options = item_permissions_sql($channel_id);
+
+ $randfunc = db_getfunc('RAND');
+
+ $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 . '%'),
+ intval(ITEM_TYPE_BLOCK)
+ );
+
+ if($r) {
+ $o = '<div class="widget bblock">';
+ if($r[0]['title'])
+ $o .= '<h3>' . $r[0]['title'] . '</h3>';
+
+ $o .= prepare_text($r[0]['body'],$r[0]['mimetype']);
+ $o .= '</div>';
+ }
+
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Rating.php b/Zotlabs/Widget/Rating.php
new file mode 100644
index 000000000..5e09f457b
--- /dev/null
+++ b/Zotlabs/Widget/Rating.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Rating {
+
+ function widget($arr) {
+
+
+ $rating_enabled = get_config('system','rating_enabled');
+ if(! $rating_enabled) {
+ return;
+ }
+
+ if($arr['target'])
+ $hash = $arr['target'];
+ else
+ $hash = \App::$poi['xchan_hash'];
+
+ if(! $hash)
+ return;
+
+ $url = '';
+ $remote = false;
+
+ if(remote_channel() && ! local_channel()) {
+ $ob = \App::get_observer();
+ if($ob && $ob['xchan_url']) {
+ $p = parse_url($ob['xchan_url']);
+ if($p) {
+ $url = $p['scheme'] . '://' . $p['host'] . (($p['port']) ? ':' . $p['port'] : '');
+ $url .= '/rate?f=&target=' . urlencode($hash);
+ }
+ $remote = true;
+ }
+ }
+
+ $self = false;
+
+ if(local_channel()) {
+ $channel = \App::get_channel();
+
+ if($hash == $channel['channel_hash'])
+ $self = true;
+
+ head_add_js('ratings.js');
+ }
+
+
+ $o = '<div class="widget">';
+ $o .= '<h3>' . t('Rating Tools') . '</h3>';
+
+ if((($remote) || (local_channel())) && (! $self)) {
+ if($remote)
+ $o .= '<a class="btn btn-block btn-primary btn-sm" href="' . $url . '"><i class="fa fa-pencil"></i> ' . t('Rate Me') . '</a>';
+ else
+ $o .= '<div class="btn btn-block btn-primary btn-sm" onclick="doRatings(\'' . $hash . '\'); return false;"><i class="fa fa-pencil"></i> ' . t('Rate Me') . '</div>';
+ }
+
+ $o .= '<a class="btn btn-block btn-default btn-sm" href="ratings/' . $hash . '"><i class="fa fa-eye"></i> ' . t('View Ratings') . '</a>';
+ $o .= '</div>';
+
+ return $o;
+
+ }
+}
+
diff --git a/Zotlabs/Widget/Savedsearch.php b/Zotlabs/Widget/Savedsearch.php
new file mode 100644
index 000000000..378c27139
--- /dev/null
+++ b/Zotlabs/Widget/Savedsearch.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Savedsearch {
+
+ function widget($arr) {
+
+ if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch')))
+ return '';
+
+ $search = ((x($_GET,'netsearch')) ? $_GET['netsearch'] : '');
+ if(! $search)
+ $search = ((x($_GET,'search')) ? $_GET['search'] : '');
+
+ if(x($_GET,'searchsave') && $search) {
+ $r = q("select * from term where uid = %d and ttype = %d and term = '%s' limit 1",
+ intval(local_channel()),
+ intval(TERM_SAVEDSEARCH),
+ dbesc($search)
+ );
+ if(! $r) {
+ q("insert into term ( uid,ttype,term ) values ( %d, %d, '%s') ",
+ intval(local_channel()),
+ intval(TERM_SAVEDSEARCH),
+ dbesc($search)
+ );
+ }
+ }
+
+ if(x($_GET,'searchremove') && $search) {
+ q("delete from term where uid = %d and ttype = %d and term = '%s'",
+ intval(local_channel()),
+ intval(TERM_SAVEDSEARCH),
+ dbesc($search)
+ );
+ $search = '';
+ }
+
+ $srchurl = \App::$query_string;
+
+ $srchurl = rtrim(preg_replace('/searchsave\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $hasq = ((strpos($srchurl,'?') !== false) ? true : false);
+ $srchurl = rtrim(preg_replace('/searchremove\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+
+ $srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
+
+
+ $hasq = ((strpos($srchurl,'?') !== false) ? true : false);
+ $hasamp = ((strpos($srchurl,'&') !== false) ? true : false);
+
+ if(($hasamp) && (! $hasq))
+ $srchurl = substr($srchurl,0,strpos($srchurl,'&')) . '?f=&' . substr($srchurl,strpos($srchurl,'&')+1);
+
+ $o = '';
+
+ $r = q("select tid,term from term WHERE uid = %d and ttype = %d ",
+ intval(local_channel()),
+ intval(TERM_SAVEDSEARCH)
+ );
+
+ $saved = array();
+
+ if(count($r)) {
+ foreach($r as $rr) {
+ $saved[] = array(
+ 'id' => $rr['tid'],
+ 'term' => $rr['term'],
+ 'dellink' => z_root() . '/' . $srchurl . (($hasq || $hasamp) ? '' : '?f=') . '&amp;searchremove=1&amp;search=' . urlencode($rr['term']),
+ 'srchlink' => z_root() . '/' . $srchurl . (($hasq || $hasamp) ? '' : '?f=') . '&amp;search=' . urlencode($rr['term']),
+ 'displayterm' => htmlspecialchars($rr['term'], ENT_COMPAT,'UTF-8'),
+ 'encodedterm' => urlencode($rr['term']),
+ 'delete' => t('Remove term'),
+ 'selected' => ($search==$rr['term']),
+ );
+ }
+ }
+
+ $tpl = get_markup_template("saved_searches.tpl");
+ $o = replace_macros($tpl, array(
+ '$title' => t('Saved Searches'),
+ '$add' => t('add'),
+ '$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), true),
+ '$saved' => $saved,
+ ));
+
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php
new file mode 100644
index 000000000..c15ad0980
--- /dev/null
+++ b/Zotlabs/Widget/Settings_menu.php
@@ -0,0 +1,139 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Settings_menu {
+
+ function widget($arr) {
+
+ if(! local_channel())
+ return;
+
+
+ $channel = \App::get_channel();
+
+ $abook_self_id = 0;
+
+ // Retrieve the 'self' address book entry for use in the auto-permissions link
+
+ $role = get_pconfig(local_channel(),'system','permissions_role');
+
+ $abk = q("select abook_id from abook where abook_channel = %d and abook_self = 1 limit 1",
+ intval(local_channel())
+ );
+ if($abk)
+ $abook_self_id = $abk[0]['abook_id'];
+
+ $x = q("select count(*) as total from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 ",
+ dbesc($channel['channel_hash'])
+ );
+
+ $hublocs = (($x && $x[0]['total'] > 1) ? true : false);
+
+ $tabs = array(
+ array(
+ 'label' => t('Account settings'),
+ 'url' => z_root().'/settings/account',
+ 'selected' => ((argv(1) === 'account') ? 'active' : ''),
+ ),
+
+ array(
+ 'label' => t('Channel settings'),
+ 'url' => z_root().'/settings/channel',
+ 'selected' => ((argv(1) === 'channel') ? 'active' : ''),
+ ),
+
+ );
+
+ if(get_account_techlevel() > 0 && get_features()) {
+ $tabs[] = array(
+ 'label' => t('Additional features'),
+ 'url' => z_root().'/settings/features',
+ 'selected' => ((argv(1) === 'features') ? 'active' : ''),
+ );
+ }
+
+ $tabs[] = array(
+ 'label' => t('Feature/Addon settings'),
+ 'url' => z_root().'/settings/featured',
+ 'selected' => ((argv(1) === 'featured') ? 'active' : ''),
+ );
+
+ $tabs[] = array(
+ 'label' => t('Display settings'),
+ 'url' => z_root().'/settings/display',
+ 'selected' => ((argv(1) === 'display') ? 'active' : ''),
+ );
+
+ if($hublocs) {
+ $tabs[] = array(
+ 'label' => t('Manage locations'),
+ 'url' => z_root() . '/locs',
+ 'selected' => ((argv(1) === 'locs') ? 'active' : ''),
+ );
+ }
+
+ $tabs[] = array(
+ 'label' => t('Export channel'),
+ 'url' => z_root() . '/uexport',
+ 'selected' => ''
+ );
+
+ if(get_account_techlevel() > 0) {
+ $tabs[] = array(
+ 'label' => t('Connected apps'),
+ 'url' => z_root() . '/settings/oauth',
+ 'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
+ );
+ }
+
+ if(get_account_techlevel() > 2) {
+ $tabs[] = array(
+ 'label' => t('Guest Access Tokens'),
+ 'url' => z_root() . '/settings/tokens',
+ 'selected' => ((argv(1) === 'tokens') ? 'active' : ''),
+ );
+ }
+
+ if(feature_enabled(local_channel(),'permcats')) {
+ $tabs[] = array(
+ 'label' => t('Permission Groups'),
+ 'url' => z_root() . '/settings/permcats',
+ 'selected' => ((argv(1) === 'permcats') ? 'active' : ''),
+ );
+ }
+
+
+ if($role === false || $role === 'custom') {
+ $tabs[] = array(
+ 'label' => t('Connection Default Permissions'),
+ 'url' => z_root() . '/connedit/' . $abook_self_id,
+ 'selected' => ''
+ );
+ }
+
+ if(feature_enabled(local_channel(),'premium_channel')) {
+ $tabs[] = array(
+ 'label' => t('Premium Channel Settings'),
+ 'url' => z_root() . '/connect/' . $channel['channel_address'],
+ 'selected' => ''
+ );
+ }
+
+ if(feature_enabled(local_channel(),'channel_sources')) {
+ $tabs[] = array(
+ 'label' => t('Channel Sources'),
+ 'url' => z_root() . '/sources',
+ 'selected' => ''
+ );
+ }
+
+ $tabtpl = get_markup_template("generic_links_widget.tpl");
+ return replace_macros($tabtpl, array(
+ '$title' => t('Settings'),
+ '$class' => 'settings-widget',
+ '$items' => $tabs,
+ ));
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Widget/Shortprofile.php b/Zotlabs/Widget/Shortprofile.php
new file mode 100644
index 000000000..9c2a46e75
--- /dev/null
+++ b/Zotlabs/Widget/Shortprofile.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Shortprofile {
+
+ function widget($arr) {
+
+ if(! \App::$profile['profile_uid'])
+ return;
+
+ $block = observer_prohibited();
+
+ return profile_sidebar(\App::$profile, $block, true, true);
+ }
+
+}
+
diff --git a/Zotlabs/Widget/Sitesearch.php b/Zotlabs/Widget/Sitesearch.php
new file mode 100644
index 000000000..b3a25d76a
--- /dev/null
+++ b/Zotlabs/Widget/Sitesearch.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Sitesearch {
+
+ function widget($arr) {
+
+ $search = ((x($_GET,'search')) ? $_GET['search'] : '');
+
+ $srchurl = \App::$query_string;
+
+ $srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is','',$srchurl),'&');
+ $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
+
+
+ $hasq = ((strpos($srchurl,'?') !== false) ? true : false);
+ $hasamp = ((strpos($srchurl,'&') !== false) ? true : false);
+
+ if(($hasamp) && (! $hasq))
+ $srchurl = substr($srchurl,0,strpos($srchurl,'&')) . '?f=&' . substr($srchurl,strpos($srchurl,'&')+1);
+
+ $o = '';
+
+ $saved = array();
+
+ $tpl = get_markup_template("sitesearch.tpl");
+ $o = replace_macros($tpl, array(
+ '$title' => t('Search'),
+ '$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), false),
+ '$saved' => $saved,
+ ));
+
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Suggestedchats.php b/Zotlabs/Widget/Suggestedchats.php
new file mode 100644
index 000000000..7df42944d
--- /dev/null
+++ b/Zotlabs/Widget/Suggestedchats.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Suggestedchats {
+
+ function widget($arr) {
+
+ if(! feature_enabled(\App::$profile['profile_uid'],'ajaxchat'))
+ return '';
+
+ // There are reports that this tool does not ever remove chatrooms on dead sites,
+ // and also will happily link to private chats which you cannot enter.
+ // For those reasons, it will be disabled until somebody decides it's worth
+ // fixing and comes up with a plan for doing so.
+
+ return '';
+
+ // probably should restrict this to your friends, but then the widget will only work
+ // if you are logged in locally.
+
+ $h = get_observer_hash();
+ if(! $h)
+ return;
+ $r = q("select xchat_url, xchat_desc, count(xchat_xchan) as total from xchat group by xchat_url, xchat_desc order by total desc, xchat_desc limit 24");
+ if($r) {
+ for($x = 0; $x < count($r); $x ++) {
+ $r[$x]['xchat_url'] = zid($r[$x]['xchat_url']);
+ }
+ }
+ return replace_macros(get_markup_template('bookmarkedchats.tpl'),array(
+ '$header' => t('Suggested Chatrooms'),
+ '$rooms' => $r
+ ));
+ }
+}
+
diff --git a/Zotlabs/Widget/Suggestions.php b/Zotlabs/Widget/Suggestions.php
new file mode 100644
index 000000000..5fb3d3e8b
--- /dev/null
+++ b/Zotlabs/Widget/Suggestions.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/socgraph.php');
+
+
+class Suggestions {
+
+ function widget($arr) {
+
+ if((! local_channel()) || (! feature_enabled(local_channel(),'suggest')))
+ return '';
+
+
+ $r = suggestion_query(local_channel(),get_observer_hash(),0,20);
+
+ if(! $r) {
+ return;
+ }
+
+ $arr = array();
+
+ // Get two random entries from the top 20 returned.
+ // We'll grab the first one and the one immediately following.
+ // This will throw some entropy intot he situation so you won't
+ // be looking at the same two mug shots every time the widget runs
+
+ $index = ((count($r) > 2) ? mt_rand(0,count($r) - 2) : 0);
+
+ for($x = $index; $x <= ($index+1); $x ++) {
+ $rr = $r[$x];
+ if(! $rr['xchan_url'])
+ break;
+
+ $connlnk = z_root() . '/follow/?url=' . $rr['xchan_addr'];
+
+ $arr[] = array(
+ 'url' => chanlink_url($rr['xchan_url']),
+ 'profile' => $rr['xchan_url'],
+ 'name' => $rr['xchan_name'],
+ 'photo' => $rr['xchan_photo_m'],
+ 'ignlnk' => z_root() . '/directory?ignore=' . $rr['xchan_hash'],
+ 'conntxt' => t('Connect'),
+ 'connlnk' => $connlnk,
+ 'ignore' => t('Ignore/Hide')
+ );
+ }
+
+ $o = replace_macros(get_markup_template('suggest_widget.tpl'),array(
+ '$title' => t('Suggestions'),
+ '$more' => t('See more...'),
+ '$entries' => $arr
+ ));
+
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Tagcloud.php b/Zotlabs/Widget/Tagcloud.php
new file mode 100644
index 000000000..cf7a4932e
--- /dev/null
+++ b/Zotlabs/Widget/Tagcloud.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+// @FIXME The problem with this widget is that we don't have a search function for webpages
+// that we can send the links to. Then we should also provide an option to search webpages
+// and conversations.
+
+class Tagcloud {
+
+ function widget($args) {
+
+ $o = '';
+ $uid = \App::$profile_uid;
+ $count = ((x($args,'count')) ? intval($args['count']) : 24);
+ $flags = 0;
+ $type = TERM_CATEGORY;
+
+ // @FIXME there exists no $authors variable
+ $r = tagadelic($uid, $count, $authors, $owner, $flags, ITEM_TYPE_WEBPAGE, $type);
+
+ // @FIXME this should use a template
+
+ if($r) {
+ $o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">';
+ foreach($r as $rv) {
+ $o .= '<span class="tag' . $rv[2] . '">' . $rv[0] .' </span> ' . "\r\n";
+ }
+ $o .= '</div></div>';
+ }
+ return $o;
+ }
+}
diff --git a/Zotlabs/Widget/Tagcloud_wall.php b/Zotlabs/Widget/Tagcloud_wall.php
new file mode 100644
index 000000000..7cff6ce09
--- /dev/null
+++ b/Zotlabs/Widget/Tagcloud_wall.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Tagcloud_wall {
+
+ function widget($arr) {
+
+ if((! \App::$profile['profile_uid']) || (! \App::$profile['channel_hash']))
+ return '';
+ if(! perm_is_allowed(\App::$profile['profile_uid'], get_observer_hash(), 'view_stream'))
+ return '';
+
+ $limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 50);
+ if(feature_enabled(\App::$profile['profile_uid'], 'tagadelic'))
+ return wtagblock(\App::$profile['profile_uid'], $limit, '', \App::$profile['channel_hash'], 'wall');
+
+ return '';
+ }
+}
diff --git a/Zotlabs/Widget/Tasklist.php b/Zotlabs/Widget/Tasklist.php
new file mode 100644
index 000000000..3961eecce
--- /dev/null
+++ b/Zotlabs/Widget/Tasklist.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/event.php');
+
+class Tasklist {
+
+ function widget($arr) {
+
+ if (! local_channel())
+ return;
+
+ $o .= '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>';
+ $o .= '<script>function taskComplete(id) { $.post("tasks/complete/"+id, function(data) { tasksFetch();}); }
+ function tasksFetch() {
+ $.get("tasks/fetch" + ((tasksShowAll) ? "/all" : ""), function(data) {
+ $(".tasklist-tasks").html(data.html);
+ });
+ }
+ </script>';
+
+ $o .= '<div class="widget">' . '<h3>' . t('Tasks') . '</h3><div class="tasklist-tasks">';
+ $o .= '</div><form id="tasklist-new-form" action="" ><input id="tasklist-new-summary" type="text" name="summary" value="" /></form>';
+ $o .= '</div>';
+ return $o;
+
+ }
+}
+
diff --git a/Zotlabs/Widget/Vcard.php b/Zotlabs/Widget/Vcard.php
new file mode 100644
index 000000000..cab05dfdd
--- /dev/null
+++ b/Zotlabs/Widget/Vcard.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Vcard {
+
+ function widget($arr) {
+ return vcard_from_xchan('', \App::get_observer());
+ }
+
+}
+
diff --git a/Zotlabs/Widget/Website_portation_tools.php b/Zotlabs/Widget/Website_portation_tools.php
new file mode 100644
index 000000000..1cf3bb78a
--- /dev/null
+++ b/Zotlabs/Widget/Website_portation_tools.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Website_portation_tools {
+
+ function widget($arr) {
+
+ // mod menu doesn't load a profile. For any modules which load a profile, check it.
+ // otherwise local_channel() is sufficient for permissions.
+
+ if(\App::$profile['profile_uid'])
+ if((\App::$profile['profile_uid'] != local_channel()) && (! \App::$is_sys))
+ return '';
+
+ if(! local_channel())
+ return '';
+
+ return website_portation_tools();
+ }
+}
diff --git a/Zotlabs/Widget/Wiki_list.php b/Zotlabs/Widget/Wiki_list.php
new file mode 100644
index 000000000..62f32dbf0
--- /dev/null
+++ b/Zotlabs/Widget/Wiki_list.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Wiki_list {
+
+ function widget($arr) {
+
+ $channel = channelx_by_n(\App::$profile_uid);
+
+ $wikis = \Zotlabs\Lib\NativeWiki::listwikis($channel,get_observer_hash());
+
+ if($wikis) {
+ return replace_macros(get_markup_template('wikilist_widget.tpl'), array(
+ '$header' => t('Wiki List'),
+ '$channel' => $channel['channel_address'],
+ '$wikis' => $wikis['wikis']
+ ));
+ }
+ return '';
+ }
+
+}
diff --git a/Zotlabs/Widget/Wiki_page_history.php b/Zotlabs/Widget/Wiki_page_history.php
new file mode 100644
index 000000000..dcec9a037
--- /dev/null
+++ b/Zotlabs/Widget/Wiki_page_history.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Wiki_page_history {
+
+ function widget($arr) {
+
+ $pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
+
+ $pageHistory = \Zotlabs\Lib\NativeWikiPage::page_history([
+ 'channel_id' => \App::$profile_uid,
+ 'observer_hash' => get_observer_hash(),
+ 'resource_id' => $resource_id,
+ 'pageUrlName' => $pageUrlName
+ ]);
+
+ return replace_macros(get_markup_template('nwiki_page_history.tpl'), array(
+ '$pageHistory' => $pageHistory['history'],
+ '$permsWrite' => $arr['permsWrite'],
+ '$name_lbl' => t('Name'),
+ '$msg_label' => t('Message','wiki_history')
+ ));
+
+ }
+}
diff --git a/Zotlabs/Widget/Wiki_pages.php b/Zotlabs/Widget/Wiki_pages.php
new file mode 100644
index 000000000..ac44b8d88
--- /dev/null
+++ b/Zotlabs/Widget/Wiki_pages.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+
+class Wiki_pages {
+
+ function widget($arr) {
+
+ if(argc() < 3)
+ return;
+
+ if(! $arr['resource_id']) {
+ $c = channelx_by_nick(argv(1));
+ $w = \Zotlabs\Lib\NativeWiki::exists_by_name($c['channel_id'],argv(2));
+ $arr = array(
+ 'resource_id' => $w['resource_id'],
+ 'channel_id' => $c['channel_id'],
+ 'channel_address' => $c['channel_address'],
+ 'refresh' => false
+ );
+ }
+
+ $wikiname = '';
+
+ $pages = array();
+
+ $p = \Zotlabs\Lib\NativeWikiPage::page_list($arr['channel_id'],get_observer_hash(),$arr['resource_id']);
+
+ if($p['pages']) {
+ $pages = $p['pages'];
+ $w = $p['wiki'];
+ // Wiki item record is $w['wiki']
+ $wikiname = $w['urlName'];
+ if (!$wikiname) {
+ $wikiname = '';
+ }
+ $typelock = $w['typelock'];
+ }
+
+ $can_create = perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'write_wiki');
+
+ $can_delete = ((local_channel() && (local_channel() == \App::$profile['uid'])) ? true : false);
+
+ return replace_macros(get_markup_template('wiki_page_list.tpl'), array(
+ '$resource_id' => $arr['resource_id'],
+ '$header' => t('Wiki Pages'),
+ '$channel_address' => $arr['channel_address'],
+ '$wikiname' => $wikiname,
+ '$pages' => $pages,
+ '$canadd' => $can_create,
+ '$candel' => $can_delete,
+ '$addnew' => t('Add new page'),
+ '$typelock' => $typelock,
+ '$lockedtype' => $w['mimeType'],
+ '$mimetype' => mimetype_select(0,$w['mimeType'],
+ [ 'text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]),
+ '$pageName' => array('pageName', t('Page name')),
+ '$refresh' => $arr['refresh'],
+ '$options' => t('Options'),
+ '$submit' => t('Submit')
+ ));
+ }
+}
+
+
diff --git a/Zotlabs/Widget/Zcard.php b/Zotlabs/Widget/Zcard.php
new file mode 100644
index 000000000..12e53eaab
--- /dev/null
+++ b/Zotlabs/Widget/Zcard.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Zcard {
+
+ function widget($args) {
+ $channel = channelx_by_n(\App::$profile_uid);
+ return get_zcard($channel,get_observer_hash(),array('width' => 875));
+ }
+}
diff --git a/Zotlabs/Zot/Auth.php b/Zotlabs/Zot/Auth.php
index d4d3bee1d..8d198f506 100644
--- a/Zotlabs/Zot/Auth.php
+++ b/Zotlabs/Zot/Auth.php
@@ -43,6 +43,12 @@ class Auth {
$this->Finalise();
}
+ if(strpbrk($this->sec,'.:')) {
+ logger('illegal security context');
+ $this->Debug('illegal security context.');
+ $this->Finalise();
+ }
+
$x = $this->GetHublocs($this->address);
if($x) {
@@ -109,6 +115,14 @@ class Auth {
$this->remote_hub = $hubloc['hubloc_url'];
$this->dnt = 0;
+ if(! $this->sec) {
+ logger('missing security context.');
+ if($this->test)
+ $this->Debug('missing security context.');
+ return false;
+ }
+
+
// check credentials and access
// If they are already authenticated and haven't changed credentials,
@@ -176,7 +190,7 @@ class Auth {
return false;
}
- $this->Debug('auth check request returned .' . print_r($j, true));
+ $this->Debug('auth check request returned ' . print_r($j, true));
if(! $j['success'])
return false;
diff --git a/Zotlabs/Zot/Finger.php b/Zotlabs/Zot/Finger.php
index 7e0f5fb7c..348171bdc 100644
--- a/Zotlabs/Zot/Finger.php
+++ b/Zotlabs/Zot/Finger.php
@@ -22,6 +22,7 @@ class Finger {
*
* @return zotinfo array (with 'success' => true) or array('success' => false);
*/
+
static public function run($webbie, $channel = null, $autofallback = true) {
$ret = array('success' => false);
@@ -84,18 +85,27 @@ class Finger {
'token' => self::$token
);
- $result = z_post_url($url . $rhs,$postvars);
+ $headers = [];
+ $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
+ $headers['X-Zot-Nonce'] = random_string();
+ $xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
+ 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
+
+ $retries = 0;
+
+ $result = z_post_url($url . $rhs,$postvars,$retries, [ 'headers' => $xhead ]);
if ((! $result['success']) && ($autofallback)) {
if ($https) {
logger('zot_finger: https failed. falling back to http');
- $result = z_post_url('http://' . $host . $rhs,$postvars);
+ $result = z_post_url('http://' . $host . $rhs,$postvars, $retries, [ 'headers' => $xhead ]);
}
}
- } else {
+ }
+ else {
$rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token;
- $result = z_fetch_url($url . $rhs);
+ $result = z_fetch_url($url . $rhs);
if((! $result['success']) && ($autofallback)) {
if($https) {
logger('zot_finger: https failed. falling back to http');
@@ -111,7 +121,10 @@ class Finger {
}
$x = json_decode($result['body'], true);
- if($x) {
+
+ $verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : ''));
+
+ if($x && (! $verify['header_valid'])) {
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
if($signed_token) {
$valid = rsa_verify('token.' . self::$token, base64url_decode($signed_token), $x['key']);
@@ -123,9 +136,7 @@ class Finger {
}
else {
logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING);
- // after 2017-01-01 this will be a hard error unless you over-ride it.
- if((time() > 1483228800) && (! get_config('system', 'allow_unsigned_zotfinger')))
- return $ret;
+ return $ret;
}
}
diff --git a/Zotlabs/Zot/IHandler.php b/Zotlabs/Zot/IHandler.php
index eeca1555c..dd82f5be6 100644
--- a/Zotlabs/Zot/IHandler.php
+++ b/Zotlabs/Zot/IHandler.php
@@ -12,6 +12,8 @@ interface IHandler {
function Request($data);
+ function Rekey($sender,$data);
+
function AuthCheck($data,$encrypted);
function Purge($sender,$recipients);
diff --git a/Zotlabs/Zot/Receiver.php b/Zotlabs/Zot/Receiver.php
index 71d57eb35..c521c9d64 100644
--- a/Zotlabs/Zot/Receiver.php
+++ b/Zotlabs/Zot/Receiver.php
@@ -120,6 +120,10 @@ class Receiver {
$this->handler->Notify($this->data);
break;
+ case 'rekey':
+ $this->handler->Rekey($this->sender, $this->data);
+ break;
+
default:
$this->response['message'] = 'Not implemented';
json_return_and_die($this->response);
@@ -138,7 +142,6 @@ class Receiver {
* This packet is optionally encrypted, which we will discover if the json has an 'iv' element.
* $contents => array( 'alg' => 'aes256cbc', 'iv' => initialisation vector, 'key' => decryption key, 'data' => encrypted data);
* $contents->iv and $contents->key are random strings encrypted with this site's RSA public key and then base64url encoded.
- * Currently only 'aes256cbc' is used, but this is extensible should that algorithm prove inadequate.
*
* Once decrypted, one will find the normal json_encoded zot message packet.
*
@@ -156,7 +159,8 @@ class Receiver {
* },
* "recipients": { optional recipient array },
* "callback":"\/post",
- * "version":1,
+ * "version":"1.2",
+ * "encryption":["aes256cbc"],
* "secret":"1eaa...",
* "secret_sig": "df89025470fac8..."
* }
diff --git a/Zotlabs/Zot/Verify.php b/Zotlabs/Zot/Verify.php
index 06bd3188c..1d9e6de3f 100644
--- a/Zotlabs/Zot/Verify.php
+++ b/Zotlabs/Zot/Verify.php
@@ -31,6 +31,22 @@ class Verify {
return false;
}
+
+ function get_meta($type,$channel_id,$token) {
+ $r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
+ dbesc($type),
+ intval($channel_id),
+ dbesc($token)
+ );
+ if($r) {
+ q("delete from verify where id = %d",
+ intval($r[0]['id'])
+ );
+ return $r[0]['meta'];
+ }
+ return false;
+ }
+
function purge($type,$interval) {
q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s",
dbesc($type),
diff --git a/Zotlabs/Zot/ZotHandler.php b/Zotlabs/Zot/ZotHandler.php
index aab336545..ab8815b3d 100644
--- a/Zotlabs/Zot/ZotHandler.php
+++ b/Zotlabs/Zot/ZotHandler.php
@@ -20,6 +20,10 @@ class ZotHandler implements IHandler {
zot_reply_message_request($data);
}
+ function Rekey($sender,$data) {
+ zot_rekey_request($sender,$data);
+ }
+
function AuthCheck($data,$encrypted) {
zot_reply_auth_check($data,$encrypted);
}