diff --git a/LICENSE b/LICENSE index 25c4bf1a3..abae6bf44 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,9 @@ -Copyright (c) 2010-2017 the Hubzilla Community +Copyright (c) 2010-2017 Mike Macgirvin All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/README.md b/README.md index 54f80bebe..95e136b20 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,7 @@ -![Hubzilla](images/hubzilla-banner.png) -Hubzilla - Community Server -=========================== +red +=== -

-Installing Hubzilla -

+This is red. - -**What is Hubzilla?** - -Hubzilla is a general purpose communication server integrated with a web publishing system and a decentralised permission system. If this sounds like a bunch of technical mumbo-jumbo to you, just think of it as an independent platform for sharing stuff online. - -Hubzilla contains some social network bits, some cloud storage bits, some blog and forum bits, and some content management bits. These are all integrated within a common privacy framework - and it is all decentralised. - -Everything you publish or share can be restricted to those channels and people you wish to share them with; and these permissions work completely invisibly - even with channels on different servers or other communications services. - -Migration and live backups of your connections, settings, and everything you publish are built-in, so you never need worry about server failure. - -Hubzilla is completely decentralised and open source, for you modify or adapt to your needs and desires. Plugins, themes, and numerous configuration options extend the overall capabilities to do anything you can imagine. - - -**Who Are We?** - -The Hubzilla community consists of passionate volunteers creating an open source commons of decentralised services which are highly integrated and can rival the feature set of large centralised providers. We do our best to provide ethical software which places you in control of your online communications and privacy expectations. - - -[![Build Status](https://travis-ci.org/redmatrix/hubzilla.svg)](https://travis-ci.org/redmatrix/hubzilla) +![red](https://gitlab.com/macgirvin/red/raw/046e5e239fd28996f8c658900a83c33dbe0011ba/images/red-koala.png) diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php index 74286934f..62c4af0ff 100644 --- a/Zotlabs/Access/Permissions.php +++ b/Zotlabs/Access/Permissions.php @@ -201,6 +201,7 @@ class Permissions { * * \e array \b perms Permission array * * \e int \b automatic 0 or 1 */ + static public function connect_perms($channel_id) { $my_perms = []; 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/Notifier.php b/Zotlabs/Daemon/Notifier.php index 16246b081..20dd96ddd 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -64,8 +64,6 @@ require_once('include/bbcode.php'); * purge_all channel_id * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) - * single_activity item_id (deliver to a singleton network from the appropriate clone) - * single_mail mail_id (deliver to a singleton network from the appropriate clone) * location channel_id * request channel_id xchan_hash message_id * rating xlink_id @@ -105,7 +103,7 @@ class Notifier { $normal_mode = true; $packet_type = 'undefined'; - if($cmd === 'mail' || $cmd === 'single_mail') { + if($cmd === 'mail') { $normal_mode = false; $mail = true; $private = true; @@ -392,7 +390,6 @@ class Notifier { return; } } - } $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false); @@ -409,7 +406,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); @@ -422,40 +419,39 @@ 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, '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' => false, + 'location' => $location, + 'request' => $request, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + 'queued' => [] + ]; call_hooks('notifier_process', $narr); if($narr['queued']) { @@ -492,8 +488,6 @@ 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. @@ -524,49 +518,47 @@ class Notifier { if($hub['hubloc_network'] == 'zot') { if(! in_array($hub['hubloc_sitekey'],$keys)) { $hublist[] = $hub['hubloc_host']; - $dhubs[] = $hub; - $keys[] = $hub['hubloc_sitekey']; + $dhubs[] = $hub; + $keys[] = $hub['hubloc_sitekey']; } } else { if(! in_array($hub['hubloc_url'],$urls)) { $hublist[] = $hub['hubloc_host']; - $dhubs[] = $hub; - $urls[] = $hub['hubloc_url']; + $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, + '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' => false, + 'location' => $location, + 'request' => $request, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + 'queued' => [] + ]; call_hooks('notifier_hub',$narr); @@ -578,21 +570,6 @@ class Notifier { } - // singleton deliveries by definition 'not got zot'. - // 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. - - if($cmd === 'single_mail' || $cmd === 'single_activity') { - continue; - } - - // default: zot protocol - $hash = random_string(); $packet = null; @@ -618,14 +595,16 @@ class Notifier { else { $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(array( - 'hash' => $hash, - 'account_id' => $target_item['aid'], - 'channel_id' => $target_item['uid'], - 'posturl' => $hub['hubloc_callback'], - 'notify' => $packet, - 'msg' => json_encode($encoded_item) - )); + 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'))) { @@ -646,9 +625,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/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/Apps.php b/Zotlabs/Lib/Apps.php index ed18ff3cb..68587df49 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -209,6 +209,7 @@ class Apps { static public function translate_system_apps(&$arr) { $apps = array( + 'Apps' => t('Apps'), 'Site Admin' => t('Site Admin'), 'Report Bug' => t('Report Bug'), 'View Bookmarks' => t('View Bookmarks'), @@ -664,11 +665,6 @@ class Apps { } - - - - - static public function app_decode($s) { $x = base64_decode(str_replace(array('
',"\r","\n",' '),array('','','',''),$s)); return json_decode($x,true); 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/Enotify.php b/Zotlabs/Lib/Enotify.php index 90662ce84..9f3347d19 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -170,7 +170,7 @@ class Enotify { xchan_query($p); - $moderated = (($p[0]['item_blocked'] = ITEM_MODERATED) ? true : false); + $moderated = (($p[0]['item_blocked'] == ITEM_MODERATED) ? true : false); $item_post_type = item_post_type($p[0]); // $private = $p[0]['item_private']; diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php index d70697fbc..25478e764 100644 --- a/Zotlabs/Lib/PConfig.php +++ b/Zotlabs/Lib/PConfig.php @@ -119,7 +119,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/System.php b/Zotlabs/Lib/System.php index 306c90f4a..3d5b18506 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -54,12 +54,8 @@ class System { return 'https://github.com/redmatrix/hubzilla'; } - - 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'; + return 'pro'; } static public function get_std_version() { @@ -72,11 +68,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/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 917397686..72d8af4dd 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -251,8 +251,6 @@ class ThreadItem { ); } - $server_role = get_config('system','server_role'); - $has_bookmarks = false; if(is_array($item['term'])) { foreach($item['term'] as $t) { diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php index 536d85dde..f2918dffc 100644 --- a/Zotlabs/Module/Admin.php +++ b/Zotlabs/Module/Admin.php @@ -91,10 +91,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 +105,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 +118,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.' - . '
PHP 5.3 has reached its End of Life (EOL) in August 2014.' - . ' A list about current PHP versions can be found here.'; - } $vmaster = get_repository_version('master'); $vdev = get_repository_version('dev'); diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index d05e70aa9..4c5b82e78 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); @@ -68,7 +67,6 @@ class Site { 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); @@ -254,12 +252,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'), @@ -286,8 +278,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') ], 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 @@ +validateAuthorizeRequest($request, $response)) { + $response->send(); + killme(); + } + + // display an authorization form + if (empty($_POST)) { + + return ' +
+
+ + +
'; + } + + // 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/Cdav.php b/Zotlabs/Module/Cdav.php new file mode 100644 index 000000000..f91dead04 --- /dev/null +++ b/Zotlabs/Module/Cdav.php @@ -0,0 +1,1202 @@ +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']; + } + + + $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_hash']; + + 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['channel_hash']; + $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( '' . t('INVALID EVENT DISMISSED!') . '' . EOL . + '' . t('Summary: ') . '' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . + '' . t('Date: ') . '' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . + '' . t('Reason: ') . '' . $ret[0]['message'] . EOL + ); + } + + if($_REQUEST['a_upload']) { + notice( '' . t('INVALID CARD DISMISSED!') . '' . EOL . + '' . t('Name: ') . '' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . + '' . t('Reason: ') . '' . $ret[0]['message'] . EOL + ); + } + } + } + } + @unlink($src); + } + } + + function get() { + + if(!local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_hash']; + + + if(!cdav_principal($principalUri)) { + $this->activate($channel); + if(!cdav_principal($principalUri)) { + return; + } + } + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + head_add_css('cdav.css'); + + if(argv(1) === 'calendar') { + $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['channel_hash']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = 4; + $caldavBackend->updateInvites($id, [$sharee]); + + killme(); + } + + + if(argv(1) === 'addressbook') { + $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($channel) { + + if(! $channel) + return; + + $uri = 'principals/' . $channel['channel_hash']; + + + $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 + $r = q("insert into calendars (components) values('%s') ", + dbesc('VEVENT,VTODO') + ); + + $r = q("insert into calendarinstances (principaluri, displayname, uri, description, calendarcolor) values( '%s', '%s', '%s', '%s', '%s') ", + dbesc($uri), + dbesc(t('Default Calendar')), + dbesc('default'), + dbesc($channel['channel_name']), + dbesc('#3a87ad') + ); + + //create default addressbook + $r = q("insert into addressbooks (principaluri, displayname, uri) values('%s', '%s', '%s') ", + dbesc($uri), + dbesc(t('Default Addressbook')), + dbesc('default') + ); + } + } + + +} diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 98a1e6c88..51c937270 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -365,10 +365,10 @@ class Channel extends \Zotlabs\Web\Controller { 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/Cloud.php b/Zotlabs/Module/Cloud.php index 7370eeda3..75191a279 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -86,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/Connections.php b/Zotlabs/Module/Connections.php index b079ae860..b3c5e8ee9 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -19,7 +19,7 @@ class Connections extends \Zotlabs\Web\Controller { } - function get() { + function get() { $sort_type = 0; $o = ''; @@ -63,8 +63,8 @@ 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': @@ -168,10 +168,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( @@ -243,7 +243,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) { @@ -257,11 +258,12 @@ 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'), diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 484e69b52..d301c2d45 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -842,6 +842,22 @@ class Connedit extends \Zotlabs\Web\Controller { } else $locstr = t('none'); + + $clone_warn = ''; + $clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false); + if(! $clonable) { + $clone_warn = ''; + $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 .= '
' . 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'])), @@ -856,6 +872,7 @@ class Connedit extends \Zotlabs\Web\Controller { '$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/Display.php b/Zotlabs/Module/Display.php index 815672091..df3cb1e2b 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -308,12 +308,12 @@ class Display extends \Zotlabs\Web\Controller { 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) { diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php index 629bdd3fd..a54c42e7f 100644 --- a/Zotlabs/Module/Editpost.php +++ b/Zotlabs/Module/Editpost.php @@ -39,6 +39,11 @@ class Editpost extends \Zotlabs\Web\Controller { return; } + if($itm[0]['resource_type'] === 'photo' && $itm[0]['resource_id']) { + notice( t('Item is not editable') . EOL); + return; + } + if($itm[0]['resource_type'] === 'event' && $itm[0]['resource_id']) { goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1'); } diff --git a/Zotlabs/Module/Hcard.php b/Zotlabs/Module/Hcard.php index 13097939e..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(); diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php index e247416d9..0373a4aab 100644 --- a/Zotlabs/Module/Help.php +++ b/Zotlabs/Module/Help.php @@ -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,13 @@ 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(); 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 )); } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index ce3fd469a..40ce8f6d1 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -121,8 +121,7 @@ class Import extends \Zotlabs\Web\Controller { $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) @@ -333,6 +332,10 @@ class Import extends \Zotlabs\Web\Controller { $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)) { diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php index 6b6f80a31..927e7beae 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; } diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 952ecf487..e96d4c669 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -818,7 +818,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(); diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php index 92df58858..9af43420d 100644 --- a/Zotlabs/Module/Moderate.php +++ b/Zotlabs/Module/Moderate.php @@ -68,8 +68,7 @@ class Moderate extends \Zotlabs\Web\Controller { $items = array(); } - $o = conversation($a,$items,'moderate',false,'traditional'); - + $o = conversation($items,'moderate',false,'traditional'); return $o; } diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 1c7c70019..f2ad77dd7 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -551,7 +551,7 @@ class Network extends \Zotlabs\Web\Controller { $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..cfd45e909 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -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.') . ' ' . t('Read more about roles') . '',$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.') . ' ' . t('Read more about roles') . '',$perm_roles); $o = replace_macros(get_markup_template('new_channel.tpl'), array( '$title' => t('Create Channel'), diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php index 7bc90c091..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 { diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index dc4ae670e..8a110f925 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -154,7 +154,9 @@ class Photo extends \Zotlabs\Web\Controller { intval($resolution) ); - if($r && $r[0]['photo_usage'] == PHOTO_COVER) + // 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 ]; diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php index cf8d83023..ea50e821a 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; diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 46210abb1..28c34425c 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -167,7 +167,7 @@ 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(($items) && (! $update)) $o .= alt_pager($a,count($items)); diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php index 1d8944d8e..d4573156c 100644 --- a/Zotlabs/Module/Register.php +++ b/Zotlabs/Module/Register.php @@ -151,7 +151,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']; @@ -237,14 +237,12 @@ class Register 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 = '@' . 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.') . ' ' . t('Read more about roles') . '',$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.') . ' ' . t('Read more about roles') . '',$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/Search.php b/Zotlabs/Module/Search.php index a78a023ff..2b949ebc7 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -225,7 +225,7 @@ class Search extends \Zotlabs\Web\Controller { else $o .= '

' . sprintf( t('Search results for: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '

'; - $o .= conversation($a,$items,'search',$update,'client'); + $o .= conversation($items,'search',$update,'client'); $o .= ''; 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 12ad25d51..3e6adcf8d 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -489,7 +489,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), diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php index d4c31fd4e..e5b54cc5f 100644 --- a/Zotlabs/Module/Setup.php +++ b/Zotlabs/Module/Setup.php @@ -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(), @@ -324,11 +318,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 +337,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(), 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/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 @@ +handleTokenRequest(\OAuth2\Request::createFromGlobals())->send(); + + killme(); + } + +} \ No newline at end of file diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php index 641e84b70..d59fcdb9f 100644 --- a/Zotlabs/Module/Webpages.php +++ b/Zotlabs/Module/Webpages.php @@ -179,11 +179,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", @@ -191,12 +188,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'; diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php index 2f1fa01b7..85481754f 100644 --- a/Zotlabs/Module/Wiki.php +++ b/Zotlabs/Module/Wiki.php @@ -355,6 +355,7 @@ class Wiki extends \Zotlabs\Web\Controller { $html = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))),$wikiURL); } else { + $bb = Zlib\NativeWikiPage::bbcode($content); $x = new ZLib\MarkdownSoap($bb); $md = $x->clean(); diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php index 7b36576e0..9630e9ab4 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,11 +44,11 @@ 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, '$profile_url' => z_root() . '/channel/' . $r[0]['channel_address'], '$hcard_url' => z_root() . '/hcard/' . $r[0]['channel_address'], @@ -61,12 +56,8 @@ class Xrd extends \Zotlabs\Web\Controller { '$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']) )); diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index 7162161ef..9dc393167 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 @@ -257,7 +258,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(); + $this->build_page = true; } /** diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php new file mode 100644 index 000000000..1b33668ad --- /dev/null +++ b/Zotlabs/Widget/Cdav.php @@ -0,0 +1,176 @@ +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 .= '' . "\r\n"; + foreach($local_channels as $local_channel) { + $sharee_options .= '' . "\r\n"; + } + + $access_options = '' . "\r\n"; + $access_options .= '' . "\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/Conversations.php b/Zotlabs/Widget/Conversations.php index 27e517c02..4fd754f66 100644 --- a/Zotlabs/Widget/Conversations.php +++ b/Zotlabs/Widget/Conversations.php @@ -12,10 +12,6 @@ class Conversations { if(argc() > 1) { switch(argv(1)) { - case 'combined': - $mailbox = 'combined'; - $header = t('Conversations'); - break; case 'inbox': $mailbox = 'inbox'; $header = t('Received Messages'); @@ -58,7 +54,7 @@ class Conversations { 'body' => $rr['body'], 'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], 'c'), 'seen' => $rr['seen'], - 'selected' => ((argv(2)) ? (argv(2) == $rr['id']) : ($r[0]['id'] == $rr['id'])) + 'selected' => ((argc() == 2) ? (intval(argv(1)) == intval($rr['id'])) : ($r[0]['id'] == $rr['id'])) ); } @@ -71,4 +67,6 @@ class Conversations { } return $o; } + } + diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php index 753390c23..c15ad0980 100644 --- a/Zotlabs/Widget/Settings_menu.php +++ b/Zotlabs/Widget/Settings_menu.php @@ -79,11 +79,13 @@ class Settings_menu { 'selected' => '' ); - $tabs[] = array( - 'label' => t('Connected apps'), - 'url' => z_root() . '/settings/oauth', - 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), - ); + 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( diff --git a/Zotlabs/Widget/Tasklist.php b/Zotlabs/Widget/Tasklist.php index 6f7a8aaed..3961eecce 100644 --- a/Zotlabs/Widget/Tasklist.php +++ b/Zotlabs/Widget/Tasklist.php @@ -8,8 +8,8 @@ class Tasklist { function widget($arr) { - if (! local_channel()) - return; + if (! local_channel()) + return; $o .= ''; $o .= ' - + + @@ -207,5 +207,5 @@ - + diff --git a/library/blueimp_upload/basic-plus.html b/library/blueimp_upload/basic-plus.html index 59b73b60c..9e5c2321f 100644 --- a/library/blueimp_upload/basic-plus.html +++ b/library/blueimp_upload/basic-plus.html @@ -1,14 +1,14 @@ @@ -86,9 +86,9 @@
- + @@ -150,7 +150,7 @@ $(function () { dataType: 'json', autoUpload: false, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, - maxFileSize: 5000000, // 5 MB + maxFileSize: 999000, // Enable image resizing, except for Android and Opera, // which actually support image resizing, but fail to // send Blob objects via XHR requests: @@ -222,5 +222,5 @@ $(function () { .parent().addClass($.support.fileInput ? undefined : 'disabled'); }); - + diff --git a/library/blueimp_upload/basic.html b/library/blueimp_upload/basic.html index f248f4d80..c0df639b4 100644 --- a/library/blueimp_upload/basic.html +++ b/library/blueimp_upload/basic.html @@ -1,14 +1,14 @@ @@ -86,17 +86,17 @@
- + @@ -132,5 +132,5 @@ $(function () { .parent().addClass($.support.fileInput ? undefined : 'disabled'); }); - + diff --git a/library/blueimp_upload/blueimp-file-upload.jquery.json b/library/blueimp_upload/blueimp-file-upload.jquery.json deleted file mode 100644 index d6d8c911c..000000000 --- a/library/blueimp_upload/blueimp-file-upload.jquery.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "blueimp-file-upload", - "version": "9.8.0", - "title": "jQuery File Upload", - "author": { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], - "dependencies": { - "jquery": ">=1.6" - }, - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", - "keywords": [ - "jquery", - "file", - "upload", - "widget", - "multiple", - "selection", - "drag", - "drop", - "progress", - "preview", - "cross-domain", - "cross-site", - "chunk", - "resume", - "gae", - "go", - "python", - "php", - "bootstrap" - ], - "homepage": "https://github.com/blueimp/jQuery-File-Upload", - "docs": "https://github.com/blueimp/jQuery-File-Upload/wiki", - "demo": "https://blueimp.github.io/jQuery-File-Upload/", - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ] -} diff --git a/library/blueimp_upload/bower-version-update.js b/library/blueimp_upload/bower-version-update.js new file mode 100755 index 000000000..09ce3927e --- /dev/null +++ b/library/blueimp_upload/bower-version-update.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +'use strict'; + +var path = require('path'); +var packageJSON = require(path.join(__dirname, 'package.json')); +var bowerFile = path.join(__dirname, 'bower.json'); +var bowerJSON = require('bower-json').parse( + require(bowerFile), + {normalize: true} +); +bowerJSON.version = packageJSON.version; +require('fs').writeFileSync( + bowerFile, + JSON.stringify(bowerJSON, null, 2) + '\n' +); diff --git a/library/blueimp_upload/bower.json b/library/blueimp_upload/bower.json index c0d3d3259..90c74c792 100644 --- a/library/blueimp_upload/bower.json +++ b/library/blueimp_upload/bower.json @@ -1,8 +1,8 @@ { "name": "blueimp-file-upload", - "version": "9.8.0", + "version": "9.18.0", "title": "jQuery File Upload", - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images.", "keywords": [ "jquery", "file", @@ -40,12 +40,7 @@ "url": "git://github.com/blueimp/jQuery-File-Upload.git" }, "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], + "license": "MIT", "dependencies": { "jquery": ">=1.6", "blueimp-tmpl": ">=2.5.4", @@ -53,23 +48,7 @@ "blueimp-canvas-to-blob": ">=2.1.1" }, "main": [ - "css/jquery.fileupload.css", - "css/jquery.fileupload-ui.css", - "css/jquery.fileupload-noscript.css", - "css/jquery.fileupload-ui-noscript.css", - "js/cors/jquery.postmessage-transport.js", - "js/cors/jquery.xdr-transport.js", - "js/vendor/jquery.ui.widget.js", - "js/jquery.fileupload.js", - "js/jquery.fileupload-process.js", - "js/jquery.fileupload-validate.js", - "js/jquery.fileupload-image.js", - "js/jquery.fileupload-audio.js", - "js/jquery.fileupload-video.js", - "js/jquery.fileupload-ui.js", - "js/jquery.fileupload-jquery-ui.js", - "js/jquery.fileupload-angular.js", - "js/jquery.iframe-transport.js" + "js/jquery.fileupload.js" ], "ignore": [ "/*.*", diff --git a/library/blueimp_upload/cors/postmessage.html b/library/blueimp_upload/cors/postmessage.html index 3d1448f08..6db288cf9 100644 --- a/library/blueimp_upload/cors/postmessage.html +++ b/library/blueimp_upload/cors/postmessage.html @@ -1,14 +1,14 @@ @@ -72,4 +72,4 @@ $(window).on('message', function (e) { }); - \ No newline at end of file + diff --git a/library/blueimp_upload/cors/result.html b/library/blueimp_upload/cors/result.html index 225131495..e3d629814 100644 --- a/library/blueimp_upload/cors/result.html +++ b/library/blueimp_upload/cors/result.html @@ -1,14 +1,14 @@ diff --git a/library/blueimp_upload/css/demo-ie8.css b/library/blueimp_upload/css/demo-ie8.css index 262493d08..e0e8ea9b0 100644 --- a/library/blueimp_upload/css/demo-ie8.css +++ b/library/blueimp_upload/css/demo-ie8.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Demo CSS Fixes for IE<9 1.0.0 + * jQuery File Upload Demo CSS Fixes for IE<9 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .navigation { diff --git a/library/blueimp_upload/css/demo.css b/library/blueimp_upload/css/demo.css index 2b4d43934..d7d524df5 100644 --- a/library/blueimp_upload/css/demo.css +++ b/library/blueimp_upload/css/demo.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Demo CSS 1.1.0 + * jQuery File Upload Demo CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ body { diff --git a/library/blueimp_upload/css/jquery.fileupload-noscript.css b/library/blueimp_upload/css/jquery.fileupload-noscript.css index 64d728fc3..2409bfb0a 100644 --- a/library/blueimp_upload/css/jquery.fileupload-noscript.css +++ b/library/blueimp_upload/css/jquery.fileupload-noscript.css @@ -1,20 +1,20 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin NoScript CSS 1.2.0 + * jQuery File Upload Plugin NoScript CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileinput-button input { position: static; opacity: 1; filter: none; - font-size: inherit; + font-size: inherit !important; direction: inherit; } .fileinput-button span { diff --git a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css index 87f110cdb..30651acf0 100644 --- a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css +++ b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin NoScript CSS 8.8.5 + * jQuery File Upload UI Plugin NoScript CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileinput-button i, diff --git a/library/blueimp_upload/css/jquery.fileupload-ui.css b/library/blueimp_upload/css/jquery.fileupload-ui.css index 76fb376de..9e36c42c5 100644 --- a/library/blueimp_upload/css/jquery.fileupload-ui.css +++ b/library/blueimp_upload/css/jquery.fileupload-ui.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin CSS 9.0.0 + * jQuery File Upload UI Plugin CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileupload-buttonbar .btn, diff --git a/library/blueimp_upload/css/jquery.fileupload.css b/library/blueimp_upload/css/jquery.fileupload.css index fb6044d34..8ae3b09d4 100644 --- a/library/blueimp_upload/css/jquery.fileupload.css +++ b/library/blueimp_upload/css/jquery.fileupload.css @@ -1,18 +1,19 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin CSS 1.3.0 + * jQuery File Upload Plugin CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileinput-button { position: relative; overflow: hidden; + display: inline-block; } .fileinput-button input { position: absolute; @@ -21,7 +22,7 @@ margin: 0; opacity: 0; -ms-filter: 'alpha(opacity=0)'; - font-size: 200px; + font-size: 200px !important; direction: ltr; cursor: pointer; } diff --git a/library/blueimp_upload/css/style.css b/library/blueimp_upload/css/style.css index b2c60a6f1..3aee25689 100644 --- a/library/blueimp_upload/css/style.css +++ b/library/blueimp_upload/css/style.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin CSS Example 8.8.2 + * jQuery File Upload Plugin CSS Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ body { diff --git a/library/blueimp_upload/index.html b/library/blueimp_upload/index.html index f92f04aab..2a8dc1521 100644 --- a/library/blueimp_upload/index.html +++ b/library/blueimp_upload/index.html @@ -1,14 +1,14 @@ @@ -121,9 +121,9 @@