Merge pull request #7103 from nupplaphil/task/mod_smilies
authorHypolite Petovan <hypolite@mrpetovan.com>
Mon, 6 May 2019 16:53:45 +0000 (12:53 -0400)
committerGitHub <noreply@github.com>
Mon, 6 May 2019 16:53:45 +0000 (12:53 -0400)
Move mod/smilies to src/Module/Smilies

45 files changed:
config/dbstructure.config.php
database.sql
images/friendica-404_svg_flexy-o-hare.png [new file with mode: 0644]
images/friendica-404_svg_hare-bottom-light-inside.png [new file with mode: 0644]
mod/dfrn_confirm.php
mod/filerm.php [deleted file]
mod/follow.php
mod/friendica.php [deleted file]
mod/maintenance.php [deleted file]
mod/modexp.php [deleted file]
mod/pretheme.php [deleted file]
mod/robots_txt.php [deleted file]
mod/viewsrc.php [deleted file]
src/App.php
src/App/Router.php
src/Core/System.php
src/Core/Update.php
src/Model/APContact.php
src/Model/Contact.php
src/Model/Item.php
src/Model/Profile.php
src/Model/User.php
src/Module/BookMarklet.php [deleted file]
src/Module/Bookmarklet.php [new file with mode: 0644]
src/Module/Filer.php [deleted file]
src/Module/Filer/RemoveTag.php [new file with mode: 0644]
src/Module/Filer/SaveTag.php [new file with mode: 0644]
src/Module/Friendica.php [new file with mode: 0644]
src/Module/ItemBody.php [new file with mode: 0644]
src/Module/Maintenance.php [new file with mode: 0644]
src/Module/PublicRSAKey.php [new file with mode: 0644]
src/Module/ReallySimpleDiscovery.php
src/Module/RobotsTxt.php [new file with mode: 0644]
src/Module/Special/HTTPException.php
src/Module/ThemeDetails.php [new file with mode: 0644]
src/Network/HTTPException/ServiceUnavaiableException.php [deleted file]
src/Network/HTTPException/ServiceUnavailableException.php [new file with mode: 0644]
src/Protocol/ActivityPub/Processor.php
src/Worker/OnePoll.php
view/global.css
view/templates/exception.tpl
view/templates/feedtest.tpl
view/templates/friendica.tpl [new file with mode: 0644]
view/templates/rsd.tpl [deleted file]
view/theme/frio/css/style.css

index 3996205..86965a2 100755 (executable)
@@ -34,7 +34,7 @@
 use Friendica\Database\DBA;
 
 if (!defined('DB_UPDATE_VERSION')) {
-       define('DB_UPDATE_VERSION', 1310);
+       define('DB_UPDATE_VERSION', 1311);
 }
 
 return [
@@ -74,6 +74,7 @@ return [
                        "alias" => ["type" => "varchar(255)", "comment" => ""],
                        "pubkey" => ["type" => "text", "comment" => ""],
                        "baseurl" => ["type" => "varchar(255)", "comment" => "baseurl of the ap contact"],
+                       "generator" => ["type" => "varchar(255)", "comment" => "Name of the contact's system"],
                        "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""]
                ],
                "indexes" => [
@@ -185,7 +186,8 @@ return [
                        "remote_self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                        "rel" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "The kind of the relation between the user and the contact"],
                        "duplex" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                       "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network protocol of the contact"],
+                       "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network of the contact"],
+                       "protocol" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Protocol of the contact"],
                        "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name that this contact is known by"],
                        "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Nick- and user name of the contact"],
                        "location" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
index b9e7009..dde37cd 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
 -- Friendica 2019.06-dev (Dalmatian Bellflower)
--- DB_UPDATE_VERSION 1310
+-- DB_UPDATE_VERSION 1311
 -- ------------------------------------------
 
 
@@ -40,6 +40,7 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
        `alias` varchar(255) COMMENT '',
        `pubkey` text COMMENT '',
        `baseurl` varchar(255) COMMENT 'baseurl of the ap contact',
+       `generator` varchar(255) COMMENT 'Name of the contact\'s system',
        `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
         PRIMARY KEY(`url`),
         INDEX `addr` (`addr`(32)),
@@ -143,7 +144,8 @@ CREATE TABLE IF NOT EXISTS `contact` (
        `remote_self` boolean NOT NULL DEFAULT '0' COMMENT '',
        `rel` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'The kind of the relation between the user and the contact',
        `duplex` boolean NOT NULL DEFAULT '0' COMMENT '',
-       `network` char(4) NOT NULL DEFAULT '' COMMENT 'Network protocol of the contact',
+       `network` char(4) NOT NULL DEFAULT '' COMMENT 'Network of the contact',
+       `protocol` char(4) NOT NULL DEFAULT '' COMMENT 'Protocol of the contact',
        `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name that this contact is known by',
        `nick` varchar(255) NOT NULL DEFAULT '' COMMENT 'Nick- and user name of the contact',
        `location` varchar(255) DEFAULT '' COMMENT '',
diff --git a/images/friendica-404_svg_flexy-o-hare.png b/images/friendica-404_svg_flexy-o-hare.png
new file mode 100644 (file)
index 0000000..36d6b5c
Binary files /dev/null and b/images/friendica-404_svg_flexy-o-hare.png differ
diff --git a/images/friendica-404_svg_hare-bottom-light-inside.png b/images/friendica-404_svg_hare-bottom-light-inside.png
new file mode 100644 (file)
index 0000000..6c9189e
Binary files /dev/null and b/images/friendica-404_svg_hare-bottom-light-inside.png differ
index 97d19f1..fe7323a 100644 (file)
@@ -24,7 +24,6 @@ use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Core\System;
 use Friendica\Database\DBA;
-use Friendica\Model\APContact;
 use Friendica\Model\Contact;
 use Friendica\Model\Group;
 use Friendica\Model\User;
@@ -138,21 +137,16 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                $dfrn_confirm = $contact['confirm'];
                $aes_allow    = $contact['aes_allow'];
 
-               $network = ((strlen($contact['issued-id'])) ? Protocol::DFRN : Protocol::OSTATUS);
-
-               if ($contact['network']) {
-                       $network = $contact['network'];
-               }
-
                // an empty DFRN-ID tells us that it had been a request via AP from a Friendica contact
-               if (($network === Protocol::DFRN) && empty($dfrn_id) && !empty($contact['hub-verify'])) {
-                       $apcontact = APContact::getByURL($contact['url']);
-                       if (!empty($apcontact)) {
-                               $network = Protocol::ACTIVITYPUB;
-                       }
+               if (!empty($contact['protocol'])) {
+                       $protocol = $contact['protocol'];
+               } elseif (($contact['network'] === Protocol::DFRN) && empty($dfrn_id)) {
+                       $protocol = Contact::getProtocol($contact['url'], $contact['network']);
+               } else {
+                       $protocol = $contact['network'];
                }
 
-               if ($network === Protocol::DFRN) {
+               if ($protocol === Protocol::DFRN) {
                        /*
                         * Generate a key pair for all further communications with this person.
                         * We have a keypair for every contact, and a site key for unknown people.
@@ -166,11 +160,8 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                        $public_key  = $res['pubkey'];
 
                        // Save the private key. Send them the public key.
-                       q("UPDATE `contact` SET `prvkey` = '%s' WHERE `id` = %d AND `uid` = %d",
-                               DBA::escape($private_key),
-                               intval($contact_id),
-                               intval($uid)
-                       );
+                       $fields = ['prvkey' => $private_key, 'protocol' => Protocol::DFRN];
+                       DBA::update('contact', $fields, ['id' => $contact_id]);
 
                        $params = [];
 
@@ -302,6 +293,8 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                        if ($status != 0) {
                                return;
                        }
+               } else {
+                       DBA::update('contact', ['protocol' => $protocol], ['id' => $contact_id]);
                }
 
                /*
@@ -315,7 +308,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
 
                Logger::log('dfrn_confirm: confirm - imported photos');
 
-               if ($network === Protocol::DFRN) {
+               if ($protocol === Protocol::DFRN) {
                        $new_relation = Contact::FOLLOWER;
 
                        if (($relation == Contact::SHARING) || ($duplex)) {
@@ -344,7 +337,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                                intval($contact_id)
                        );
                } else {
-                       if ($network == Protocol::ACTIVITYPUB) {
+                       if ($protocol == Protocol::ACTIVITYPUB) {
                                ActivityPub\Transmitter::sendContactAccept($contact['url'], $contact['hub-verify'], $uid);
                                // Setting "pending" to true on a bidirectional contact request could create a problem when it isn't accepted on the other side
                                // Then we have got a situation where - although one direction is accepted - the contact still appears as pending.
@@ -356,10 +349,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                                $pending = false;
                        }
 
-                       // $network !== Protocol::DFRN
-                       $network = defaults($contact, 'network', Protocol::OSTATUS);
-
-                       $arr = Probe::uri($contact['url'], $network);
+                       $arr = Probe::uri($contact['url'], $protocol);
 
                        $notify  = defaults($contact, 'notify' , $arr['notify']);
                        $poll    = defaults($contact, 'poll'   , $arr['poll']);
@@ -369,7 +359,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                        $new_relation = $contact['rel'];
                        $writable = $contact['writable'];
 
-                       if (in_array($network, [Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
+                       if (in_array($protocol, [Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
                                if ($duplex) {
                                        $new_relation = Contact::FRIEND;
                                } else {
@@ -386,7 +376,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
                        $fields = ['name-date' => DateTimeFormat::utcNow(),
                                'uri-date' => DateTimeFormat::utcNow(), 'addr' => $addr,
                                'notify' => $notify, 'poll' => $poll, 'blocked' => false,
-                               'pending' => $pending, 'network' => $network,
+                               'pending' => $pending, 'protocol' => $protocol,
                                'writable' => $writable, 'hidden' => $hidden, 'rel' => $new_relation];
                        DBA::update('contact', $fields, ['id' => $contact_id]);
                }
@@ -397,7 +387,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
 
                // reload contact info
                $contact = DBA::selectFirst('contact', [], ['id' => $contact_id]);
-               if ((isset($new_relation) && $new_relation == Contact::FRIEND)) {
+               if (isset($new_relation) && ($new_relation == Contact::FRIEND)) {
                        if (DBA::isResult($contact) && ($contact['network'] === Protocol::DIASPORA)) {
                                $ret = Diaspora::sendShare($user, $contact);
                                Logger::log('share returns: ' . $ret);
@@ -406,7 +396,7 @@ function dfrn_confirm_post(App $a, $handsfree = null)
 
                Group::addMember(User::getDefaultGroup($uid, $contact["network"]), $contact['id']);
 
-               if ($network == Protocol::ACTIVITYPUB && $duplex) {
+               if (($protocol == Protocol::ACTIVITYPUB) && $duplex) {
                        ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $uid);
                }
 
diff --git a/mod/filerm.php b/mod/filerm.php
deleted file mode 100644 (file)
index 9013dd6..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\Logger;
-use Friendica\Model\FileTag;
-use Friendica\Util\XML;
-
-function filerm_content(App $a)
-{
-       if (! local_user())
-       {
-               exit();
-       }
-
-       $term = XML::unescape(trim(defaults($_GET, 'term', '')));
-       $cat = XML::unescape(trim(defaults($_GET, 'cat', '')));
-
-       $category = (($cat) ? true : false);
-
-       if ($category)
-       {
-               $term = $cat;
-       }
-
-       $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
-
-       Logger::log('filerm: tag ' . $term . ' item ' . $item_id  . ' category ' . ($category ? 'true' :  'false'));
-
-       if ($item_id && strlen($term)) {
-               if (FileTag::unsaveFile(local_user(), $item_id, $term, $category)) {
-                       info('Item removed');
-               }
-       }
-       else {
-               info('Item was not deleted');
-       }
-
-       $a->internalRedirect('/network?f=&file=' . rawurlencode($term));
-       exit();
-}
index e0b6e17..8a00e05 100644 (file)
@@ -91,32 +91,34 @@ function follow_content(App $a)
 
        $ret = Probe::uri($url);
 
-       if (($ret['network'] == Protocol::DIASPORA) && !Config::get('system', 'diaspora_enabled')) {
+       $protocol = Contact::getProtocol($ret['url'], $ret['network']);
+
+       if (($protocol == Protocol::DIASPORA) && !Config::get('system', 'diaspora_enabled')) {
                notice(L10n::t("Diaspora support isn't enabled. Contact can't be added."));
                $submit = '';
                //$a->internalRedirect($_SESSION['return_path']);
                // NOTREACHED
        }
 
-       if (($ret['network'] == Protocol::OSTATUS) && Config::get('system', 'ostatus_disabled')) {
+       if (($protocol == Protocol::OSTATUS) && Config::get('system', 'ostatus_disabled')) {
                notice(L10n::t("OStatus support is disabled. Contact can't be added."));
                $submit = '';
                //$a->internalRedirect($_SESSION['return_path']);
                // NOTREACHED
        }
 
-       if ($ret['network'] == Protocol::PHANTOM) {
+       if ($protocol == Protocol::PHANTOM) {
                notice(L10n::t("The network type couldn't be detected. Contact can't be added."));
                $submit = '';
                //$a->internalRedirect($_SESSION['return_path']);
                // NOTREACHED
        }
 
-       if ($ret['network'] == Protocol::MAIL) {
+       if ($protocol == Protocol::MAIL) {
                $ret['url'] = $ret['addr'];
        }
 
-       if (($ret['network'] === Protocol::DFRN) && !DBA::isResult($r)) {
+       if (($protocol === Protocol::DFRN) && !DBA::isResult($r)) {
                $request = $ret['request'];
                $tpl = Renderer::getMarkupTemplate('dfrn_request.tpl');
        } else {
@@ -147,7 +149,7 @@ function follow_content(App $a)
                $gcontact_id = $r[0]['id'];
        }
 
-       if ($ret['network'] === Protocol::DIASPORA) {
+       if ($protocol === Protocol::DIASPORA) {
                $r[0]['location'] = '';
                $r[0]['about'] = '';
        }
diff --git a/mod/friendica.php b/mod/friendica.php
deleted file mode 100644 (file)
index 4942e4c..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-/**
- * @file mod/friendica.php
- */
-
-use Friendica\App;
-use Friendica\Core\Addon;
-use Friendica\Core\Config;
-use Friendica\Core\Hook;
-use Friendica\Core\L10n;
-use Friendica\Core\System;
-use Friendica\Database\DBA;
-use Friendica\Module\Register;
-
-function friendica_init(App $a)
-{
-       if (!empty($a->argv[1]) && ($a->argv[1] == "json")) {
-               $register_policies = [
-                       Register::CLOSED  => 'REGISTER_CLOSED',
-                       Register::APPROVE => 'REGISTER_APPROVE',
-                       Register::OPEN    => 'REGISTER_OPEN'
-               ];
-
-               $register_policy_int = intval(Config::get('config', 'register_policy'));
-               if ($register_policy_int !== Register::CLOSED && Config::get('config', 'invitation_only')) {
-                       $register_policy = 'REGISTER_INVITATION';
-               } else {
-                       $register_policy = $register_policies[$register_policy_int];
-               }
-
-               $condition = [];
-               $admin = false;
-               if (!empty(Config::get('config', 'admin_nickname'))) {
-                       $condition['nickname'] = Config::get('config', 'admin_nickname');
-               }
-               if (!empty(Config::get('config', 'admin_email'))) {
-                       $adminlist = explode(",", str_replace(" ", "", Config::get('config', 'admin_email')));
-                       $condition['email'] = $adminlist[0];
-                       $administrator = DBA::selectFirst('user', ['username', 'nickname'], $condition);
-                       if (DBA::isResult($administrator)) {
-                               $admin = [
-                                       'name' => $administrator['username'],
-                                       'profile'=> System::baseUrl() . '/profile/' . $administrator['nickname'],
-                               ];
-                       }
-               }
-
-               $visible_addons = Addon::getVisibleList();
-
-               Config::load('feature_lock');
-               $locked_features = [];
-               $featureLock = Config::get('config', 'feature_lock');
-               if (isset($featureLock)) {
-                       foreach ($featureLock as $k => $v) {
-                               if ($k === 'config_loaded') {
-                                       continue;
-                               }
-
-                               $locked_features[$k] = intval($v);
-                       }
-               }
-
-               $data = [
-                       'version'          => FRIENDICA_VERSION,
-                       'url'              => System::baseUrl(),
-                       'addons'           => $visible_addons,
-                       'locked_features'  => $locked_features,
-                       'explicit_content' => (int)Config::get('system', 'explicit_content', false),
-                       'language'         => Config::get('system','language'),
-                       'register_policy'  => $register_policy,
-                       'admin'            => $admin,
-                       'site_name'        => Config::get('config', 'sitename'),
-                       'platform'         => FRIENDICA_PLATFORM,
-                       'info'             => Config::get('config', 'info'),
-                       'no_scrape_url'    => System::baseUrl().'/noscrape'
-               ];
-
-               header('Content-type: application/json; charset=utf-8');
-               echo json_encode($data);
-               exit();
-       }
-}
-
-function friendica_content(App $a)
-{
-       $o = '<h1>Friendica</h1>' . PHP_EOL;
-       $o .= '<p>';
-       $o .= L10n::t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.',
-               '<strong>' . FRIENDICA_VERSION . '</strong>', System::baseUrl(), '<strong>' . DB_UPDATE_VERSION . '</strong>',
-               '<strong>' . Config::get("system", "post_update_version") . '</strong>');
-       $o .= '</p>' . PHP_EOL;
-
-       $o .= '<p>';
-       $o .= L10n::t('Please visit <a href="https://friendi.ca">Friendi.ca</a> to learn more about the Friendica project.') . PHP_EOL;
-       $o .= '</p>' . PHP_EOL;
-
-       $o .= '<p>';
-       $o .= L10n::t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">'.L10n::t('the bugtracker at github').'</a>';
-       $o .= '</p>' . PHP_EOL;
-       $o .= '<p>';
-       $o .= L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca');
-       $o .= '</p>' . PHP_EOL;
-
-       $visible_addons = Addon::getVisibleList();
-       if (count($visible_addons)) {
-               $o .= '<p>' . L10n::t('Installed addons/apps:') . '</p>' . PHP_EOL;
-               $sorted = $visible_addons;
-               $s = '';
-               sort($sorted);
-               foreach ($sorted as $p) {
-                       if (strlen($p)) {
-                               if (strlen($s)) {
-                                       $s .= ', ';
-                               }
-                               $s .= $p;
-                       }
-               }
-               $o .= '<div style="margin-left: 25px; margin-right: 25px; margin-bottom: 25px;">' . $s . '</div>' . PHP_EOL;
-       } else {
-               $o .= '<p>' . L10n::t('No installed addons/apps') . '</p>' . PHP_EOL;
-       }
-
-       if (Config::get('system', 'tosdisplay'))
-       {
-               $o .= '<p>'.L10n::t('Read about the <a href="%1$s/tos">Terms of Service</a> of this node.', System::baseurl()).'</p>';
-       }
-
-       $blocklist = Config::get('system', 'blocklist', []);
-       if (!empty($blocklist)) {
-               $o .= '<div id="about_blocklist"><p>' . L10n::t('On this server the following remote servers are blocked.') . '</p>' . PHP_EOL;
-               $o .= '<table class="table"><thead><tr><th>' . L10n::t('Blocked domain') . '</th><th>' . L10n::t('Reason for the block') . '</th></thead><tbody>' . PHP_EOL;
-               foreach ($blocklist as $b) {
-                       $o .= '<tr><td>' . $b['domain'] .'</td><td>' . $b['reason'] . '</td></tr>' . PHP_EOL;
-               }
-               $o .= '</tbody></table></div>' . PHP_EOL;
-       }
-
-       Hook::callAll('about_hook', $o);
-
-       return $o;
-}
diff --git a/mod/maintenance.php b/mod/maintenance.php
deleted file mode 100644 (file)
index 8e0197b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-/**
- * @file mod/maintenance.php
- */
-use Friendica\App;
-use Friendica\Core\Config;
-use Friendica\Core\L10n;
-use Friendica\Core\Renderer;
-use Friendica\Util\Strings;
-
-function maintenance_content(App $a)
-{
-       $reason = Config::get('system', 'maintenance_reason');
-
-       if (substr(Strings::normaliseLink($reason), 0, 7) == 'http://') {
-               header("HTTP/1.1 307 Temporary Redirect");
-               header("Location:".$reason);
-               return;
-       }
-
-       header('HTTP/1.1 503 Service Temporarily Unavailable');
-       header('Status: 503 Service Temporarily Unavailable');
-       header('Retry-After: 600');
-
-       return Renderer::replaceMacros(Renderer::getMarkupTemplate('maintenance.tpl'), [
-               '$sysdown' => L10n::t('System down for maintenance'),
-               '$reason' => $reason
-       ]);
-}
diff --git a/mod/modexp.php b/mod/modexp.php
deleted file mode 100644 (file)
index cae91c4..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Database\DBA;
-
-function modexp_init(App $a) {
-
-       if($a->argc != 2)
-               exit();
-
-       $nick = $a->argv[1];
-       $r = q("SELECT `spubkey` FROM `user` WHERE `nickname` = '%s' LIMIT 1",
-                       DBA::escape($nick)
-       );
-
-       if (! DBA::isResult($r)) {
-               exit();
-       }
-
-       $lines = explode("\n",$r[0]['spubkey']);
-       unset($lines[0]);
-       unset($lines[count($lines)]);
-       $x = base64_decode(implode('',$lines));
-
-       $r = ASN_BASE::parseASNString($x);
-
-       $m = $r[0]->asnData[1]->asnData[0]->asnData[0]->asnData;
-       $e = $r[0]->asnData[1]->asnData[0]->asnData[1]->asnData;
-
-       header("Content-type: application/magic-public-key");
-       echo 'RSA' . '.' . $m . '.' . $e;
-
-       exit();
-
-}
-
diff --git a/mod/pretheme.php b/mod/pretheme.php
deleted file mode 100644 (file)
index 14d1f2b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\Theme;
-
-function pretheme_init(App $a) {
-
-       if ($_REQUEST['theme']) {
-               $theme = $_REQUEST['theme'];
-               $info = Theme::getInfo($theme);
-               if ($info) {
-                       // unfortunately there will be no translation for this string
-                       $desc = $info['description'];
-                       $version = $info['version'];
-                       $credits = $info['credits'];
-               } else {
-                       $desc = '';
-                       $version = '';
-                       $credits = '';
-               }
-               echo json_encode(['img' => Theme::getScreenshot($theme), 'desc' => $desc, 'version' => $version, 'credits' => $credits]);
-       }
-
-       exit();
-}
diff --git a/mod/robots_txt.php b/mod/robots_txt.php
deleted file mode 100644 (file)
index 0575742..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-/**
- * @file mod/robots_text.php
- * @brief Module which returns the default robots.txt
- * @version 0.1.2
- */
-
-use Friendica\App;
-
-/**
- * @brief Return default robots.txt when init
- * @param App $a
- * @return void
- */
-function robots_txt_init(App $a)
-{
-       $allDisalloweds = [
-               '/settings/',
-               '/admin/',
-               '/message/',
-       ];
-
-       header('Content-Type: text/plain');
-       echo 'User-agent: *' . PHP_EOL;
-       foreach ($allDisalloweds as $disallowed) {
-               echo 'Disallow: ' . $disallowed . PHP_EOL;
-       }
-       exit();
-}
diff --git a/mod/viewsrc.php b/mod/viewsrc.php
deleted file mode 100644 (file)
index 55eb0b9..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * @file mod/viewsrc.php
- */
-use Friendica\App;
-use Friendica\Core\L10n;
-use Friendica\Database\DBA;
-use Friendica\Model\Item;
-
-function viewsrc_content(App $a)
-{
-       if (!local_user()) {
-               notice(L10n::t('Access denied.') . EOL);
-               return;
-       }
-
-       $o = '';
-       $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
-
-       if (!$item_id) {
-               throw new \Friendica\Network\HTTPException\NotFoundException(L10n::t('Item not found.'));
-       }
-
-       $item = Item::selectFirst(['body'], ['uid' => local_user(), 'id' => $item_id]);
-
-       if (DBA::isResult($item)) {
-               if ($a->isAjax()) {
-                       echo str_replace("\n", '<br />', $item['body']);
-                       exit();
-               } else {
-                       $o .= str_replace("\n", '<br />', $item['body']);
-               }
-       }
-       return $o;
-}
index 017661c..0f0c053 100644 (file)
@@ -988,7 +988,7 @@ class App
                        header('Refresh: 120; url=' . $this->getBaseURL() . "/" . $this->query_string);
 
                        Module\Special\HTTPException::rawContent(
-                               new HTTPException\ServiceUnavaiableException('The node is currently overloaded. Please try again later.')
+                               new HTTPException\ServiceUnavailableException('The node is currently overloaded. Please try again later.')
                        );
                }
 
@@ -1077,10 +1077,10 @@ class App
 
                // in install mode, any url loads install module
                // but we need "view" module for stylesheet
-               if ($this->getMode()->isInstall() && $this->module != 'view') {
-                       $this->module = 'install';
-               } elseif (!$this->getMode()->has(App\Mode::MAINTENANCEDISABLED) && $this->module != 'view') {
-                       $this->module = 'maintenance';
+               if ($this->getMode()->isInstall() && $this->module !== 'install') {
+                       $this->internalRedirect('install');
+               } elseif (!$this->getMode()->has(App\Mode::MAINTENANCEDISABLED) && $this->module !== 'maintenance') {
+                       $this->internalRedirect('maintenance');
                } else {
                        $this->checkURL();
                        Core\Update::check($this->getBasePath(), false, $this->getMode());
index 3037566..fc9bbdf 100644 (file)
@@ -89,12 +89,13 @@ class Router
                $this->routeCollector->addRoute(['GET'],         '/apps',                Module\Apps::class);
                $this->routeCollector->addRoute(['GET'],         '/attach/{item:\d+}',   Module\Attach::class);
                $this->routeCollector->addRoute(['GET'],         '/babel',               Module\Babel::class);
-               $this->routeCollector->addRoute(['GET'],         '/bookmarklet',         Module\BookMarklet::class);
+               $this->routeCollector->addRoute(['GET'],         '/bookmarklet',         Module\Bookmarklet::class);
                $this->routeCollector->addGroup('/contact', function (RouteCollector $collector) {
                        $collector->addRoute(['GET'], '[/]',                                 Module\Contact::class);
                        $collector->addRoute(['GET'], '/{id:\d+}[/posts|conversations]',     Module\Contact::class);
                });
                $this->routeCollector->addRoute(['GET'],         '/credits',             Module\Credits::class);
+               $this->routeCollector->addRoute(['GET'],         '/directory',           Module\Directory::class);
                $this->routeCollector->addGroup('/feed', function (RouteCollector $collector) {
                        $collector->addRoute(['GET'], '/{nickname}',                         Module\Feed::class);
                        $collector->addRoute(['GET'], '/{nickname}/posts',                   Module\Feed::class);
@@ -102,16 +103,17 @@ class Router
                        $collector->addRoute(['GET'], '/{nickname}/replies',                 Module\Feed::class);
                        $collector->addRoute(['GET'], '/{nickname}/activity',                Module\Feed::class);
                });
-               $this->routeCollector->addRoute(['GET'],         '/directory',           Module\Directory::class);
                $this->routeCollector->addRoute(['GET'],         '/feedtest',            Module\Feedtest::class);
                $this->routeCollector->addGroup('/fetch', function (RouteCollector $collector) {
                        $collector->addRoute(['GET'], '/{guid}/post',                        Module\Diaspora\Fetch::class);
                        $collector->addRoute(['GET'], '/{guid}/status_message',              Module\Diaspora\Fetch::class);
                        $collector->addRoute(['GET'], '/{guid}/reshare',                     Module\Diaspora\Fetch::class);
                });
-               $this->routeCollector->addRoute(['GET'],         '/filer[/{id:\d+}]',    Module\Filer::class);
+               $this->routeCollector->addRoute(['GET'],         '/filer[/{id:\d+}]',    Module\Filer\SaveTag::class);
+               $this->routeCollector->addRoute(['GET'],         '/filerm/{id:\d+}',     Module\Filer\RemoveTag::class);
                $this->routeCollector->addRoute(['GET'],         '/followers/{owner}',   Module\Followers::class);
                $this->routeCollector->addRoute(['GET'],         '/following/{owner}',   Module\Following::class);
+               $this->routeCollector->addRoute(['GET'],         '/friendica[/json]',    Module\Friendica::class);
                $this->routeCollector->addGroup('/group', function (RouteCollector $collector) {
                        $collector->addRoute(['GET', 'POST'], '[/]',                         Module\Group::class);
                        $collector->addRoute(['GET', 'POST'], '/{group:\d+}',                Module\Group::class);
@@ -138,7 +140,9 @@ class Router
                $this->routeCollector->addRoute(['GET', 'POST'], '/login',               Module\Login::class);
                $this->routeCollector->addRoute(['GET', 'POST'], '/logout',              Module\Logout::class);
                $this->routeCollector->addRoute(['GET'],         '/magic',               Module\Magic::class);
+               $this->routeCollector->addRoute(['GET'],         '/maintenance',         Module\Maintenance::class);
                $this->routeCollector->addRoute(['GET'],         '/manifest',            Module\Manifest::class);
+               $this->routeCollector->addRoute(['GET'],         '/modexp/{nick}',       Module\PublicRSAKey::class);
                $this->routeCollector->addRoute(['GET'],         '/nodeinfo/1.0',        Module\NodeInfo::class);
                $this->routeCollector->addRoute(['GET'],         '/nogroup',             Module\Group::class);
                $this->routeCollector->addRoute(['GET'],         '/objects/{guid}',      Module\Objects::class);
@@ -153,6 +157,7 @@ class Router
                        $collector->addRoute(['GET'], '/{type}/{name}',                      Module\Photo::class);
                        $collector->addRoute(['GET'], '/{type}/{customize}/{name}',          Module\Photo::class);
                });
+               $this->routeCollector->addRoute(['GET'],         '/pretheme',            Module\ThemeDetails::class);
                $this->routeCollector->addGroup('/profile', function (RouteCollector $collector) {
                        $collector->addRoute(['GET'], '/{nickname}',                         Module\Profile::class);
                        $collector->addRoute(['GET'], '/{profile:\d+}/view',                 Module\Profile::class);
@@ -164,10 +169,12 @@ class Router
                        $collector->addRoute(['GET'], '/{sub1}/{sub2}/{url}'               , Module\Proxy::class);
                });
                $this->routeCollector->addRoute(['GET', 'POST'], '/register',            Module\Register::class);
+               $this->routeCollector->addRoute(['GET'],         '/robots.txt',          Module\RobotsTxt::class);
                $this->routeCollector->addRoute(['GET'],         '/rsd.xml',             Module\ReallySimpleDiscovery::class);
                $this->routeCollector->addRoute(['GET'],         '/smilies[/json]',      Module\Smilies::class);
                $this->routeCollector->addRoute(['GET'],         '/statistics.json',     Module\Statistics::class);
                $this->routeCollector->addRoute(['GET'],         '/tos',                 Module\Tos::class);
+               $this->routeCollector->addRoute(['GET'],         '/viewsrc/{item:\d+}',  Module\ItemBody::class);
                $this->routeCollector->addRoute(['GET'],         '/webfinger',           Module\WebFinger::class);
                $this->routeCollector->addRoute(['GET'],         '/xrd',                 Module\Xrd::class);
        }
index 31934af..4258757 100644 (file)
@@ -242,6 +242,9 @@ class System extends BaseObject
                        case 301:
                                header('HTTP/1.1 301 Moved Permanently');
                                break;
+                       case 307:
+                               header('HTTP/1.1 307 Temporary Redirect');
+                               break;
                }
 
                header("Location: $url");
index 3a356d1..a52ef90 100644 (file)
@@ -305,6 +305,7 @@ class Update
                                                'uid' => $admin['uid'],
                                                'type' => SYSTEM_EMAIL,
                                                'to_email' => $admin['email'],
+                                               'subject'  => l10n::t('[Friendica Notify] Database update'),
                                                'preamble' => $preamble,
                                                'body' => $preamble,
                                                'language' => $lang]
index 47bbe7d..cf1f9b7 100644 (file)
@@ -167,10 +167,15 @@ class APContact extends BaseObject
 
                $apcontact['manually-approve'] = (int)JsonLD::fetchElement($compacted, 'as:manuallyApprovesFollowers');
 
+               if (!empty($compacted['as:generator'])) {
+                       $apcontact['baseurl'] = JsonLD::fetchElement($compacted['as:generator'], 'as:url', '@id');
+                       $apcontact['generator'] = JsonLD::fetchElement($compacted['as:generator'], 'as:name', '@value');
+               }
+
                // To-Do
 
                // Unhandled
-               // @context, tag, attachment, image, nomadicLocations, signature, following, followers, featured, movedTo, liked
+               // tag, attachment, image, nomadicLocations, signature, featured, movedTo, liked
 
                // Unhandled from Misskey
                // sharedInbox, isCat
@@ -185,6 +190,9 @@ class APContact extends BaseObject
                        $apcontact['baseurl'] = Network::unparseURL($parts);
                } else {
                        $apcontact['addr'] = null;
+               }
+
+               if (empty($apcontact['baseurl'])) {
                        $apcontact['baseurl'] = null;
                }
 
index f4c62fe..a0e746f 100644 (file)
@@ -689,9 +689,15 @@ class Contact extends BaseObject
                if (empty($contact['network'])) {
                        return;
                }
-               if (($contact['network'] == Protocol::DFRN) && $dissolve) {
+
+               $protocol = $contact['network'];
+               if (($protocol == Protocol::DFRN) && !self::isLegacyDFRNContact($contact)) {
+                       $protocol = Protocol::ACTIVITYPUB;
+               }
+
+               if (($protocol == Protocol::DFRN) && $dissolve) {
                        DFRN::deliver($user, $contact, 'placeholder', true);
-               } elseif (in_array($contact['network'], [Protocol::OSTATUS, Protocol::DFRN])) {
+               } elseif (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) {
                        // create an unfollow slap
                        $item = [];
                        $item['verb'] = NAMESPACE_OSTATUS . "/unfollow";
@@ -706,9 +712,9 @@ class Contact extends BaseObject
                        if (!empty($contact['notify'])) {
                                Salmon::slapper($user, $contact['notify'], $slap);
                        }
-               } elseif ($contact['network'] == Protocol::DIASPORA) {
+               } elseif ($protocol == Protocol::DIASPORA) {
                        Diaspora::sendUnshare($user, $contact);
-               } elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
+               } elseif ($protocol == Protocol::ACTIVITYPUB) {
                        ActivityPub\Transmitter::sendContactUndo($contact['url'], $contact['id'], $user['uid']);
 
                        if ($dissolve) {
@@ -1168,7 +1174,7 @@ class Contact extends BaseObject
                // The link could be provided as http although we stored it as https
                $ssl_url = str_replace('http://', 'https://', $url);
 
-               $fields = ['url', 'addr', 'alias', 'notify', 'poll', 'name', 'nick',
+               $fields = ['id', 'uid', 'url', 'addr', 'alias', 'notify', 'poll', 'name', 'nick',
                        'photo', 'keywords', 'location', 'about', 'network',
                        'priority', 'batch', 'request', 'confirm', 'poco'];
 
@@ -1804,6 +1810,40 @@ class Contact extends BaseObject
                return true;
        }
 
+       /**
+        * Detects if a given contact array belongs to a legacy DFRN connection
+        *
+        * @param array $contact
+        * @return boolean
+        */
+       public static function isLegacyDFRNContact($contact)
+       {
+               // Newer Friendica contacts are connected via AP, then these fields aren't set
+               return !empty($contact['dfrn-id']) || !empty($contact['issued-id']);
+       }
+
+       /**
+        * Detects the communication protocol for a given contact url.
+        * This is used to detect Friendica contacts that we can communicate via AP.
+        *
+        * @param string $url contact url
+        * @param string $network Network of that contact
+        * @return string with protocol
+        */
+       public static function getProtocol($url, $network)
+       {
+               if ($network != Protocol::DFRN) {
+                       return $network;
+               }
+
+               $apcontact = APContact::getByURL($url);
+               if (!empty($apcontact) && !empty($apcontact['generator'])) {
+                       return Protocol::ACTIVITYPUB;
+               } else {
+                       return $network;
+               }
+       }
+
        /**
         * Takes a $uid and a url/handle and adds a new contact
         * Currently if the contact is DFRN, interactive needs to be true, to redirect to the
@@ -1879,7 +1919,9 @@ class Contact extends BaseObject
                        $contact = DBA::selectFirst('contact', ['id', 'rel'], $condition);
                }
 
-               if (($ret['network'] === Protocol::DFRN) && !DBA::isResult($contact)) {
+               $protocol = self::getProtocol($url, $ret['network']);
+
+               if (($protocol === Protocol::DFRN) && !DBA::isResult($contact)) {
                        if ($interactive) {
                                if (strlen($a->getURLPath())) {
                                        $myaddr = bin2hex(System::baseUrl() . '/profile/' . $a->user['nickname']);
@@ -1898,7 +1940,7 @@ class Contact extends BaseObject
                }
 
                // This extra param just confuses things, remove it
-               if ($ret['network'] === Protocol::DIASPORA) {
+               if ($protocol === Protocol::DIASPORA) {
                        $ret['url'] = str_replace('?absolute=true', '', $ret['url']);
                }
 
@@ -1921,7 +1963,7 @@ class Contact extends BaseObject
                        return $result;
                }
 
-               if ($ret['network'] === Protocol::OSTATUS && Config::get('system', 'ostatus_disabled')) {
+               if ($protocol === Protocol::OSTATUS && Config::get('system', 'ostatus_disabled')) {
                        $result['message'] .= L10n::t('The profile address specified belongs to a network which has been disabled on this site.') . EOL;
                        $ret['notify'] = '';
                }
@@ -1930,15 +1972,15 @@ class Contact extends BaseObject
                        $result['message'] .= L10n::t('Limited profile. This person will be unable to receive direct/personal notifications from you.') . EOL;
                }
 
-               $writeable = ((($ret['network'] === Protocol::OSTATUS) && ($ret['notify'])) ? 1 : 0);
+               $writeable = ((($protocol === Protocol::OSTATUS) && ($ret['notify'])) ? 1 : 0);
 
-               $subhub = (($ret['network'] === Protocol::OSTATUS) ? true : false);
+               $subhub = (($protocol === Protocol::OSTATUS) ? true : false);
 
-               $hidden = (($ret['network'] === Protocol::MAIL) ? 1 : 0);
+               $hidden = (($protocol === Protocol::MAIL) ? 1 : 0);
 
-               $pending = in_array($ret['network'], [Protocol::ACTIVITYPUB]);
+               $pending = in_array($protocol, [Protocol::ACTIVITYPUB]);
 
-               if (in_array($ret['network'], [Protocol::MAIL, Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
+               if (in_array($protocol, [Protocol::MAIL, Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
                        $writeable = 1;
                }
 
@@ -1949,7 +1991,7 @@ class Contact extends BaseObject
                        $fields = ['rel' => $new_relation, 'subhub' => $subhub, 'readonly' => false];
                        DBA::update('contact', $fields, ['id' => $contact['id']]);
                } else {
-                       $new_relation = (in_array($ret['network'], [Protocol::MAIL]) ? self::FRIEND : self::SHARING);
+                       $new_relation = (in_array($protocol, [Protocol::MAIL]) ? self::FRIEND : self::SHARING);
 
                        // create contact record
                        DBA::insert('contact', [
@@ -1966,6 +2008,7 @@ class Contact extends BaseObject
                                'name'    => $ret['name'],
                                'nick'    => $ret['nick'],
                                'network' => $ret['network'],
+                               'protocol' => $protocol,
                                'pubkey'  => $ret['pubkey'],
                                'rel'     => $new_relation,
                                'priority'=> $ret['priority'],
@@ -1999,7 +2042,7 @@ class Contact extends BaseObject
                $owner = User::getOwnerDataById($uid);
 
                if (DBA::isResult($owner)) {
-                       if (in_array($contact['network'], [Protocol::OSTATUS, Protocol::DFRN])) {
+                       if (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) {
                                // create a follow slap
                                $item = [];
                                $item['verb'] = ACTIVITY_FOLLOW;
@@ -2015,10 +2058,10 @@ class Contact extends BaseObject
                                if (!empty($contact['notify'])) {
                                        Salmon::slapper($owner, $contact['notify'], $slap);
                                }
-                       } elseif ($contact['network'] == Protocol::DIASPORA) {
+                       } elseif ($protocol == Protocol::DIASPORA) {
                                $ret = Diaspora::sendShare($a->user, $contact);
                                Logger::log('share returns: ' . $ret);
-                       } elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
+                       } elseif ($protocol == Protocol::ACTIVITYPUB) {
                                $activity_id = ActivityPub\Transmitter::activityIDFromContact($contact_id);
                                if (empty($activity_id)) {
                                        // This really should never happen
@@ -2076,7 +2119,7 @@ class Contact extends BaseObject
                return $contact;
        }
 
-       public static function addRelationship($importer, $contact, $datarray, $item = '', $sharing = false) {
+       public static function addRelationship($importer, $contact, $datarray, $item = '', $sharing = false, $note = '') {
                // Should always be set
                if (empty($datarray['author-id'])) {
                        return;
@@ -2096,18 +2139,25 @@ class Contact extends BaseObject
                $network = $pub_contact['network'];
 
                if (is_array($contact)) {
+                       // Make sure that the existing contact isn't archived
+                       self::unmarkForArchival($contact);
+
+                       $protocol = self::getProtocol($url, $contact['network']);
+
                        if (($contact['rel'] == self::SHARING)
                                || ($sharing && $contact['rel'] == self::FOLLOWER)) {
-                               DBA::update('contact', ['rel' => self::FRIEND, 'writable' => true],
+                               DBA::update('contact', ['rel' => self::FRIEND, 'writable' => true, 'pending' => false],
                                                ['id' => $contact['id'], 'uid' => $importer['uid']]);
                        }
 
-                       if ($contact['network'] == Protocol::ACTIVITYPUB) {
+                       if ($protocol == Protocol::ACTIVITYPUB) {
                                ActivityPub\Transmitter::sendContactAccept($contact['url'], $contact['hub-verify'], $importer['uid']);
                        }
 
                        // send email notification to owner?
                } else {
+                       $protocol = self::getProtocol($url, $network);
+
                        if (DBA::exists('contact', ['nurl' => Strings::normaliseLink($url), 'uid' => $importer['uid'], 'pending' => true])) {
                                Logger::log('ignoring duplicated connection request from pending contact ' . $url);
                                return;
@@ -2146,7 +2196,7 @@ class Contact extends BaseObject
 
                                if (is_array($contact_record)) {
                                        DBA::insert('intro', ['uid' => $importer['uid'], 'contact-id' => $contact_record['id'],
-                                                               'blocked' => false, 'knowyou' => false,
+                                                               'blocked' => false, 'knowyou' => false, 'note' => $note,
                                                                'hash' => $hash, 'datetime' => DateTimeFormat::utcNow()]);
                                }
 
@@ -2176,8 +2226,9 @@ class Contact extends BaseObject
                                DBA::update('contact', ['pending' => false], $condition);
 
                                $contact = DBA::selectFirst('contact', ['url', 'network', 'hub-verify'], ['id' => $contact_record['id']]);
+                               $protocol = self::getProtocol($contact['url'], $contact['network']);
 
-                               if ($contact['network'] == Protocol::ACTIVITYPUB) {
+                               if ($protocol == Protocol::ACTIVITYPUB) {
                                        ActivityPub\Transmitter::sendContactAccept($contact['url'], $contact['hub-verify'], $importer['uid']);
                                }
                        }
@@ -2322,6 +2373,10 @@ class Contact extends BaseObject
         */
        public static function magicLinkByContact($contact, $url = '')
        {
+               if (empty($contact['id']) || empty($contact['uid'])) {
+                       return $url ?: $contact['url'];
+               }
+
                if ((!local_user() && !remote_user()) || ($contact['network'] != Protocol::DFRN)) {
                        return $url ?: $contact['url']; // Equivalent to ($url != '') ? $url : $contact['url'];
                }
index 387014d..a01ff61 100644 (file)
@@ -62,7 +62,7 @@ class Item extends BaseObject
 
        // Field list that is used to deliver items via the protocols
        const DELIVER_FIELDLIST = ['uid', 'id', 'parent', 'uri', 'thr-parent', 'parent-uri', 'guid',
-                       'created', 'edited', 'verb', 'object-type', 'object', 'target',
+                       'parent-guid', 'created', 'edited', 'verb', 'object-type', 'object', 'target',
                        'private', 'title', 'body', 'location', 'coord', 'app',
                        'attach', 'tag', 'deleted', 'extid', 'post-type',
                        'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
index 9d2600b..a854b1c 100644 (file)
@@ -1249,56 +1249,96 @@ class Profile
         */
        public static function searchProfiles($start = 0, $count = 100, $search = null)
        {
-               if ($search) {
-                       $search = DBA::escape($search);
-
-                       $sql_extra = " AND ((`profile`.`name` LIKE '%$search%') OR
-                               (`user`.`nickname` LIKE '%$search%') OR
-                               (`profile`.`pdesc` LIKE '%$search%') OR
-                               (`profile`.`locality` LIKE '%$search%') OR
-                               (`profile`.`region` LIKE '%$search%') OR
-                               (`profile`.`country-name` LIKE '%$search%') OR
-                               (`profile`.`gender` LIKE '%$search%') OR
-                               (`profile`.`marital` LIKE '%$search%') OR
-                               (`profile`.`sexual` LIKE '%$search%') OR
-                               (`profile`.`about` LIKE '%$search%') OR
-                               (`profile`.`romance` LIKE '%$search%') OR
-                               (`profile`.`work` LIKE '%$search%') OR
-                               (`profile`.`education` LIKE '%$search%') OR
-                               (`profile`.`pub_keywords` LIKE '%$search%') OR
-                               (`profile`.`prv_keywords` LIKE '%$search%'))";
-               } else {
-                       $sql_extra = '';
-               }
-
                $publish = (Config::get('system', 'publish_all') ? '' : " AND `publish` = 1 ");
-
                $total = 0;
-               $cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` 
+
+               if (!empty($search)) {
+                       $searchTerm = '%' . $search . '%';
+                       $cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` 
                                FROM `profile`
                                LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
-                               WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` $sql_extra");
+                               WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`
+                               AND ((`profile`.`name` LIKE ?) OR
+                               (`user`.`nickname` LIKE ?) OR
+                               (`profile`.`pdesc` LIKE ?) OR
+                               (`profile`.`locality` LIKE ?) OR
+                               (`profile`.`region` LIKE ?) OR
+                               (`profile`.`country-name` LIKE ?) OR
+                               (`profile`.`gender` LIKE ?) OR
+                               (`profile`.`marital` LIKE ?) OR
+                               (`profile`.`sexual` LIKE ?) OR
+                               (`profile`.`about` LIKE ?) OR
+                               (`profile`.`romance` LIKE ?) OR
+                               (`profile`.`work` LIKE ?) OR
+                               (`profile`.`education` LIKE ?) OR
+                               (`profile`.`pub_keywords` LIKE ?) OR
+                               (`profile`.`prv_keywords` LIKE ?))",
+                               $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm,
+                               $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm);
+               } else {
+                       $cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` 
+                               FROM `profile`
+                               LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
+                               WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`");
+               }
+
                if (DBA::isResult($cnt)) {
                        $total = $cnt['total'];
                }
 
                $order = " ORDER BY `name` ASC ";
-               $limit = $start . ',' . $count;
+               $profiles = [];
+
+               // If nothing found, don't try to select details
+               if ($total > 0) {
+                       if (!empty($search)) {
+                               $searchTerm = '%' . $search . '%';
 
-               $profiles = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`,
+                               $profiles = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`,
                        `contact`.`addr`, `contact`.`url` AS `profile_url`
                        FROM `profile`
                        LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
                        LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
                        WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
-                       $sql_extra $order LIMIT $limit"
-               );
+                       AND ((`profile`.`name` LIKE ?) OR
+                               (`user`.`nickname` LIKE ?) OR
+                               (`profile`.`pdesc` LIKE ?) OR
+                               (`profile`.`locality` LIKE ?) OR
+                               (`profile`.`region` LIKE ?) OR
+                               (`profile`.`country-name` LIKE ?) OR
+                               (`profile`.`gender` LIKE ?) OR
+                               (`profile`.`marital` LIKE ?) OR
+                               (`profile`.`sexual` LIKE ?) OR
+                               (`profile`.`about` LIKE ?) OR
+                               (`profile`.`romance` LIKE ?) OR
+                               (`profile`.`work` LIKE ?) OR
+                               (`profile`.`education` LIKE ?) OR
+                               (`profile`.`pub_keywords` LIKE ?) OR
+                               (`profile`.`prv_keywords` LIKE ?))
+                       $order LIMIT ?,?",
+                                       $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm,
+                                       $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm,
+                                       $start, $count
+                               );
+                       } else {
+                               $profiles = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`,
+                       `contact`.`addr`, `contact`.`url` AS `profile_url`
+                       FROM `profile`
+                       LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
+                       LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
+                       WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
+                       $order LIMIT ?,?",
+                                       $start, $count
+                               );
+                       }
+               }
 
-               if (DBA::isResult($profiles)) {
+               if (DBA::isResult($profiles) && $total > 0) {
                        return [
                                'total'   => $total,
                                'entries' => DBA::toArray($profiles),
                        ];
+
                } else {
                        return [
                                'total'   => $total,
index c575b44..6425394 100644 (file)
@@ -129,6 +129,21 @@ class User
                }
        }
 
+       /**
+        * Get a user based on its email
+        *
+        * @param string        $email
+        * @param array          $fields
+        *
+        * @return array|boolean User record if it exists, false otherwise
+        *
+        * @throws Exception
+        */
+       public static function getByEmail($email, array $fields = [])
+       {
+               return DBA::selectFirst('user', $fields, ['email' => $email]);
+       }
+
        /**
         * @brief Get owner data by user id
         *
diff --git a/src/Module/BookMarklet.php b/src/Module/BookMarklet.php
deleted file mode 100644 (file)
index 51feb25..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-namespace Friendica\Module;
-
-use Friendica\BaseModule;
-use Friendica\Core\ACL;
-use Friendica\Core\L10n;
-use Friendica\Network\HTTPException;
-use Friendica\Util\Strings;
-
-/**
- * Creates a bookmarklet
- * Shows either a editor browser or adds the given bookmarklet to the current user
- */
-class BookMarklet extends BaseModule
-{
-       public static function content()
-       {
-               $_GET['mode'] = 'minimal';
-
-               $app = self::getApp();
-               $config = $app->getConfig();
-
-               if (!local_user()) {
-                       $output = '<h2>' . L10n::t('Login') . '</h2>';
-                       $output .= Login::form($app->query_string, intval($config->get('config', 'register_policy')) === Register::CLOSED ? false : true);
-                       return $output;
-               }
-
-               $referer = Strings::normaliseLink(defaults($_SERVER, 'HTTP_REFERER', ''));
-               $page = Strings::normaliseLink($app->getBaseURL() . "/bookmarklet");
-
-               if (!strstr($referer, $page)) {
-                       if (empty($_REQUEST["url"])) {
-                               throw new HTTPException\BadRequestException(L10n::t('This page is missing a url parameter.'));
-                       }
-
-                       $content = add_page_info($_REQUEST["url"]);
-
-                       $x = [
-                               'is_owner'         => true,
-                               'allow_location'   => $app->user['allow_location'],
-                               'default_location' => $app->user['default-location'],
-                               'nickname'         => $app->user['nickname'],
-                               'lockstate'        => ((is_array($app->user) && ((strlen($app->user['allow_cid'])) || (strlen($a->user['allow_gid'])) || (strlen($app->user['deny_cid'])) || (strlen($app->user['deny_gid'])))) ? 'lock' : 'unlock'),
-                               'default_perms'    => ACL::getDefaultUserPermissions($app->user),
-                               'acl'              => ACL::getFullSelectorHTML($app->user, true),
-                               'bang'             => '',
-                               'visitor'          => 'block',
-                               'profile_uid'      => local_user(),
-                               'title'            => trim(defaults($_REQUEST, 'title', ''), '*'),
-                               'content'          => $content
-                       ];
-                       $output = status_editor($app, $x, 0, false);
-                       $output .= "<script>window.resizeTo(800,550);</script>";
-               } else {
-                       $output = '<h2>' . L10n::t('The post was created') . '</h2>';
-                       $output .= "<script>window.close()</script>";
-               }
-
-               return $output;
-       }
-}
diff --git a/src/Module/Bookmarklet.php b/src/Module/Bookmarklet.php
new file mode 100644 (file)
index 0000000..1b6ff38
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+use Friendica\Core\ACL;
+use Friendica\Core\L10n;
+use Friendica\Network\HTTPException;
+use Friendica\Util\Strings;
+
+/**
+ * Creates a bookmarklet
+ * Shows either a editor browser or adds the given bookmarklet to the current user
+ */
+class Bookmarklet extends BaseModule
+{
+       public static function content()
+       {
+               $_GET['mode'] = 'minimal';
+
+               $app = self::getApp();
+               $config = $app->getConfig();
+
+               if (!local_user()) {
+                       $output = '<h2>' . L10n::t('Login') . '</h2>';
+                       $output .= Login::form($app->query_string, intval($config->get('config', 'register_policy')) === Register::CLOSED ? false : true);
+                       return $output;
+               }
+
+               $referer = Strings::normaliseLink(defaults($_SERVER, 'HTTP_REFERER', ''));
+               $page = Strings::normaliseLink($app->getBaseURL() . "/bookmarklet");
+
+               if (!strstr($referer, $page)) {
+                       if (empty($_REQUEST["url"])) {
+                               throw new HTTPException\BadRequestException(L10n::t('This page is missing a url parameter.'));
+                       }
+
+                       $content = add_page_info($_REQUEST["url"]);
+
+                       $x = [
+                               'is_owner'         => true,
+                               'allow_location'   => $app->user['allow_location'],
+                               'default_location' => $app->user['default-location'],
+                               'nickname'         => $app->user['nickname'],
+                               'lockstate'        => ((is_array($app->user) && ((strlen($app->user['allow_cid'])) || (strlen($a->user['allow_gid'])) || (strlen($app->user['deny_cid'])) || (strlen($app->user['deny_gid'])))) ? 'lock' : 'unlock'),
+                               'default_perms'    => ACL::getDefaultUserPermissions($app->user),
+                               'acl'              => ACL::getFullSelectorHTML($app->user, true),
+                               'bang'             => '',
+                               'visitor'          => 'block',
+                               'profile_uid'      => local_user(),
+                               'title'            => trim(defaults($_REQUEST, 'title', ''), '*'),
+                               'content'          => $content
+                       ];
+                       $output = status_editor($app, $x, 0, false);
+                       $output .= "<script>window.resizeTo(800,550);</script>";
+               } else {
+                       $output = '<h2>' . L10n::t('The post was created') . '</h2>';
+                       $output .= "<script>window.close()</script>";
+               }
+
+               return $output;
+       }
+}
diff --git a/src/Module/Filer.php b/src/Module/Filer.php
deleted file mode 100644 (file)
index da59084..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-namespace Friendica\Module;
-
-use Friendica\BaseModule;
-use Friendica\Core\L10n;
-use Friendica\Core\PConfig;
-use Friendica\Core\Renderer;
-use Friendica\Model;
-use Friendica\Util\XML;
-
-/**
- * Shows a dialog for adding tags to a file
- */
-class Filer extends BaseModule
-{
-       public static function init()
-       {
-               if (!local_user()) {
-                       info(L10n::t('You must be logged in to use this module'));
-                       self::getApp()->internalRedirect();
-               }
-       }
-
-       public static function rawContent()
-       {
-               $a = self::getApp();
-               $logger = $a->getLogger();
-
-               $term = XML::unescape(trim(defaults($_GET, 'term', '')));
-               // @TODO: Replace with parameter from router
-               $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
-
-               $logger->info('filer', ['tag' => $term, 'item' => $item_id]);
-
-               if ($item_id && strlen($term)) {
-                       // file item
-                       Model\FileTag::saveFile(local_user(), $item_id, $term);
-                       info(L10n::t('Filetag %s saved to item', $term));
-               }
-
-               // return filer dialog
-               $filetags = PConfig::get(local_user(), 'system', 'filetags');
-               $filetags = Model\FileTag::fileToList($filetags, 'file');
-               $filetags = explode(",", $filetags);
-
-               $tpl = Renderer::getMarkupTemplate("filer_dialog.tpl");
-               echo Renderer::replaceMacros($tpl, [
-                       '$field' => ['term', L10n::t("Save to Folder:"), '', '', $filetags, L10n::t('- select -')],
-                       '$submit' => L10n::t('Save'),
-               ]);
-
-               exit;
-       }
-}
diff --git a/src/Module/Filer/RemoveTag.php b/src/Module/Filer/RemoveTag.php
new file mode 100644 (file)
index 0000000..bddaaf9
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+namespace Friendica\Module\Filer;
+
+use Friendica\BaseModule;
+use Friendica\Model\FileTag;
+use Friendica\Network\HTTPException;
+use Friendica\Util\XML;
+
+/**
+ * Remove a tag from a file
+ */
+class RemoveTag extends BaseModule
+{
+       public static function content()
+       {
+               if (!local_user()) {
+                       throw new HTTPException\ForbiddenException();
+               }
+
+               $app = self::getApp();
+               $logger = $app->getLogger();
+
+               $item_id = (($app->argc > 1) ? intval($app->argv[1]) : 0);
+
+               $term = XML::unescape(trim(defaults($_GET, 'term', '')));
+               $cat = XML::unescape(trim(defaults($_GET, 'cat', '')));
+
+               $category = (($cat) ? true : false);
+
+               if ($category) {
+                       $term = $cat;
+               }
+
+               $logger->info('Filer - Remove Tag', [
+                       'term'     => $term,
+                       'item'     => $item_id,
+                       'category' => ($category ? 'true' : 'false')
+               ]);
+
+               if ($item_id && strlen($term)) {
+                       if (FileTag::unsaveFile(local_user(), $item_id, $term, $category)) {
+                               info('Item removed');
+                       }
+               } else {
+                       info('Item was not deleted');
+               }
+
+               $app->internalRedirect('/network?f=&file=' . rawurlencode($term));
+       }
+}
diff --git a/src/Module/Filer/SaveTag.php b/src/Module/Filer/SaveTag.php
new file mode 100644 (file)
index 0000000..f5d6115
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+
+namespace Friendica\Module\Filer;
+
+use Friendica\BaseModule;
+use Friendica\Core\L10n;
+use Friendica\Core\PConfig;
+use Friendica\Core\Renderer;
+use Friendica\Model;
+use Friendica\Util\XML;
+
+/**
+ * Shows a dialog for adding tags to a file
+ */
+class SaveTag extends BaseModule
+{
+       public static function init()
+       {
+               if (!local_user()) {
+                       info(L10n::t('You must be logged in to use this module'));
+                       self::getApp()->internalRedirect();
+               }
+       }
+
+       public static function rawContent()
+       {
+               $a = self::getApp();
+               $logger = $a->getLogger();
+
+               $term = XML::unescape(trim(defaults($_GET, 'term', '')));
+               // @TODO: Replace with parameter from router
+               $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
+
+               $logger->info('filer', ['tag' => $term, 'item' => $item_id]);
+
+               if ($item_id && strlen($term)) {
+                       // file item
+                       Model\FileTag::saveFile(local_user(), $item_id, $term);
+                       info(L10n::t('Filetag %s saved to item', $term));
+               }
+
+               // return filer dialog
+               $filetags = PConfig::get(local_user(), 'system', 'filetags');
+               $filetags = Model\FileTag::fileToList($filetags, 'file');
+               $filetags = explode(",", $filetags);
+
+               $tpl = Renderer::getMarkupTemplate("filer_dialog.tpl");
+               echo Renderer::replaceMacros($tpl, [
+                       '$field' => ['term', L10n::t("Save to Folder:"), '', '', $filetags, L10n::t('- select -')],
+                       '$submit' => L10n::t('Save'),
+               ]);
+
+               exit;
+       }
+}
diff --git a/src/Module/Friendica.php b/src/Module/Friendica.php
new file mode 100644 (file)
index 0000000..ae8ea14
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+use Friendica\Core\Addon;
+use Friendica\Core\Hook;
+use Friendica\Core\L10n;
+use Friendica\Core\Renderer;
+use Friendica\Model\User;
+
+/**
+ * Prints information about the current node
+ * Either in human readable form or in JSON
+ */
+class Friendica extends BaseModule
+{
+       public static function content()
+       {
+               $app = self::getApp();
+               $config = $app->getConfig();
+
+               $visibleAddonList = Addon::getVisibleList();
+               if (!empty($visibleAddonList)) {
+
+                       $sorted = $visibleAddonList;
+                       sort($sorted);
+
+                       $sortedAddonList = '';
+
+                       foreach ($sorted as $addon) {
+                               if (strlen($addon)) {
+                                       if (strlen($sortedAddonList)) {
+                                               $sortedAddonList .= ', ';
+                                       }
+                                       $sortedAddonList .= $addon;
+                               }
+                       }
+                       $addon = [
+                               'title' => L10n::t('Installed addons/apps:'),
+                               'list'  => $sortedAddonList,
+                       ];
+               } else {
+                       $addon = [
+                               'title' => L10n::t('No installed addons/apps'),
+                       ];
+               }
+
+               $tos = ($config->get('system', 'tosdisplay')) ?
+                       L10n::t('Read about the <a href="%1$s/tos">Terms of Service</a> of this node.', $app->getBaseURL()) :
+                       '';
+
+               $blockList = $config->get('system', 'blocklist');
+
+               if (!empty($blockList)) {
+                       $blocked = [
+                               'title'  => L10n::t('On this server the following remote servers are blocked.'),
+                               'header' => [
+                                       L10n::t('Blocked domain'),
+                                       L10n::t('Reason for the block'),
+                               ],
+                               'list'   => $blockList,
+                       ];
+               } else {
+                       $blocked = null;
+               }
+
+               $hooked = '';
+
+               Hook::callAll('about_hook', $hooked);
+
+               $tpl = Renderer::getMarkupTemplate('friendica.tpl');
+
+               return Renderer::replaceMacros($tpl, [
+                       'about'     => L10n::t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.',
+                               '<strong>' . FRIENDICA_VERSION . '</strong>',
+                               $app->getBaseURL(),
+                               '<strong>' . DB_UPDATE_VERSION . '</strong>',
+                               '<strong>' . $config->get('system', 'post_update_version') . '</strong>'),
+                       'friendica' => L10n::t('Please visit <a href="https://friendi.ca">Friendi.ca</a> to learn more about the Friendica project.'),
+                       'bugs'      => L10n::t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">' . L10n::t('the bugtracker at github') . '</a>',
+                       'info'      => L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'),
+
+                       'visible_addons' => $addon,
+                       'tos'            => $tos,
+                       'block_list'     => $blocked,
+                       'hooked'         => $hooked,
+               ]);
+       }
+
+       public static function rawContent()
+       {
+               $app = self::getApp();
+
+               // @TODO: Replace with parameter from router
+               if ($app->argc <= 1 || ($app->argv[1] !== 'json')) {
+                       return;
+               }
+
+               $config = $app->getConfig();
+
+               $register_policies = [
+                       Register::CLOSED  => 'REGISTER_CLOSED',
+                       Register::APPROVE => 'REGISTER_APPROVE',
+                       Register::OPEN    => 'REGISTER_OPEN'
+               ];
+
+               $register_policy_int = intval($config->get('config', 'register_policy'));
+               if ($register_policy_int !== Register::CLOSED && $config->get('config', 'invitation_only')) {
+                       $register_policy = 'REGISTER_INVITATION';
+               } else {
+                       $register_policy = $register_policies[$register_policy_int];
+               }
+
+               $condition = [];
+               $admin = false;
+               if (!empty($config->get('config', 'admin_nickname'))) {
+                       $condition['nickname'] = $config->get('config', 'admin_nickname');
+               }
+               if (!empty($config->get('config', 'admin_email'))) {
+                       $adminList = explode(',', str_replace(' ', '', $config->get('config', 'admin_email')));
+                       $condition['email'] = $adminList[0];
+                       $administrator = User::getByEmail($adminList[0], ['username', 'nickname']);
+                       if (!empty($administrator)) {
+                               $admin = [
+                                       'name'    => $administrator['username'],
+                                       'profile' => $app->getBaseURL() . '/profile/' . $administrator['nickname'],
+                               ];
+                       }
+               }
+
+               $visible_addons = Addon::getVisibleList();
+
+               $config->load('feature_lock');
+               $locked_features = [];
+               $featureLocks = $config->get('config', 'feature_lock');
+               if (isset($featureLocks)) {
+                       foreach ($featureLocks as $feature => $lock) {
+                               if ($feature === 'config_loaded') {
+                                       continue;
+                               }
+
+                               $locked_features[$feature] = intval($lock);
+                       }
+               }
+
+               $data = [
+                       'version'          => FRIENDICA_VERSION,
+                       'url'              => $app->getBaseURL(),
+                       'addons'           => $visible_addons,
+                       'locked_features'  => $locked_features,
+                       'explicit_content' => intval($config->get('system', 'explicit_content', 0)),
+                       'language'         => $config->get('system', 'language'),
+                       'register_policy'  => $register_policy,
+                       'admin'            => $admin,
+                       'site_name'        => $config->get('config', 'sitename'),
+                       'platform'         => FRIENDICA_PLATFORM,
+                       'info'             => $config->get('config', 'info'),
+                       'no_scrape_url'    => $app->getBaseURL() . '/noscrape',
+               ];
+
+               header('Content-type: application/json; charset=utf-8');
+               echo json_encode($data);
+               exit();
+       }
+}
diff --git a/src/Module/ItemBody.php b/src/Module/ItemBody.php
new file mode 100644 (file)
index 0000000..ee50b52
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+use Friendica\Core\L10n;
+use Friendica\Model\Item;
+use Friendica\Network\HTTPException;
+
+/**
+ * Print the body of an Item
+ */
+class ItemBody extends BaseModule
+{
+       public static function content()
+       {
+               if (!local_user()) {
+                       throw new HTTPException\UnauthorizedException(L10n::t('Access denied.'));
+               }
+
+               $app = self::getApp();
+
+               // @TODO: Replace with parameter from router
+               $itemId = (($app->argc > 1) ? intval($app->argv[1]) : 0);
+
+               if (!$itemId) {
+                       throw new HTTPException\NotFoundException(L10n::t('Item not found.'));
+               }
+
+               $item = Item::selectFirst(['body'], ['uid' => local_user(), 'id' => $itemId]);
+
+               if (!empty($item)) {
+                       if ($app->isAjax()) {
+                               echo str_replace("\n", '<br />', $item['body']);
+                               exit();
+                       } else {
+                               return str_replace("\n", '<br />', $item['body']);
+                       }
+               } else {
+                       throw new HTTPException\NotFoundException(L10n::t('Item not found.'));
+               }
+       }
+}
diff --git a/src/Module/Maintenance.php b/src/Module/Maintenance.php
new file mode 100644 (file)
index 0000000..24140bb
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+use Friendica\Core\L10n;
+use Friendica\Core\System;
+use Friendica\Network\HTTPException;
+use Friendica\Util\Strings;
+
+/**
+ * Shows the maintenance reason
+ * or redirects to the alternate location
+ */
+class Maintenance extends BaseModule
+{
+       public static function content()
+       {
+               $config = self::getApp()->getConfig();
+
+               $reason = $config->get('system', 'maintenance_reason');
+
+               if ((substr(Strings::normaliseLink($reason), 0, 7) === 'http://') ||
+                       (substr(Strings::normaliseLink($reason), 0, 8) === 'https://')) {
+                       System::externalRedirect($reason, 307);
+               }
+
+               $exception = new HTTPException\ServiceUnavailableException($reason);
+               $exception->httpdesc = L10n::t('System down for maintenance');
+               throw $exception;
+       }
+}
diff --git a/src/Module/PublicRSAKey.php b/src/Module/PublicRSAKey.php
new file mode 100644 (file)
index 0000000..ed09961
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+namespace Friendica\Module;
+
+use ASN_BASE;
+use Friendica\BaseModule;
+use Friendica\Model\User;
+use Friendica\Network\HTTPException\BadRequestException;
+
+/**
+ * prints the public RSA key of a user
+ */
+class PublicRSAKey extends BaseModule
+{
+       public static function rawContent()
+       {
+               $app = self::getApp();
+
+               // @TODO: Replace with parameter from router
+               if ($app->argc !== 2) {
+                       throw new BadRequestException();
+               }
+
+               // @TODO: Replace with parameter from router
+               $nick = $app->argv[1];
+
+               $user = User::getByNickname($nick, ['spubkey']);
+               if (empty($user) || empty($user['spubkey'])) {
+                       throw new BadRequestException();
+               }
+
+               $lines = explode("\n", $user['spubkey']);
+               unset($lines[0]);
+               unset($lines[count($lines)]);
+
+               $asnString = base64_decode(implode('', $lines));
+               $asnBase = ASN_BASE::parseASNString($asnString);
+
+               $m = $asnBase[0]->asnData[1]->asnData[0]->asnData[0]->asnData;
+               $e = $asnBase[0]->asnData[1]->asnData[0]->asnData[1]->asnData;
+
+               header('Content-type: application/magic-public-key');
+               echo 'RSA' . '.' . $m . '.' . $e;
+
+               exit();
+       }
+}
index 4c14d3c..515285d 100644 (file)
@@ -3,7 +3,7 @@
 namespace Friendica\Module;
 
 use Friendica\BaseModule;
-use Friendica\Core\Renderer;
+use Friendica\Util\XML;
 
 /**
  * Prints the rsd.xml
@@ -13,9 +13,43 @@ class ReallySimpleDiscovery extends BaseModule
 {
        public static function rawContent()
        {
-               header ('Content-Type: text/xml');
-               $tpl = Renderer::getMarkupTemplate('rsd.tpl');
-               echo Renderer::replaceMacros($tpl);
+               header('Content-Type: text/xml');
+
+               $app = self::getApp();
+               $xml = null;
+               echo XML::fromArray([
+                       'rsd' => [
+                               '@attributes' => [
+                                       'version' => '1.0',
+                                       'xmlns'   => 'http://archipelago.phrasewise.com/rsd',
+                               ],
+                               'service'     => [
+                                       'engineName' => 'Friendica',
+                                       'engineLink' => 'http://friendica.com',
+                                       'apis'       => [
+                                               'api' => [
+                                                       '@attributes' => [
+                                                               'name'      => 'Twitter',
+                                                               'preferred' => 'true',
+                                                               'apiLink'   => $app->getBaseURL(),
+                                                               'blogID'    => '',
+                                                       ],
+                                                       'settings'    => [
+                                                               'docs'    => [
+                                                                       'http://status.net/wiki/TwitterCompatibleAPI',
+                                                               ],
+                                                               'setting' => [
+                                                                       '@attributes' => [
+                                                                               'name' => 'OAuth',
+                                                                       ],
+                                                                       'false',
+                                                               ],
+                                                       ],
+                                               ]
+                                       ],
+                               ],
+                       ],
+               ], $xml);
                exit();
        }
 }
diff --git a/src/Module/RobotsTxt.php b/src/Module/RobotsTxt.php
new file mode 100644 (file)
index 0000000..3648f6f
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+
+/**
+ * Return the default robots.txt
+ */
+class RobotsTxt extends BaseModule
+{
+       public static function rawContent()
+       {
+               $allDisalloweds = [
+                       '/settings/',
+                       '/admin/',
+                       '/message/',
+               ];
+
+               header('Content-Type: text/plain');
+               echo 'User-agent: *' . PHP_EOL;
+               foreach ($allDisalloweds as $disallowed) {
+                       echo 'Disallow: ' . $disallowed . PHP_EOL;
+               }
+               exit();
+       }
+}
index 5c6ff79..6446ec3 100644 (file)
@@ -52,14 +52,14 @@ class HTTPException
                        $message = defaults($explanation, $e->getCode(), '');
                }
 
-               return ['$title' => $title, '$description' => $message];
+               return ['$title' => $title, '$message' => $message, '$back' => L10n::t('Go back')];
        }
 
        /**
         * Displays a bare message page with no theming at all.
         *
         * @param \Friendica\Network\HTTPException $e
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        * @throws \Exception
         */
        public static function rawContent(\Friendica\Network\HTTPException $e)
        {
@@ -78,7 +78,7 @@ class HTTPException
         *
         * @param \Friendica\Network\HTTPException $e
         * @return string
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        * @throws \Exception
         */
        public static function content(\Friendica\Network\HTTPException $e)
        {
diff --git a/src/Module/ThemeDetails.php b/src/Module/ThemeDetails.php
new file mode 100644 (file)
index 0000000..7b53d1c
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+use Friendica\Core\Theme;
+
+/**
+ * Prints theme specific details as a JSON string
+ */
+class ThemeDetails extends BaseModule
+{
+       public static function rawContent()
+       {
+               if (!empty($_REQUEST['theme'])) {
+                       $theme = $_REQUEST['theme'];
+                       $info = Theme::getInfo($theme);
+
+                       // Unfortunately there will be no translation for this string
+                       $description = defaults($info, 'description', '');
+                       $version     = defaults($info, 'version'    , '');
+                       $credits     = defaults($info, 'credits'    , '');
+
+                       echo json_encode([
+                               'img'     => Theme::getScreenshot($theme),
+                               'desc'    => $description,
+                               'version' => $version,
+                               'credits' => $credits,
+                       ]);
+               }
+               exit();
+       }
+}
diff --git a/src/Network/HTTPException/ServiceUnavaiableException.php b/src/Network/HTTPException/ServiceUnavaiableException.php
deleted file mode 100644 (file)
index 6c0e659..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-namespace Friendica\Network\HTTPException;
-
-use Friendica\Network\HTTPException;
-
-class ServiceUnavaiableException extends HTTPException
-{
-       protected $code = 503;
-}
diff --git a/src/Network/HTTPException/ServiceUnavailableException.php b/src/Network/HTTPException/ServiceUnavailableException.php
new file mode 100644 (file)
index 0000000..257b8c8
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+namespace Friendica\Network\HTTPException;
+
+use Friendica\Network\HTTPException;
+
+class ServiceUnavailableException extends HTTPException
+{
+       protected $code = 503;
+}
index 475ccfc..3bb0639 100644 (file)
@@ -454,7 +454,7 @@ class Processor
                $cid = Contact::getIdForURL($activity['actor'], $uid);
                if (!empty($cid)) {
                        self::switchContact($cid);
-                       DBA::update('contact', ['hub-verify' => $activity['id']], ['id' => $cid]);
+                       DBA::update('contact', ['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]);
                        $contact = DBA::selectFirst('contact', [], ['id' => $cid, 'network' => Protocol::NATIVE_SUPPORT]);
                } else {
                        $contact = false;
@@ -463,17 +463,19 @@ class Processor
                $item = ['author-id' => Contact::getIdForURL($activity['actor']),
                        'author-link' => $activity['actor']];
 
+               $note = Strings::escapeTags(trim(defaults($activity, 'content', '')));
+
                // Ensure that the contact has got the right network type
                self::switchContact($item['author-id']);
 
-               Contact::addRelationship($owner, $contact, $item);
+               Contact::addRelationship($owner, $contact, $item, '', false, $note);
                $cid = Contact::getIdForURL($activity['actor'], $uid);
                if (empty($cid)) {
                        return;
                }
 
                if (empty($contact)) {
-                       DBA::update('contact', ['hub-verify' => $activity['id']], ['id' => $cid]);
+                       DBA::update('contact', ['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]);
                }
 
                Logger::log('Follow user ' . $uid . ' from contact ' . $cid . ' with id ' . $activity['id']);
@@ -578,7 +580,7 @@ class Processor
 
                self::switchContact($cid);
 
-               if (DBA::exists('contact', ['id' => $cid, 'rel' => Contact::SHARING, 'pending' => true])) {
+               if (DBA::exists('contact', ['id' => $cid, 'rel' => Contact::SHARING])) {
                        Contact::remove($cid);
                        Logger::log('Rejected contact request from contact ' . $cid . ' for user ' . $uid . ' - contact had been removed.', Logger::DEBUG);
                } else {
@@ -653,7 +655,7 @@ class Processor
        private static function switchContact($cid)
        {
                $contact = DBA::selectFirst('contact', ['network'], ['id' => $cid, 'network' => Protocol::NATIVE_SUPPORT]);
-               if (!DBA::isResult($contact) || ($contact['network'] == Protocol::ACTIVITYPUB)) {
+               if (!DBA::isResult($contact) || in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN])) {
                        return;
                }
 
index 8523ce2..8f494af 100644 (file)
@@ -48,20 +48,27 @@ class OnePoll
                        return;
                }
 
+               if (($contact['network'] == Protocol::DFRN) && !Contact::isLegacyDFRNContact($contact)) {
+                       $protocol = Protocol::ACTIVITYPUB;
+               } else {
+                       $protocol = $contact['network'];
+               }
+
                $importer_uid = $contact['uid'];
 
                // Possibly switch the remote contact to AP
-               if ($contact['network'] === Protocol::OSTATUS) {
+               if ($protocol === Protocol::OSTATUS) {
                        ActivityPub\Receiver::switchContact($contact['id'], $importer_uid, $contact['url']);
                        $contact = DBA::selectFirst('contact', [], ['id' => $contact_id]);
                }
 
+               $updated = DateTimeFormat::utcNow();
+
                // These three networks can be able to speak AP, so we are trying to fetch AP profile data here
-               if (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DIASPORA, Protocol::DFRN])) {
+               if (in_array($protocol, [Protocol::ACTIVITYPUB, Protocol::DIASPORA, Protocol::DFRN])) {
                        $apcontact = APContact::getByURL($contact['url'], true);
 
-                       $updated = DateTimeFormat::utcNow();
-                       if (($contact['network'] === Protocol::ACTIVITYPUB) && empty($apcontact)) {
+                       if (($protocol === Protocol::ACTIVITYPUB) && empty($apcontact)) {
                                self::updateContact($contact, ['last-update' => $updated, 'failure_update' => $updated]);
                                Contact::markForArchival($contact);
                                Logger::log('Contact archived');
@@ -74,9 +81,8 @@ class OnePoll
                }
 
                // Diaspora users, archived users and followers are only checked if they still exist.
-               if (($contact['network'] != Protocol::ACTIVITYPUB) && ($contact['archive'] || ($contact["network"] == Protocol::DIASPORA) || ($contact["rel"] == Contact::FOLLOWER))) {
+               if (($protocol != Protocol::ACTIVITYPUB) && ($contact['archive'] || ($contact["network"] == Protocol::DIASPORA) || ($contact["rel"] == Contact::FOLLOWER))) {
                        $last_updated = PortableContact::lastUpdated($contact["url"], true);
-                       $updated = DateTimeFormat::utcNow();
 
                        if ($last_updated) {
                                Logger::log('Contact '.$contact['id'].' had last update on '.$last_updated, Logger::DEBUG);
@@ -98,10 +104,9 @@ class OnePoll
                }
 
                // Update the contact entry
-               if (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN])) {
-                       $updated = DateTimeFormat::utcNow();
+               if (in_array($protocol, [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN])) {
                        // Currently we can't check every AP implementation, so we don't do it at all
-                       if (($contact['network'] != Protocol::ACTIVITYPUB) && !PortableContact::reachable($contact['url'])) {
+                       if (($protocol != Protocol::ACTIVITYPUB) && !PortableContact::reachable($contact['url'])) {
                                Logger::log("Skipping probably dead contact ".$contact['url']);
 
                                // set the last-update so we don't keep polling
@@ -140,25 +145,25 @@ class OnePoll
                        Logger::log("Don't poll follower");
 
                        // set the last-update so we don't keep polling
-                       DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                       DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                        return;
                }
 
                // Don't poll if polling is deactivated (But we poll feeds and mails anyway)
-               if (!in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) && Config::get('system', 'disable_polling')) {
+               if (!in_array($protocol, [Protocol::FEED, Protocol::MAIL]) && Config::get('system', 'disable_polling')) {
                        Logger::log('Polling is disabled');
 
                        // set the last-update so we don't keep polling
-                       DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                       DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                        return;
                }
 
                // We don't poll AP contacts by now
-               if ($contact['network'] === Protocol::ACTIVITYPUB) {
+               if ($protocol === Protocol::ACTIVITYPUB) {
                        Logger::log("Don't poll AP contact");
 
                        // set the last-update so we don't keep polling
-                       DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                       DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                        return;
                }
 
@@ -166,7 +171,7 @@ class OnePoll
                        Logger::log('Ignore public contacts');
 
                        // set the last-update so we don't keep polling
-                       DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                       DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                        return;
                }
 
@@ -178,7 +183,7 @@ class OnePoll
                        Logger::log('No self contact for user '.$importer_uid);
 
                        // set the last-update so we don't keep polling
-                       DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                       DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                        return;
                }
 
@@ -203,9 +208,9 @@ class OnePoll
                        : DateTimeFormat::utc($contact['last-update'], DateTimeFormat::ATOM)
                );
 
-               Logger::log("poll: ({$contact['network']}-{$contact['id']}) IMPORTER: {$importer['name']}, CONTACT: {$contact['name']}");
+               Logger::log("poll: ({$protocol}-{$contact['id']}) IMPORTER: {$importer['name']}, CONTACT: {$contact['name']}");
 
-               if ($contact['network'] === Protocol::DFRN) {
+               if ($protocol === Protocol::DFRN) {
                        $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
                        if (intval($contact['duplex']) && $contact['dfrn-id']) {
                                $idtosend = '0:' . $orig_id;
@@ -233,7 +238,7 @@ class OnePoll
 
                        if (!$curlResult->isSuccess() && ($curlResult->getErrorNumber() == CURLE_OPERATION_TIMEDOUT)) {
                                // set the last-update so we don't keep polling
-                               self::updateContact($contact, ['last-update' => DateTimeFormat::utcNow()]);
+                               self::updateContact($contact, ['last-update' => $updated]);
                                Contact::markForArchival($contact);
                                Logger::log('Contact archived');
                                return;
@@ -251,7 +256,7 @@ class OnePoll
                                Logger::log("$url appears to be dead - marking for death ");
 
                                // set the last-update so we don't keep polling
-                               $fields = ['last-update' => DateTimeFormat::utcNow(), 'failure_update' => DateTimeFormat::utcNow()];
+                               $fields = ['last-update' => $updated, 'failure_update' => $updated];
                                self::updateContact($contact, $fields);
                                Contact::markForArchival($contact);
                                return;
@@ -260,7 +265,7 @@ class OnePoll
                        if (!strstr($handshake_xml, '<')) {
                                Logger::log('response from ' . $url . ' did not contain XML.');
 
-                               $fields = ['last-update' => DateTimeFormat::utcNow(), 'failure_update' => DateTimeFormat::utcNow()];
+                               $fields = ['last-update' => $updated, 'failure_update' => $updated];
                                self::updateContact($contact, $fields);
                                Contact::markForArchival($contact);
                                return;
@@ -274,7 +279,7 @@ class OnePoll
                                Logger::log("$url replied status 1 - marking for death ");
 
                                // set the last-update so we don't keep polling
-                               $fields = ['last-update' => DateTimeFormat::utcNow(), 'failure_update' => DateTimeFormat::utcNow()];
+                               $fields = ['last-update' => $updated, 'failure_update' => $updated];
                                self::updateContact($contact, $fields);
                                Contact::markForArchival($contact);
                        } elseif ($contact['term-date'] > DBA::NULL_DATETIME) {
@@ -283,7 +288,7 @@ class OnePoll
 
                        if ((intval($res->status) != 0) || !strlen($res->challenge) || !strlen($res->dfrn_id)) {
                                // set the last-update so we don't keep polling
-                               DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                               DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                                Logger::log('Contact status is ' . $res->status);
                                return;
                        }
@@ -326,7 +331,7 @@ class OnePoll
                                Logger::log('ID did not decode: ' . $contact['id'] . ' orig: ' . $orig_id . ' final: ' . $final_dfrn_id);
 
                                // set the last-update so we don't keep polling
-                               DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                               DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                                Contact::markForArchival($contact);
                                return;
                        }
@@ -337,9 +342,9 @@ class OnePoll
 
                        $xml = Network::post($contact['poll'], $postvars)->getBody();
 
-               } elseif (($contact['network'] === Protocol::OSTATUS)
-                       || ($contact['network'] === Protocol::DIASPORA)
-                       || ($contact['network'] === Protocol::FEED)) {
+               } elseif (($protocol === Protocol::OSTATUS)
+                       || ($protocol === Protocol::DIASPORA)
+                       || ($protocol === Protocol::FEED)) {
 
                        // Upgrading DB fields from an older Friendica version
                        // Will only do this once per notify-enabled OStatus contact
@@ -348,7 +353,7 @@ class OnePoll
                        $stat_writeable = ((($contact['notify']) && ($contact['rel'] == Contact::FOLLOWER || $contact['rel'] == Contact::FRIEND)) ? 1 : 0);
 
                        // Contacts from OStatus are always writable
-                       if ($contact['network'] === Protocol::OSTATUS) {
+                       if ($protocol === Protocol::OSTATUS) {
                                $stat_writeable = 1;
                        }
 
@@ -360,7 +365,7 @@ class OnePoll
                        // Are we allowed to import from this person?
                        if ($contact['rel'] == Contact::FOLLOWER || $contact['blocked']) {
                                // set the last-update so we don't keep polling
-                               DBA::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
+                               DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]);
                                Logger::log('Contact is blocked or only a follower');
                                return;
                        }
@@ -371,7 +376,7 @@ class OnePoll
 
                        if ($curlResult->isTimeout()) {
                                // set the last-update so we don't keep polling
-                               self::updateContact($contact, ['last-update' => DateTimeFormat::utcNow()]);
+                               self::updateContact($contact, ['last-update' => $updated]);
                                Contact::markForArchival($contact);
                                Logger::log('Contact archived');
                                return;
@@ -379,13 +384,13 @@ class OnePoll
 
                        $xml = $curlResult->getBody();
 
-               } elseif ($contact['network'] === Protocol::MAIL) {
+               } elseif ($protocol === Protocol::MAIL) {
                        Logger::log("Mail: Fetching for ".$contact['addr'], Logger::DEBUG);
 
                        $mail_disabled = ((function_exists('imap_open') && !Config::get('system', 'imap_disabled')) ? 0 : 1);
                        if ($mail_disabled) {
                                // set the last-update so we don't keep polling
-                               self::updateContact($contact, ['last-update' => DateTimeFormat::utcNow()]);
+                               self::updateContact($contact, ['last-update' => $updated]);
                                Contact::markForArchival($contact);
                                Logger::log('Contact archived');
                                return;
@@ -406,7 +411,7 @@ class OnePoll
                                unset($password);
                                Logger::log("Mail: Connect to " . $mailconf['user']);
                                if ($mbox) {
-                                       $fields = ['last_check' => DateTimeFormat::utcNow()];
+                                       $fields = ['last_check' => $updated];
                                        DBA::update('mailacct', $fields, ['id' => $mailconf['id']]);
                                        Logger::log("Mail: Connected to " . $mailconf['user']);
                                } else {
@@ -448,7 +453,7 @@ class OnePoll
                                                                // Only delete when mails aren't automatically moved or deleted
                                                                if (($mailconf['action'] != 1) && ($mailconf['action'] != 3))
                                                                        if ($meta->deleted && ! $item['deleted']) {
-                                                                               $fields = ['deleted' => true, 'changed' => DateTimeFormat::utcNow()];
+                                                                               $fields = ['deleted' => true, 'changed' => $updated];
                                                                                Item::update($fields, ['id' => $item['id']]);
                                                                        }
 
@@ -579,7 +584,7 @@ class OnePoll
                                                        if ($datarray['parent-uri'] === $datarray['uri']) {
                                                                $datarray['private'] = 1;
                                                        }
-                                                       if (($contact['network'] === Protocol::MAIL) && !PConfig::get($importer_uid, 'system', 'allow_public_email_replies')) {
+                                                       if (($protocol === Protocol::MAIL) && !PConfig::get($importer_uid, 'system', 'allow_public_email_replies')) {
                                                                $datarray['private'] = 1;
                                                                $datarray['allow_cid'] = '<' . $contact['id'] . '>';
                                                        }
@@ -622,7 +627,7 @@ class OnePoll
                        if (!strstr($xml, '<')) {
                                Logger::log('post_handshake: response from ' . $url . ' did not contain XML.');
 
-                               $fields = ['last-update' => DateTimeFormat::utcNow(), 'failure_update' => DateTimeFormat::utcNow()];
+                               $fields = ['last-update' => $updated, 'failure_update' => $updated];
                                self::updateContact($contact, $fields);
                                Contact::markForArchival($contact);
                                return;
@@ -634,16 +639,16 @@ class OnePoll
                        consume_feed($xml, $importer, $contact, $hub);
 
                        // do it a second time for DFRN so that any children find their parents.
-                       if ($contact['network'] === Protocol::DFRN) {
+                       if ($protocol === Protocol::DFRN) {
                                consume_feed($xml, $importer, $contact, $hub);
                        }
 
                        $hubmode = 'subscribe';
-                       if ($contact['network'] === Protocol::DFRN || $contact['blocked']) {
+                       if ($protocol === Protocol::DFRN || $contact['blocked']) {
                                $hubmode = 'unsubscribe';
                        }
 
-                       if (($contact['network'] === Protocol::OSTATUS ||  $contact['network'] == Protocol::FEED) && (! $contact['hub-verify'])) {
+                       if (($protocol === Protocol::OSTATUS ||  $protocol == Protocol::FEED) && (! $contact['hub-verify'])) {
                                $hub_update = true;
                        }
 
@@ -651,9 +656,9 @@ class OnePoll
                                $hub_update = true;
                        }
 
-                       Logger::log("Contact ".$contact['id']." returned hub: ".$hub." Network: ".$contact['network']." Relation: ".$contact['rel']." Update: ".$hub_update);
+                       Logger::log("Contact ".$contact['id']." returned hub: ".$hub." Network: ".$protocol." Relation: ".$contact['rel']." Update: ".$hub_update);
 
-                       if (strlen($hub) && $hub_update && (($contact['rel'] != Contact::FOLLOWER) || $contact['network'] == Protocol::FEED)) {
+                       if (strlen($hub) && $hub_update && (($contact['rel'] != Contact::FOLLOWER) || $protocol == Protocol::FEED)) {
                                Logger::log('hub ' . $hubmode . ' : ' . $hub . ' contact name : ' . $contact['name'] . ' local user : ' . $importer['name']);
                                $hubs = explode(',', $hub);
 
@@ -670,19 +675,15 @@ class OnePoll
                                }
                        }
 
-                       $updated = DateTimeFormat::utcNow();
-
                        self::updateContact($contact, ['last-update' => $updated, 'success_update' => $updated]);
                        DBA::update('gcontact', ['last_contact' => $updated], ['nurl' => $contact['nurl']]);
                        Contact::unmarkForArchival($contact);
                } elseif (in_array($contact["network"], [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, Protocol::FEED])) {
-                       $updated = DateTimeFormat::utcNow();
-
                        self::updateContact($contact, ['last-update' => $updated, 'failure_update' => $updated]);
                        DBA::update('gcontact', ['last_failure' => $updated], ['nurl' => $contact['nurl']]);
                        Contact::markForArchival($contact);
                } else {
-                       self::updateContact($contact, ['last-update' => DateTimeFormat::utcNow()]);
+                       self::updateContact($contact, ['last-update' => $updated]);
                }
 
                Logger::log('End');
index b48fa1a..0eaf448 100644 (file)
@@ -5,7 +5,7 @@ details > summary {
   cursor: pointer;
 }
 
-/* General designing elements */
+/* General design elements */
 .btn {
   outline: none;
   -moz-box-shadow: inset 0px 1px 0px 0px #ffffff;
@@ -87,7 +87,6 @@ span.connector {
 
 .wall-item-container .wall-item-content .type-link img.attachment-image,
 .type-link img.attachment-image, .type-video img.attachment-image  {
-  /* max-width: 640px; */
   max-width: 100%;
   max-height: initial;
   float: initial;
@@ -621,3 +620,22 @@ span.emoji.mastodon img {
   height: 1.2em;
   vertical-align: middle;
 }
+
+/* Exception page */
+
+#exception {
+  overflow: hidden;
+  background-image: url('../images/friendica-404_svg_hare-bottom-light-inside.png');
+  background-position: 50px bottom;
+  background-repeat: no-repeat;
+}
+
+#exception .hare {
+  float: right;
+}
+
+@media screen and (max-width: 600px) {
+  #exception .hare {
+    display: none;
+  }
+}
index 02b7648..6c26168 100644 (file)
@@ -1,4 +1,6 @@
 <div id="exception" class="generic-page-wrapper">
+    <img class="hare" src="images/friendica-404_svg_flexy-o-hare.png"/>
     <h1>{{$title}}</h1>
     <p>{{$message}}</p>
+       <p><button type="button" onclick="window.history.back()" class="btn btn-primary">{{$back}}</button></p>
 </div>
index 2147198..709ad4d 100644 (file)
@@ -1,30 +1,32 @@
-<h2>Feed Test</h2>
-<form action="feedtest" method="get" class="panel panel-default">
-       <div class="panel-body">
-               <div class="form-group">
-                       {{include file="field_input.tpl" field=$url}}
-               </div>
-               <p><button type="submit" class="btn btn-primary">Submit</button></p>
-       </div>
-</form>
-
-{{if $result}}
-<div class="feedtest-result">
-       <div class="panel panel-default">
-               <div class="panel-heading">
-                       <h3 class="panel-title">Output Items</h3>
-               </div>
+<div id="feedtest" class="generic-page-wrapper">
+       <h2>Feed Test</h2>
+       <form action="feedtest" method="get" class="panel panel-default">
                <div class="panel-body">
-                       <pre>{{$result.output}}</pre>
+                       <div class="form-group">
+                               {{include file="field_input.tpl" field=$url}}
+                       </div>
+                       <p><button type="submit" class="btn btn-primary">Submit</button></p>
                </div>
-       </div>
-       <div class="panel panel-default">
-               <div class="panel-heading">
-                       <h3 class="panel-title">Input Feed XML</h3>
+       </form>
+
+       {{if $result}}
+       <div class="feedtest-result">
+               <div class="panel panel-default">
+                       <div class="panel-heading">
+                               <h3 class="panel-title">Output Items</h3>
+                       </div>
+                       <div class="panel-body">
+                               <pre>{{$result.output}}</pre>
+                       </div>
                </div>
-               <div class="panel-body">
-                       {{$result.input}}
+               <div class="panel panel-default">
+                       <div class="panel-heading">
+                               <h3 class="panel-title">Input Feed XML</h3>
+                       </div>
+                       <div class="panel-body">
+                               {{$result.input}}
+                       </div>
                </div>
        </div>
+       {{/if}}
 </div>
-{{/if}}
\ No newline at end of file
diff --git a/view/templates/friendica.tpl b/view/templates/friendica.tpl
new file mode 100644 (file)
index 0000000..f890a58
--- /dev/null
@@ -0,0 +1,47 @@
+<div id="friendica" class="generic-page-wrapper">
+       <h1>Friendica</h1>
+       <br>
+       <p>{{$about nofilter}}</p>
+       <br>
+       <p>{{$friendica nofilter}}</p>
+       <br>
+       <p>{{$bugs nofilter}}</p>
+       <br>
+       <p>{{$info nofilter}}</p>
+       <br>
+
+       <p>{{$visible_addons.title nofilter}}</p>
+       {{if $visible_addons.list}}
+       <div style="margin-left: 25px; margin-right: 25px; margin-bottom: 25px;">{{$visible_addons.list nofilter}}</div>
+       {{/if}}
+
+       {{if $tos}}
+       <p>{{$tos nofilter}}</p>
+       {{/if}}
+
+       {{if $block_list}}
+       <div id="about_blocklist">
+               <p>{{$block_list.title nofilter}}</p>
+               <br>
+               <table class="table">
+                       <thead>
+                               <tr>
+                                       <th>{{$block_list.header[0] nofilter}}</th>
+                                       <th>{{$block_list.header[1] nofilter}}</th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                       {{foreach $block_list.list as $blocked}}
+                               <tr>
+                                       <td>{{$blocked.domain nofilter}}</td>
+                                       <td>{{$blocked.reason nofilter}}</td>
+                               </tr>
+                       {{/foreach}}
+                       </tbody>
+               </table>
+       </div>
+
+       {{/if}}
+
+{{$hooked nofilter}}
+</div>
diff --git a/view/templates/rsd.tpl b/view/templates/rsd.tpl
deleted file mode 100644 (file)
index c194e8f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
-       <service>
-               <engineName>Friendica</engineName>
-               <engineLink>http://friendica.com/</engineLink>
-               <apis>
-                       <api name="Twitter" preferred="true" apiLink="{{$baseurl}}/api/" blogID="">
-                               <settings>
-                                       <docs>http://status.net/wiki/TwitterCompatibleAPI</docs>
-                                       <setting name="OAuth">false</setting>
-                               </settings>
-                       </api>
-               </apis>
-       </service>
-</rsd>
index e6b42e5..4a72628 100644 (file)
@@ -105,6 +105,9 @@ blockquote {
  * mobile aside
  */
 @media screen and (max-width: 990px) {
+    body {
+        padding-top: 105px;
+    }
     aside{
         position: fixed!important;
         top: 0!important;
@@ -616,6 +619,10 @@ nav.navbar a, nav.navbar .btn-link {
     display: flex;
 }
 
+#friendica-logo-mask {
+    display: block;
+}
+
 
 /* Notification Menu */
 #topbar-first #nav-notifications-menu {