diff --git a/boot.php b/boot.php
index 94e1e0ab8c..58b4bc0983 100644
--- a/boot.php
+++ b/boot.php
@@ -6,11 +6,11 @@
/**
* Friendica
- *
+ *
* Friendica is a communications platform for integrated social communications
* utilising decentralised communications and linkage to several indie social
* projects - as well as popular mainstream providers.
- *
+ *
* Our mission is to free our friends and families from the clutches of
* data-harvesting corporations, and pave the way to a future where social
* communications are free and open and flow between alternate providers as
@@ -18,7 +18,7 @@
*/
require_once('include/autoloader.php');
-
+
require_once('include/config.php');
require_once('include/network.php');
require_once('include/plugin.php');
@@ -30,7 +30,7 @@ require_once('include/cache.php');
require_once('library/Mobile_Detect/Mobile_Detect.php');
require_once('include/features.php');
require_once('include/identity.php');
-
+require_once('include/pidfile.php');
require_once('update.php');
require_once('include/dbstructure.php');
@@ -465,11 +465,12 @@ class App {
public $plugins;
public $apps = array();
public $identities;
- public $is_mobile;
- public $is_tablet;
+ public $is_mobile = false;
+ public $is_tablet = false;
public $is_friendica_app;
public $performance = array();
public $callstack = array();
+ public $theme_info = array();
public $nav_sel;
@@ -855,11 +856,11 @@ class App {
$shortcut_icon = get_config("system", "shortcut_icon");
if ($shortcut_icon == "")
- $shortcut_icon = $this->get_baseurl()."/images/friendica-32.png";
+ $shortcut_icon = "images/friendica-32.png";
$touch_icon = get_config("system", "touch_icon");
if ($touch_icon == "")
- $touch_icon = $this->get_baseurl()."/images/friendica-128.png";
+ $touch_icon = "images/friendica-128.png";
$tpl = get_markup_template('head.tpl');
$this->page['htmlhead'] = replace_macros($tpl,array(
@@ -938,6 +939,25 @@ class App {
}
+ /**
+ * @brief Removes the baseurl from an url. This avoids some mixed content problems.
+ *
+ * @param string $url
+ *
+ * @return string The cleaned url
+ */
+ function remove_baseurl($url){
+
+ // Is the function called statically?
+ if (!is_object($this))
+ return(self::$a->remove_baseurl($url));
+
+ $url = normalise_link($url);
+ $base = normalise_link($this->get_baseurl());
+ $url = str_replace($base."/", "", $url);
+ return $url;
+ }
+
/**
* @brief Register template engine class
*
@@ -1027,11 +1047,21 @@ class App {
function save_timestamp($stamp, $value) {
$duration = (float)(microtime(true)-$stamp);
+ if (!isset($this->performance[$value])) {
+ // Prevent ugly E_NOTICE
+ $this->performance[$value] = 0;
+ }
+
$this->performance[$value] += (float)$duration;
$this->performance["marktime"] += (float)$duration;
$callstack = $this->callstack();
+ if (!isset($this->callstack[$value][$callstack])) {
+ // Prevent ugly E_NOTICE
+ $this->callstack[$value][$callstack] = 0;
+ }
+
$this->callstack[$value][$callstack] += (float)$duration;
}
@@ -1068,6 +1098,55 @@ class App {
return($this->is_friendica_app);
}
+ /**
+ * @brief Checks if the maximum load is reached
+ *
+ * @return bool Is the load reached?
+ */
+ function maxload_reached() {
+
+ $maxsysload = intval(get_config('system', 'maxloadavg'));
+ if ($maxsysload < 1)
+ $maxsysload = 50;
+
+ $load = current_load();
+ if ($load) {
+ if (intval($load) > $maxsysload) {
+ logger('system: load '.$load.' too high.');
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @brief Checks if the process is already running
+ *
+ * @param string $taskname The name of the task that will be used for the name of the lockfile
+ * @param string $task The path and name of the php script
+ * @param int $timeout The timeout after which a task should be killed
+ *
+ * @return bool Is the process running?
+ */
+ function is_already_running($taskname, $task = "", $timeout = 540) {
+
+ $lockpath = get_lockpath();
+ if ($lockpath != '') {
+ $pidfile = new pidfile($lockpath, $taskname);
+ if ($pidfile->is_already_running()) {
+ logger("Already running");
+ if ($pidfile->running_time() > $timeout) {
+ $pidfile->kill();
+ logger("killed stale process");
+ // Calling a new instance
+ if ($task != "")
+ proc_run('php', $task);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
}
/**
@@ -1419,7 +1498,7 @@ function login($register = false, $hiddens=false) {
$noid = get_config('system','no_openid');
- $dest_url = $a->get_baseurl(true) . '/' . $a->query_string;
+ $dest_url = $a->query_string;
if(local_user()) {
$tpl = get_markup_template("logout.tpl");
@@ -1479,6 +1558,9 @@ function killme() {
* @brief Redirect to another URL and terminate this process.
*/
function goaway($s) {
+ if (!strstr(normalise_link($s), "http://"))
+ $s = App::get_baseurl()."/".$s;
+
header("Location: $s");
killme();
}
@@ -1738,9 +1820,9 @@ function current_theme_url() {
$opts = (($a->profile_uid) ? '?f=&puid=' . $a->profile_uid : '');
if (file_exists('view/theme/' . $t . '/style.php'))
- return($a->get_baseurl() . '/view/theme/' . $t . '/style.pcss' . $opts);
+ return('view/theme/'.$t.'/style.pcss'.$opts);
- return($a->get_baseurl() . '/view/theme/' . $t . '/style.css');
+ return('view/theme/'.$t.'/style.css');
}
function feed_birthday($uid,$tz) {
diff --git a/database.sql b/database.sql
index 25faf0f4c0..89b821e23a 100644
--- a/database.sql
+++ b/database.sql
@@ -201,17 +201,6 @@ CREATE TABLE IF NOT EXISTS `deliverq` (
PRIMARY KEY(`id`)
) DEFAULT CHARSET=utf8;
---
--- TABLE dsprphotoq
---
-CREATE TABLE IF NOT EXISTS `dsprphotoq` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `uid` int(11) NOT NULL DEFAULT 0,
- `msg` mediumtext NOT NULL,
- `attempt` tinyint(4) NOT NULL DEFAULT 0,
- PRIMARY KEY(`id`)
-) DEFAULT CHARSET=utf8;
-
--
-- TABLE event
--
@@ -912,13 +901,11 @@ CREATE TABLE IF NOT EXISTS `session` (
CREATE TABLE IF NOT EXISTS `sign` (
`id` int(10) unsigned NOT NULL auto_increment,
`iid` int(10) unsigned NOT NULL DEFAULT 0,
- `retract_iid` int(10) unsigned NOT NULL DEFAULT 0,
`signed_text` mediumtext NOT NULL,
`signature` text NOT NULL,
`signer` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
- INDEX `iid` (`iid`),
- INDEX `retract_iid` (`retract_iid`)
+ INDEX `iid` (`iid`)
) DEFAULT CHARSET=utf8;
--
diff --git a/doc/Accesskeys.md b/doc/Accesskeys.md
index c49e79c0ab..4f16ba2536 100644
--- a/doc/Accesskeys.md
+++ b/doc/Accesskeys.md
@@ -37,10 +37,7 @@ General
* o: Profile
* t: Contacts
* d: Common friends
-* b: Toggle Blocked status
-* i: Toggle Ignored status
-* v: Toggle Archive status
-* r: Repair
+* r: Advanced
/message
--------
diff --git a/doc/BBCode.md b/doc/BBCode.md
index fe7c1481f6..186b1cda93 100644
--- a/doc/BBCode.md
+++ b/doc/BBCode.md
@@ -143,6 +143,56 @@ Map
You can embed maps from coordinates or addresses.
This require "openstreetmap" addon version 1.3 or newer.
+-----------------------------------------------------------
+
+Abstract for longer posts
+-------------------------
+
+If you want to spread your post to several third party networks you can have the problem that these networks have (for example) a length limitation.
+(Like on Twitter)
+
+Friendica is using a semi intelligent mechanism to generate a fitting abstract.
+But it can be interesting to define an own abstract that will only be displayed on the external network.
+This is done with the [abstract]-element.
+Example:
+
+
[abstract]Totally interesting! A must-see! Please click the link![/abstract]
+I want to tell you a really boring story that you really never wanted
+to hear.
+
+Twitter would display the text "Totally interesting! A must-see! Please click the link!".
+On Friendica you would only see the text after "I want to tell you a really ..."
+
+It is even possible to define abstracts for separate networks:
+
+
+[abstract]Hi friends Here are my newest pictures![abstract]
+[abstract=twit]Hi my dear Twitter followers. Do you want to see my new
+pictures?[abstract]
+[abstract=apdn]Helly my dear followers on ADN. I made sone new pictures
+that I wanted to share with you.[abstract]
+Today I was in the woods and took some real cool pictures ...
+
+
+For Twitter and App.net the system will use the defined abstracts.
+For other networks (e.g. when you are using the "statusnet" connector that is used to post to GNU Social) the general abstract element will be used.
+
+If you use (for example) the "buffer" connector to post to Facebook or Google+ you can use this element to define an abstract for a longer blogpost that you don't want to post completely to these networks.
+
+Networks like Facebook or Google+ aren't length limited.
+For this reason the [abstract] element isn't used.
+Instead you have to name the explicit network:
+
+
+[abstract]These days I had a strange encounter ...[abstract]
+[abstract=goog]Helly my dear Google+ followers. You have to read my
+newest blog post![abstract]
+[abstract=face]Hello my Facebook friends. These days happened something
+really cool.[abstract]
+While taking pictures in the woods I had a really strange encounter ...
+
+The [abstract] element isn't working with the native OStatus connection or with connectors where we post the HTML.
+(Like Tumblr, Wordpress or Pump.io)
Special
-------
@@ -150,5 +200,3 @@ Special
If you need to put literal bbcode in a message, [noparse], [nobb] or [pre] are used to escape bbcode:
[noparse][b]bold[/b][/noparse]
: [b]bold[/b]
-
-
diff --git a/doc/Bugs-and-Issues.md b/doc/Bugs-and-Issues.md
index 366b2ed662..0ece265a24 100644
--- a/doc/Bugs-and-Issues.md
+++ b/doc/Bugs-and-Issues.md
@@ -6,6 +6,8 @@ Bugs and Issues
If your server has a support page, you should report any bugs/issues you encounter there first.
Reporting to your support page before reporting to the developers makes their job easier, as they don't have to deal with bug reports that might not have anything to do with them.
This helps us get new features faster.
+You can also contact the [friendica support forum](https://helpers.pyxis.uberspace.de/profile/helpers) and report your problem there.
+Maybe someone from another node encountered the problem as well and can help you.
If you're a technical user, or your site doesn't have a support page, you'll need to use the [Bug Tracker](http://bugs.friendica.com/).
Please perform a search to see if there's already an open bug that matches yours before submitting anything.
diff --git a/doc/Connectors.md b/doc/Connectors.md
index cd4b643f14..148352c552 100644
--- a/doc/Connectors.md
+++ b/doc/Connectors.md
@@ -57,13 +57,15 @@ All that the pages need to have is a discoverable feed using either the RSS or A
Twitter
---
-To follow a Twitter member, put the URL of the Twitter member's main page into the Connect box on your [Contacts](contacts) page.
+To follow a Twitter member, the Twitter-Connector (Addon) needs to be configured on your node.
+If this is the case put the URL of the Twitter member's main page into the Connect box on your [Contacts](contacts) page.
To reply, you must have the Twitter connector installed, and reply using your own status editor.
Begin the message with @twitterperson replacing with the Twitter username.
Email
---
+If the php module for IMAP support is available on your server, Friendica can connect to email contacts as well.
Configure the email connector from your [Settings](settings) page.
Once this has been done, you may enter an email address to connect with using the Connect box on your [Contacts](contacts) page.
They must be the sender of a message which is currently in your INBOX for the connection to succeed.
diff --git a/doc/Developers-Intro.md b/doc/Developers-Intro.md
index 10bbd5632a..8e3cd03b18 100644
--- a/doc/Developers-Intro.md
+++ b/doc/Developers-Intro.md
@@ -83,11 +83,11 @@ Ask us to find out whom to talk to about their experiences.
Do not worry about cross-posting.
###Client software
-There are free software clients that do somehow work with Friendica but most of them need love and maintenance.
-Also, they were mostly made for other platforms using the GNU Social API.
-This means they lack the features that are really specific to Friendica.
-Popular clients you might want to have a look at are:
+As Friendica is using a [Twitter/GNU Social compatible API](help/api) any of the clients for those platforms should work with Friendica as well.
+Furthermore there are several client projects, especially for use with Friendica.
+If you are interested in improving those clients, please contact the developers of the clients directly.
-* [Hotot (Linux)](http://hotot.org/) - abandoned
-* [Friendica for Android](https://github.com/max-weller/friendica-for-android) - abandoned
-* You can find more working client software in [Wikipedia](https://en.wikipedia.org/wiki/Friendica).
+* Android / CynogenMod: **Friendica for Android** [src](https://github.com/max-weller/friendica-for-android), [homepage](http://friendica.android.max-weller.de/) - abandoned
+* iOS: *currently no client*
+* SailfishOS: **Friendiy** [src](https://kirgroup.com/projects/fabrixxm/harbour-friendly) - developed by [Fabio](https://kirgroup.com/profile/fabrixxm/?tab=profile)
+* Windows: **Friendica Mobile** for Windows versions [before 8.1](http://windowsphone.com/s?appid=e3257730-c9cf-4935-9620-5261e3505c67) and [Windows 10](https://www.microsoft.com/store/apps/9nblggh0fhmn) - developed by [Gerhard Seeber](http://mozartweg.dyndns.org/friendica/profile/gerhard/?tab=profile)
diff --git a/doc/Settings.md b/doc/Settings.md
index 86254cb29e..7d909afa09 100644
--- a/doc/Settings.md
+++ b/doc/Settings.md
@@ -11,8 +11,6 @@ Hot Keys
Friendica traps the following keyboard events:
* [Pause] - Pauses "Ajax" update activity. This is the process that provides updates without reloading the page. You may wish to pause it to reduce network usage and/or as a debugging aid for javascript developers. A pause indicator will appear at the lower right hand corner of the page. Hit the [pause] key once again to resume.
-* [F8] - Displays a language selector
-
Birthday Notifications
---
diff --git a/doc/api.md b/doc/api.md
index c020f403ff..7d6f440c58 100644
--- a/doc/api.md
+++ b/doc/api.md
@@ -1,6 +1,6 @@
Friendica API
===
-The Friendica API aims to be compatible to the [GNU Social API](http://skilledtests.com/wiki/Twitter-compatible_API) and the [Twitter API](https://dev.twitter.com/rest/public).
+The Friendica API aims to be compatible to the [GNU Social API](http://wiki.gnusocial.de/gnusocial:api) and the [Twitter API](https://dev.twitter.com/rest/public).
Please refer to the linked documentation for further information.
@@ -388,6 +388,18 @@ Friendica doesn't allow showing friends of other users.
---
### statusnet/config (*)
+---
+### statusnet/conversation (*; AUTH)
+It shows all direct answers (excluding the original post) to a given id.
+
+#### Parameter
+* id: id of the post
+* count: Items per page (default: 20)
+* page: page number
+* since_id: minimal id
+* max_id: maximum id
+* include_entities: "true" shows entities for pictures and links (Default: false)
+
---
### statusnet/version (*)
diff --git a/doc/database.md b/doc/database.md
index e37df05e09..f48404c17d 100644
--- a/doc/database.md
+++ b/doc/database.md
@@ -15,7 +15,6 @@ Database Tables
| [contact](help/database/db_contact) | contact table |
| [conv](help/database/db_conv) | private messages |
| [deliverq](help/database/db_deliverq) | |
-| [dsprphotoq](help/database/db_dsprphotoq) | |
| [event](help/database/db_event) | Events |
| [fcontact](help/database/db_fcontact) | friend suggestion stuff |
| [ffinder](help/database/db_ffinder) | friend suggestion stuff |
diff --git a/doc/database/db_dsprphotoq.md b/doc/database/db_dsprphotoq.md
deleted file mode 100644
index 6af4d030e0..0000000000
--- a/doc/database/db_dsprphotoq.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Table dsprphotoq
-================
-
-| Field | Description | Type | Null | Key | Default | Extra |
-|---------|------------------|------------------|------|-----|---------|----------------|
-| id | sequential ID | int(10) unsigned | NO | PRI | NULL | auto_increment |
-| uid | | int(11) | NO | | 0 | |
-| msg | | mediumtext | NO | | NULL | |
-| attempt | | tinyint(4) | NO | | 0 | |
-
-Return to [database documentation](help/database)
diff --git a/doc/database/db_sign.md b/doc/database/db_sign.md
index 8de59ac675..6986613e59 100644
--- a/doc/database/db_sign.md
+++ b/doc/database/db_sign.md
@@ -5,7 +5,6 @@ Table sign
| ------------ | ------------- | ---------------- | ---- | --- | ------- | --------------- |
| id | sequential ID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| iid | item.id | int(10) unsigned | NO | MUL | 0 | |
-| retract_iid | | int(10) unsigned | NO | MUL | 0 | |
| signed_text | | mediumtext | NO | | NULL | |
| signature | | text | NO | | NULL | |
| signer | | varchar(255) | NO | | | |
diff --git a/doc/de/BBCode.md b/doc/de/BBCode.md
index d3e205f0fa..cd9fa7673e 100644
--- a/doc/de/BBCode.md
+++ b/doc/de/BBCode.md
@@ -131,8 +131,7 @@ Außerdem kann *url* die genaue url zu einer ogg Datei sein, die dann per H
[url]*url*[/url]
-Wenn *url* entweder oembed oder opengraph unterstützt wird das eingebettete
-Objekt (z.B. ein Dokument von scribd) eingebunden.
+Wenn *url* entweder oembed oder opengraph unterstützt wird das eingebettete Objekt (z.B. ein Dokument von scribd) eingebunden.
Der Titel der Seite mit einem Link zur *url* wird ebenfalls angezeigt.
Um eine Karte in einen Beitrag einzubinden, muss das *openstreetmap* Addon aktiviert werden. Ist dies der Fall, kann mit
@@ -145,11 +144,54 @@ eine Karte von [OpenStreetmap](http://openstreetmap.org) eingebettet werden. Zur
oder eine Adresse in obiger Form verwendet werden.
+Zusammenfassung für längere Beiträge
+------------------------------------
+
+Wenn man seine Beiträge über mehrere Netzwerke verbreiten möchte, hat man häufig das Problem, dass diese Netzwerke z.B. eine Längenbeschränkung haben.
+(Z.B. Twitter).
+
+Friendica benutzt zum Erzeugen eines Anreißtextes eine halbwegs intelligente Logik.
+Es kann aber dennoch von Interesse sein, eine eigene Zusammenfassung zu erstellen, die nur auf dem Fremdnetzwerk dargestellt wird.
+Dies geschieht mit dem [abstract]-Element.
+Beispiel:
+
+
[abstract]Total spannend! Unbedingt diesen Link anklicken![/abstract]
+Hier erzähle ich euch eine total langweilige Geschichte, die ihr noch
+nie hören wolltet.
+
+Auf Twitter würde das "Total spannend! Unbedingt diesen Link anklicken!" stehen, auf Friendica würde nur der Text nach "Hier erzähle ..." erscheinen.
+
+Es ist sogar möglich, für einzelne Netzwerke eigene Zusammenfassungen zu erstellen:
+
+
+[abstract]Hallo Leute, hier meine neuesten Bilder![abstract]
+[abstract=twit]Hallo Twitter-User, hier meine neuesten Bilder![abstract]
+[abstract=apdn]Hallo App.net-User, hier meine neuesten Bilder![abstract]
+Ich war heute wieder im Wald unterwegs und habe tolle Bilder geschossen ...
+
+
+Für Twitter und App.net nimmt das System die entsprechenden Texte.
+Bei anderen Netzwerken, bei denen der Inhalt gekürzt wird (z.B. beim "statusnet"-Connector, der für das Posten nach GNU Social verwendet wird) wird dann die Zusammenfassung unter [abstract] verwendet.
+
+Wenn man z.B. den "buffer"-Connector verwendet, um nach Facebook oder Google+ zu posten, kann man dieses Element ebenfalls verwenden, wenn man z.B. einen längeren Blogbeitrag erstellt hat, aber ihn nicht komplett in diese Netzwerke posten möchte.
+
+Netzwerke wie Facebook oder Google+ sind nicht in der Postinglänge beschränkt.
+Aus diesem Grund greift nicht die [abstract]-Zusammenfassung. Stattdessen muss man das Netzwerk explizit angeben:
+
+
+[abstract]Ich habe neulich wieder etwas erlebt, was ich euch mitteilen möchte.[abstract]
+[abstract=goog]Hallo meine Google+-Kreislinge. Ich habe neulich wieder
+etwas erlebt, was ich euch mitteilen möchte.[abstract]
+[abstract=face]Hallo Facebook-Freunde! Ich habe neulich wieder etwas
+erlebt, was ich euch mitteilen möchte.[abstract]
+Beim Bildermachen im Wald habe ich neulich eine interessante Person
+getroffen ...
+
+Das [abstract]-Element greift nicht bei der nativen OStatus-Verbindung oder bei Connectoren, die den HTML-Text posten wie z.B. die Connectoren zu Tumblr, Wordpress oder Pump.io.
+
Spezielle Tags
-------
Wenn Du über BBCode Tags in einer Nachricht schreiben möchtest, kannst Du [noparse], [nobb] oder [pre] verwenden um den BBCode Tags vor der Evaluierung zu schützen:
[noparse][b]fett[/b][/noparse]
: [b]fett[/b]
-
-
diff --git a/doc/de/Settings.md b/doc/de/Settings.md
index 988b3657c0..4ad9f39ba5 100644
--- a/doc/de/Settings.md
+++ b/doc/de/Settings.md
@@ -14,9 +14,6 @@ Friendica erfasst die folgenden Tastaturbefehle:
* [Pause] - Pausiert die Update-Aktivität via "Ajax". Das ist ein Prozess, der Updates durchführt, ohne die Seite neu zu laden. Du kannst diesen Prozess pausieren, um deine Netzwerkauslastung zu reduzieren und/oder um es in der Javascript-Programmierung zum Debuggen zu nutzen. Ein Pausenzeichen erscheint unten links im Fenster. Klicke die [Pause]-Taste ein weiteres Mal, um die Pause zu beenden.
-* [F8] - Zeigt eine Sprachauswahl an
-
-
**Geburtstagsbenachrichtigung**
Geburtstage erscheinen auf deiner Startseite für alle Freunde, die in den nächsten 6 Tagen Geburtstag haben.
diff --git a/doc/htconfig.md b/doc/htconfig.md
index f9c92bfa08..a36e0bef22 100644
--- a/doc/htconfig.md
+++ b/doc/htconfig.md
@@ -64,9 +64,6 @@ line to your .htconfig.php:
* throttle_limit_week - Maximum number of posts that a user can send per week with the API.
* throttle_limit_month - Maximum number of posts that a user can send per month with the API.
* wall-to-wall_share (Boolean) - Displays forwarded posts like "wall-to-wall" posts.
-* worker (Boolean) - (Experimental) Use the worker system instead of calling several background processes. Reduces the overall load and speeds up item delivery.
-* worker_dont_fork (Boolean) - if enabled, the workers are only called from the poller process. Useful on systems that permit the use of "proc_open".
-* worker_queues - Number of parallel workers. Default value is 10 queues.
* xrd_timeout - Timeout for fetching the XRD links. Default value is 20 seconds.
## service_class ##
diff --git a/include/Contact.php b/include/Contact.php
index 3799e0b189..79a14ab581 100644
--- a/include/Contact.php
+++ b/include/Contact.php
@@ -129,7 +129,7 @@ function terminate_friendship($user,$self,$contact) {
}
elseif($contact['network'] === NETWORK_DIASPORA) {
require_once('include/diaspora.php');
- diaspora_unshare($user,$contact);
+ diaspora::send_unshare($user,$contact);
}
elseif($contact['network'] === NETWORK_DFRN) {
require_once('include/dfrn.php');
@@ -555,60 +555,6 @@ function posts_from_gcontact($a, $gcontact_id) {
return $o;
}
-/**
- * @brief set the gcontact-id in all item entries
- *
- * This job has to be started multiple times until all entries are set.
- * It isn't started in the update function since it would consume too much time and can be done in the background.
- */
-function item_set_gcontact() {
- define ('POST_UPDATE_VERSION', 1192);
-
- // Was the script completed?
- if (get_config("system", "post_update_version") >= POST_UPDATE_VERSION)
- return;
-
- // Check if the first step is done (Setting "gcontact-id" in the item table)
- $r = q("SELECT `author-link`, `author-name`, `author-avatar`, `uid`, `network` FROM `item` WHERE `gcontact-id` = 0 LIMIT 1000");
- if (!$r) {
- // Are there unfinished entries in the thread table?
- $r = q("SELECT COUNT(*) AS `total` FROM `thread`
- INNER JOIN `item` ON `item`.`id` =`thread`.`iid`
- WHERE `thread`.`gcontact-id` = 0 AND
- (`thread`.`uid` IN (SELECT `uid` from `user`) OR `thread`.`uid` = 0)");
-
- if ($r AND ($r[0]["total"] == 0)) {
- set_config("system", "post_update_version", POST_UPDATE_VERSION);
- return false;
- }
-
- // Update the thread table from the item table
- q("UPDATE `thread` INNER JOIN `item` ON `item`.`id`=`thread`.`iid`
- SET `thread`.`gcontact-id` = `item`.`gcontact-id`
- WHERE `thread`.`gcontact-id` = 0 AND
- (`thread`.`uid` IN (SELECT `uid` from `user`) OR `thread`.`uid` = 0)");
-
- return false;
- }
-
- $item_arr = array();
- foreach ($r AS $item) {
- $index = $item["author-link"]."-".$item["uid"];
- $item_arr[$index] = array("author-link" => $item["author-link"],
- "uid" => $item["uid"],
- "network" => $item["network"]);
- }
-
- // Set the "gcontact-id" in the item table and add a new gcontact entry if needed
- foreach($item_arr AS $item) {
- $gcontact_id = get_gcontact_id(array("url" => $item['author-link'], "network" => $item['network'],
- "photo" => $item['author-avatar'], "name" => $item['author-name']));
- q("UPDATE `item` SET `gcontact-id` = %d WHERE `uid` = %d AND `author-link` = '%s' AND `gcontact-id` = 0",
- intval($gcontact_id), intval($item["uid"]), dbesc($item["author-link"]));
- }
- return true;
-}
-
/**
* @brief Returns posts from a given contact
*
diff --git a/include/ForumManager.php b/include/ForumManager.php
index 49417d1831..6fede0204d 100644
--- a/include/ForumManager.php
+++ b/include/ForumManager.php
@@ -95,12 +95,12 @@ class ForumManager {
$selected = (($cid == $contact['id']) ? ' forum-selected' : '');
$entry = array(
- 'url' => z_root() . '/network?f=&cid=' . $contact['id'],
- 'external_url' => z_root() . '/redir/' . $contact['id'],
+ 'url' => 'network?f=&cid=' . $contact['id'],
+ 'external_url' => 'redir/' . $contact['id'],
'name' => $contact['name'],
'cid' => $contact['id'],
'selected' => $selected,
- 'micro' => proxy_url($contact['micro'], false, PROXY_SIZE_MICRO),
+ 'micro' => App::remove_baseurl(proxy_url($contact['micro'], false, PROXY_SIZE_MICRO)),
'id' => ++$id,
);
$entries[] = $entry;
@@ -187,4 +187,4 @@ class ForumManager {
return $r;
}
-}
\ No newline at end of file
+}
diff --git a/include/Scrape.php b/include/Scrape.php
index e8e9a97a16..68926a997e 100644
--- a/include/Scrape.php
+++ b/include/Scrape.php
@@ -23,13 +23,15 @@ function scrape_dfrn($url, $dont_probe = false) {
if (is_array($noscrapedata)) {
if ($noscrapedata["nick"] != "")
return($noscrapedata);
+ else
+ unset($noscrapedata["nick"]);
} else
$noscrapedata = array();
}
$s = fetch_url($url);
- if(! $s)
+ if (!$s)
return $ret;
if (!$dont_probe) {
@@ -356,7 +358,7 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
$result = array();
- if(! $url)
+ if (!$url)
return $result;
$result = Cache::get("probe_url:".$mode.":".$url);
@@ -365,6 +367,7 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
return $result;
}
+ $original_url = $url;
$network = null;
$diaspora = false;
$diaspora_base = '';
@@ -393,7 +396,12 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
else
$links = lrdd($url);
- if(count($links)) {
+ if ((count($links) == 0) AND strstr($url, "/index.php")) {
+ $url = str_replace("/index.php", "", $url);
+ $links = lrdd($url);
+ }
+
+ if (count($links)) {
$has_lrdd = true;
logger('probe_url: found lrdd links: ' . print_r($links,true), LOGGER_DATA);
@@ -440,12 +448,21 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
// aliases, let's hope we're lucky and get one that matches the feed author-uri because
// otherwise we're screwed.
+ $backup_alias = "";
+
foreach($links as $link) {
if($link['@attributes']['rel'] === 'alias') {
if(strpos($link['@attributes']['href'],'@') === false) {
if(isset($profile)) {
- if($link['@attributes']['href'] !== $profile)
- $alias = unamp($link['@attributes']['href']);
+ $alias_url = $link['@attributes']['href'];
+
+ if(($alias_url !== $profile) AND ($backup_alias == "") AND
+ ($alias_url !== str_replace("/index.php", "", $profile)))
+ $backup_alias = $alias_url;
+
+ if(($alias_url !== $profile) AND !strstr($alias_url, "index.php") AND
+ ($alias_url !== str_replace("/index.php", "", $profile)))
+ $alias = $alias_url;
}
else
$profile = unamp($link['@attributes']['href']);
@@ -453,6 +470,9 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
}
}
+ if ($alias == "")
+ $alias = $backup_alias;
+
// If the profile is different from the url then the url is abviously an alias
if (($alias == "") AND ($profile != "") AND !$at_addr AND (normalise_link($profile) != normalise_link($url)))
$alias = $url;
@@ -685,7 +705,14 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
if (($vcard["nick"] == "") AND ($data["header"]["author-nick"] != ""))
$vcard["nick"] = $data["header"]["author-nick"];
- if(!$profile AND ($data["header"]["author-link"] != "") AND !in_array($network, array("", NETWORK_FEED)))
+ if ($network == NETWORK_OSTATUS) {
+ if ($data["header"]["author-id"] != "")
+ $alias = $data["header"]["author-id"];
+
+ if ($data["header"]["author-link"] != "")
+ $profile = $data["header"]["author-link"];
+
+ } elseif(!$profile AND ($data["header"]["author-link"] != "") AND !in_array($network, array("", NETWORK_FEED)))
$profile = $data["header"]["author-link"];
}
}
@@ -769,6 +796,9 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
if (($baseurl == "") AND ($poll != ""))
$baseurl = matching_url(normalise_link($profile), normalise_link($poll));
+ if (substr($baseurl, -10) == "/index.php")
+ $baseurl = str_replace("/index.php", "", $baseurl);
+
$baseurl = rtrim($baseurl, "/");
if(strpos($url,'@') AND ($addr == "") AND ($network == NETWORK_DFRN))
@@ -816,8 +846,28 @@ function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
}
// Only store into the cache if the value seems to be valid
- if ($result['network'] != NETWORK_PHANTOM)
- Cache::set("probe_url:".$mode.":".$url,serialize($result), CACHE_DAY);
+ if ($result['network'] != NETWORK_PHANTOM) {
+ Cache::set("probe_url:".$mode.":".$original_url,serialize($result), CACHE_DAY);
+
+ /// @todo temporary fix - we need a real contact update function that updates only changing fields
+ /// The biggest problem is the avatar picture that could have a reduced image size.
+ /// It should only be updated if the existing picture isn't existing anymore.
+ if (($result['network'] != NETWORK_FEED) AND ($mode == PROBE_NORMAL) AND
+ $result["name"] AND $result["nick"] AND $result["url"] AND $result["addr"] AND $result["poll"])
+ q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `url` = '%s', `addr` = '%s',
+ `notify` = '%s', `poll` = '%s', `alias` = '%s', `success_update` = '%s'
+ WHERE `nurl` = '%s' AND NOT `self` AND `uid` = 0",
+ dbesc($result["name"]),
+ dbesc($result["nick"]),
+ dbesc($result["url"]),
+ dbesc($result["addr"]),
+ dbesc($result["notify"]),
+ dbesc($result["poll"]),
+ dbesc($result["alias"]),
+ dbesc(datetime_convert()),
+ dbesc(normalise_link($result['url']))
+ );
+ }
return $result;
}
diff --git a/include/api.php b/include/api.php
index e5ca8ca787..887b449fc0 100644
--- a/include/api.php
+++ b/include/api.php
@@ -161,10 +161,7 @@
if (!isset($_SERVER['PHP_AUTH_USER'])) {
logger('API_login: ' . print_r($_SERVER,true), LOGGER_DEBUG);
header('WWW-Authenticate: Basic realm="Friendica"');
- header('HTTP/1.0 401 Unauthorized');
- die((api_error($a, 'json', "This api requires login")));
-
- //die('This api requires login');
+ throw new UnauthorizedException("This API requires login");
}
$user = $_SERVER['PHP_AUTH_USER'];
@@ -216,8 +213,9 @@
if((! $record) || (! count($record))) {
logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG);
header('WWW-Authenticate: Basic realm="Friendica"');
- header('HTTP/1.0 401 Unauthorized');
- die('This api requires login');
+ #header('HTTP/1.0 401 Unauthorized');
+ #die('This api requires login');
+ throw new UnauthorizedException("This API requires login");
}
authenticate_success($record); $_SESSION["allow_api"] = true;
@@ -332,7 +330,8 @@
*
* @param Api $a
* @param string $type Return type (xml, json, rss, as)
- * @param string $error Error message
+ * @param HTTPException $error Error object
+ * @return strin error message formatted as $type
*/
function api_error(&$a, $type, $e) {
$error = ($e->getMessage()!==""?$e->getMessage():$e->httpdesc);
@@ -904,7 +903,8 @@
if ($posts_day > $throttle_day) {
logger('Daily posting limit reached for user '.api_user(), LOGGER_DEBUG);
- die(api_error($a, $type, sprintf(t("Daily posting limit of %d posts reached. The post was rejected."), $throttle_day)));
+ #die(api_error($a, $type, sprintf(t("Daily posting limit of %d posts reached. The post was rejected."), $throttle_day)));
+ throw new TooManyRequestsException(sprintf(t("Daily posting limit of %d posts reached. The post was rejected."), $throttle_day));
}
}
@@ -923,7 +923,9 @@
if ($posts_week > $throttle_week) {
logger('Weekly posting limit reached for user '.api_user(), LOGGER_DEBUG);
- die(api_error($a, $type, sprintf(t("Weekly posting limit of %d posts reached. The post was rejected."), $throttle_week)));
+ #die(api_error($a, $type, sprintf(t("Weekly posting limit of %d posts reached. The post was rejected."), $throttle_week)));
+ throw new TooManyRequestsException(sprintf(t("Weekly posting limit of %d posts reached. The post was rejected."), $throttle_week));
+
}
}
@@ -942,7 +944,8 @@
if ($posts_month > $throttle_month) {
logger('Monthly posting limit reached for user '.api_user(), LOGGER_DEBUG);
- die(api_error($a, $type, sprintf(t("Monthly posting limit of %d posts reached. The post was rejected."), $throttle_month)));
+ #die(api_error($a, $type, sprintf(t("Monthly posting limit of %d posts reached. The post was rejected."), $throttle_month)));
+ throw new TooManyRequestsException(sprintf(t("Monthly posting limit of %d posts reached. The post was rejected."), $throttle_month));
}
}
@@ -1548,6 +1551,7 @@
return api_apply_template("timeline", $type, $data);
}
api_register_func('api/conversation/show','api_conversation_show', true);
+ api_register_func('api/statusnet/conversation','api_conversation_show', true);
/**
@@ -1689,13 +1693,13 @@
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
- FROM `item`, `contact`
+ FROM `item` FORCE INDEX (`uid_id`), `contact`
WHERE `item`.`uid` = %d AND `verb` = '%s'
AND NOT (`item`.`author-link` IN ('https://%s', 'http://%s'))
- AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
+ AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted`
AND `contact`.`id` = `item`.`contact-id`
- AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
- AND `item`.`parent` IN (SELECT `iid` from thread where uid = %d AND `mention` AND !`ignored`)
+ AND NOT `contact`.`blocked` AND NOT `contact`.`pending`
+ AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `uid` = %d AND `mention` AND !`ignored`)
$sql_extra
AND `item`.`id`>%d
ORDER BY `item`.`id` DESC LIMIT %d ,%d ",
@@ -1810,7 +1814,7 @@
$action_argv_id=2;
if ($a->argv[1]=="1.1") $action_argv_id=3;
- if ($a->argc<=$action_argv_id) die(api_error($a, $type, t("Invalid request.")));
+ if ($a->argc<=$action_argv_id) throw new BadRequestException("Invalid request.");
$action = str_replace(".".$type,"",$a->argv[$action_argv_id]);
if ($a->argc==$action_argv_id+2) {
$itemid = intval($a->argv[$action_argv_id+1]);
diff --git a/include/bbcode.php b/include/bbcode.php
index 6a44e19ec4..8545b2ff82 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -311,6 +311,9 @@ function tryoembed($match){
$o = oembed_fetch_url($url);
+ if (!is_object($o))
+ return $match[0];
+
if (isset($match[2]))
$o->title = $match[2];
@@ -858,6 +861,8 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_spacefy',$Text);
$Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text);
+ // Remove the abstract element. It is a non visible element.
+ $Text = remove_abstract($Text);
// Move all spaces out of the tags
$Text = preg_replace("/\[(\w*)\](\s*)/ism", '$2[$1]', $Text);
@@ -1300,4 +1305,43 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
return trim($Text);
}
+
+/**
+ * @brief Removes the "abstract" element from the text
+ *
+ * @param string $text The text with BBCode
+ * @return string The same text - but without "abstract" element
+ */
+function remove_abstract($text) {
+ $text = preg_replace("/[\s|\n]*\[abstract\].*?\[\/abstract\][\s|\n]*/ism", '', $text);
+ $text = preg_replace("/[\s|\n]*\[abstract=.*?\].*?\[\/abstract][\s|\n]*/ism", '', $text);
+
+ return $text;
+}
+
+/**
+ * @brief Returns the value of the "abstract" element
+ *
+ * @param string $text The text that maybe contains the element
+ * @param string $addon The addon for which the abstract is meant for
+ * @return string The abstract
+ */
+function fetch_abstract($text, $addon = "") {
+ $abstract = "";
+ $abstracts = array();
+ $addon = strtolower($addon);
+
+ if (preg_match_all("/\[abstract=(.*?)\](.*?)\[\/abstract\]/ism",$text, $results, PREG_SET_ORDER))
+ foreach ($results AS $result)
+ $abstracts[strtolower($result[1])] = $result[2];
+
+ if (isset($abstracts[$addon]))
+ $abstract = $abstracts[$addon];
+
+ if ($abstract == "")
+ if (preg_match("/\[abstract\](.*?)\[\/abstract\]/ism",$text, $result))
+ $abstract = $result[1];
+
+ return $abstract;
+}
?>
diff --git a/include/contact_selectors.php b/include/contact_selectors.php
index a884a6b52b..3bf68f764e 100644
--- a/include/contact_selectors.php
+++ b/include/contact_selectors.php
@@ -99,7 +99,7 @@ function network_to_name($s, $profile = "") {
$networkname = str_replace($search,$replace,$s);
- if (($s == NETWORK_DIASPORA) AND ($profile != "") AND diaspora_is_redmatrix($profile)) {
+ if (($s == NETWORK_DIASPORA) AND ($profile != "") AND diaspora::is_redmatrix($profile)) {
$networkname = t("Hubzilla/Redmatrix");
$r = q("SELECT `gserver`.`platform` FROM `gcontact`
diff --git a/include/conversation.php b/include/conversation.php
index 6c33be84fb..a52502ec39 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -614,7 +614,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
if(($normalised != 'mailbox') && (x($a->contacts[$normalised])))
$profile_avatar = $a->contacts[$normalised]['thumb'];
else
- $profile_avatar = ((strlen($item['author-avatar'])) ? $a->get_cached_avatar_image($item['author-avatar']) : $item['thumb']);
+ $profile_avatar = $a->remove_baseurl(((strlen($item['author-avatar'])) ? $item['author-avatar'] : $item['thumb']));
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
call_hooks('render_location',$locate);
@@ -707,8 +707,8 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
'like' => '',
'dislike' => '',
'comment' => '',
- //'conv' => (($preview) ? '' : array('href'=> $a->get_baseurl($ssl_state) . '/display/' . $nickname . '/' . $item['id'], 'title'=> t('View in context'))),
- 'conv' => (($preview) ? '' : array('href'=> $a->get_baseurl($ssl_state) . '/display/'.$item['guid'], 'title'=> t('View in context'))),
+ //'conv' => (($preview) ? '' : array('href'=> 'display/' . $nickname . '/' . $item['id'], 'title'=> t('View in context'))),
+ 'conv' => (($preview) ? '' : array('href'=> 'display/'.$item['guid'], 'title'=> t('View in context'))),
'previewing' => $previewing,
'wait' => t('Please wait'),
'thread_level' => 1,
@@ -868,7 +868,7 @@ function item_photo_menu($item){
$status_link = $profile_link . "?url=status";
$photos_link = $profile_link . "?url=photos";
$profile_link = $profile_link . "?url=profile";
- $pm_url = $a->get_baseurl($ssl_state) . '/message/new/' . $cid;
+ $pm_url = 'message/new/' . $cid;
$zurl = '';
}
else {
@@ -882,23 +882,23 @@ function item_photo_menu($item){
$cid = $r[0]["id"];
if ($r[0]["network"] == NETWORK_DIASPORA)
- $pm_url = $a->get_baseurl($ssl_state) . '/message/new/' . $cid;
+ $pm_url = 'message/new/' . $cid;
} else
$cid = 0;
}
}
if(($cid) && (! $item['self'])) {
- $poke_link = $a->get_baseurl($ssl_state) . '/poke/?f=&c=' . $cid;
- $contact_url = $a->get_baseurl($ssl_state) . '/contacts/' . $cid;
- $posts_link = $a->get_baseurl($ssl_state) . '/contacts/' . $cid . '/posts';
+ $poke_link = 'poke/?f=&c=' . $cid;
+ $contact_url = 'contacts/' . $cid;
+ $posts_link = 'contacts/' . $cid . '/posts';
$clean_url = normalise_link($item['author-link']);
if((local_user()) && (local_user() == $item['uid'])) {
if(isset($a->contacts) && x($a->contacts,$clean_url)) {
if($a->contacts[$clean_url]['network'] === NETWORK_DIASPORA) {
- $pm_url = $a->get_baseurl($ssl_state) . '/message/new/' . $cid;
+ $pm_url = 'message/new/' . $cid;
}
}
}
@@ -921,7 +921,7 @@ function item_photo_menu($item){
if ((($cid == 0) OR ($a->contacts[$clean_url]['rel'] == CONTACT_IS_FOLLOWER)) AND
in_array($item['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
- $menu[t("Connect/Follow")] = $a->get_baseurl($ssl_state)."/follow?url=".urlencode($item['author-link']);
+ $menu[t("Connect/Follow")] = "follow?url=".urlencode($item['author-link']);
} else
$menu = array(t("View Profile") => $item['author-link']);
@@ -980,7 +980,7 @@ function builtin_activity_puller($item, &$conv_responses) {
if((activity_match($item['verb'], $verb)) && ($item['id'] != $item['parent'])) {
$url = $item['author-link'];
if((local_user()) && (local_user() == $item['uid']) && ($item['network'] === NETWORK_DFRN) && (! $item['self']) && (link_compare($item['author-link'],$item['url']))) {
- $url = z_root(true) . '/redir/' . $item['contact-id'];
+ $url = 'redir/' . $item['contact-id'];
$sparkle = ' class="sparkle" ';
}
else
@@ -1178,7 +1178,7 @@ function status_editor($a,$x, $notes_cid = 0, $popup=false) {
$o .= replace_macros($tpl,array(
'$return_path' => $query_str,
- '$action' => $a->get_baseurl(true) . '/item',
+ '$action' => 'item',
'$share' => (x($x,'button') ? $x['button'] : t('Share')),
'$upload' => t('Upload photo'),
'$shortupload' => t('upload photo'),
diff --git a/include/cron.php b/include/cron.php
index 3acf711dd1..00dd500704 100644
--- a/include/cron.php
+++ b/include/cron.php
@@ -34,22 +34,18 @@ function cron_run(&$argv, &$argc){
require_once('include/Contact.php');
require_once('include/email.php');
require_once('include/socgraph.php');
- require_once('include/pidfile.php');
require_once('mod/nodeinfo.php');
+ require_once('include/post_update.php');
load_config('config');
load_config('system');
- $maxsysload = intval(get_config('system','maxloadavg'));
- if($maxsysload < 1)
- $maxsysload = 50;
-
- $load = current_load();
- if($load) {
- if(intval($load) > $maxsysload) {
- logger('system: load ' . $load . ' too high. cron deferred to next scheduled run.');
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run") {
+ if (App::maxload_reached())
+ return;
+ if (App::is_already_running('cron', 'include/cron.php', 540))
return;
- }
}
$last = get_config('system','last_cron');
@@ -66,23 +62,6 @@ function cron_run(&$argv, &$argc){
}
}
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'cron');
- if($pidfile->is_already_running()) {
- logger("cron: Already running");
- if ($pidfile->running_time() > 9*60) {
- $pidfile->kill();
- logger("cron: killed stale process");
- // Calling a new instance
- proc_run('php','include/cron.php');
- }
- exit;
- }
- }
-
-
-
$a->set_baseurl(get_config('system','url'));
load_hooks();
@@ -93,10 +72,6 @@ function cron_run(&$argv, &$argc){
proc_run('php',"include/queue.php");
- // run diaspora photo queue process in the background
-
- proc_run('php',"include/dsprphotoq.php");
-
// run the process to discover global contacts in the background
proc_run('php',"include/discover_poco.php");
@@ -127,13 +102,14 @@ function cron_run(&$argv, &$argc){
// Check OStatus conversations
// Check only conversations with mentions (for a longer time)
- check_conversations(true);
+ ostatus::check_conversations(true);
// Check every conversation
- check_conversations(false);
+ ostatus::check_conversations(false);
- // Set the gcontact-id in the item table if missing
- item_set_gcontact();
+ // Call possible post update functions
+ // see include/post_update.php for more details
+ post_update();
// update nodeinfo data
nodeinfo_cron();
@@ -361,35 +337,37 @@ function cron_clear_cache(&$a) {
if ($max_tablesize == 0)
$max_tablesize = 100 * 1000000; // Default are 100 MB
- // Minimum fragmentation level in percent
- $fragmentation_level = intval(get_config('system','optimize_fragmentation')) / 100;
- if ($fragmentation_level == 0)
- $fragmentation_level = 0.3; // Default value is 30%
+ if ($max_tablesize > 0) {
+ // Minimum fragmentation level in percent
+ $fragmentation_level = intval(get_config('system','optimize_fragmentation')) / 100;
+ if ($fragmentation_level == 0)
+ $fragmentation_level = 0.3; // Default value is 30%
- // Optimize some tables that need to be optimized
- $r = q("SHOW TABLE STATUS");
- foreach($r as $table) {
+ // Optimize some tables that need to be optimized
+ $r = q("SHOW TABLE STATUS");
+ foreach($r as $table) {
- // Don't optimize tables that are too large
- if ($table["Data_length"] > $max_tablesize)
- continue;
+ // Don't optimize tables that are too large
+ if ($table["Data_length"] > $max_tablesize)
+ continue;
- // Don't optimize empty tables
- if ($table["Data_length"] == 0)
- continue;
+ // Don't optimize empty tables
+ if ($table["Data_length"] == 0)
+ continue;
- // Calculate fragmentation
- $fragmentation = $table["Data_free"] / $table["Data_length"];
+ // Calculate fragmentation
+ $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]);
- logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG);
+ logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG);
- // Don't optimize tables that needn't to be optimized
- if ($fragmentation < $fragmentation_level)
- continue;
+ // Don't optimize tables that needn't to be optimized
+ if ($fragmentation < $fragmentation_level)
+ continue;
- // So optimize it
- logger("Optimize Table ".$table["Name"], LOGGER_DEBUG);
- q("OPTIMIZE TABLE `%s`", dbesc($table["Name"]));
+ // So optimize it
+ logger("Optimize Table ".$table["Name"], LOGGER_DEBUG);
+ q("OPTIMIZE TABLE `%s`", dbesc($table["Name"]));
+ }
}
set_config('system','cache_last_cleared', time());
@@ -429,6 +407,9 @@ function cron_repair_database() {
// This call is very "cheap" so we can do it at any time without a problem
q("UPDATE `item` INNER JOIN `item` AS `parent` ON `parent`.`uri` = `item`.`parent-uri` AND `parent`.`uid` = `item`.`uid` SET `item`.`parent` = `parent`.`id` WHERE `item`.`parent` = 0");
+ // There was an issue where the nick vanishes from the contact table
+ q("UPDATE `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` SET `nick` = `nickname` WHERE `self` AND `nick`=''");
+
/// @todo
/// - remove thread entries without item
/// - remove sign entries without item
diff --git a/include/cronhooks.php b/include/cronhooks.php
index 8c70008e45..b6cf0e7237 100644
--- a/include/cronhooks.php
+++ b/include/cronhooks.php
@@ -19,21 +19,16 @@ function cronhooks_run(&$argv, &$argc){
require_once('include/session.php');
require_once('include/datetime.php');
- require_once('include/pidfile.php');
load_config('config');
load_config('system');
- $maxsysload = intval(get_config('system','maxloadavg'));
- if($maxsysload < 1)
- $maxsysload = 50;
-
- $load = current_load();
- if($load) {
- if(intval($load) > $maxsysload) {
- logger('system: load ' . $load . ' too high. Cronhooks deferred to next scheduled run.');
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run") {
+ if (App::maxload_reached())
+ return;
+ if (App::is_already_running('cronhooks', 'include/cronhooks.php', 1140))
return;
- }
}
$last = get_config('system','last_cronhook');
@@ -50,21 +45,6 @@ function cronhooks_run(&$argv, &$argc){
}
}
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'cronhooks');
- if($pidfile->is_already_running()) {
- logger("cronhooks: Already running");
- if ($pidfile->running_time() > 19*60) {
- $pidfile->kill();
- logger("cronhooks: killed stale process");
- // Calling a new instance
- proc_run('php','include/cronhooks.php');
- }
- exit;
- }
- }
-
$a->set_baseurl(get_config('system','url'));
load_hooks();
diff --git a/include/dbstructure.php b/include/dbstructure.php
index ddf036f2c1..e34e409023 100644
--- a/include/dbstructure.php
+++ b/include/dbstructure.php
@@ -537,17 +537,6 @@ function db_definition() {
"PRIMARY" => array("id"),
)
);
- $database["dsprphotoq"] = array(
- "fields" => array(
- "id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
- "uid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
- "msg" => array("type" => "mediumtext", "not null" => "1"),
- "attempt" => array("type" => "tinyint(4)", "not null" => "1", "default" => "0"),
- ),
- "indexes" => array(
- "PRIMARY" => array("id"),
- )
- );
$database["event"] = array(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
@@ -1246,7 +1235,6 @@ function db_definition() {
"fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"iid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
- "retract_iid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
"signed_text" => array("type" => "mediumtext", "not null" => "1"),
"signature" => array("type" => "text", "not null" => "1"),
"signer" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@@ -1254,7 +1242,6 @@ function db_definition() {
"indexes" => array(
"PRIMARY" => array("id"),
"iid" => array("iid"),
- "retract_iid" => array("retract_iid"),
)
);
$database["spam"] = array(
diff --git a/include/delivery.php b/include/delivery.php
index 021ceb9968..fe33774382 100644
--- a/include/delivery.php
+++ b/include/delivery.php
@@ -10,11 +10,11 @@ require_once("include/dfrn.php");
function delivery_run(&$argv, &$argc){
global $a, $db;
- if(is_null($a)){
+ if (is_null($a)){
$a = new App;
}
- if(is_null($db)) {
+ if (is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
@@ -32,12 +32,12 @@ function delivery_run(&$argv, &$argc){
load_hooks();
- if($argc < 3)
+ if ($argc < 3)
return;
$a->set_baseurl(get_config('system','url'));
- logger('delivery: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
+ logger('delivery: invoked: '. print_r($argv,true), LOGGER_DEBUG);
$cmd = $argv[1];
$item_id = intval($argv[2]);
@@ -53,21 +53,12 @@ function delivery_run(&$argv, &$argc){
dbesc($item_id),
dbesc($contact_id)
);
- if(! count($r)) {
+ if (!count($r)) {
continue;
}
- $maxsysload = intval(get_config('system','maxloadavg'));
- if($maxsysload < 1)
- $maxsysload = 50;
-
- $load = current_load();
- if($load) {
- if(intval($load) > $maxsysload) {
- logger('system: load ' . $load . ' too high. Delivery deferred to next queue run.');
- return;
- }
- }
+ if (App::maxload_reached())
+ return;
// It's ours to deliver. Remove it from the queue.
@@ -77,7 +68,7 @@ function delivery_run(&$argv, &$argc){
dbesc($contact_id)
);
- if((! $item_id) || (! $contact_id))
+ if (!$item_id || !$contact_id)
continue;
$expire = false;
@@ -93,20 +84,20 @@ function delivery_run(&$argv, &$argc){
$recipients[] = $contact_id;
- if($cmd === 'mail') {
+ if ($cmd === 'mail') {
$normal_mode = false;
$mail = true;
$message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
- if(! count($message)){
+ if (!count($message)){
return;
}
$uid = $message[0]['uid'];
$recipients[] = $message[0]['contact-id'];
$item = $message[0];
}
- elseif($cmd === 'expire') {
+ elseif ($cmd === 'expire') {
$normal_mode = false;
$expire = true;
$items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
@@ -115,22 +106,22 @@ function delivery_run(&$argv, &$argc){
);
$uid = $item_id;
$item_id = 0;
- if(! count($items))
+ if (!count($items))
continue;
}
- elseif($cmd === 'suggest') {
+ elseif ($cmd === 'suggest') {
$normal_mode = false;
$fsuggest = true;
$suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
- if(! count($suggest))
+ if (!count($suggest))
return;
$uid = $suggest[0]['uid'];
$recipients[] = $suggest[0]['cid'];
$item = $suggest[0];
- } elseif($cmd === 'relocate') {
+ } elseif ($cmd === 'relocate') {
$normal_mode = false;
$relocate = true;
$uid = $item_id;
@@ -140,7 +131,7 @@ function delivery_run(&$argv, &$argc){
intval($item_id)
);
- if((! count($r)) || (! intval($r[0]['parent']))) {
+ if ((!count($r)) || (!intval($r[0]['parent']))) {
continue;
}
@@ -154,32 +145,32 @@ function delivery_run(&$argv, &$argc){
intval($parent_id)
);
- if(! count($items)) {
+ if (!count($items)) {
continue;
}
$icontacts = null;
$contacts_arr = array();
foreach($items as $item)
- if(! in_array($item['contact-id'],$contacts_arr))
+ if (!in_array($item['contact-id'],$contacts_arr))
$contacts_arr[] = intval($item['contact-id']);
- if(count($contacts_arr)) {
+ if (count($contacts_arr)) {
$str_contacts = implode(',',$contacts_arr);
$icontacts = q("SELECT * FROM `contact`
WHERE `id` IN ( $str_contacts ) "
);
}
- if( ! ($icontacts && count($icontacts)))
+ if ( !($icontacts && count($icontacts)))
continue;
// avoid race condition with deleting entries
- if($items[0]['deleted']) {
+ if ($items[0]['deleted']) {
foreach($items as $item)
$item['deleted'] = 1;
}
- if((count($items) == 1) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
+ if ((count($items) == 1) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
logger('delivery: top level post');
$top_level = true;
}
@@ -193,7 +184,7 @@ function delivery_run(&$argv, &$argc){
intval($uid)
);
- if(! count($r))
+ if (!count($r))
continue;
$owner = $r[0];
@@ -202,7 +193,7 @@ function delivery_run(&$argv, &$argc){
$public_message = true;
- if(! ($mail || $fsuggest || $relocate)) {
+ if (!($mail || $fsuggest || $relocate)) {
require_once('include/group.php');
$parent = $items[0];
@@ -226,7 +217,7 @@ function delivery_run(&$argv, &$argc){
$localhost = $a->get_hostname();
- if(strpos($localhost,':'))
+ if (strpos($localhost,':'))
$localhost = substr($localhost,0,strpos($localhost,':'));
/**
@@ -239,20 +230,21 @@ function delivery_run(&$argv, &$argc){
$relay_to_owner = false;
- if((! $top_level) && ($parent['wall'] == 0) && (! $expire) && (stristr($target_item['uri'],$localhost))) {
+ if (!$top_level && ($parent['wall'] == 0) && !$expire && stristr($target_item['uri'],$localhost)) {
$relay_to_owner = true;
}
- if($relay_to_owner) {
+ if ($relay_to_owner) {
logger('followup '.$target_item["guid"], LOGGER_DEBUG);
// local followup to remote post
$followup = true;
}
- if((strlen($parent['allow_cid']))
+ if ((strlen($parent['allow_cid']))
|| (strlen($parent['allow_gid']))
|| (strlen($parent['deny_cid']))
- || (strlen($parent['deny_gid']))) {
+ || (strlen($parent['deny_gid']))
+ || $parent["private"]) {
$public_message = false; // private recipients, not public
}
@@ -262,10 +254,10 @@ function delivery_run(&$argv, &$argc){
intval($contact_id)
);
- if(count($r))
+ if (count($r))
$contact = $r[0];
- if($contact['self'])
+ if ($contact['self'])
continue;
$deliver_status = 0;
@@ -275,7 +267,7 @@ function delivery_run(&$argv, &$argc){
switch($contact['network']) {
case NETWORK_DFRN:
- logger('notifier: '.$target_item["guid"].' dfrndelivery: ' . $contact['name']);
+ logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']);
if ($mail) {
$item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']);
@@ -285,13 +277,13 @@ function delivery_run(&$argv, &$argc){
q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));
} elseif ($relocate)
$atom = dfrn::relocate($owner, $uid);
- elseif($followup) {
+ elseif ($followup) {
$msgitems = array();
foreach($items as $item) { // there is only one item
- if(!$item['parent'])
+ if (!$item['parent'])
continue;
- if($item['id'] == $item_id) {
- logger('followup: item: ' . print_r($item,true), LOGGER_DATA);
+ if ($item['id'] == $item_id) {
+ logger('followup: item: '. print_r($item,true), LOGGER_DATA);
$msgitems[] = $item;
}
}
@@ -299,19 +291,19 @@ function delivery_run(&$argv, &$argc){
} else {
$msgitems = array();
foreach($items as $item) {
- if(!$item['parent'])
+ if (!$item['parent'])
continue;
// private emails may be in included in public conversations. Filter them.
- if(($public_message) && $item['private'])
+ if ($public_message && $item['private'])
continue;
$item_contact = get_item_contact($item,$icontacts);
- if(!$item_contact)
+ if (!$item_contact)
continue;
- if($normal_mode) {
- if($item_id == $item['id'] || $item['id'] == $item['parent']) {
+ if ($normal_mode) {
+ if ($item_id == $item['id'] || $item['id'] == $item['parent']) {
$item["entry:comment-allow"] = true;
$item["entry:cid"] = (($top_level) ? $contact['id'] : 0);
$msgitems[] = $item;
@@ -326,15 +318,15 @@ function delivery_run(&$argv, &$argc){
logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG);
- logger('notifier: ' . $atom, LOGGER_DATA);
+ logger('notifier: '.$atom, LOGGER_DATA);
$basepath = implode('/', array_slice(explode('/',$contact['url']),0,3));
// perform local delivery if we are on the same site
- if(link_compare($basepath,$a->get_baseurl())) {
+ if (link_compare($basepath,$a->get_baseurl())) {
$nickname = basename($contact['url']);
- if($contact['issued-id'])
+ if ($contact['issued-id'])
$sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
else
$sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
@@ -356,10 +348,10 @@ function delivery_run(&$argv, &$argc){
dbesc($nickname)
);
- if($x && count($x)) {
+ if ($x && count($x)) {
$write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false);
- if((($owner['page-flags'] == PAGE_COMMUNITY) || ($write_flag)) && (! $x[0]['writable'])) {
- q("update contact set writable = 1 where id = %d",
+ if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) {
+ q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d",
intval($x[0]['id'])
);
$x[0]['writable'] = 1;
@@ -379,14 +371,14 @@ function delivery_run(&$argv, &$argc){
}
}
- if(! was_recently_delayed($contact['id']))
+ if (!was_recently_delayed($contact['id']))
$deliver_status = dfrn::deliver($owner,$contact,$atom);
else
$deliver_status = (-1);
logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status);
- if($deliver_status == (-1)) {
+ if ($deliver_status == (-1)) {
logger('notifier: delivery failed: queuing message');
add_to_queue($contact['id'],NETWORK_DFRN,$atom);
}
@@ -394,9 +386,9 @@ function delivery_run(&$argv, &$argc){
case NETWORK_OSTATUS:
// Do not send to otatus if we are not configured to send to public networks
- if($owner['prvnets'])
+ if ($owner['prvnets'])
break;
- if(get_config('system','ostatus_disabled') || get_config('system','dfrn_only'))
+ if (get_config('system','ostatus_disabled') || get_config('system','dfrn_only'))
break;
// There is currently no code here to distribute anything to OStatus.
@@ -406,67 +398,67 @@ function delivery_run(&$argv, &$argc){
case NETWORK_MAIL:
case NETWORK_MAIL2:
- if(get_config('system','dfrn_only'))
+ if (get_config('system','dfrn_only'))
break;
// WARNING: does not currently convert to RFC2047 header encodings, etc.
$addr = $contact['addr'];
- if(! strlen($addr))
+ if (!strlen($addr))
break;
- if($cmd === 'wall-new' || $cmd === 'comment-new') {
+ if ($cmd === 'wall-new' || $cmd === 'comment-new') {
$it = null;
- if($cmd === 'wall-new')
+ if ($cmd === 'wall-new')
$it = $items[0];
else {
$r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($argv[2]),
intval($uid)
);
- if(count($r))
+ if (count($r))
$it = $r[0];
}
- if(! $it)
+ if (!$it)
break;
$local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
- if(! count($local_user))
+ if (!count($local_user))
break;
$reply_to = '';
$r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
- if($r1 && $r1[0]['reply_to'])
+ if ($r1 && $r1[0]['reply_to'])
$reply_to = $r1[0]['reply_to'];
$subject = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ;
// only expose our real email address to true friends
- if(($contact['rel'] == CONTACT_IS_FRIEND) && (! $contact['blocked'])) {
- if($reply_to) {
+ if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
+ if ($reply_to) {
$headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n";
$headers .= 'Sender: '.$local_user[0]['email']."\n";
} else
$headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n";
} else
- $headers = 'From: ' . email_header_encode($local_user[0]['username'],'UTF-8') . ' <' . t('noreply') . '@' . $a->get_hostname() . '>' . "\n";
+ $headers = 'From: '. email_header_encode($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n";
- //if($reply_to)
- // $headers .= 'Reply-to: ' . $reply_to . "\n";
+ //if ($reply_to)
+ // $headers .= 'Reply-to: '.$reply_to . "\n";
- $headers .= 'Message-Id: <' . iri2msgid($it['uri']). '>' . "\n";
+ $headers .= 'Message-Id: <'. iri2msgid($it['uri']).'>'. "\n";
//logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
- if($it['uri'] !== $it['parent-uri']) {
+ if ($it['uri'] !== $it['parent-uri']) {
$headers .= "References: <".iri2msgid($it["parent-uri"]).">";
// If Threading is enabled, write down the correct parent
@@ -474,23 +466,23 @@ function delivery_run(&$argv, &$argc){
$headers .= " <".iri2msgid($it["thr-parent"]).">";
$headers .= "\n";
- if(!$it['title']) {
+ if (!$it['title']) {
$r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($it['parent-uri']),
intval($uid));
- if(count($r) AND ($r[0]['title'] != ''))
+ if (count($r) AND ($r[0]['title'] != ''))
$subject = $r[0]['title'];
else {
$r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($it['parent-uri']),
intval($uid));
- if(count($r) AND ($r[0]['title'] != ''))
+ if (count($r) AND ($r[0]['title'] != ''))
$subject = $r[0]['title'];
}
}
- if(strncasecmp($subject,'RE:',3))
+ if (strncasecmp($subject,'RE:',3))
$subject = 'Re: '.$subject;
}
email_send($addr, $subject, $headers, $it);
@@ -498,60 +490,59 @@ function delivery_run(&$argv, &$argc){
break;
case NETWORK_DIASPORA:
- if($public_message)
- $loc = 'public batch ' . $contact['batch'];
+ if ($public_message)
+ $loc = 'public batch '.$contact['batch'];
else
$loc = $contact['name'];
- logger('delivery: diaspora batch deliver: ' . $loc);
+ logger('delivery: diaspora batch deliver: '.$loc);
- if(get_config('system','dfrn_only') || (!get_config('system','diaspora_enabled')))
+ if (get_config('system','dfrn_only') || (!get_config('system','diaspora_enabled')))
break;
- if($mail) {
- diaspora_send_mail($item,$owner,$contact);
+ if ($mail) {
+ diaspora::send_mail($item,$owner,$contact);
break;
}
- if(!$normal_mode)
+ if (!$normal_mode)
break;
- if((! $contact['pubkey']) && (! $public_message))
+ if (!$contact['pubkey'] && !$public_message)
break;
$unsupported_activities = array(ACTIVITY_DISLIKE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE);
//don't transmit activities which are not supported by diaspora
foreach($unsupported_activities as $act) {
- if(activity_match($target_item['verb'],$act)) {
+ if (activity_match($target_item['verb'],$act)) {
break 2;
}
}
- if(($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
+ if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
// top-level retraction
- logger('delivery: diaspora retract: ' . $loc);
-
- diaspora_send_retraction($target_item,$owner,$contact,$public_message);
+ logger('diaspora retract: '.$loc);
+ diaspora::send_retraction($target_item,$owner,$contact,$public_message);
break;
- } elseif($followup) {
+ } elseif ($followup) {
// send comments and likes to owner to relay
- diaspora_send_followup($target_item,$owner,$contact,$public_message);
+ logger('diaspora followup: '.$loc);
+ diaspora::send_followup($target_item,$owner,$contact,$public_message);
break;
- } elseif($target_item['uri'] !== $target_item['parent-uri']) {
+ } elseif ($target_item['uri'] !== $target_item['parent-uri']) {
// we are the relay - send comments, likes and relayable_retractions to our conversants
- logger('delivery: diaspora relay: ' . $loc);
-
- diaspora_send_relay($target_item,$owner,$contact,$public_message);
+ logger('diaspora relay: '.$loc);
+ diaspora::send_relay($target_item,$owner,$contact,$public_message);
break;
- } elseif(($top_level) && (! $walltowall)) {
+ } elseif ($top_level && !$walltowall) {
// currently no workable solution for sending walltowall
- logger('delivery: diaspora status: ' . $loc);
- diaspora_send_status($target_item,$owner,$contact,$public_message);
+ logger('diaspora status: '.$loc);
+ diaspora::send_status($target_item,$owner,$contact,$public_message);
break;
}
- logger('delivery: diaspora unknown mode: ' . $contact['name']);
+ logger('delivery: diaspora unknown mode: '.$contact['name']);
break;
diff --git a/include/dfrn.php b/include/dfrn.php
index f7a05bdb63..14be747305 100644
--- a/include/dfrn.php
+++ b/include/dfrn.php
@@ -18,6 +18,8 @@ require_once("include/event.php");
require_once("include/text.php");
require_once("include/oembed.php");
require_once("include/html2bbcode.php");
+require_once("include/bbcode.php");
+require_once("include/xml.php");
/**
* @brief This class contain functions to create and send DFRN XML files
@@ -84,7 +86,7 @@ class dfrn {
$converse = true;
if($a->argv[$x] == 'starred')
$starred = true;
- if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1]))
+ if($a->argv[$x] == 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1]))
$category = $a->argv[$x+1];
}
}
@@ -243,7 +245,7 @@ class dfrn {
foreach($items as $item) {
// prevent private email from leaking.
- if($item['network'] === NETWORK_MAIL)
+ if($item['network'] == NETWORK_MAIL)
continue;
// public feeds get html, our own nodes use bbcode
@@ -285,17 +287,17 @@ class dfrn {
$mail = $doc->createElement("dfrn:mail");
$sender = $doc->createElement("dfrn:sender");
- xml_add_element($doc, $sender, "dfrn:name", $owner['name']);
- xml_add_element($doc, $sender, "dfrn:uri", $owner['url']);
- xml_add_element($doc, $sender, "dfrn:avatar", $owner['thumb']);
+ xml::add_element($doc, $sender, "dfrn:name", $owner['name']);
+ xml::add_element($doc, $sender, "dfrn:uri", $owner['url']);
+ xml::add_element($doc, $sender, "dfrn:avatar", $owner['thumb']);
$mail->appendChild($sender);
- xml_add_element($doc, $mail, "dfrn:id", $item['uri']);
- xml_add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']);
- xml_add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME));
- xml_add_element($doc, $mail, "dfrn:subject", $item['title']);
- xml_add_element($doc, $mail, "dfrn:content", $item['body']);
+ xml::add_element($doc, $mail, "dfrn:id", $item['uri']);
+ xml::add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']);
+ xml::add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME));
+ xml::add_element($doc, $mail, "dfrn:subject", $item['title']);
+ xml::add_element($doc, $mail, "dfrn:content", $item['body']);
$root->appendChild($mail);
@@ -318,11 +320,11 @@ class dfrn {
$suggest = $doc->createElement("dfrn:suggest");
- xml_add_element($doc, $suggest, "dfrn:url", $item['url']);
- xml_add_element($doc, $suggest, "dfrn:name", $item['name']);
- xml_add_element($doc, $suggest, "dfrn:photo", $item['photo']);
- xml_add_element($doc, $suggest, "dfrn:request", $item['request']);
- xml_add_element($doc, $suggest, "dfrn:note", $item['note']);
+ xml::add_element($doc, $suggest, "dfrn:url", $item['url']);
+ xml::add_element($doc, $suggest, "dfrn:name", $item['name']);
+ xml::add_element($doc, $suggest, "dfrn:photo", $item['photo']);
+ xml::add_element($doc, $suggest, "dfrn:request", $item['request']);
+ xml::add_element($doc, $suggest, "dfrn:note", $item['note']);
$root->appendChild($suggest);
@@ -364,16 +366,16 @@ class dfrn {
$relocate = $doc->createElement("dfrn:relocate");
- xml_add_element($doc, $relocate, "dfrn:url", $owner['url']);
- xml_add_element($doc, $relocate, "dfrn:name", $owner['name']);
- xml_add_element($doc, $relocate, "dfrn:photo", $photos[4]);
- xml_add_element($doc, $relocate, "dfrn:thumb", $photos[5]);
- xml_add_element($doc, $relocate, "dfrn:micro", $photos[6]);
- xml_add_element($doc, $relocate, "dfrn:request", $owner['request']);
- xml_add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']);
- xml_add_element($doc, $relocate, "dfrn:notify", $owner['notify']);
- xml_add_element($doc, $relocate, "dfrn:poll", $owner['poll']);
- xml_add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey'));
+ xml::add_element($doc, $relocate, "dfrn:url", $owner['url']);
+ xml::add_element($doc, $relocate, "dfrn:name", $owner['name']);
+ xml::add_element($doc, $relocate, "dfrn:photo", $photos[4]);
+ xml::add_element($doc, $relocate, "dfrn:thumb", $photos[5]);
+ xml::add_element($doc, $relocate, "dfrn:micro", $photos[6]);
+ xml::add_element($doc, $relocate, "dfrn:request", $owner['request']);
+ xml::add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']);
+ xml::add_element($doc, $relocate, "dfrn:notify", $owner['notify']);
+ xml::add_element($doc, $relocate, "dfrn:poll", $owner['poll']);
+ xml::add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey'));
$root->appendChild($relocate);
@@ -409,39 +411,39 @@ class dfrn {
$root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
$root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
- xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]);
- xml_add_element($doc, $root, "title", $owner["name"]);
+ xml::add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]);
+ xml::add_element($doc, $root, "title", $owner["name"]);
$attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION);
- xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes);
+ xml::add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes);
$attributes = array("rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/");
- xml_add_element($doc, $root, "link", "", $attributes);
+ xml::add_element($doc, $root, "link", "", $attributes);
$attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink);
- xml_add_element($doc, $root, "link", "", $attributes);
+ xml::add_element($doc, $root, "link", "", $attributes);
if ($public) {
// DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed.
- ostatus_hublinks($doc, $root);
+ ostatus::hublinks($doc, $root);
$attributes = array("rel" => "salmon", "href" => app::get_baseurl()."/salmon/".$owner["nick"]);
- xml_add_element($doc, $root, "link", "", $attributes);
+ xml::add_element($doc, $root, "link", "", $attributes);
$attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => app::get_baseurl()."/salmon/".$owner["nick"]);
- xml_add_element($doc, $root, "link", "", $attributes);
+ xml::add_element($doc, $root, "link", "", $attributes);
$attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => app::get_baseurl()."/salmon/".$owner["nick"]);
- xml_add_element($doc, $root, "link", "", $attributes);
+ xml::add_element($doc, $root, "link", "", $attributes);
}
if ($owner['page-flags'] == PAGE_COMMUNITY)
- xml_add_element($doc, $root, "dfrn:community", 1);
+ xml::add_element($doc, $root, "dfrn:community", 1);
/// @todo We need a way to transmit the different page flags like "PAGE_PRVGROUP"
- xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
+ xml::add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
$author = self::add_author($doc, $owner, $authorelement, $public);
$root->appendChild($author);
@@ -467,26 +469,26 @@ class dfrn {
$picdate = datetime_convert('UTC', 'UTC', $owner['avatar-date'].'+00:00', ATOM_TIME);
$attributes = array("dfrn:updated" => $namdate);
- xml_add_element($doc, $author, "name", $owner["name"], $attributes);
+ xml::add_element($doc, $author, "name", $owner["name"], $attributes);
$attributes = array("dfrn:updated" => $namdate);
- xml_add_element($doc, $author, "uri", app::get_baseurl().'/profile/'.$owner["nickname"], $attributes);
+ xml::add_element($doc, $author, "uri", app::get_baseurl().'/profile/'.$owner["nickname"], $attributes);
$attributes = array("dfrn:updated" => $namdate);
- xml_add_element($doc, $author, "dfrn:handle", $owner["addr"], $attributes);
+ xml::add_element($doc, $author, "dfrn:handle", $owner["addr"], $attributes);
$attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate,
"media:width" => 175, "media:height" => 175, "href" => $owner['photo']);
- xml_add_element($doc, $author, "link", "", $attributes);
+ xml::add_element($doc, $author, "link", "", $attributes);
$attributes = array("rel" => "avatar", "type" => "image/jpeg", "dfrn:updated" => $picdate,
"media:width" => 175, "media:height" => 175, "href" => $owner['photo']);
- xml_add_element($doc, $author, "link", "", $attributes);
+ xml::add_element($doc, $author, "link", "", $attributes);
$birthday = feed_birthday($owner['uid'], $owner['timezone']);
if ($birthday)
- xml_add_element($doc, $author, "dfrn:birthday", $birthday);
+ xml::add_element($doc, $author, "dfrn:birthday", $birthday);
// The following fields will only be generated if this isn't for a public feed
if ($public)
@@ -501,25 +503,25 @@ class dfrn {
intval($owner['uid']));
if ($r) {
$profile = $r[0];
- xml_add_element($doc, $author, "poco:displayName", $profile["name"]);
- xml_add_element($doc, $author, "poco:updated", $namdate);
+ xml::add_element($doc, $author, "poco:displayName", $profile["name"]);
+ xml::add_element($doc, $author, "poco:updated", $namdate);
if (trim($profile["dob"]) != "0000-00-00")
- xml_add_element($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"])));
+ xml::add_element($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"])));
- xml_add_element($doc, $author, "poco:note", $profile["about"]);
- xml_add_element($doc, $author, "poco:preferredUsername", $profile["nickname"]);
+ xml::add_element($doc, $author, "poco:note", $profile["about"]);
+ xml::add_element($doc, $author, "poco:preferredUsername", $profile["nickname"]);
$savetz = date_default_timezone_get();
date_default_timezone_set($profile["timezone"]);
- xml_add_element($doc, $author, "poco:utcOffset", date("P"));
+ xml::add_element($doc, $author, "poco:utcOffset", date("P"));
date_default_timezone_set($savetz);
if (trim($profile["homepage"]) != "") {
$urls = $doc->createElement("poco:urls");
- xml_add_element($doc, $urls, "poco:type", "homepage");
- xml_add_element($doc, $urls, "poco:value", $profile["homepage"]);
- xml_add_element($doc, $urls, "poco:primary", "true");
+ xml::add_element($doc, $urls, "poco:type", "homepage");
+ xml::add_element($doc, $urls, "poco:value", $profile["homepage"]);
+ xml::add_element($doc, $urls, "poco:primary", "true");
$author->appendChild($urls);
}
@@ -527,7 +529,7 @@ class dfrn {
$keywords = explode(",", $profile["pub_keywords"]);
foreach ($keywords AS $keyword)
- xml_add_element($doc, $author, "poco:tags", trim($keyword));
+ xml::add_element($doc, $author, "poco:tags", trim($keyword));
}
@@ -535,25 +537,25 @@ class dfrn {
$xmpp = "";
if (trim($xmpp) != "") {
$ims = $doc->createElement("poco:ims");
- xml_add_element($doc, $ims, "poco:type", "xmpp");
- xml_add_element($doc, $ims, "poco:value", $xmpp);
- xml_add_element($doc, $ims, "poco:primary", "true");
+ xml::add_element($doc, $ims, "poco:type", "xmpp");
+ xml::add_element($doc, $ims, "poco:value", $xmpp);
+ xml::add_element($doc, $ims, "poco:primary", "true");
$author->appendChild($ims);
}
if (trim($profile["locality"].$profile["region"].$profile["country-name"]) != "") {
$element = $doc->createElement("poco:address");
- xml_add_element($doc, $element, "poco:formatted", formatted_location($profile));
+ xml::add_element($doc, $element, "poco:formatted", formatted_location($profile));
if (trim($profile["locality"]) != "")
- xml_add_element($doc, $element, "poco:locality", $profile["locality"]);
+ xml::add_element($doc, $element, "poco:locality", $profile["locality"]);
if (trim($profile["region"]) != "")
- xml_add_element($doc, $element, "poco:region", $profile["region"]);
+ xml::add_element($doc, $element, "poco:region", $profile["region"]);
if (trim($profile["country-name"]) != "")
- xml_add_element($doc, $element, "poco:country", $profile["country-name"]);
+ xml::add_element($doc, $element, "poco:country", $profile["country-name"]);
$author->appendChild($element);
}
@@ -577,9 +579,9 @@ class dfrn {
$contact = get_contact_details_by_url($contact_url, $item["uid"]);
$author = $doc->createElement($element);
- xml_add_element($doc, $author, "name", $contact["name"]);
- xml_add_element($doc, $author, "uri", $contact["url"]);
- xml_add_element($doc, $author, "dfrn:handle", $contact["addr"]);
+ xml::add_element($doc, $author, "name", $contact["name"]);
+ xml::add_element($doc, $author, "uri", $contact["url"]);
+ xml::add_element($doc, $author, "dfrn:handle", $contact["addr"]);
/// @Todo
/// - Check real image type and image size
@@ -590,7 +592,7 @@ class dfrn {
"media:width" => 80,
"media:height" => 80,
"href" => $contact["photo"]);
- xml_add_element($doc, $author, "link", "", $attributes);
+ xml::add_element($doc, $author, "link", "", $attributes);
$attributes = array(
"rel" => "avatar",
@@ -598,7 +600,7 @@ class dfrn {
"media:width" => 80,
"media:height" => 80,
"href" => $contact["photo"]);
- xml_add_element($doc, $author, "link", "", $attributes);
+ xml::add_element($doc, $author, "link", "", $attributes);
return $author;
}
@@ -621,13 +623,13 @@ class dfrn {
if(!$r)
return false;
if($r->type)
- xml_add_element($doc, $entry, "activity:object-type", $r->type);
+ xml::add_element($doc, $entry, "activity:object-type", $r->type);
if($r->id)
- xml_add_element($doc, $entry, "id", $r->id);
+ xml::add_element($doc, $entry, "id", $r->id);
if($r->title)
- xml_add_element($doc, $entry, "title", $r->title);
+ xml::add_element($doc, $entry, "title", $r->title);
if($r->link) {
- if(substr($r->link,0,1) === '<') {
+ if(substr($r->link,0,1) == '<') {
if(strstr($r->link,'&') && (! strstr($r->link,'&')))
$r->link = str_replace('&','&', $r->link);
@@ -640,16 +642,16 @@ class dfrn {
$attributes = array();
foreach ($link->attributes() AS $parameter => $value)
$attributes[$parameter] = $value;
- xml_add_element($doc, $entry, "link", "", $attributes);
+ xml::add_element($doc, $entry, "link", "", $attributes);
}
}
} else {
$attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link);
- xml_add_element($doc, $entry, "link", "", $attributes);
+ xml::add_element($doc, $entry, "link", "", $attributes);
}
}
if($r->content)
- xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html"));
+ xml::add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html"));
return $entry;
}
@@ -683,7 +685,7 @@ class dfrn {
if(trim($matches[4]) != "")
$attributes["title"] = trim($matches[4]);
- xml_add_element($doc, $root, "link", "", $attributes);
+ xml::add_element($doc, $root, "link", "", $attributes);
}
}
}
@@ -710,7 +712,7 @@ class dfrn {
if($item['deleted']) {
$attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME));
- return xml_create_element($doc, "at:deleted-entry", "", $attributes);
+ return xml::create_element($doc, "at:deleted-entry", "", $attributes);
}
$entry = $doc->createElement("entry");
@@ -720,6 +722,9 @@ class dfrn {
else
$body = $item['body'];
+ // Remove the abstract element. It is only locally important.
+ $body = remove_abstract($body);
+
if ($type == 'html') {
$htmlbody = $body;
@@ -741,66 +746,66 @@ class dfrn {
$attributes = array("ref" => $parent_item, "type" => "text/html",
"href" => app::get_baseurl().'/display/'.$parent[0]['guid'],
"dfrn:diaspora_guid" => $parent[0]['guid']);
- xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes);
+ xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes);
}
- xml_add_element($doc, $entry, "id", $item["uri"]);
- xml_add_element($doc, $entry, "title", $item["title"]);
+ xml::add_element($doc, $entry, "id", $item["uri"]);
+ xml::add_element($doc, $entry, "title", $item["title"]);
- xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME));
- xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME));
+ xml::add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME));
+ xml::add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME));
// "dfrn:env" is used to read the content
- xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true));
+ xml::add_element($doc, $entry, "dfrn:env", base64url_encode($body, true));
// The "content" field is not read by the receiver. We could remove it when the type is "text"
// We keep it at the moment, maybe there is some old version that doesn't read "dfrn:env"
- xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type));
+ xml::add_element($doc, $entry, "content", (($type == 'html') ? $htmlbody : $body), array("type" => $type));
// We save this value in "plink". Maybe we should read it from there as well?
- xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html",
+ xml::add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html",
"href" => app::get_baseurl()."/display/".$item["guid"]));
// "comment-allow" is some old fashioned stuff for old Friendica versions.
// It is included in the rewritten code for completeness
if ($comment)
- xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child']));
+ xml::add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child']));
if($item['location'])
- xml_add_element($doc, $entry, "dfrn:location", $item['location']);
+ xml::add_element($doc, $entry, "dfrn:location", $item['location']);
if($item['coord'])
- xml_add_element($doc, $entry, "georss:point", $item['coord']);
+ xml::add_element($doc, $entry, "georss:point", $item['coord']);
if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']))
- xml_add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1));
+ xml::add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1));
if($item['extid'])
- xml_add_element($doc, $entry, "dfrn:extid", $item['extid']);
+ xml::add_element($doc, $entry, "dfrn:extid", $item['extid']);
if($item['bookmark'])
- xml_add_element($doc, $entry, "dfrn:bookmark", "true");
+ xml::add_element($doc, $entry, "dfrn:bookmark", "true");
if($item['app'])
- xml_add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app']));
+ xml::add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app']));
- xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]);
+ xml::add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]);
// The signed text contains the content in Markdown, the sender handle and the signatur for the content
// It is needed for relayed comments to Diaspora.
if($item['signed_text']) {
$sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer'])));
- xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign);
+ xml::add_element($doc, $entry, "dfrn:diaspora_signature", $sign);
}
- xml_add_element($doc, $entry, "activity:verb", construct_verb($item));
+ xml::add_element($doc, $entry, "activity:verb", construct_verb($item));
if ($item['object-type'] != "")
- xml_add_element($doc, $entry, "activity:object-type", $item['object-type']);
+ xml::add_element($doc, $entry, "activity:object-type", $item['object-type']);
elseif ($item['id'] == $item['parent'])
- xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_NOTE);
+ xml::add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_NOTE);
else
- xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_COMMENT);
+ xml::add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_COMMENT);
$actobj = self::create_activity($doc, "activity:object", $item['object']);
if ($actobj)
@@ -815,7 +820,7 @@ class dfrn {
if(count($tags)) {
foreach($tags as $t)
if (($type != 'html') OR ($t[0] != "@"))
- xml_add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2]));
+ xml::add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2]));
}
if(count($tags))
@@ -828,11 +833,11 @@ class dfrn {
intval($owner["uid"]),
dbesc(normalise_link($mention)));
if ($r[0]["forum"] OR $r[0]["prv"])
- xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
+ xml::add_element($doc, $entry, "link", "", array("rel" => "mentioned",
"ostatus:object-type" => ACTIVITY_OBJ_GROUP,
"href" => $mention));
else
- xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
+ xml::add_element($doc, $entry, "link", "", array("rel" => "mentioned",
"ostatus:object-type" => ACTIVITY_OBJ_PERSON,
"href" => $mention));
}
@@ -1319,7 +1324,7 @@ class dfrn {
$obj_element = $obj_doc->createElementNS(NAMESPACE_ATOM1, $element);
$activity_type = $xpath->query("activity:object-type/text()", $activity)->item(0)->nodeValue;
- xml_add_element($obj_doc, $obj_element, "type", $activity_type);
+ xml::add_element($obj_doc, $obj_element, "type", $activity_type);
$id = $xpath->query("atom:id", $activity)->item(0);
if (is_object($id))
@@ -1769,6 +1774,9 @@ class dfrn {
* @return bool Should the processing of the entries be continued?
*/
private function process_verbs($entrytype, $importer, &$item, &$is_like) {
+
+ logger("Process verb ".$item["verb"]." and object-type ".$item["object-type"]." for entrytype ".$entrytype, LOGGER_DEBUG);
+
if (($entrytype == DFRN_TOP_LEVEL)) {
// The filling of the the "contact" variable is done for legcy reasons
// The functions below are partly used by ostatus.php as well - where we have this variable
@@ -1799,11 +1807,11 @@ class dfrn {
return false;
}
} else {
- if(($item["verb"] === ACTIVITY_LIKE)
- || ($item["verb"] === ACTIVITY_DISLIKE)
- || ($item["verb"] === ACTIVITY_ATTEND)
- || ($item["verb"] === ACTIVITY_ATTENDNO)
- || ($item["verb"] === ACTIVITY_ATTENDMAYBE)) {
+ if(($item["verb"] == ACTIVITY_LIKE)
+ || ($item["verb"] == ACTIVITY_DISLIKE)
+ || ($item["verb"] == ACTIVITY_ATTEND)
+ || ($item["verb"] == ACTIVITY_ATTENDNO)
+ || ($item["verb"] == ACTIVITY_ATTENDMAYBE)) {
$is_like = true;
$item["type"] = "activity";
$item["gravity"] = GRAVITY_LIKE;
@@ -1829,7 +1837,7 @@ class dfrn {
} else
$is_like = false;
- if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) {
+ if(($item["verb"] == ACTIVITY_TAG) && ($item["object-type"] == ACTIVITY_OBJ_TAGTERM)) {
$xo = parse_xml_string($item["object"],false);
$xt = parse_xml_string($item["target"],false);
@@ -2018,14 +2026,28 @@ class dfrn {
$categories = $xpath->query("atom:category", $entry);
if ($categories) {
foreach ($categories AS $category) {
- foreach($category->attributes AS $attributes)
- if ($attributes->name == "term") {
+ $term = "";
+ $scheme = "";
+ foreach($category->attributes AS $attributes) {
+ if ($attributes->name == "term")
$term = $attributes->textContent;
+
+ if ($attributes->name == "scheme")
+ $scheme = $attributes->textContent;
+ }
+
+ if (($term != "") AND ($scheme != "")) {
+ $parts = explode(":", $scheme);
+ if ((count($parts) >= 4) AND (array_shift($parts) == "X-DFRN")) {
+ $termhash = array_shift($parts);
+ $termurl = implode(":", $parts);
+
if(strlen($item["tag"]))
$item["tag"] .= ",";
- $item["tag"] .= "#[url=".App::get_baseurl()."/search?tag=".$term."]".$term."[/url]";
+ $item["tag"] .= $termhash."[url=".$termurl."]".$term."[/url]";
}
+ }
}
}
@@ -2243,15 +2265,17 @@ class dfrn {
else
return;
- if($item["object-type"] === ACTIVITY_OBJ_EVENT) {
+ if($item["object-type"] == ACTIVITY_OBJ_EVENT) {
logger("Deleting event ".$item["event-id"], LOGGER_DEBUG);
event_delete($item["event-id"]);
}
- if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) {
+ if(($item["verb"] == ACTIVITY_TAG) && ($item["object-type"] == ACTIVITY_OBJ_TAGTERM)) {
+
$xo = parse_xml_string($item["object"],false);
$xt = parse_xml_string($item["target"],false);
- if($xt->type === ACTIVITY_OBJ_NOTE) {
+
+ if($xt->type == ACTIVITY_OBJ_NOTE) {
$i = q("SELECT `id`, `contact-id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($xt->id),
intval($importer["importer_uid"])
diff --git a/include/diaspora.php b/include/diaspora.php
index 93fe2a472f..e3a3dcd78c 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -1,1663 +1,1122 @@
0, "page-flags" => PAGE_FREELOVE);
- $result = diaspora_dispatch($importer,$msg);
- logger("Dispatcher reported ".$result, LOGGER_DEBUG);
+ $serverdata = get_config("system", "relay_server");
+ if ($serverdata == "")
+ return array();
- // Now distribute it to the followers
- $r = q("SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
- ( SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s' )
- AND `account_expired` = 0 AND `account_removed` = 0 ",
- dbesc(NETWORK_DIASPORA),
- dbesc($msg['author'])
- );
- if(count($r)) {
- foreach($r as $rr) {
- logger('diaspora_public: delivering to: ' . $rr['username']);
- diaspora_dispatch($rr,$msg);
+ $relay = array();
+
+ $servers = explode(",", $serverdata);
+
+ foreach($servers AS $server) {
+ $server = trim($server);
+ $batch = $server."/receive/public";
+
+ $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1", dbesc($batch));
+
+ if (!$relais) {
+ $addr = "relay@".str_replace("http://", "", normalise_link($server));
+
+ $r = q("INSERT INTO `contact` (`uid`, `created`, `name`, `nick`, `addr`, `url`, `nurl`, `batch`, `network`, `rel`, `blocked`, `pending`, `writable`, `name-date`, `uri-date`, `avatar-date`)
+ VALUES (0, '%s', '%s', 'relay', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, '%s', '%s', '%s')",
+ datetime_convert(),
+ dbesc($addr),
+ dbesc($addr),
+ dbesc($server),
+ dbesc(normalise_link($server)),
+ dbesc($batch),
+ dbesc(NETWORK_DIASPORA),
+ intval(CONTACT_IS_FOLLOWER),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert())
+ );
+
+ $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1", dbesc($batch));
+ if ($relais)
+ $relay[] = $relais[0];
+ } else
+ $relay[] = $relais[0];
}
- }
- else
- logger('diaspora_public: no subscribers for '.$msg["author"].' '.print_r($msg, true));
-}
-
-
-function diaspora_dispatch($importer,$msg,$attempt=1) {
-
- $ret = 0;
-
- $enabled = intval(get_config('system','diaspora_enabled'));
- if(! $enabled) {
- logger('mod-diaspora: disabled');
- return;
+ return $relay;
}
- // php doesn't like dashes in variable names
+ /**
+ * @brief repairs a signature that was double encoded
+ *
+ * The function is unused at the moment. It was copied from the old implementation.
+ *
+ * @param string $signature The signature
+ * @param string $handle The handle of the signature owner
+ * @param integer $level This value is only set inside this function to avoid endless loops
+ *
+ * @return string the repaired signature
+ */
+ private function repair_signature($signature, $handle = "", $level = 1) {
- $msg['message'] = str_replace(
- array('',''),
- array('',''),
- $msg['message']);
+ if ($signature == "")
+ return ($signature);
+ if (base64_encode(base64_decode(base64_decode($signature))) == base64_decode($signature)) {
+ $signature = base64_decode($signature);
+ logger("Repaired double encoded signature from Diaspora/Hubzilla handle ".$handle." - level ".$level, LOGGER_DEBUG);
- $parsed_xml = parse_xml_string($msg['message'],false);
-
- $xmlbase = $parsed_xml->post;
-
- logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DEBUG);
-
-
- if($xmlbase->request) {
- $ret = diaspora_request($importer,$xmlbase->request);
- }
- elseif($xmlbase->status_message) {
- $ret = diaspora_post($importer,$xmlbase->status_message,$msg);
- }
- elseif($xmlbase->profile) {
- $ret = diaspora_profile($importer,$xmlbase->profile,$msg);
- }
- elseif($xmlbase->comment) {
- $ret = diaspora_comment($importer,$xmlbase->comment,$msg);
- }
- elseif($xmlbase->like) {
- $ret = diaspora_like($importer,$xmlbase->like,$msg);
- }
- elseif($xmlbase->asphoto) {
- $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg);
- }
- elseif($xmlbase->reshare) {
- $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg);
- }
- elseif($xmlbase->retraction) {
- $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
- }
- elseif($xmlbase->signed_retraction) {
- $ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
- }
- elseif($xmlbase->relayable_retraction) {
- $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
- }
- elseif($xmlbase->photo) {
- $ret = diaspora_photo($importer,$xmlbase->photo,$msg,$attempt);
- }
- elseif($xmlbase->conversation) {
- $ret = diaspora_conversation($importer,$xmlbase->conversation,$msg);
- }
- elseif($xmlbase->message) {
- $ret = diaspora_message($importer,$xmlbase->message,$msg);
- }
- elseif($xmlbase->participation) {
- $ret = diaspora_participation($importer,$xmlbase->participation);
- }
- else {
- logger('diaspora_dispatch: unknown message type: ' . print_r($xmlbase,true));
- }
- return $ret;
-}
-
-function diaspora_handle_from_contact($contact_id) {
- $handle = False;
-
- logger("diaspora_handle_from_contact: contact id is " . $contact_id, LOGGER_DEBUG);
-
- $r = q("SELECT network, addr, self, url, nick FROM contact WHERE id = %d",
- intval($contact_id)
- );
- if($r) {
- $contact = $r[0];
-
- logger("diaspora_handle_from_contact: contact 'self' = " . $contact['self'] . " 'url' = " . $contact['url'], LOGGER_DEBUG);
-
- if($contact['network'] === NETWORK_DIASPORA) {
- $handle = $contact['addr'];
-
-// logger("diaspora_handle_from_contact: contact id is a Diaspora person, handle = " . $handle, LOGGER_DEBUG);
+ // Do a recursive call to be able to fix even multiple levels
+ if ($level < 10)
+ $signature = self::repair_signature($signature, $handle, ++$level);
}
- elseif(($contact['network'] === NETWORK_DFRN) || ($contact['self'] == 1)) {
- $baseurl_start = strpos($contact['url'],'://') + 3;
- $baseurl_length = strpos($contact['url'],'/profile') - $baseurl_start; // allows installations in a subdirectory--not sure how Diaspora will handle
- $baseurl = substr($contact['url'], $baseurl_start, $baseurl_length);
- $handle = $contact['nick'] . '@' . $baseurl;
-// logger("diaspora_handle_from_contact: contact id is a DFRN person, handle = " . $handle, LOGGER_DEBUG);
- }
+ return($signature);
}
- return $handle;
-}
+ /**
+ * @brief: Decodes incoming Diaspora message
+ *
+ * @param array $importer Array of the importer user
+ * @param string $xml urldecoded Diaspora salmon
+ *
+ * @return array
+ * 'message' -> decoded Diaspora XML message
+ * 'author' -> author diaspora handle
+ * 'key' -> author public key (converted to pkcs#8)
+ */
+ public static function decode($importer, $xml) {
-function diaspora_get_contact_by_handle($uid,$handle) {
- $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND `uid` = %d AND `addr` = '%s' LIMIT 1",
- dbesc(NETWORK_DIASPORA),
- intval($uid),
- dbesc($handle)
- );
- if($r && count($r))
- return $r[0];
+ $public = false;
+ $basedom = parse_xml_string($xml);
- $handle_parts = explode("@", $handle);
- $nurl_sql = '%%://' . $handle_parts[1] . '%%/profile/' . $handle_parts[0];
- $r = q("SELECT * FROM contact WHERE network = '%s' AND uid = %d AND nurl LIKE '%s' LIMIT 1",
- dbesc(NETWORK_DFRN),
- intval($uid),
- dbesc($nurl_sql)
- );
- if($r && count($r))
- return $r[0];
+ if (!is_object($basedom))
+ return false;
- return false;
-}
+ $children = $basedom->children('https://joindiaspora.com/protocol');
-function find_diaspora_person_by_handle($handle) {
+ if($children->header) {
+ $public = true;
+ $author_link = str_replace('acct:','',$children->header->author_id);
+ } else {
- $person = false;
- $update = false;
- $got_lock = false;
+ $encrypted_header = json_decode(base64_decode($children->encrypted_header));
- $endlessloop = 0;
- $maxloops = 10;
+ $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
+ $ciphertext = base64_decode($encrypted_header->ciphertext);
- do {
- $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1",
+ $outer_key_bundle = '';
+ openssl_private_decrypt($encrypted_aes_key_bundle,$outer_key_bundle,$importer['prvkey']);
+
+ $j_outer_key_bundle = json_decode($outer_key_bundle);
+
+ $outer_iv = base64_decode($j_outer_key_bundle->iv);
+ $outer_key = base64_decode($j_outer_key_bundle->key);
+
+ $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv);
+
+
+ $decrypted = pkcs5_unpad($decrypted);
+
+ logger('decrypted: '.$decrypted, LOGGER_DEBUG);
+ $idom = parse_xml_string($decrypted,false);
+
+ $inner_iv = base64_decode($idom->iv);
+ $inner_aes_key = base64_decode($idom->aes_key);
+
+ $author_link = str_replace('acct:','',$idom->author_id);
+ }
+
+ $dom = $basedom->children(NAMESPACE_SALMON_ME);
+
+ // figure out where in the DOM tree our data is hiding
+
+ if($dom->provenance->data)
+ $base = $dom->provenance;
+ elseif($dom->env->data)
+ $base = $dom->env;
+ elseif($dom->data)
+ $base = $dom;
+
+ if (!$base) {
+ logger('unable to locate salmon data in xml');
+ http_status_exit(400);
+ }
+
+
+ // Stash the signature away for now. We have to find their key or it won't be good for anything.
+ $signature = base64url_decode($base->sig);
+
+ // unpack the data
+
+ // strip whitespace so our data element will return to one big base64 blob
+ $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
+
+
+ // stash away some other stuff for later
+
+ $type = $base->data[0]->attributes()->type[0];
+ $keyhash = $base->sig[0]->attributes()->keyhash[0];
+ $encoding = $base->encoding;
+ $alg = $base->alg;
+
+
+ $signed_data = $data.'.'.base64url_encode($type).'.'.base64url_encode($encoding).'.'.base64url_encode($alg);
+
+
+ // decode the data
+ $data = base64url_decode($data);
+
+
+ if($public)
+ $inner_decrypted = $data;
+ else {
+
+ // Decode the encrypted blob
+
+ $inner_encrypted = base64_decode($data);
+ $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv);
+ $inner_decrypted = pkcs5_unpad($inner_decrypted);
+ }
+
+ if (!$author_link) {
+ logger('Could not retrieve author URI.');
+ http_status_exit(400);
+ }
+ // Once we have the author URI, go to the web and try to find their public key
+ // (first this will look it up locally if it is in the fcontact cache)
+ // This will also convert diaspora public key from pkcs#1 to pkcs#8
+
+ logger('Fetching key for '.$author_link);
+ $key = self::key($author_link);
+
+ if (!$key) {
+ logger('Could not retrieve author key.');
+ http_status_exit(400);
+ }
+
+ $verify = rsa_verify($signed_data,$signature,$key);
+
+ if (!$verify) {
+ logger('Message did not verify. Discarding.');
+ http_status_exit(400);
+ }
+
+ logger('Message verified.');
+
+ return array('message' => (string)$inner_decrypted,
+ 'author' => unxmlify($author_link),
+ 'key' => (string)$key);
+
+ }
+
+
+ /**
+ * @brief Dispatches public messages and find the fitting receivers
+ *
+ * @param array $msg The post that will be dispatched
+ *
+ * @return int The message id of the generated message, "true" or "false" if there was an error
+ */
+ public static function dispatch_public($msg) {
+
+ $enabled = intval(get_config("system", "diaspora_enabled"));
+ if (!$enabled) {
+ logger("diaspora is disabled");
+ return false;
+ }
+
+ // Use a dummy importer to import the data for the public copy
+ $importer = array("uid" => 0, "page-flags" => PAGE_FREELOVE);
+ $message_id = self::dispatch($importer,$msg);
+
+ // Now distribute it to the followers
+ $r = q("SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
+ (SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s')
+ AND NOT `account_expired` AND NOT `account_removed`",
+ dbesc(NETWORK_DIASPORA),
+ dbesc($msg["author"])
+ );
+ if($r) {
+ foreach($r as $rr) {
+ logger("delivering to: ".$rr["username"]);
+ self::dispatch($rr,$msg);
+ }
+ } else
+ logger("No subscribers for ".$msg["author"]." ".print_r($msg, true));
+
+ return $message_id;
+ }
+
+ /**
+ * @brief Dispatches the different message types to the different functions
+ *
+ * @param array $importer Array of the importer user
+ * @param array $msg The post that will be dispatched
+ *
+ * @return int The message id of the generated message, "true" or "false" if there was an error
+ */
+ public static function dispatch($importer, $msg) {
+
+ // The sender is the handle of the contact that sent the message.
+ // This will often be different with relayed messages (for example "like" and "comment")
+ $sender = $msg["author"];
+
+ if (!diaspora::valid_posting($msg, $fields)) {
+ logger("Invalid posting");
+ return false;
+ }
+
+ $type = $fields->getName();
+
+ logger("Received message type ".$type." from ".$sender." for user ".$importer["uid"], LOGGER_DEBUG);
+
+ switch ($type) {
+ case "account_deletion":
+ return self::receive_account_deletion($importer, $fields);
+
+ case "comment":
+ return self::receive_comment($importer, $sender, $fields, $msg["message"]);
+
+ case "contact":
+ return self::receive_contact_request($importer, $fields);
+
+ case "conversation":
+ return self::receive_conversation($importer, $msg, $fields);
+
+ case "like":
+ return self::receive_like($importer, $sender, $fields);
+
+ case "message":
+ return self::receive_message($importer, $fields);
+
+ case "participation": // Not implemented
+ return self::receive_participation($importer, $fields);
+
+ case "photo": // Not implemented
+ return self::receive_photo($importer, $fields);
+
+ case "poll_participation": // Not implemented
+ return self::receive_poll_participation($importer, $fields);
+
+ case "profile":
+ return self::receive_profile($importer, $fields);
+
+ case "reshare":
+ return self::receive_reshare($importer, $fields, $msg["message"]);
+
+ case "retraction":
+ return self::receive_retraction($importer, $sender, $fields);
+
+ case "status_message":
+ return self::receive_status_message($importer, $fields, $msg["message"]);
+
+ default:
+ logger("Unknown message type ".$type);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Checks if a posting is valid and fetches the data fields.
+ *
+ * This function does not only check the signature.
+ * It also does the conversion between the old and the new diaspora format.
+ *
+ * @param array $msg Array with the XML, the sender handle and the sender signature
+ * @param object $fields SimpleXML object that contains the posting when it is valid
+ *
+ * @return bool Is the posting valid?
+ */
+ private function valid_posting($msg, &$fields) {
+
+ $data = parse_xml_string($msg["message"], false);
+
+ if (!is_object($data))
+ return false;
+
+ $first_child = $data->getName();
+
+ // Is this the new or the old version?
+ if ($data->getName() == "XML") {
+ $oldXML = true;
+ foreach ($data->post->children() as $child)
+ $element = $child;
+ } else {
+ $oldXML = false;
+ $element = $data;
+ }
+
+ $type = $element->getName();
+ $orig_type = $type;
+
+ // All retractions are handled identically from now on.
+ // In the new version there will only be "retraction".
+ if (in_array($type, array("signed_retraction", "relayable_retraction")))
+ $type = "retraction";
+
+ if ($type == "request")
+ $type = "contact";
+
+ $fields = new SimpleXMLElement("<".$type."/>");
+
+ $signed_data = "";
+
+ foreach ($element->children() AS $fieldname => $entry) {
+ if ($oldXML) {
+ // Translation for the old XML structure
+ if ($fieldname == "diaspora_handle")
+ $fieldname = "author";
+
+ if ($fieldname == "participant_handles")
+ $fieldname = "participants";
+
+ if (in_array($type, array("like", "participation"))) {
+ if ($fieldname == "target_type")
+ $fieldname = "parent_type";
+ }
+
+ if ($fieldname == "sender_handle")
+ $fieldname = "author";
+
+ if ($fieldname == "recipient_handle")
+ $fieldname = "recipient";
+
+ if ($fieldname == "root_diaspora_id")
+ $fieldname = "root_author";
+
+ if ($type == "retraction") {
+ if ($fieldname == "post_guid")
+ $fieldname = "target_guid";
+
+ if ($fieldname == "type")
+ $fieldname = "target_type";
+ }
+ }
+
+ if ($fieldname == "author_signature")
+ $author_signature = base64_decode($entry);
+ elseif ($fieldname == "parent_author_signature")
+ $parent_author_signature = base64_decode($entry);
+ elseif ($fieldname != "target_author_signature") {
+ if ($signed_data != "") {
+ $signed_data .= ";";
+ $signed_data_parent .= ";";
+ }
+
+ $signed_data .= $entry;
+ }
+ if (!in_array($fieldname, array("parent_author_signature", "target_author_signature")) OR
+ ($orig_type == "relayable_retraction"))
+ xml::copy($entry, $fields, $fieldname);
+ }
+
+ // This is something that shouldn't happen at all.
+ if (in_array($type, array("status_message", "reshare", "profile")))
+ if ($msg["author"] != $fields->author) {
+ logger("Message handle is not the same as envelope sender. Quitting this message.");
+ return false;
+ }
+
+ // Only some message types have signatures. So we quit here for the other types.
+ if (!in_array($type, array("comment", "message", "like")))
+ return true;
+
+ // No author_signature? This is a must, so we quit.
+ if (!isset($author_signature))
+ return false;
+
+ if (isset($parent_author_signature)) {
+ $key = self::key($msg["author"]);
+
+ if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256"))
+ return false;
+ }
+
+ $key = self::key($fields->author);
+
+ return rsa_verify($signed_data, $author_signature, $key, "sha256");
+ }
+
+ /**
+ * @brief Fetches the public key for a given handle
+ *
+ * @param string $handle The handle
+ *
+ * @return string The public key
+ */
+ private function key($handle) {
+ $handle = strval($handle);
+
+ logger("Fetching diaspora key for: ".$handle);
+
+ $r = self::person_by_handle($handle);
+ if($r)
+ return $r["pubkey"];
+
+ return "";
+ }
+
+ /**
+ * @brief Fetches data for a given handle
+ *
+ * @param string $handle The handle
+ *
+ * @return array the queried data
+ */
+ private function person_by_handle($handle) {
+
+ $r = q("SELECT * FROM `fcontact` WHERE `network` = '%s' AND `addr` = '%s' LIMIT 1",
dbesc(NETWORK_DIASPORA),
dbesc($handle)
);
- if(count($r)) {
+ if ($r) {
$person = $r[0];
- logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DEBUG);
+ logger("In cache ".print_r($r,true), LOGGER_DEBUG);
// update record occasionally so it doesn't get stale
- $d = strtotime($person['updated'] . ' +00:00');
- if($d < strtotime('now - 14 days'))
+ $d = strtotime($person["updated"]." +00:00");
+ if ($d < strtotime("now - 14 days"))
$update = true;
}
+ if (!$person OR $update) {
+ logger("create or refresh", LOGGER_DEBUG);
+ $r = probe_url($handle, PROBE_DIASPORA);
- // FETCHING PERSON INFORMATION FROM REMOTE SERVER
- //
- // If the person isn't in our 'fcontact' table, or if he/she is but
- // his/her information hasn't been updated for more than 14 days, then
- // we want to fetch the person's information from the remote server.
- //
- // Note that $person isn't changed by this block of code unless the
- // person's information has been successfully fetched from the remote
- // server. So if $person was 'false' to begin with (because he/she wasn't
- // in the local cache), it'll stay false, and if $person held the local
- // cache information to begin with, it'll keep that information. That way
- // if there's a problem with the remote fetch, we can at least use our
- // cached information--it's better than nothing.
-
- if((! $person) || ($update)) {
- // Lock the function to prevent race conditions if multiple items
- // come in at the same time from a person who doesn't exist in
- // fcontact
- //
- // Don't loop forever. On the last loop, try to create the contact
- // whether the function is locked or not. Maybe the locking thread
- // has died or something. At any rate, a duplicate in 'fcontact'
- // is a much smaller problem than a deadlocked thread
- $got_lock = lock_function('find_diaspora_person_by_handle', false);
- if(($endlessloop + 1) >= $maxloops)
- $got_lock = true;
-
- if($got_lock) {
- logger('find_diaspora_person_by_handle: create or refresh', LOGGER_DEBUG);
- require_once('include/Scrape.php');
- $r = probe_url($handle, PROBE_DIASPORA);
-
- // Note that Friendica contacts can return a "Diaspora person"
- // if Diaspora connectivity is enabled on their server
- if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) {
- add_fcontact($r,$update);
- $person = ($r);
- }
-
- unlock_function('find_diaspora_person_by_handle');
- }
- else {
- logger('find_diaspora_person_by_handle: couldn\'t lock function', LOGGER_DEBUG);
- if(! $person)
- block_on_function_lock('find_diaspora_person_by_handle');
+ // Note that Friendica contacts will return a "Diaspora person"
+ // if Diaspora connectivity is enabled on their server
+ if ($r AND ($r["network"] === NETWORK_DIASPORA)) {
+ self::add_fcontact($r, $update);
+ $person = $r;
}
}
- } while((! $person) && (! $got_lock) && (++$endlessloop < $maxloops));
- // We need to try again if the person wasn't in 'fcontact' but the function was locked.
- // The fact that the function was locked may mean that another process was creating the
- // person's record. It could also mean another process was creating or updating an unrelated
- // person.
- //
- // At any rate, we need to keep trying until we've either got the person or had a chance to
- // try to fetch his/her remote information. But we don't want to block on locking the
- // function, because if the other process is creating the record, then when we acquire the lock
- // we'll dive right into creating another, duplicate record. We DO want to at least wait
- // until the lock is released, so we don't flood the database with requests.
- //
- // If the person was in the 'fcontact' table, don't try again. It's not worth the time, since
- // we do have some information for the person
-
- return $person;
-}
-
-
-function get_diaspora_key($uri) {
- logger('Fetching diaspora key for: ' . $uri);
-
- $r = find_diaspora_person_by_handle($uri);
- if($r)
- return $r['pubkey'];
- return '';
-}
-
-
-function diaspora_pubmsg_build($msg,$user,$contact,$prvkey,$pubkey) {
- $a = get_app();
-
- logger('diaspora_pubmsg_build: ' . $msg, LOGGER_DATA);
-
-
- $handle = $user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-
-// $b64_data = base64_encode($msg);
-// $b64url_data = base64url_encode($b64_data);
-
- $b64url_data = base64url_encode($msg);
-
- $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data);
-
- $type = 'application/xml';
- $encoding = 'base64url';
- $alg = 'RSA-SHA256';
-
- $signable_data = $data . '.' . base64url_encode($type) . '.'
- . base64url_encode($encoding) . '.' . base64url_encode($alg) ;
-
- $signature = rsa_sign($signable_data,$prvkey);
- $sig = base64url_encode($signature);
-
-$magic_env = <<< EOT
-
-
-
- $handle
-
-
- base64url
- RSA-SHA256
- $data
- $sig
-
-
-EOT;
-
- logger('diaspora_pubmsg_build: magic_env: ' . $magic_env, LOGGER_DATA);
- return $magic_env;
-
-}
-
-
-
-
-function diaspora_msg_build($msg,$user,$contact,$prvkey,$pubkey,$public = false) {
- $a = get_app();
-
- if($public)
- return diaspora_pubmsg_build($msg,$user,$contact,$prvkey,$pubkey);
-
- logger('diaspora_msg_build: ' . $msg, LOGGER_DATA);
-
- // without a public key nothing will work
-
- if(! $pubkey) {
- logger('diaspora_msg_build: pubkey missing: contact id: ' . $contact['id']);
- return '';
+ return $person;
}
- $inner_aes_key = random_string(32);
- $b_inner_aes_key = base64_encode($inner_aes_key);
- $inner_iv = random_string(16);
- $b_inner_iv = base64_encode($inner_iv);
+ /**
+ * @brief Updates the fcontact table
+ *
+ * @param array $arr The fcontact data
+ * @param bool $update Update or insert?
+ *
+ * @return string The id of the fcontact entry
+ */
+ private function add_fcontact($arr, $update = false) {
- $outer_aes_key = random_string(32);
- $b_outer_aes_key = base64_encode($outer_aes_key);
- $outer_iv = random_string(16);
- $b_outer_iv = base64_encode($outer_iv);
-
- $handle = $user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-
- $padded_data = pkcs5_pad($msg,16);
- $inner_encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $padded_data, MCRYPT_MODE_CBC, $inner_iv);
-
- $b64_data = base64_encode($inner_encrypted);
-
-
- $b64url_data = base64url_encode($b64_data);
- $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data);
-
- $type = 'application/xml';
- $encoding = 'base64url';
- $alg = 'RSA-SHA256';
-
- $signable_data = $data . '.' . base64url_encode($type) . '.'
- . base64url_encode($encoding) . '.' . base64url_encode($alg) ;
-
- $signature = rsa_sign($signable_data,$prvkey);
- $sig = base64url_encode($signature);
-
-$decrypted_header = <<< EOT
-
- $b_inner_iv
- $b_inner_aes_key
- $handle
-
-EOT;
-
- $decrypted_header = pkcs5_pad($decrypted_header,16);
-
- $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $outer_aes_key, $decrypted_header, MCRYPT_MODE_CBC, $outer_iv);
-
- $outer_json = json_encode(array('iv' => $b_outer_iv,'key' => $b_outer_aes_key));
-
- $encrypted_outer_key_bundle = '';
- openssl_public_encrypt($outer_json,$encrypted_outer_key_bundle,$pubkey);
-
- $b64_encrypted_outer_key_bundle = base64_encode($encrypted_outer_key_bundle);
-
- logger('outer_bundle: ' . $b64_encrypted_outer_key_bundle . ' key: ' . $pubkey, LOGGER_DATA);
-
- $encrypted_header_json_object = json_encode(array('aes_key' => base64_encode($encrypted_outer_key_bundle),
- 'ciphertext' => base64_encode($ciphertext)));
- $cipher_json = base64_encode($encrypted_header_json_object);
-
- $encrypted_header = '' . $cipher_json . '';
-
-$magic_env = <<< EOT
-
-
- $encrypted_header
-
- base64url
- RSA-SHA256
- $data
- $sig
-
-
-EOT;
-
- logger('diaspora_msg_build: magic_env: ' . $magic_env, LOGGER_DATA);
- return $magic_env;
-
-}
-
-/**
- *
- * diaspora_decode($importer,$xml)
- * array $importer -> from user table
- * string $xml -> urldecoded Diaspora salmon
- *
- * Returns array
- * 'message' -> decoded Diaspora XML message
- * 'author' -> author diaspora handle
- * 'key' -> author public key (converted to pkcs#8)
- *
- * Author and key are used elsewhere to save a lookup for verifying replies and likes
- */
-
-
-function diaspora_decode($importer,$xml) {
-
- $public = false;
- $basedom = parse_xml_string($xml);
-
- $children = $basedom->children('https://joindiaspora.com/protocol');
-
- if($children->header) {
- $public = true;
- $author_link = str_replace('acct:','',$children->header->author_id);
- }
- else {
-
- $encrypted_header = json_decode(base64_decode($children->encrypted_header));
-
- $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
- $ciphertext = base64_decode($encrypted_header->ciphertext);
-
- $outer_key_bundle = '';
- openssl_private_decrypt($encrypted_aes_key_bundle,$outer_key_bundle,$importer['prvkey']);
-
- $j_outer_key_bundle = json_decode($outer_key_bundle);
-
- $outer_iv = base64_decode($j_outer_key_bundle->iv);
- $outer_key = base64_decode($j_outer_key_bundle->key);
-
- $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv);
-
-
- $decrypted = pkcs5_unpad($decrypted);
-
- /**
- * $decrypted now contains something like
- *
- *
- * 8e+G2+ET8l5BPuW0sVTnQw==
- * UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU=
-
-***** OBSOLETE
-
- *
- * Ryan Hughes
- * acct:galaxor@diaspora.pirateship.org
- *
-
-***** CURRENT
-
- * galaxor@diaspora.priateship.org
-
-***** END DIFFS
-
- *
- */
-
- logger('decrypted: ' . $decrypted, LOGGER_DEBUG);
- $idom = parse_xml_string($decrypted,false);
-
- $inner_iv = base64_decode($idom->iv);
- $inner_aes_key = base64_decode($idom->aes_key);
-
- $author_link = str_replace('acct:','',$idom->author_id);
+ if($update) {
+ $r = q("UPDATE `fcontact` SET
+ `name` = '%s',
+ `photo` = '%s',
+ `request` = '%s',
+ `nick` = '%s',
+ `addr` = '%s',
+ `batch` = '%s',
+ `notify` = '%s',
+ `poll` = '%s',
+ `confirm` = '%s',
+ `alias` = '%s',
+ `pubkey` = '%s',
+ `updated` = '%s'
+ WHERE `url` = '%s' AND `network` = '%s'",
+ dbesc($arr["name"]),
+ dbesc($arr["photo"]),
+ dbesc($arr["request"]),
+ dbesc($arr["nick"]),
+ dbesc($arr["addr"]),
+ dbesc($arr["batch"]),
+ dbesc($arr["notify"]),
+ dbesc($arr["poll"]),
+ dbesc($arr["confirm"]),
+ dbesc($arr["alias"]),
+ dbesc($arr["pubkey"]),
+ dbesc(datetime_convert()),
+ dbesc($arr["url"]),
+ dbesc($arr["network"])
+ );
+ } else {
+ $r = q("INSERT INTO `fcontact` (`url`,`name`,`photo`,`request`,`nick`,`addr`,
+ `batch`, `notify`,`poll`,`confirm`,`network`,`alias`,`pubkey`,`updated`)
+ VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')",
+ dbesc($arr["url"]),
+ dbesc($arr["name"]),
+ dbesc($arr["photo"]),
+ dbesc($arr["request"]),
+ dbesc($arr["nick"]),
+ dbesc($arr["addr"]),
+ dbesc($arr["batch"]),
+ dbesc($arr["notify"]),
+ dbesc($arr["poll"]),
+ dbesc($arr["confirm"]),
+ dbesc($arr["network"]),
+ dbesc($arr["alias"]),
+ dbesc($arr["pubkey"]),
+ dbesc(datetime_convert())
+ );
+ }
+ return $r;
}
- $dom = $basedom->children(NAMESPACE_SALMON_ME);
+ /**
+ * @brief get a handle (user@domain.tld) from a given contact id or gcontact id
+ *
+ * @param int $contact_id The id in the contact table
+ * @param int $gcontact_id The id in the gcontact table
+ *
+ * @return string the handle
+ */
+ public static function handle_from_contact($contact_id, $gcontact_id = 0) {
+ $handle = False;
- // figure out where in the DOM tree our data is hiding
+ logger("contact id is ".$contact_id." - gcontact id is ".$gcontact_id, LOGGER_DEBUG);
- if($dom->provenance->data)
- $base = $dom->provenance;
- elseif($dom->env->data)
- $base = $dom->env;
- elseif($dom->data)
- $base = $dom;
+ if ($gcontact_id != 0) {
+ $r = q("SELECT `addr` FROM `gcontact` WHERE `id` = %d AND `addr` != ''",
+ intval($gcontact_id));
+ if ($r)
+ return $r[0]["addr"];
+ }
- if(! $base) {
- logger('mod-diaspora: unable to locate salmon data in xml ');
- http_status_exit(400);
+ $r = q("SELECT `network`, `addr`, `self`, `url`, `nick` FROM `contact` WHERE `id` = %d",
+ intval($contact_id));
+ if ($r) {
+ $contact = $r[0];
+
+ logger("contact 'self' = ".$contact['self']." 'url' = ".$contact['url'], LOGGER_DEBUG);
+
+ if($contact['addr'] != "")
+ $handle = $contact['addr'];
+ else {
+ $baseurl_start = strpos($contact['url'],'://') + 3;
+ $baseurl_length = strpos($contact['url'],'/profile') - $baseurl_start; // allows installations in a subdirectory--not sure how Diaspora will handle
+ $baseurl = substr($contact['url'], $baseurl_start, $baseurl_length);
+ $handle = $contact['nick'].'@'.$baseurl;
+ }
+ }
+
+ return $handle;
}
+ /**
+ * @brief Get a contact id for a given handle
+ *
+ * @param int $uid The user id
+ * @param string $handle The handle in the format user@domain.tld
+ *
+ * @return The contact id
+ */
+ private function contact_by_handle($uid, $handle) {
+ $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `addr` = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($handle)
+ );
- // Stash the signature away for now. We have to find their key or it won't be good for anything.
- $signature = base64url_decode($base->sig);
+ if ($r)
+ return $r[0];
- // unpack the data
+ $handle_parts = explode("@", $handle);
+ $nurl_sql = "%%://".$handle_parts[1]."%%/profile/".$handle_parts[0];
+ $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND `uid` = %d AND `nurl` LIKE '%s' LIMIT 1",
+ dbesc(NETWORK_DFRN),
+ intval($uid),
+ dbesc($nurl_sql)
+ );
+ if($r)
+ return $r[0];
- // strip whitespace so our data element will return to one big base64 blob
- $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
-
-
- // stash away some other stuff for later
-
- $type = $base->data[0]->attributes()->type[0];
- $keyhash = $base->sig[0]->attributes()->keyhash[0];
- $encoding = $base->encoding;
- $alg = $base->alg;
-
-
- $signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg);
-
-
- // decode the data
- $data = base64url_decode($data);
-
-
- if($public) {
- $inner_decrypted = $data;
- }
- else {
-
- // Decode the encrypted blob
-
- $inner_encrypted = base64_decode($data);
- $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv);
- $inner_decrypted = pkcs5_unpad($inner_decrypted);
+ return false;
}
- if(! $author_link) {
- logger('mod-diaspora: Could not retrieve author URI.');
- http_status_exit(400);
- }
-
- // Once we have the author URI, go to the web and try to find their public key
- // (first this will look it up locally if it is in the fcontact cache)
- // This will also convert diaspora public key from pkcs#1 to pkcs#8
-
- logger('mod-diaspora: Fetching key for ' . $author_link );
- $key = get_diaspora_key($author_link);
-
- if(! $key) {
- logger('mod-diaspora: Could not retrieve author key.');
- http_status_exit(400);
- }
-
- $verify = rsa_verify($signed_data,$signature,$key);
-
- if(! $verify) {
- logger('mod-diaspora: Message did not verify. Discarding.');
- http_status_exit(400);
- }
-
- logger('mod-diaspora: Message verified.');
-
- return array('message' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
-
-}
-
-
-function diaspora_request($importer,$xml) {
-
- $a = get_app();
-
- $sender_handle = unxmlify($xml->sender_handle);
- $recipient_handle = unxmlify($xml->recipient_handle);
-
- if(! $sender_handle || ! $recipient_handle)
- return;
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
-
- if($contact) {
+ /**
+ * @brief Check if posting is allowed for this contact
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact that is checked
+ * @param bool $is_comment Is the check for a comment?
+ *
+ * @return bool is the contact allowed to post?
+ */
+ private function post_allow($importer, $contact, $is_comment = false) {
// perhaps we were already sharing with this person. Now they're sharing with us.
// That makes us friends.
-
- if($contact['rel'] == CONTACT_IS_FOLLOWER && in_array($importer['page-flags'], array(PAGE_FREELOVE))) {
+ // Normally this should have handled by getting a request - but this could get lost
+ if($contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) {
q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d",
intval(CONTACT_IS_FRIEND),
- intval($contact['id']),
- intval($importer['uid'])
+ intval($contact["id"]),
+ intval($importer["uid"])
);
- }
- // send notification
-
- $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1",
- intval($importer['uid'])
- );
-
- if((count($r)) && (!$r[0]['hide-friends']) && (!$contact['hidden']) && intval(get_pconfig($importer['uid'],'system','post_newfriend'))) {
- require_once('include/items.php');
-
- $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
- intval($importer['uid'])
- );
-
- // they are not CONTACT_IS_FOLLOWER anymore but that's what we have in the array
-
- if(count($self) && $contact['rel'] == CONTACT_IS_FOLLOWER) {
-
- $arr = array();
- $arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $importer['uid']);
- $arr['uid'] = $importer['uid'];
- $arr['contact-id'] = $self[0]['id'];
- $arr['wall'] = 1;
- $arr['type'] = 'wall';
- $arr['gravity'] = 0;
- $arr['origin'] = 1;
- $arr['author-name'] = $arr['owner-name'] = $self[0]['name'];
- $arr['author-link'] = $arr['owner-link'] = $self[0]['url'];
- $arr['author-avatar'] = $arr['owner-avatar'] = $self[0]['thumb'];
- $arr['verb'] = ACTIVITY_FRIEND;
- $arr['object-type'] = ACTIVITY_OBJ_PERSON;
-
- $A = '[url=' . $self[0]['url'] . ']' . $self[0]['name'] . '[/url]';
- $B = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
- $BPhoto = '[url=' . $contact['url'] . ']' . '[img]' . $contact['thumb'] . '[/img][/url]';
- $arr['body'] = sprintf( t('%1$s is now friends with %2$s'), $A, $B)."\n\n\n".$Bphoto;
-
- $arr['object'] = '' . "\n";
- $arr['last-child'] = 1;
-
- $arr['allow_cid'] = $user[0]['allow_cid'];
- $arr['allow_gid'] = $user[0]['allow_gid'];
- $arr['deny_cid'] = $user[0]['deny_cid'];
- $arr['deny_gid'] = $user[0]['deny_gid'];
-
- $i = item_store($arr);
- if($i)
- proc_run('php',"include/notifier.php","activity","$i");
-
- }
-
+ $contact["rel"] = CONTACT_IS_FRIEND;
+ logger("defining user ".$contact["nick"]." as friend");
}
- return;
- }
+ if(($contact["blocked"]) || ($contact["readonly"]) || ($contact["archive"]))
+ return false;
+ if($contact["rel"] == CONTACT_IS_SHARING || $contact["rel"] == CONTACT_IS_FRIEND)
+ return true;
+ if($contact["rel"] == CONTACT_IS_FOLLOWER)
+ if(($importer["page-flags"] == PAGE_COMMUNITY) OR $is_comment)
+ return true;
- $ret = find_diaspora_person_by_handle($sender_handle);
-
-
- if((! count($ret)) || ($ret['network'] != NETWORK_DIASPORA)) {
- logger('diaspora_request: Cannot resolve diaspora handle ' . $sender_handle . ' for ' . $recipient_handle);
- return;
- }
-
- $batch = (($ret['batch']) ? $ret['batch'] : implode('/', array_slice(explode('/',$ret['url']),0,3)) . '/receive/public');
-
-
-
- $r = q("INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`)
- VALUES ( %d, '%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d) ",
- intval($importer['uid']),
- dbesc($ret['network']),
- dbesc($ret['addr']),
- datetime_convert(),
- dbesc($ret['url']),
- dbesc(normalise_link($ret['url'])),
- dbesc($batch),
- dbesc($ret['name']),
- dbesc($ret['nick']),
- dbesc($ret['photo']),
- dbesc($ret['pubkey']),
- dbesc($ret['notify']),
- dbesc($ret['poll']),
- 1,
- 2
- );
-
- // find the contact record we just created
-
- $contact_record = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
-
- if(! $contact_record) {
- logger('diaspora_request: unable to locate newly created contact record.');
- return;
- }
-
- $g = q("select def_gid from user where uid = %d limit 1",
- intval($importer['uid'])
- );
- if($g && intval($g[0]['def_gid'])) {
- require_once('include/group.php');
- group_add_member($importer['uid'],'',$contact_record['id'],$g[0]['def_gid']);
- }
-
- if($importer['page-flags'] == PAGE_NORMAL) {
-
- $hash = random_string() . (string) time(); // Generate a confirm_key
-
- $ret = q("INSERT INTO `intro` ( `uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime` )
- VALUES ( %d, %d, %d, %d, '%s', '%s', '%s' )",
- intval($importer['uid']),
- intval($contact_record['id']),
- 0,
- 0,
- dbesc( t('Sharing notification from Diaspora network')),
- dbesc($hash),
- dbesc(datetime_convert())
- );
- }
- else {
-
- // automatic friend approval
-
- require_once('include/Photo.php');
-
- update_contact_avatar($contact_record['photo'],$importer['uid'],$contact_record['id']);
-
- // technically they are sharing with us (CONTACT_IS_SHARING),
- // but if our page-type is PAGE_COMMUNITY or PAGE_SOAPBOX
- // we are going to change the relationship and make them a follower.
-
- if($importer['page-flags'] == PAGE_FREELOVE)
- $new_relation = CONTACT_IS_FRIEND;
- else
- $new_relation = CONTACT_IS_FOLLOWER;
-
- $r = q("UPDATE `contact` SET `rel` = %d,
- `name-date` = '%s',
- `uri-date` = '%s',
- `blocked` = 0,
- `pending` = 0,
- `writable` = 1
- WHERE `id` = %d
- ",
- intval($new_relation),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- intval($contact_record['id'])
- );
-
- $u = q("select * from user where uid = %d limit 1",intval($importer['uid']));
- if($u)
- $ret = diaspora_share($u[0],$contact_record);
- }
-
- return;
-}
-
-function diaspora_post_allow($importer,$contact, $is_comment = false) {
-
- // perhaps we were already sharing with this person. Now they're sharing with us.
- // That makes us friends.
- // Normally this should have handled by getting a request - but this could get lost
- if($contact['rel'] == CONTACT_IS_FOLLOWER && in_array($importer['page-flags'], array(PAGE_FREELOVE))) {
- q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d",
- intval(CONTACT_IS_FRIEND),
- intval($contact['id']),
- intval($importer['uid'])
- );
- $contact['rel'] = CONTACT_IS_FRIEND;
- logger('diaspora_post_allow: defining user '.$contact["nick"].' as friend');
- }
-
- if(($contact['blocked']) || ($contact['readonly']) || ($contact['archive']))
- return false;
- if($contact['rel'] == CONTACT_IS_SHARING || $contact['rel'] == CONTACT_IS_FRIEND)
- return true;
- if($contact['rel'] == CONTACT_IS_FOLLOWER)
- if(($importer['page-flags'] == PAGE_COMMUNITY) OR $is_comment)
+ // Messages for the global users are always accepted
+ if ($importer["uid"] == 0)
return true;
- // Messages for the global users are always accepted
- if ($importer['uid'] == 0)
- return true;
-
- return false;
-}
-
-function diaspora_is_redmatrix($url) {
- return(strstr($url, "/channel/"));
-}
-
-function diaspora_plink($addr, $guid) {
- $r = q("SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", dbesc($addr));
-
- // Fallback
- if (!$r)
- return 'https://'.substr($addr,strpos($addr,'@')+1).'/posts/'.$guid;
-
- // Friendica contacts are often detected as Diaspora contacts in the "fcontact" table
- // So we try another way as well.
- $s = q("SELECT `network` FROM `gcontact` WHERE `nurl`='%s' LIMIT 1", dbesc(normalise_link($r[0]["url"])));
- if ($s)
- $r[0]["network"] = $s[0]["network"];
-
- if ($r[0]["network"] == NETWORK_DFRN)
- return(str_replace("/profile/".$r[0]["nick"]."/", "/display/".$guid, $r[0]["url"]."/"));
-
- if (diaspora_is_redmatrix($r[0]["url"]))
- return $r[0]["url"]."/?f=&mid=".$guid;
-
- return 'https://'.substr($addr,strpos($addr,'@')+1).'/posts/'.$guid;
-}
-
-function diaspora_repair_signature($signature, $handle = "", $level = 1) {
-
- if ($signature == "")
- return($signature);
-
- if (base64_encode(base64_decode(base64_decode($signature))) == base64_decode($signature)) {
- $signature = base64_decode($signature);
- logger("Repaired double encoded signature from Diaspora/Hubzilla handle ".$handle." - level ".$level, LOGGER_DEBUG);
-
- // Do a recursive call to be able to fix even multiple levels
- if ($level < 10)
- $signature = diaspora_repair_signature($signature, $handle, ++$level);
- }
-
- return($signature);
-}
-
-function diaspora_post($importer,$xml,$msg) {
-
- $a = get_app();
- $guid = notags(unxmlify($xml->guid));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
-
- if($diaspora_handle != $msg['author']) {
- logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.');
- return 202;
- }
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact) {
- logger('diaspora_post: A Contact for handle '.$diaspora_handle.' and user '.$importer['uid'].' was not found');
- return 203;
- }
-
- if(! diaspora_post_allow($importer,$contact, false)) {
- logger('diaspora_post: Ignoring this author.');
- return 202;
- }
-
- $message_id = $diaspora_handle . ':' . $guid;
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($r)) {
- logger('diaspora_post: message exists: ' . $guid);
- return 208;
- }
-
- $created = unxmlify($xml->created_at);
- $private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
-
- $body = diaspora2bb($xml->raw_message);
-
- $datarray = array();
-
- $datarray["object"] = json_encode($xml);
-
- if($xml->photo->remote_photo_path AND $xml->photo->remote_photo_name)
- $datarray["object-type"] = ACTIVITY_OBJ_PHOTO;
- else {
- $datarray['object-type'] = ACTIVITY_OBJ_NOTE;
- // Add OEmbed and other information to the body
- if (!diaspora_is_redmatrix($contact['url']))
- $body = add_page_info_to_body($body, false, true);
- }
-
- $str_tags = '';
-
- $cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
- if($cnt) {
- foreach($matches as $mtch) {
- if(strlen($str_tags))
- $str_tags .= ',';
- $str_tags .= '@[url=' . $mtch[1] . '[/url]';
- }
- }
-
- $plink = diaspora_plink($diaspora_handle, $guid);
-
- $datarray['uid'] = $importer['uid'];
- $datarray['contact-id'] = $contact['id'];
- $datarray['wall'] = 0;
- $datarray['network'] = NETWORK_DIASPORA;
- $datarray['verb'] = ACTIVITY_POST;
- $datarray['guid'] = $guid;
- $datarray['uri'] = $datarray['parent-uri'] = $message_id;
- $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
- $datarray['private'] = $private;
- $datarray['parent'] = 0;
- $datarray['plink'] = $plink;
- $datarray['owner-name'] = $contact['name'];
- $datarray['owner-link'] = $contact['url'];
- //$datarray['owner-avatar'] = $contact['thumb'];
- $datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']);
- $datarray['author-name'] = $contact['name'];
- $datarray['author-link'] = $contact['url'];
- $datarray['author-avatar'] = $contact['thumb'];
- $datarray['body'] = $body;
- $datarray['tag'] = $str_tags;
- if ($xml->provider_display_name)
- $datarray["app"] = unxmlify($xml->provider_display_name);
- else
- $datarray['app'] = 'Diaspora';
-
- // if empty content it might be a photo that hasn't arrived yet. If a photo arrives, we'll make it visible.
-
- $datarray['visible'] = ((strlen($body)) ? 1 : 0);
-
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
-
- logger("Stored item with message id ".$message_id, LOGGER_DEBUG);
-
- return 201;
-
-}
-
-function DiasporaFetchGuid($item) {
- preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
- function ($match) use ($item){
- return(DiasporaFetchGuidSub($match, $item));
- },$item["body"]);
-}
-
-function DiasporaFetchGuidSub($match, $item) {
- $a = get_app();
-
- if (!diaspora_store_by_guid($match[1], $item["author-link"]))
- diaspora_store_by_guid($match[1], $item["owner-link"]);
-}
-
-function diaspora_store_by_guid($guid, $server, $uid = 0) {
- require_once("include/Contact.php");
-
- $serverparts = parse_url($server);
- $server = $serverparts["scheme"]."://".$serverparts["host"];
-
- logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
-
- $item = diaspora_fetch_message($guid, $server);
-
- if (!$item)
return false;
+ }
- logger("Successfully fetched item ".$guid." from ".$server, LOGGER_DEBUG);
-
- $body = $item["body"];
- $str_tags = $item["tag"];
- $app = $item["app"];
- $created = $item["created"];
- $author = $item["author"];
- $guid = $item["guid"];
- $private = $item["private"];
- $object = $item["object"];
- $objecttype = $item["object-type"];
-
- $message_id = $author.':'.$guid;
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($uid),
- dbesc($guid)
- );
- if(count($r))
- return $r[0]["id"];
-
- $person = find_diaspora_person_by_handle($author);
-
- $contact_id = get_contact($person['url'], $uid);
-
- $contacts = q("SELECT * FROM `contact` WHERE `id` = %d", intval($contact_id));
- $importers = q("SELECT * FROM `user` WHERE `uid` = %d", intval($uid));
-
- if ($contacts AND $importers)
- if(!diaspora_post_allow($importers[0],$contacts[0], false)) {
- logger('Ignoring author '.$person['url'].' for uid '.$uid);
+ /**
+ * @brief Fetches the contact id for a handle and checks if posting is allowed
+ *
+ * @param array $importer Array of the importer user
+ * @param string $handle The checked handle in the format user@domain.tld
+ * @param bool $is_comment Is the check for a comment?
+ *
+ * @return array The contact data
+ */
+ private function allowed_contact_by_handle($importer, $handle, $is_comment = false) {
+ $contact = self::contact_by_handle($importer["uid"], $handle);
+ if (!$contact) {
+ logger("A Contact for handle ".$handle." and user ".$importer["uid"]." was not found");
return false;
- } else
- logger('Author '.$person['url'].' is allowed for uid '.$uid);
+ }
- $datarray = array();
- $datarray['uid'] = $uid;
- $datarray['contact-id'] = $contact_id;
- $datarray['wall'] = 0;
- $datarray['network'] = NETWORK_DIASPORA;
- $datarray['guid'] = $guid;
- $datarray['uri'] = $datarray['parent-uri'] = $message_id;
- $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
- $datarray['private'] = $private;
- $datarray['parent'] = 0;
- $datarray['plink'] = diaspora_plink($author, $guid);
- $datarray['author-name'] = $person['name'];
- $datarray['author-link'] = $person['url'];
- $datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
- $datarray['owner-name'] = $datarray['author-name'];
- $datarray['owner-link'] = $datarray['author-link'];
- $datarray['owner-avatar'] = $datarray['author-avatar'];
- $datarray['body'] = $body;
- $datarray['tag'] = $str_tags;
- $datarray['app'] = $app;
- $datarray['visible'] = ((strlen($body)) ? 1 : 0);
- $datarray['object'] = $object;
- $datarray['object-type'] = $objecttype;
+ if (!self::post_allow($importer, $contact, $is_comment)) {
+ logger("The handle: ".$handle." is not allowed to post to user ".$importer["uid"]);
+ return false;
+ }
+ return $contact;
+ }
- if ($datarray['contact-id'] == 0)
- return false;
+ /**
+ * @brief Does the message already exists on the system?
+ *
+ * @param int $uid The user id
+ * @param string $guid The guid of the message
+ *
+ * @return int|bool message id if the message already was stored into the system - or false.
+ */
+ private function message_exists($uid, $guid) {
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($guid)
+ );
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
+ if($r) {
+ logger("message ".$guid." already exists for user ".$uid);
+ return $r[0]["id"];
+ }
- /// @TODO
- /// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
-
- return $message_id;
-}
-
-function diaspora_fetch_message($guid, $server, $level = 0) {
-
- if ($level > 5)
- return false;
-
- $a = get_app();
-
- // This will not work if the server is not a Diaspora server
- $source_url = $server.'/p/'.$guid.'.xml';
- $x = fetch_url($source_url);
- if(!$x)
- return false;
-
- $x = str_replace(array('',''),array('',''),$x);
- $source_xml = parse_xml_string($x,false);
-
- $item = array();
- $item["app"] = 'Diaspora';
- $item["guid"] = $guid;
- $body = "";
-
- if ($source_xml->post->status_message->created_at)
- $item["created"] = unxmlify($source_xml->post->status_message->created_at);
-
- if ($source_xml->post->status_message->provider_display_name)
- $item["app"] = unxmlify($source_xml->post->status_message->provider_display_name);
-
- if ($source_xml->post->status_message->diaspora_handle)
- $item["author"] = unxmlify($source_xml->post->status_message->diaspora_handle);
-
- if ($source_xml->post->status_message->guid)
- $item["guid"] = unxmlify($source_xml->post->status_message->guid);
-
- $item["private"] = (unxmlify($source_xml->post->status_message->public) == 'false');
- $item["object"] = json_encode($source_xml->post);
-
- if(strlen($source_xml->post->asphoto->objectId) && ($source_xml->post->asphoto->objectId != 0) && ($source_xml->post->asphoto->image_url)) {
- $item["object-type"] = ACTIVITY_OBJ_PHOTO;
- $body = '[url=' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '][img]' . notags(unxmlify($source_xml->post->asphoto->objectId)) . '[/img][/url]' . "\n";
- $body = scale_external_images($body,false);
- } elseif($source_xml->post->asphoto->image_url) {
- $item["object-type"] = ACTIVITY_OBJ_PHOTO;
- $body = '[img]' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '[/img]' . "\n";
- $body = scale_external_images($body);
- } elseif($source_xml->post->status_message) {
- $body = diaspora2bb($source_xml->post->status_message->raw_message);
-
- // Checking for embedded pictures
- if($source_xml->post->status_message->photo->remote_photo_path AND
- $source_xml->post->status_message->photo->remote_photo_name) {
-
- $item["object-type"] = ACTIVITY_OBJ_PHOTO;
-
- $remote_photo_path = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_path));
- $remote_photo_name = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_name));
-
- $body = '[img]'.$remote_photo_path.$remote_photo_name.'[/img]'."\n".$body;
-
- logger('embedded picture link found: '.$body, LOGGER_DEBUG);
- } else
- $item["object-type"] = ACTIVITY_OBJ_NOTE;
-
- $body = scale_external_images($body);
-
- // Add OEmbed and other information to the body
- /// @TODO It could be a repeated redmatrix item
- /// Then we shouldn't add further data to it
- if ($item["object-type"] == ACTIVITY_OBJ_NOTE)
- $body = add_page_info_to_body($body, false, true);
-
- } elseif($source_xml->post->reshare) {
- // Reshare of a reshare
- return diaspora_fetch_message($source_xml->post->reshare->root_guid, $server, ++$level);
- } else {
- // Maybe it is a reshare of a photo that will be delivered at a later time (testing)
- logger('no content found: '.print_r($source_xml,true));
return false;
}
- if (trim($body) == "")
- return false;
-
- $item["tag"] = '';
- $item["body"] = $body;
-
- return $item;
-}
-
-function diaspora_reshare($importer,$xml,$msg) {
-
- logger('diaspora_reshare: init: ' . print_r($xml,true));
-
- $a = get_app();
- $guid = notags(unxmlify($xml->guid));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
-
-
- if($diaspora_handle != $msg['author']) {
- logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.');
- return 202;
+ /**
+ * @brief Checks for links to posts in a message
+ *
+ * @param array $item The item array
+ */
+ private function fetch_guid($item) {
+ preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
+ function ($match) use ($item){
+ return(self::fetch_guid_sub($match, $item));
+ },$item["body"]);
}
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact)
- return;
-
- if(! diaspora_post_allow($importer,$contact, false)) {
- logger('diaspora_reshare: Ignoring this author: ' . $diaspora_handle . ' ' . print_r($xml,true));
- return 202;
+ /**
+ * @brief sub function of "fetch_guid" which checks for links in messages
+ *
+ * @param array $match array containing a link that has to be checked for a message link
+ * @param array $item The item array
+ */
+ private function fetch_guid_sub($match, $item) {
+ if (!self::store_by_guid($match[1], $item["author-link"]))
+ self::store_by_guid($match[1], $item["owner-link"]);
}
- $message_id = $diaspora_handle . ':' . $guid;
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($r)) {
- logger('diaspora_reshare: message exists: ' . $guid);
- return;
+ /**
+ * @brief Fetches an item with a given guid from a given server
+ *
+ * @param string $guid the message guid
+ * @param string $server The server address
+ * @param int $uid The user id of the user
+ *
+ * @return int the message id of the stored message or false
+ */
+ private function store_by_guid($guid, $server, $uid = 0) {
+ $serverparts = parse_url($server);
+ $server = $serverparts["scheme"]."://".$serverparts["host"];
+
+ logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
+
+ $msg = self::message($guid, $server);
+
+ if (!$msg)
+ return false;
+
+ logger("Successfully fetched item ".$guid." from ".$server, LOGGER_DEBUG);
+
+ // Now call the dispatcher
+ return self::dispatch_public($msg);
}
- $orig_author = notags(unxmlify($xml->root_diaspora_id));
- $orig_guid = notags(unxmlify($xml->root_guid));
- $orig_url = $a->get_baseurl()."/display/".$orig_guid;
+ /**
+ * @brief Fetches a message from a server
+ *
+ * @param string $guid message guid
+ * @param string $server The url of the server
+ * @param int $level Endless loop prevention
+ *
+ * @return array
+ * 'message' => The message XML
+ * 'author' => The author handle
+ * 'key' => The public key of the author
+ */
+ private function message($guid, $server, $level = 0) {
- $create_original_post = false;
+ if ($level > 5)
+ return false;
- // Do we already have this item?
- $r = q("SELECT `body`, `tag`, `app`, `created`, `plink`, `object`, `object-type`, `uri` FROM `item` WHERE `guid` = '%s' AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1",
- dbesc($orig_guid),
- dbesc(NETWORK_DIASPORA)
- );
- if(count($r)) {
- logger('reshared message '.$orig_guid." reshared by ".$guid.' already exists on system.');
+ // This will work for Diaspora and newer Friendica servers
+ $source_url = $server."/p/".$guid.".xml";
+ $x = fetch_url($source_url);
+ if(!$x)
+ return false;
- // Maybe it is already a reshared item?
- // Then refetch the content, since there can be many side effects with reshared posts from other networks or reshares from reshares
- require_once('include/api.php');
- if (api_share_as_retweet($r[0]))
- $r = array();
- else {
- $body = $r[0]["body"];
- $str_tags = $r[0]["tag"];
- $app = $r[0]["app"];
- $orig_created = $r[0]["created"];
- $orig_plink = $r[0]["plink"];
- $orig_uri = $r[0]["uri"];
- $object = $r[0]["object"];
- $objecttype = $r[0]["object-type"];
+ $source_xml = parse_xml_string($x, false);
+
+ if (!is_object($source_xml))
+ return false;
+
+ if ($source_xml->post->reshare) {
+ // Reshare of a reshare - old Diaspora version
+ return self::message($source_xml->post->reshare->root_guid, $server, ++$level);
+ } elseif ($source_xml->getName() == "reshare") {
+ // Reshare of a reshare - new Diaspora version
+ return self::message($source_xml->root_guid, $server, ++$level);
+ }
+
+ $author = "";
+
+ // Fetch the author - for the old and the new Diaspora version
+ if ($source_xml->post->status_message->diaspora_handle)
+ $author = (string)$source_xml->post->status_message->diaspora_handle;
+ elseif ($source_xml->author AND ($source_xml->getName() == "status_message"))
+ $author = (string)$source_xml->author;
+
+ // If this isn't a "status_message" then quit
+ if (!$author)
+ return false;
+
+ $msg = array("message" => $x, "author" => $author);
+
+ $msg["key"] = self::key($msg["author"]);
+
+ return $msg;
+ }
+
+ /**
+ * @brief Fetches the item record of a given guid
+ *
+ * @param int $uid The user id
+ * @param string $guid message guid
+ * @param string $author The handle of the item
+ * @param array $contact The contact of the item owner
+ *
+ * @return array the item record
+ */
+ private function parent_item($uid, $guid, $author, $contact) {
+ $r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
+ `author-name`, `author-link`, `author-avatar`,
+ `owner-name`, `owner-link`, `owner-avatar`
+ FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($uid), dbesc($guid));
+
+ if(!$r) {
+ $result = self::store_by_guid($guid, $contact["url"], $uid);
+
+ if (!$result) {
+ $person = self::person_by_handle($author);
+ $result = self::store_by_guid($guid, $person["url"], $uid);
+ }
+
+ if ($result) {
+ logger("Fetched missing item ".$guid." - result: ".$result, LOGGER_DEBUG);
+
+ $r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
+ `author-name`, `author-link`, `author-avatar`,
+ `owner-name`, `owner-link`, `owner-avatar`
+ FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($uid), dbesc($guid));
+ }
+ }
+
+ if (!$r) {
+ logger("parent item not found: parent: ".$guid." - user: ".$uid);
+ return false;
+ } else {
+ logger("parent item found: parent: ".$guid." - user: ".$uid);
+ return $r[0];
}
}
- if (!count($r)) {
- $body = "";
- $str_tags = "";
- $app = "";
+ /**
+ * @brief returns contact details
+ *
+ * @param array $contact The default contact if the person isn't found
+ * @param array $person The record of the person
+ * @param int $uid The user id
+ *
+ * @return array
+ * 'cid' => contact id
+ * 'network' => network type
+ */
+ private function author_contact_by_url($contact, $person, $uid) {
- $server = 'https://'.substr($orig_author,strpos($orig_author,'@')+1);
- logger('1st try: reshared message '.$orig_guid." reshared by ".$guid.' will be fetched from original server: '.$server);
- $item = diaspora_fetch_message($orig_guid, $server);
-
- if (!$item) {
- $server = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1);
- logger('2nd try: reshared message '.$orig_guid." reshared by ".$guid." will be fetched from sharer's server: ".$server);
- $item = diaspora_fetch_message($orig_guid, $server);
- }
- if (!$item) {
- $server = 'http://'.substr($orig_author,strpos($orig_author,'@')+1);
- logger('3rd try: reshared message '.$orig_guid." reshared by ".$guid.' will be fetched from original server: '.$server);
- $item = diaspora_fetch_message($orig_guid, $server);
- }
- if (!$item) {
- $server = 'http://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1);
- logger('4th try: reshared message '.$orig_guid." reshared by ".$guid." will be fetched from sharer's server: ".$server);
- $item = diaspora_fetch_message($orig_guid, $server);
+ $r = q("SELECT `id`, `network` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d LIMIT 1",
+ dbesc(normalise_link($person["url"])), intval($uid));
+ if ($r) {
+ $cid = $r[0]["id"];
+ $network = $r[0]["network"];
+ } else {
+ $cid = $contact["id"];
+ $network = NETWORK_DIASPORA;
}
- if ($item) {
- $body = $item["body"];
- $str_tags = $item["tag"];
- $app = $item["app"];
- $orig_created = $item["created"];
- $orig_author = $item["author"];
- $orig_guid = $item["guid"];
- $orig_plink = diaspora_plink($orig_author, $orig_guid);
- $orig_uri = $orig_author.':'.$orig_guid;
- $create_original_post = ($body != "");
- $object = $item["object"];
- $objecttype = $item["object-type"];
- }
+ return (array("cid" => $cid, "network" => $network));
}
- $plink = diaspora_plink($diaspora_handle, $guid);
-
- $person = find_diaspora_person_by_handle($orig_author);
-
- $created = unxmlify($xml->created_at);
- $private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
-
- $datarray = array();
-
- $datarray['uid'] = $importer['uid'];
- $datarray['contact-id'] = $contact['id'];
- $datarray['wall'] = 0;
- $datarray['network'] = NETWORK_DIASPORA;
- $datarray['guid'] = $guid;
- $datarray['uri'] = $datarray['parent-uri'] = $message_id;
- $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
- $datarray['private'] = $private;
- $datarray['parent'] = 0;
- $datarray['plink'] = $plink;
- $datarray['owner-name'] = $contact['name'];
- $datarray['owner-link'] = $contact['url'];
- $datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']);
- if (!intval(get_config('system','wall-to-wall_share'))) {
- $prefix = share_header($person['name'], $person['url'], ((x($person,'thumb')) ? $person['thumb'] : $person['photo']), $orig_guid, $orig_created, $orig_url);
-
- $datarray['author-name'] = $contact['name'];
- $datarray['author-link'] = $contact['url'];
- $datarray['author-avatar'] = $contact['thumb'];
- $datarray['body'] = $prefix.$body."[/share]";
- } else {
- // Let reshared messages look like wall-to-wall posts
- $datarray['author-name'] = $person['name'];
- $datarray['author-link'] = $person['url'];
- $datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
- $datarray['body'] = $body;
+ /**
+ * @brief Is the profile a hubzilla profile?
+ *
+ * @param string $url The profile link
+ *
+ * @return bool is it a hubzilla server?
+ */
+ public static function is_redmatrix($url) {
+ return(strstr($url, "/channel/"));
}
- $datarray["object"] = json_encode($xml);
- $datarray['object-type'] = $objecttype;
+ /**
+ * @brief Generate a post link with a given handle and message guid
+ *
+ * @param string $addr The user handle
+ * @param string $guid message guid
+ *
+ * @return string the post link
+ */
+ private function plink($addr, $guid) {
+ $r = q("SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", dbesc($addr));
- $datarray['tag'] = $str_tags;
- $datarray['app'] = $app;
+ // Fallback
+ if (!$r)
+ return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
- // if empty content it might be a photo that hasn't arrived yet. If a photo arrives, we'll make it visible. (testing)
- $datarray['visible'] = ((strlen($body)) ? 1 : 0);
+ // Friendica contacts are often detected as Diaspora contacts in the "fcontact" table
+ // So we try another way as well.
+ $s = q("SELECT `network` FROM `gcontact` WHERE `nurl`='%s' LIMIT 1", dbesc(normalise_link($r[0]["url"])));
+ if ($s)
+ $r[0]["network"] = $s[0]["network"];
- // Store the original item of a reshare
- if ($create_original_post) {
- require_once("include/Contact.php");
+ if ($r[0]["network"] == NETWORK_DFRN)
+ return(str_replace("/profile/".$r[0]["nick"]."/", "/display/".$guid, $r[0]["url"]."/"));
- $datarray2 = $datarray;
+ if (self::is_redmatrix($r[0]["url"]))
+ return $r[0]["url"]."/?f=&mid=".$guid;
- $datarray2['uid'] = 0;
- $datarray2['contact-id'] = get_contact($person['url'], 0);
- $datarray2['guid'] = $orig_guid;
- $datarray2['uri'] = $datarray2['parent-uri'] = $orig_uri;
- $datarray2['changed'] = $datarray2['created'] = $datarray2['edited'] = $datarray2['commented'] = $datarray2['received'] = datetime_convert('UTC','UTC',$orig_created);
- $datarray2['parent'] = 0;
- $datarray2['plink'] = $orig_plink;
-
- $datarray2['author-name'] = $person['name'];
- $datarray2['author-link'] = $person['url'];
- $datarray2['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
- $datarray2['owner-name'] = $datarray2['author-name'];
- $datarray2['owner-link'] = $datarray2['author-link'];
- $datarray2['owner-avatar'] = $datarray2['author-avatar'];
- $datarray2['body'] = $body;
- $datarray2["object"] = $object;
-
- DiasporaFetchGuid($datarray2);
- $message_id = item_store($datarray2);
-
- logger("Store original item ".$orig_guid." under message id ".$message_id);
+ return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
}
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
+ /**
+ * @brief Processes an account deletion
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool Success
+ */
+ private function receive_account_deletion($importer, $data) {
+ $author = notags(unxmlify($data->author));
- return;
-
-}
-
-
-function diaspora_asphoto($importer,$xml,$msg) {
- logger('diaspora_asphoto called');
-
- $a = get_app();
- $guid = notags(unxmlify($xml->guid));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
-
- if($diaspora_handle != $msg['author']) {
- logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.');
- return 202;
- }
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact)
- return;
-
- if(! diaspora_post_allow($importer,$contact, false)) {
- logger('diaspora_asphoto: Ignoring this author.');
- return 202;
- }
-
- $message_id = $diaspora_handle . ':' . $guid;
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($r)) {
- logger('diaspora_asphoto: message exists: ' . $guid);
- return;
- }
-
- $created = unxmlify($xml->created_at);
- $private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
-
- if(strlen($xml->objectId) && ($xml->objectId != 0) && ($xml->image_url)) {
- $body = '[url=' . notags(unxmlify($xml->image_url)) . '][img]' . notags(unxmlify($xml->objectId)) . '[/img][/url]' . "\n";
- $body = scale_external_images($body,false);
- }
- elseif($xml->image_url) {
- $body = '[img]' . notags(unxmlify($xml->image_url)) . '[/img]' . "\n";
- $body = scale_external_images($body);
- }
- else {
- logger('diaspora_asphoto: no photo url found.');
- return;
- }
-
- $plink = diaspora_plink($diaspora_handle, $guid);
-
- $datarray = array();
-
- $datarray['uid'] = $importer['uid'];
- $datarray['contact-id'] = $contact['id'];
- $datarray['wall'] = 0;
- $datarray['network'] = NETWORK_DIASPORA;
- $datarray['guid'] = $guid;
- $datarray['uri'] = $datarray['parent-uri'] = $message_id;
- $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
- $datarray['private'] = $private;
- $datarray['parent'] = 0;
- $datarray['plink'] = $plink;
- $datarray['owner-name'] = $contact['name'];
- $datarray['owner-link'] = $contact['url'];
- //$datarray['owner-avatar'] = $contact['thumb'];
- $datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']);
- $datarray['author-name'] = $contact['name'];
- $datarray['author-link'] = $contact['url'];
- $datarray['author-avatar'] = $contact['thumb'];
- $datarray['body'] = $body;
- $datarray["object"] = json_encode($xml);
- $datarray['object-type'] = ACTIVITY_OBJ_PHOTO;
-
- $datarray['app'] = 'Diaspora/Cubbi.es';
-
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
-
- //if($message_id) {
- // q("update item set plink = '%s' where id = %d",
- // dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
- // intval($message_id)
- // );
- //}
-
- return;
-
-}
-
-function diaspora_comment($importer,$xml,$msg) {
-
- $a = get_app();
- $guid = notags(unxmlify($xml->guid));
- $parent_guid = notags(unxmlify($xml->parent_guid));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
- $target_type = notags(unxmlify($xml->target_type));
- $text = unxmlify($xml->text);
- $author_signature = notags(unxmlify($xml->author_signature));
-
- $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : '');
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
- if(! $contact) {
- logger('diaspora_comment: cannot find contact: ' . $msg['author']);
- return;
- }
-
- if(! diaspora_post_allow($importer,$contact, true)) {
- logger('diaspora_comment: Ignoring this author.');
- return 202;
- }
-
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($r)) {
- logger('diaspora_comment: our comment just got relayed back to us (or there was a guid collision) : ' . $guid);
- return;
- }
-
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($parent_guid)
- );
-
- if(!count($r)) {
- $result = diaspora_store_by_guid($parent_guid, $contact['url'], $importer['uid']);
-
- if (!$result) {
- $person = find_diaspora_person_by_handle($diaspora_handle);
- $result = diaspora_store_by_guid($parent_guid, $person['url'], $importer['uid']);
+ $contact = self::contact_by_handle($importer["uid"], $author);
+ if (!$contact) {
+ logger("cannot find contact for author: ".$author);
+ return false;
}
- if ($result) {
- logger("Fetched missing item ".$parent_guid." - result: ".$result, LOGGER_DEBUG);
+ // We now remove the contact
+ contact_remove($contact["id"]);
+ return true;
+ }
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($parent_guid)
+ /**
+ * @brief Processes an incoming comment
+ *
+ * @param array $importer Array of the importer user
+ * @param string $sender The sender of the message
+ * @param object $data The message object
+ * @param string $xml The original XML of the message
+ *
+ * @return int The message id of the generated comment or "false" if there was an error
+ */
+ private function receive_comment($importer, $sender, $data, $xml) {
+ $guid = notags(unxmlify($data->guid));
+ $parent_guid = notags(unxmlify($data->parent_guid));
+ $text = unxmlify($data->text);
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::allowed_contact_by_handle($importer, $sender, true);
+ if (!$contact)
+ return false;
+
+ $message_id = self::message_exists($importer["uid"], $guid);
+ if ($message_id)
+ return $message_id;
+
+ $parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact);
+ if (!$parent_item)
+ return false;
+
+ $person = self::person_by_handle($author);
+ if (!is_array($person)) {
+ logger("unable to find author details");
+ return false;
+ }
+
+ // Fetch the contact id - if we know this contact
+ $author_contact = self::author_contact_by_url($contact, $person, $importer["uid"]);
+
+ $datarray = array();
+
+ $datarray["uid"] = $importer["uid"];
+ $datarray["contact-id"] = $author_contact["cid"];
+ $datarray["network"] = $author_contact["network"];
+
+ $datarray["author-name"] = $person["name"];
+ $datarray["author-link"] = $person["url"];
+ $datarray["author-avatar"] = ((x($person,"thumb")) ? $person["thumb"] : $person["photo"]);
+
+ $datarray["owner-name"] = $contact["name"];
+ $datarray["owner-link"] = $contact["url"];
+ $datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+
+ $datarray["guid"] = $guid;
+ $datarray["uri"] = $author.":".$guid;
+
+ $datarray["type"] = "remote-comment";
+ $datarray["verb"] = ACTIVITY_POST;
+ $datarray["gravity"] = GRAVITY_COMMENT;
+ $datarray["parent-uri"] = $parent_item["uri"];
+
+ $datarray["object-type"] = ACTIVITY_OBJ_COMMENT;
+ $datarray["object"] = $xml;
+
+ $datarray["body"] = diaspora2bb($text);
+
+ self::fetch_guid($datarray);
+
+ $message_id = item_store($datarray);
+
+ if ($message_id)
+ logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
+
+ // If we are the origin of the parent we store the original data and notify our followers
+ if($message_id AND $parent_item["origin"]) {
+
+ // Formerly we stored the signed text, the signature and the author in different fields.
+ // We now store the raw data so that we are more flexible.
+ q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
+ intval($message_id),
+ dbesc(json_encode($data))
);
+
+ // notify others
+ proc_run("php", "include/notifier.php", "comment-import", $message_id);
}
+
+ return $message_id;
}
- if(! count($r)) {
- logger('diaspora_comment: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid);
- return;
- }
- $parent_item = $r[0];
-
-
- /* How Diaspora performs comment signature checking:
-
- - If an item has been sent by the comment author to the top-level post owner to relay on
- to the rest of the contacts on the top-level post, the top-level post owner should check
- the author_signature, then create a parent_author_signature before relaying the comment on
- - If an item has been relayed on by the top-level post owner, the contacts who receive it
- check only the parent_author_signature. Basically, they trust that the top-level post
- owner has already verified the authenticity of anything he/she sends out
- - In either case, the signature that get checked is the signature created by the person
- who sent the salmon
- */
-
- $signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle;
- $key = $msg['key'];
-
- if($parent_author_signature) {
- // If a parent_author_signature exists, then we've received the comment
- // relayed from the top-level post owner. There's no need to check the
- // author_signature if the parent_author_signature is valid
-
- $parent_author_signature = base64_decode($parent_author_signature);
-
- if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
- logger('diaspora_comment: top-level owner verification failed.');
- return;
- }
- }
- else {
- // If there's no parent_author_signature, then we've received the comment
- // from the comment creator. In that case, the person is commenting on
- // our post, so he/she must be a contact of ours and his/her public key
- // should be in $msg['key']
-
- $author_signature = base64_decode($author_signature);
-
- if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) {
- logger('diaspora_comment: comment author verification failed.');
- return;
- }
- }
-
- // Phew! Everything checks out. Now create an item.
-
- // Find the original comment author information.
- // We need this to make sure we display the comment author
- // information (name and avatar) correctly.
- if(strcasecmp($diaspora_handle,$msg['author']) == 0)
- $person = $contact;
- else {
- $person = find_diaspora_person_by_handle($diaspora_handle);
-
- if(! is_array($person)) {
- logger('diaspora_comment: unable to find author details');
- return;
- }
- }
-
- // Fetch the contact id - if we know this contact
- $r = q("SELECT `id`, `network` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d LIMIT 1",
- dbesc(normalise_link($person['url'])), intval($importer['uid']));
- if ($r) {
- $cid = $r[0]['id'];
- $network = $r[0]['network'];
- } else {
- $cid = $contact['id'];
- $network = NETWORK_DIASPORA;
- }
-
- $body = diaspora2bb($text);
- $message_id = $diaspora_handle . ':' . $guid;
-
- $datarray = array();
-
- $datarray['uid'] = $importer['uid'];
- $datarray['contact-id'] = $cid;
- $datarray['type'] = 'remote-comment';
- $datarray['wall'] = $parent_item['wall'];
- $datarray['network'] = $network;
- $datarray['verb'] = ACTIVITY_POST;
- $datarray['gravity'] = GRAVITY_COMMENT;
- $datarray['guid'] = $guid;
- $datarray['uri'] = $message_id;
- $datarray['parent-uri'] = $parent_item['uri'];
-
- // No timestamps for comments? OK, we'll the use current time.
- $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert();
- $datarray['private'] = $parent_item['private'];
-
- $datarray['owner-name'] = $parent_item['owner-name'];
- $datarray['owner-link'] = $parent_item['owner-link'];
- $datarray['owner-avatar'] = $parent_item['owner-avatar'];
-
- $datarray['author-name'] = $person['name'];
- $datarray['author-link'] = $person['url'];
- $datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
- $datarray['body'] = $body;
- $datarray["object"] = json_encode($xml);
- $datarray["object-type"] = ACTIVITY_OBJ_COMMENT;
-
- // We can't be certain what the original app is if the message is relayed.
- if(($parent_item['origin']) && (! $parent_author_signature))
- $datarray['app'] = 'Diaspora';
-
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
-
- $datarray['id'] = $message_id;
-
- //if($message_id) {
- //q("update item set plink = '%s' where id = %d",
- // //dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
- // dbesc($a->get_baseurl().'/display/'.$datarray['guid']),
- // intval($message_id)
- //);
- //}
-
- // If we are the origin of the parent we store the original signature and notify our followers
- if($parent_item['origin']) {
- $author_signature_base64 = base64_encode($author_signature);
- $author_signature_base64 = diaspora_repair_signature($author_signature_base64, $diaspora_handle);
-
- q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- intval($message_id),
- dbesc($signed_data),
- dbesc($author_signature_base64),
- dbesc($diaspora_handle)
- );
-
- // notify others
- proc_run('php','include/notifier.php','comment-import',$message_id);
- }
-
- return;
-}
-
-
-
-
-function diaspora_conversation($importer,$xml,$msg) {
-
- $a = get_app();
-
- $guid = notags(unxmlify($xml->guid));
- $subject = notags(unxmlify($xml->subject));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
- $participant_handles = notags(unxmlify($xml->participant_handles));
- $created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at)));
-
- $parent_uri = $diaspora_handle . ':' . $guid;
-
- $messages = $xml->message;
-
- if(! count($messages)) {
- logger('diaspora_conversation: empty conversation');
- return;
- }
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
- if(! $contact) {
- logger('diaspora_conversation: cannot find contact: ' . $msg['author']);
- return;
- }
-
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
- logger('diaspora_conversation: Ignoring this author.');
- return 202;
- }
-
- $conversation = null;
-
- $c = q("select * from conv where uid = %d and guid = '%s' limit 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($c))
- $conversation = $c[0];
- else {
- $r = q("insert into conv (uid,guid,creator,created,updated,subject,recips) values(%d, '%s', '%s', '%s', '%s', '%s', '%s') ",
- intval($importer['uid']),
- dbesc($guid),
- dbesc($diaspora_handle),
- dbesc(datetime_convert('UTC','UTC',$created_at)),
- dbesc(datetime_convert()),
- dbesc($subject),
- dbesc($participant_handles)
- );
- if($r)
- $c = q("select * from conv where uid = %d and guid = '%s' limit 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($c))
- $conversation = $c[0];
- }
- if(! $conversation) {
- logger('diaspora_conversation: unable to create conversation.');
- return;
- }
-
- foreach($messages as $mesg) {
+ /**
+ * @brief processes and stores private messages
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact of the message
+ * @param object $data The message object
+ * @param array $msg Array of the processed message, author handle and key
+ * @param object $mesg The private message
+ * @param array $conversation The conversation record to which this message belongs
+ *
+ * @return bool "true" if it was successful
+ */
+ private function receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation) {
+ $guid = notags(unxmlify($data->guid));
+ $subject = notags(unxmlify($data->subject));
+ $author = notags(unxmlify($data->author));
$reply = 0;
@@ -1666,1469 +1125,2102 @@ function diaspora_conversation($importer,$xml,$msg) {
$msg_parent_author_signature = notags(unxmlify($mesg->parent_author_signature));
$msg_author_signature = notags(unxmlify($mesg->author_signature));
$msg_text = unxmlify($mesg->text);
- $msg_created_at = datetime_convert('UTC','UTC',notags(unxmlify($mesg->created_at)));
- $msg_diaspora_handle = notags(unxmlify($mesg->diaspora_handle));
+ $msg_created_at = datetime_convert("UTC", "UTC", notags(unxmlify($mesg->created_at)));
+
+ // "diaspora_handle" is the element name from the old version
+ // "author" is the element name from the new version
+ if ($mesg->author)
+ $msg_author = notags(unxmlify($mesg->author));
+ elseif ($mesg->diaspora_handle)
+ $msg_author = notags(unxmlify($mesg->diaspora_handle));
+ else
+ return false;
+
$msg_conversation_guid = notags(unxmlify($mesg->conversation_guid));
+
if($msg_conversation_guid != $guid) {
- logger('diaspora_conversation: message conversation guid does not belong to the current conversation. ' . $xml);
- continue;
+ logger("message conversation guid does not belong to the current conversation.");
+ return false;
}
$body = diaspora2bb($msg_text);
- $message_id = $msg_diaspora_handle . ':' . $msg_guid;
+ $message_uri = $msg_author.":".$msg_guid;
- $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid;
+ $author_signed_data = $msg_guid.";".$msg_parent_guid.";".$msg_text.";".unxmlify($mesg->created_at).";".$msg_author.";".$msg_conversation_guid;
$author_signature = base64_decode($msg_author_signature);
- if(strcasecmp($msg_diaspora_handle,$msg['author']) == 0) {
+ if(strcasecmp($msg_author,$msg["author"]) == 0) {
$person = $contact;
- $key = $msg['key'];
- }
- else {
- $person = find_diaspora_person_by_handle($msg_diaspora_handle);
+ $key = $msg["key"];
+ } else {
+ $person = self::person_by_handle($msg_author);
- if(is_array($person) && x($person,'pubkey'))
- $key = $person['pubkey'];
+ if (is_array($person) && x($person, "pubkey"))
+ $key = $person["pubkey"];
else {
- logger('diaspora_conversation: unable to find author details');
- continue;
+ logger("unable to find author details");
+ return false;
}
}
- if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) {
- logger('diaspora_conversation: verification failed.');
- continue;
+ if (!rsa_verify($author_signed_data, $author_signature, $key, "sha256")) {
+ logger("verification failed.");
+ return false;
}
if($msg_parent_author_signature) {
- $owner_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid;
+ $owner_signed_data = $msg_guid.";".$msg_parent_guid.";".$msg_text.";".unxmlify($mesg->created_at).";".$msg_author.";".$msg_conversation_guid;
$parent_author_signature = base64_decode($msg_parent_author_signature);
- $key = $msg['key'];
+ $key = $msg["key"];
- if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) {
- logger('diaspora_conversation: owner verification failed.');
- continue;
+ if (!rsa_verify($owner_signed_data, $parent_author_signature, $key, "sha256")) {
+ logger("owner verification failed.");
+ return false;
}
}
- $r = q("select id from mail where `uri` = '%s' limit 1",
- dbesc($message_id)
+ $r = q("SELECT `id` FROM `mail` WHERE `uri` = '%s' LIMIT 1",
+ dbesc($message_uri)
);
- if(count($r)) {
- logger('diaspora_conversation: duplicate message already delivered.', LOGGER_DEBUG);
- continue;
+ if($r) {
+ logger("duplicate message already delivered.", LOGGER_DEBUG);
+ return false;
}
- q("insert into mail ( `uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`) values ( %d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')",
- intval($importer['uid']),
+ q("INSERT INTO `mail` (`uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`)
+ VALUES (%d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')",
+ intval($importer["uid"]),
dbesc($msg_guid),
- intval($conversation['id']),
- dbesc($person['name']),
- dbesc($person['photo']),
- dbesc($person['url']),
- intval($contact['id']),
+ intval($conversation["id"]),
+ dbesc($person["name"]),
+ dbesc($person["photo"]),
+ dbesc($person["url"]),
+ intval($contact["id"]),
dbesc($subject),
dbesc($body),
0,
0,
- dbesc($message_id),
- dbesc($parent_uri),
+ dbesc($message_uri),
+ dbesc($author.":".$guid),
dbesc($msg_created_at)
);
- q("update conv set updated = '%s' where id = %d",
+ q("UPDATE `conv` SET `updated` = '%s' WHERE `id` = %d",
dbesc(datetime_convert()),
- intval($conversation['id'])
+ intval($conversation["id"])
);
notification(array(
- 'type' => NOTIFY_MAIL,
- 'notify_flags' => $importer['notify-flags'],
- 'language' => $importer['language'],
- 'to_name' => $importer['username'],
- 'to_email' => $importer['email'],
- 'uid' =>$importer['uid'],
- 'item' => array('subject' => $subject, 'body' => $body),
- 'source_name' => $person['name'],
- 'source_link' => $person['url'],
- 'source_photo' => $person['thumb'],
- 'verb' => ACTIVITY_POST,
- 'otype' => 'mail'
+ "type" => NOTIFY_MAIL,
+ "notify_flags" => $importer["notify-flags"],
+ "language" => $importer["language"],
+ "to_name" => $importer["username"],
+ "to_email" => $importer["email"],
+ "uid" =>$importer["uid"],
+ "item" => array("subject" => $subject, "body" => $body),
+ "source_name" => $person["name"],
+ "source_link" => $person["url"],
+ "source_photo" => $person["thumb"],
+ "verb" => ACTIVITY_POST,
+ "otype" => "mail"
));
+ return true;
}
- return;
-}
+ /**
+ * @brief Processes new private messages (answers to private messages are processed elsewhere)
+ *
+ * @param array $importer Array of the importer user
+ * @param array $msg Array of the processed message, author handle and key
+ * @param object $data The message object
+ *
+ * @return bool Success
+ */
+ private function receive_conversation($importer, $msg, $data) {
+ $guid = notags(unxmlify($data->guid));
+ $subject = notags(unxmlify($data->subject));
+ $created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
+ $author = notags(unxmlify($data->author));
+ $participants = notags(unxmlify($data->participants));
-function diaspora_message($importer,$xml,$msg) {
+ $messages = $data->message;
- $a = get_app();
-
- $msg_guid = notags(unxmlify($xml->guid));
- $msg_parent_guid = notags(unxmlify($xml->parent_guid));
- $msg_parent_author_signature = notags(unxmlify($xml->parent_author_signature));
- $msg_author_signature = notags(unxmlify($xml->author_signature));
- $msg_text = unxmlify($xml->text);
- $msg_created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at)));
- $msg_diaspora_handle = notags(unxmlify($xml->diaspora_handle));
- $msg_conversation_guid = notags(unxmlify($xml->conversation_guid));
-
- $parent_uri = $msg_diaspora_handle . ':' . $msg_parent_guid;
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$msg_diaspora_handle);
- if(! $contact) {
- logger('diaspora_message: cannot find contact: ' . $msg_diaspora_handle);
- return;
- }
-
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
- logger('diaspora_message: Ignoring this author.');
- return 202;
- }
-
- $conversation = null;
-
- $c = q("select * from conv where uid = %d and guid = '%s' limit 1",
- intval($importer['uid']),
- dbesc($msg_conversation_guid)
- );
- if(count($c))
- $conversation = $c[0];
- else {
- logger('diaspora_message: conversation not available.');
- return;
- }
-
- $reply = 0;
-
- $body = diaspora2bb($msg_text);
- $message_id = $msg_diaspora_handle . ':' . $msg_guid;
-
- $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($xml->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid;
-
-
- $author_signature = base64_decode($msg_author_signature);
-
- $person = find_diaspora_person_by_handle($msg_diaspora_handle);
- if(is_array($person) && x($person,'pubkey'))
- $key = $person['pubkey'];
- else {
- logger('diaspora_message: unable to find author details');
- return;
- }
-
- if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) {
- logger('diaspora_message: verification failed.');
- return;
- }
-
- $r = q("select id from mail where `uri` = '%s' and uid = %d limit 1",
- dbesc($message_id),
- intval($importer['uid'])
- );
- if(count($r)) {
- logger('diaspora_message: duplicate message already delivered.', LOGGER_DEBUG);
- return;
- }
-
- q("insert into mail ( `uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`) values ( %d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')",
- intval($importer['uid']),
- dbesc($msg_guid),
- intval($conversation['id']),
- dbesc($person['name']),
- dbesc($person['photo']),
- dbesc($person['url']),
- intval($contact['id']),
- dbesc($conversation['subject']),
- dbesc($body),
- 0,
- 1,
- dbesc($message_id),
- dbesc($parent_uri),
- dbesc($msg_created_at)
- );
-
- q("update conv set updated = '%s' where id = %d",
- dbesc(datetime_convert()),
- intval($conversation['id'])
- );
-
- return;
-}
-
-function diaspora_participation($importer,$xml) {
- logger("Unsupported message type 'participation' ".print_r($xml, true));
-}
-
-function diaspora_photo($importer,$xml,$msg,$attempt=1) {
-
- $a = get_app();
-
- logger('diaspora_photo: init',LOGGER_DEBUG);
-
- $remote_photo_path = notags(unxmlify($xml->remote_photo_path));
-
- $remote_photo_name = notags(unxmlify($xml->remote_photo_name));
-
- $status_message_guid = notags(unxmlify($xml->status_message_guid));
-
- $guid = notags(unxmlify($xml->guid));
-
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
-
- $public = notags(unxmlify($xml->public));
-
- $created_at = notags(unxmlify($xml_created_at));
-
- logger('diaspora_photo: status_message_guid: ' . $status_message_guid, LOGGER_DEBUG);
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
- if(! $contact) {
- logger('diaspora_photo: contact record not found: ' . $msg['author'] . ' handle: ' . $diaspora_handle);
- return;
- }
-
- if(! diaspora_post_allow($importer,$contact, false)) {
- logger('diaspora_photo: Ignoring this author.');
- return 202;
- }
-
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($status_message_guid)
- );
-
-/* deactivated by now since it can lead to multiplicated pictures in posts.
- if(!count($r)) {
- $result = diaspora_store_by_guid($status_message_guid, $contact['url'], $importer['uid']);
-
- if (!$result) {
- $person = find_diaspora_person_by_handle($diaspora_handle);
- $result = diaspora_store_by_guid($status_message_guid, $person['url'], $importer['uid']);
+ if (!count($messages)) {
+ logger("empty conversation");
+ return false;
}
- if ($result) {
- logger("Fetched missing item ".$status_message_guid." - result: ".$result, LOGGER_DEBUG);
+ $contact = self::allowed_contact_by_handle($importer, $msg["author"], true);
+ if (!$contact)
+ return false;
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($status_message_guid)
+ $conversation = null;
+
+ $c = q("SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($guid)
+ );
+ if($c)
+ $conversation = $c[0];
+ else {
+ $r = q("INSERT INTO `conv` (`uid`, `guid`, `creator`, `created`, `updated`, `subject`, `recips`)
+ VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s')",
+ intval($importer["uid"]),
+ dbesc($guid),
+ dbesc($author),
+ dbesc(datetime_convert("UTC", "UTC", $created_at)),
+ dbesc(datetime_convert()),
+ dbesc($subject),
+ dbesc($participants)
+ );
+ if($r)
+ $c = q("SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($guid)
+ );
+
+ if($c)
+ $conversation = $c[0];
+ }
+ if (!$conversation) {
+ logger("unable to create conversation.");
+ return;
+ }
+
+ foreach($messages as $mesg)
+ self::receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation);
+
+ return true;
+ }
+
+ /**
+ * @brief Creates the body for a "like" message
+ *
+ * @param array $contact The contact that send us the "like"
+ * @param array $parent_item The item array of the parent item
+ * @param string $guid message guid
+ *
+ * @return string the body
+ */
+ private function construct_like_body($contact, $parent_item, $guid) {
+ $bodyverb = t('%1$s likes %2$s\'s %3$s');
+
+ $ulink = "[url=".$contact["url"]."]".$contact["name"]."[/url]";
+ $alink = "[url=".$parent_item["author-link"]."]".$parent_item["author-name"]."[/url]";
+ $plink = "[url=".App::get_baseurl()."/display/".urlencode($guid)."]".t("status")."[/url]";
+
+ return sprintf($bodyverb, $ulink, $alink, $plink);
+ }
+
+ /**
+ * @brief Creates a XML object for a "like"
+ *
+ * @param array $importer Array of the importer user
+ * @param array $parent_item The item array of the parent item
+ *
+ * @return string The XML
+ */
+ private function construct_like_object($importer, $parent_item) {
+ $objtype = ACTIVITY_OBJ_NOTE;
+ $link = '';
+ $parent_body = $parent_item["body"];
+
+ $xmldata = array("object" => array("type" => $objtype,
+ "local" => "1",
+ "id" => $parent_item["uri"],
+ "link" => $link,
+ "title" => "",
+ "content" => $parent_body));
+
+ return xml::from_array($xmldata, $xml, true);
+ }
+
+ /**
+ * @brief Processes "like" messages
+ *
+ * @param array $importer Array of the importer user
+ * @param string $sender The sender of the message
+ * @param object $data The message object
+ *
+ * @return int The message id of the generated like or "false" if there was an error
+ */
+ private function receive_like($importer, $sender, $data) {
+ $positive = notags(unxmlify($data->positive));
+ $guid = notags(unxmlify($data->guid));
+ $parent_type = notags(unxmlify($data->parent_type));
+ $parent_guid = notags(unxmlify($data->parent_guid));
+ $author = notags(unxmlify($data->author));
+
+ // likes on comments aren't supported by Diaspora - only on posts
+ // But maybe this will be supported in the future, so we will accept it.
+ if (!in_array($parent_type, array("Post", "Comment")))
+ return false;
+
+ $contact = self::allowed_contact_by_handle($importer, $sender, true);
+ if (!$contact)
+ return false;
+
+ $message_id = self::message_exists($importer["uid"], $guid);
+ if ($message_id)
+ return $message_id;
+
+ $parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact);
+ if (!$parent_item)
+ return false;
+
+ $person = self::person_by_handle($author);
+ if (!is_array($person)) {
+ logger("unable to find author details");
+ return false;
+ }
+
+ // Fetch the contact id - if we know this contact
+ $author_contact = self::author_contact_by_url($contact, $person, $importer["uid"]);
+
+ // "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora
+ // We would accept this anyhow.
+ if ($positive == "true")
+ $verb = ACTIVITY_LIKE;
+ else
+ $verb = ACTIVITY_DISLIKE;
+
+ $datarray = array();
+
+ $datarray["uid"] = $importer["uid"];
+ $datarray["contact-id"] = $author_contact["cid"];
+ $datarray["network"] = $author_contact["network"];
+
+ $datarray["author-name"] = $person["name"];
+ $datarray["author-link"] = $person["url"];
+ $datarray["author-avatar"] = ((x($person,"thumb")) ? $person["thumb"] : $person["photo"]);
+
+ $datarray["owner-name"] = $contact["name"];
+ $datarray["owner-link"] = $contact["url"];
+ $datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+
+ $datarray["guid"] = $guid;
+ $datarray["uri"] = $author.":".$guid;
+
+ $datarray["type"] = "activity";
+ $datarray["verb"] = $verb;
+ $datarray["gravity"] = GRAVITY_LIKE;
+ $datarray["parent-uri"] = $parent_item["uri"];
+
+ $datarray["object-type"] = ACTIVITY_OBJ_NOTE;
+ $datarray["object"] = self::construct_like_object($importer, $parent_item);
+
+ $datarray["body"] = self::construct_like_body($contact, $parent_item, $guid);
+
+ $message_id = item_store($datarray);
+
+ if ($message_id)
+ logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
+
+ // If we are the origin of the parent we store the original data and notify our followers
+ if($message_id AND $parent_item["origin"]) {
+
+ // Formerly we stored the signed text, the signature and the author in different fields.
+ // We now store the raw data so that we are more flexible.
+ q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
+ intval($message_id),
+ dbesc(json_encode($data))
+ );
+
+ // notify others
+ proc_run("php", "include/notifier.php", "comment-import", $message_id);
+ }
+
+ return $message_id;
+ }
+
+ /**
+ * @brief Processes private messages
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool Success?
+ */
+ private function receive_message($importer, $data) {
+ $guid = notags(unxmlify($data->guid));
+ $parent_guid = notags(unxmlify($data->parent_guid));
+ $text = unxmlify($data->text);
+ $created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
+ $author = notags(unxmlify($data->author));
+ $conversation_guid = notags(unxmlify($data->conversation_guid));
+
+ $contact = self::allowed_contact_by_handle($importer, $author, true);
+ if (!$contact)
+ return false;
+
+ $conversation = null;
+
+ $c = q("SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($conversation_guid)
+ );
+ if($c)
+ $conversation = $c[0];
+ else {
+ logger("conversation not available.");
+ return false;
+ }
+
+ $reply = 0;
+
+ $body = diaspora2bb($text);
+ $message_uri = $author.":".$guid;
+
+ $person = self::person_by_handle($author);
+ if (!$person) {
+ logger("unable to find author details");
+ return false;
+ }
+
+ $r = q("SELECT `id` FROM `mail` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+ dbesc($message_uri),
+ intval($importer["uid"])
+ );
+ if($r) {
+ logger("duplicate message already delivered.", LOGGER_DEBUG);
+ return false;
+ }
+
+ q("INSERT INTO `mail` (`uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`)
+ VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')",
+ intval($importer["uid"]),
+ dbesc($guid),
+ intval($conversation["id"]),
+ dbesc($person["name"]),
+ dbesc($person["photo"]),
+ dbesc($person["url"]),
+ intval($contact["id"]),
+ dbesc($conversation["subject"]),
+ dbesc($body),
+ 0,
+ 1,
+ dbesc($message_uri),
+ dbesc($author.":".$parent_guid),
+ dbesc($created_at)
+ );
+
+ q("UPDATE `conv` SET `updated` = '%s' WHERE `id` = %d",
+ dbesc(datetime_convert()),
+ intval($conversation["id"])
+ );
+
+ return true;
+ }
+
+ /**
+ * @brief Processes participations - unsupported by now
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool always true
+ */
+ private function receive_participation($importer, $data) {
+ // I'm not sure if we can fully support this message type
+ return true;
+ }
+
+ /**
+ * @brief Processes photos - unneeded
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool always true
+ */
+ private function receive_photo($importer, $data) {
+ // There doesn't seem to be a reason for this function, since the photo data is transmitted in the status message as well
+ return true;
+ }
+
+ /**
+ * @brief Processes poll participations - unssupported
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool always true
+ */
+ private function receive_poll_participation($importer, $data) {
+ // We don't support polls by now
+ return true;
+ }
+
+ /**
+ * @brief Processes incoming profile updates
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool Success
+ */
+ private function receive_profile($importer, $data) {
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::contact_by_handle($importer["uid"], $author);
+ if (!$contact)
+ return false;
+
+ $name = unxmlify($data->first_name).((strlen($data->last_name)) ? " ".unxmlify($data->last_name) : "");
+ $image_url = unxmlify($data->image_url);
+ $birthday = unxmlify($data->birthday);
+ $location = diaspora2bb(unxmlify($data->location));
+ $about = diaspora2bb(unxmlify($data->bio));
+ $gender = unxmlify($data->gender);
+ $searchable = (unxmlify($data->searchable) == "true");
+ $nsfw = (unxmlify($data->nsfw) == "true");
+ $tags = unxmlify($data->tag_string);
+
+ $tags = explode("#", $tags);
+
+ $keywords = array();
+ foreach ($tags as $tag) {
+ $tag = trim(strtolower($tag));
+ if ($tag != "")
+ $keywords[] = $tag;
+ }
+
+ $keywords = implode(", ", $keywords);
+
+ $handle_parts = explode("@", $author);
+ $nick = $handle_parts[0];
+
+ if($name === "")
+ $name = $handle_parts[0];
+
+ if( preg_match("|^https?://|", $image_url) === 0)
+ $image_url = "http://".$handle_parts[1].$image_url;
+
+ update_contact_avatar($image_url, $importer["uid"], $contact["id"]);
+
+ // Generic birthday. We don't know the timezone. The year is irrelevant.
+
+ $birthday = str_replace("1000", "1901", $birthday);
+
+ if ($birthday != "")
+ $birthday = datetime_convert("UTC", "UTC", $birthday, "Y-m-d");
+
+ // this is to prevent multiple birthday notifications in a single year
+ // if we already have a stored birthday and the 'm-d' part hasn't changed, preserve the entry, which will preserve the notify year
+
+ if(substr($birthday,5) === substr($contact["bd"],5))
+ $birthday = $contact["bd"];
+
+ $r = q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `name-date` = '%s', `bd` = '%s',
+ `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `id` = %d AND `uid` = %d",
+ dbesc($name),
+ dbesc($nick),
+ dbesc($author),
+ dbesc(datetime_convert()),
+ dbesc($birthday),
+ dbesc($location),
+ dbesc($about),
+ dbesc($keywords),
+ dbesc($gender),
+ intval($contact["id"]),
+ intval($importer["uid"])
+ );
+
+ if ($searchable) {
+ poco_check($contact["url"], $name, NETWORK_DIASPORA, $image_url, $about, $location, $gender, $keywords, "",
+ datetime_convert(), 2, $contact["id"], $importer["uid"]);
+ }
+
+ $gcontact = array("url" => $contact["url"], "network" => NETWORK_DIASPORA, "generation" => 2,
+ "photo" => $image_url, "name" => $name, "location" => $location,
+ "about" => $about, "birthday" => $birthday, "gender" => $gender,
+ "addr" => $author, "nick" => $nick, "keywords" => $keywords,
+ "hide" => !$searchable, "nsfw" => $nsfw);
+
+ update_gcontact($gcontact);
+
+ logger("Profile of contact ".$contact["id"]." stored for user ".$importer["uid"], LOGGER_DEBUG);
+
+ return true;
+ }
+
+ /**
+ * @brief Processes incoming friend requests
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact that send the request
+ */
+ private function receive_request_make_friend($importer, $contact) {
+
+ $a = get_app();
+
+ if($contact["rel"] == CONTACT_IS_FOLLOWER && in_array($importer["page-flags"], array(PAGE_FREELOVE))) {
+ q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d",
+ intval(CONTACT_IS_FRIEND),
+ intval($contact["id"]),
+ intval($importer["uid"])
);
}
+ // send notification
+
+ $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1",
+ intval($importer["uid"])
+ );
+
+ if($r && !$r[0]["hide-friends"] && !$contact["hidden"] && intval(get_pconfig($importer["uid"], "system", "post_newfriend"))) {
+
+ $self = q("SELECT * FROM `contact` WHERE `self` AND `uid` = %d LIMIT 1",
+ intval($importer["uid"])
+ );
+
+ // they are not CONTACT_IS_FOLLOWER anymore but that's what we have in the array
+
+ if($self && $contact["rel"] == CONTACT_IS_FOLLOWER) {
+
+ $arr = array();
+ $arr["uri"] = $arr["parent-uri"] = item_new_uri($a->get_hostname(), $importer["uid"]);
+ $arr["uid"] = $importer["uid"];
+ $arr["contact-id"] = $self[0]["id"];
+ $arr["wall"] = 1;
+ $arr["type"] = 'wall';
+ $arr["gravity"] = 0;
+ $arr["origin"] = 1;
+ $arr["author-name"] = $arr["owner-name"] = $self[0]["name"];
+ $arr["author-link"] = $arr["owner-link"] = $self[0]["url"];
+ $arr["author-avatar"] = $arr["owner-avatar"] = $self[0]["thumb"];
+ $arr["verb"] = ACTIVITY_FRIEND;
+ $arr["object-type"] = ACTIVITY_OBJ_PERSON;
+
+ $A = "[url=".$self[0]["url"]."]".$self[0]["name"]."[/url]";
+ $B = "[url=".$contact["url"]."]".$contact["name"]."[/url]";
+ $BPhoto = "[url=".$contact["url"]."][img]".$contact["thumb"]."[/img][/url]";
+ $arr["body"] = sprintf(t("%1$s is now friends with %2$s"), $A, $B)."\n\n\n".$Bphoto;
+
+ $arr["object"] = self::construct_new_friend_object($contact);
+
+ $arr["last-child"] = 1;
+
+ $arr["allow_cid"] = $user[0]["allow_cid"];
+ $arr["allow_gid"] = $user[0]["allow_gid"];
+ $arr["deny_cid"] = $user[0]["deny_cid"];
+ $arr["deny_gid"] = $user[0]["deny_gid"];
+
+ $i = item_store($arr);
+ if($i)
+ proc_run("php", "include/notifier.php", "activity", $i);
+ }
+ }
}
+
+ /**
+ * @brief Creates a XML object for a "new friend" message
+ *
+ * @param array $contact Array of the contact
+ *
+ * @return string The XML
+ */
+ private function construct_new_friend_object($contact) {
+ $objtype = ACTIVITY_OBJ_PERSON;
+ $link = ''."\n".
+ ''."\n";
+
+ $xmldata = array("object" => array("type" => $objtype,
+ "title" => $contact["name"],
+ "id" => $contact["url"]."/".$contact["name"],
+ "link" => $link));
+
+ return xml::from_array($xmldata, $xml, true);
+ }
+
+ /**
+ * @brief Processes incoming sharing notification
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return bool Success
+ */
+ private function receive_contact_request($importer, $data) {
+ $author = unxmlify($data->author);
+ $recipient = unxmlify($data->recipient);
+
+ if (!$author || !$recipient)
+ return false;
+
+ // the current protocol version doesn't know these fields
+ // That means that we will assume their existance
+ if (isset($data->following))
+ $following = (unxmlify($data->following) == "true");
+ else
+ $following = true;
+
+ if (isset($data->sharing))
+ $sharing = (unxmlify($data->sharing) == "true");
+ else
+ $sharing = true;
+
+ $contact = self::contact_by_handle($importer["uid"],$author);
+
+ // perhaps we were already sharing with this person. Now they're sharing with us.
+ // That makes us friends.
+ if ($contact) {
+ if ($following AND $sharing) {
+ self::receive_request_make_friend($importer, $contact);
+ return true;
+ } else /// @todo Handle all possible variations of adding and retracting of permissions
+ return false;
+ }
+
+ if (!$following AND $sharing AND in_array($importer["page-flags"], array(PAGE_SOAPBOX, PAGE_NORMAL))) {
+ logger("Author ".$author." wants to share with us - but doesn't want to listen. Request is ignored.", LOGGER_DEBUG);
+ return false;
+ } elseif (!$following AND !$sharing) {
+ logger("Author ".$author." doesn't want anything - and we don't know the author. Request is ignored.", LOGGER_DEBUG);
+ return false;
+ }
+
+ $ret = self::person_by_handle($author);
+
+ if (!$ret || ($ret["network"] != NETWORK_DIASPORA)) {
+ logger("Cannot resolve diaspora handle ".$author." for ".$recipient);
+ return false;
+ }
+
+ $batch = (($ret["batch"]) ? $ret["batch"] : implode("/", array_slice(explode("/", $ret["url"]), 0, 3))."/receive/public");
+
+ $r = q("INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`)
+ VALUES (%d, '%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d)",
+ intval($importer["uid"]),
+ dbesc($ret["network"]),
+ dbesc($ret["addr"]),
+ datetime_convert(),
+ dbesc($ret["url"]),
+ dbesc(normalise_link($ret["url"])),
+ dbesc($batch),
+ dbesc($ret["name"]),
+ dbesc($ret["nick"]),
+ dbesc($ret["photo"]),
+ dbesc($ret["pubkey"]),
+ dbesc($ret["notify"]),
+ dbesc($ret["poll"]),
+ 1,
+ 2
+ );
+
+ // find the contact record we just created
+
+ $contact_record = self::contact_by_handle($importer["uid"],$author);
+
+ if (!$contact_record) {
+ logger("unable to locate newly created contact record.");
+ return;
+ }
+
+ $g = q("SELECT `def_gid` FROM `user` WHERE `uid` = %d LIMIT 1",
+ intval($importer["uid"])
+ );
+
+ if($g && intval($g[0]["def_gid"]))
+ group_add_member($importer["uid"], "", $contact_record["id"], $g[0]["def_gid"]);
+
+ if($importer["page-flags"] == PAGE_NORMAL) {
+
+ $hash = random_string().(string)time(); // Generate a confirm_key
+
+ $ret = q("INSERT INTO `intro` (`uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`)
+ VALUES (%d, %d, %d, %d, '%s', '%s', '%s')",
+ intval($importer["uid"]),
+ intval($contact_record["id"]),
+ 0,
+ 0,
+ dbesc(t("Sharing notification from Diaspora network")),
+ dbesc($hash),
+ dbesc(datetime_convert())
+ );
+ } else {
+
+ // automatic friend approval
+
+ update_contact_avatar($contact_record["photo"],$importer["uid"],$contact_record["id"]);
+
+ // technically they are sharing with us (CONTACT_IS_SHARING),
+ // but if our page-type is PAGE_COMMUNITY or PAGE_SOAPBOX
+ // we are going to change the relationship and make them a follower.
+
+ if (($importer["page-flags"] == PAGE_FREELOVE) AND $sharing AND $following)
+ $new_relation = CONTACT_IS_FRIEND;
+ elseif (($importer["page-flags"] == PAGE_FREELOVE) AND $sharing)
+ $new_relation = CONTACT_IS_SHARING;
+ else
+ $new_relation = CONTACT_IS_FOLLOWER;
+
+ $r = q("UPDATE `contact` SET `rel` = %d,
+ `name-date` = '%s',
+ `uri-date` = '%s',
+ `blocked` = 0,
+ `pending` = 0,
+ `writable` = 1
+ WHERE `id` = %d
+ ",
+ intval($new_relation),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ intval($contact_record["id"])
+ );
+
+ $u = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer["uid"]));
+ if($u)
+ $ret = self::send_share($u[0], $contact_record);
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Fetches a message with a given guid
+ *
+ * @param string $guid message guid
+ * @param string $orig_author handle of the original post
+ * @param string $author handle of the sharer
+ *
+ * @return array The fetched item
+ */
+ private function original_item($guid, $orig_author, $author) {
+
+ // Do we already have this item?
+ $r = q("SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`,
+ `author-name`, `author-link`, `author-avatar`
+ FROM `item` WHERE `guid` = '%s' AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1",
+ dbesc($guid));
+
+ if($r) {
+ logger("reshared message ".$guid." already exists on system.");
+
+ // Maybe it is already a reshared item?
+ // Then refetch the content, if it is a reshare from a reshare.
+ // If it is a reshared post from another network then reformat to avoid display problems with two share elements
+ if (self::is_reshare($r[0]["body"], true))
+ $r = array();
+ elseif (self::is_reshare($r[0]["body"], false)) {
+ $r[0]["body"] = diaspora2bb(bb2diaspora($r[0]["body"]));
+
+ // Add OEmbed and other information to the body
+ $r[0]["body"] = add_page_info_to_body($r[0]["body"], false, true);
+
+ return $r[0];
+ } else
+ return $r[0];
+ }
+
+ if (!$r) {
+ $server = "https://".substr($orig_author, strpos($orig_author, "@") + 1);
+ logger("1st try: reshared message ".$guid." will be fetched from original server: ".$server);
+ $item_id = self::store_by_guid($guid, $server);
+
+ if (!$item_id) {
+ $server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
+ logger("2nd try: reshared message ".$guid." will be fetched from original server: ".$server);
+ $item_id = self::store_by_guid($guid, $server);
+ }
+
+ // Deactivated by now since there is a risk that someone could manipulate postings through this method
+/* if (!$item_id) {
+ $server = "https://".substr($author, strpos($author, "@") + 1);
+ logger("3rd try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
+ $item_id = self::store_by_guid($guid, $server);
+ }
+ if (!$item_id) {
+ $server = "http://".substr($author, strpos($author, "@") + 1);
+ logger("4th try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
+ $item_id = self::store_by_guid($guid, $server);
+ }
*/
- if(!count($r)) {
- if($attempt <= 3) {
- q("INSERT INTO dsprphotoq (uid, msg, attempt) VALUES (%d, '%s', %d)",
- intval($importer['uid']),
- dbesc(serialize($msg)),
- intval($attempt + 1)
- );
- }
+ if ($item_id) {
+ $r = q("SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`,
+ `author-name`, `author-link`, `author-avatar`
+ FROM `item` WHERE `id` = %d AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1",
+ intval($item_id));
- logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid);
- return;
- }
+ if ($r)
+ return $r[0];
- $parent_item = $r[0];
-
- $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n";
-
- $link_text = scale_external_images($link_text, true,
- array($remote_photo_name, 'scaled_full_' . $remote_photo_name));
-
- if(strpos($parent_item['body'],$link_text) === false) {
-
- $parent_item['body'] = $link_text . $parent_item['body'];
-
- $r = q("UPDATE `item` SET `body` = '%s', `visible` = 1 WHERE `id` = %d AND `uid` = %d",
- dbesc($parent_item['body']),
- intval($parent_item['id']),
- intval($parent_item['uid'])
- );
- put_item_in_cache($parent_item, true);
- update_thread($parent_item['id']);
- }
-
- return;
-}
-
-
-
-
-function diaspora_like($importer,$xml,$msg) {
-
- $a = get_app();
- $guid = notags(unxmlify($xml->guid));
- $parent_guid = notags(unxmlify($xml->parent_guid));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
- $target_type = notags(unxmlify($xml->target_type));
- $positive = notags(unxmlify($xml->positive));
- $author_signature = notags(unxmlify($xml->author_signature));
-
- $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : '');
-
- // likes on comments not supported here and likes on photos not supported by Diaspora
-
-// if($target_type !== 'Post')
-// return;
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
- if(! $contact) {
- logger('diaspora_like: cannot find contact: ' . $msg['author']);
- return;
- }
-
- if(! diaspora_post_allow($importer,$contact, false)) {
- logger('diaspora_like: Ignoring this author.');
- return 202;
- }
-
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($parent_guid)
- );
-
- if(!count($r)) {
- $result = diaspora_store_by_guid($parent_guid, $contact['url'], $importer['uid']);
-
- if (!$result) {
- $person = find_diaspora_person_by_handle($diaspora_handle);
- $result = diaspora_store_by_guid($parent_guid, $person['url'], $importer['uid']);
- }
-
- if ($result) {
- logger("Fetched missing item ".$parent_guid." - result: ".$result, LOGGER_DEBUG);
-
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($parent_guid)
- );
- }
- }
-
- if(! count($r)) {
- logger('diaspora_like: parent item not found: ' . $guid);
- return;
- }
-
- $parent_item = $r[0];
-
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer['uid']),
- dbesc($guid)
- );
- if(count($r)) {
- if($positive === 'true') {
- logger('diaspora_like: duplicate like: ' . $guid);
- return;
- }
- // Note: I don't think "Like" objects with positive = "false" are ever actually used
- // It looks like "RelayableRetractions" are used for "unlike" instead
- if($positive === 'false') {
- logger('diaspora_like: received a like with positive set to "false"...ignoring');
-/* q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d",
- intval($r[0]['id']),
- intval($importer['uid'])
- );*/
- // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes
- // send notification via proc_run()
- return;
- }
- }
- // Note: I don't think "Like" objects with positive = "false" are ever actually used
- // It looks like "RelayableRetractions" are used for "unlike" instead
- if($positive === 'false') {
- logger('diaspora_like: received a like with positive set to "false"');
- logger('diaspora_like: unlike received with no corresponding like...ignoring');
- return;
- }
-
-
- /* How Diaspora performs "like" signature checking:
-
- - If an item has been sent by the like author to the top-level post owner to relay on
- to the rest of the contacts on the top-level post, the top-level post owner should check
- the author_signature, then create a parent_author_signature before relaying the like on
- - If an item has been relayed on by the top-level post owner, the contacts who receive it
- check only the parent_author_signature. Basically, they trust that the top-level post
- owner has already verified the authenticity of anything he/she sends out
- - In either case, the signature that get checked is the signature created by the person
- who sent the salmon
- */
-
- // Diaspora has changed the way they are signing the likes.
- // Just to make sure that we don't miss any likes we will check the old and the current way.
- $old_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
-
- $signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle;
-
- $key = $msg['key'];
-
- if ($parent_author_signature) {
- // If a parent_author_signature exists, then we've received the like
- // relayed from the top-level post owner. There's no need to check the
- // author_signature if the parent_author_signature is valid
-
- $parent_author_signature = base64_decode($parent_author_signature);
-
- if (!rsa_verify($signed_data,$parent_author_signature,$key,'sha256') AND
- !rsa_verify($old_signed_data,$parent_author_signature,$key,'sha256')) {
-
- logger('diaspora_like: top-level owner verification failed.');
- return;
- }
- } else {
- // If there's no parent_author_signature, then we've received the like
- // from the like creator. In that case, the person is "like"ing
- // our post, so he/she must be a contact of ours and his/her public key
- // should be in $msg['key']
-
- $author_signature = base64_decode($author_signature);
-
- if (!rsa_verify($signed_data,$author_signature,$key,'sha256') AND
- !rsa_verify($old_signed_data,$author_signature,$key,'sha256')) {
-
- logger('diaspora_like: like creator verification failed.');
- return;
- }
- }
-
- // Phew! Everything checks out. Now create an item.
-
- // Find the original comment author information.
- // We need this to make sure we display the comment author
- // information (name and avatar) correctly.
- if(strcasecmp($diaspora_handle,$msg['author']) == 0)
- $person = $contact;
- else {
- $person = find_diaspora_person_by_handle($diaspora_handle);
-
- if(! is_array($person)) {
- logger('diaspora_like: unable to find author details');
- return;
- }
- }
-
- $uri = $diaspora_handle . ':' . $guid;
-
- $activity = ACTIVITY_LIKE;
- $post_type = (($parent_item['resource-id']) ? t('photo') : t('status'));
- $objtype = (($parent_item['resource-id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
- $link = xmlify('' . "\n") ;
- $body = $parent_item['body'];
-
- $obj = <<< EOT
-
-
-EOT;
- $bodyverb = t('%1$s likes %2$s\'s %3$s');
-
- // Fetch the contact id - if we know this contact
- $r = q("SELECT `id`, `network` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d LIMIT 1",
- dbesc(normalise_link($person['url'])), intval($importer['uid']));
- if ($r) {
- $cid = $r[0]['id'];
- $network = $r[0]['network'];
- } else {
- $cid = $contact['id'];
- $network = NETWORK_DIASPORA;
- }
-
- $arr = array();
-
- $arr['uri'] = $uri;
- $arr['uid'] = $importer['uid'];
- $arr['guid'] = $guid;
- $arr['network'] = $network;
- $arr['contact-id'] = $cid;
- $arr['type'] = 'activity';
- $arr['wall'] = $parent_item['wall'];
- $arr['gravity'] = GRAVITY_LIKE;
- $arr['parent'] = $parent_item['id'];
- $arr['parent-uri'] = $parent_item['uri'];
-
- $arr['owner-name'] = $parent_item['name'];
- $arr['owner-link'] = $parent_item['url'];
- //$arr['owner-avatar'] = $parent_item['thumb'];
- $arr['owner-avatar'] = ((x($parent_item,'thumb')) ? $parent_item['thumb'] : $parent_item['photo']);
-
- $arr['author-name'] = $person['name'];
- $arr['author-link'] = $person['url'];
- $arr['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
-
- $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
- $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]';
- //$plink = '[url=' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . ']' . $post_type . '[/url]';
- $plink = '[url='.$a->get_baseurl().'/display/'.urlencode($guid).']'.$post_type.'[/url]';
- $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink );
-
- $arr['app'] = 'Diaspora';
-
- $arr['private'] = $parent_item['private'];
- $arr['verb'] = $activity;
- $arr['object-type'] = $objtype;
- $arr['object'] = $obj;
- $arr['visible'] = 1;
- $arr['unseen'] = 1;
- $arr['last-child'] = 0;
-
- $message_id = item_store($arr);
-
-
- //if($message_id) {
- // q("update item set plink = '%s' where id = %d",
- // //dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
- // dbesc($a->get_baseurl().'/display/'.$guid),
- // intval($message_id)
- // );
- //}
-
- // If we are the origin of the parent we store the original signature and notify our followers
- if($parent_item['origin']) {
- $author_signature_base64 = base64_encode($author_signature);
- $author_signature_base64 = diaspora_repair_signature($author_signature_base64, $diaspora_handle);
-
- q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- intval($message_id),
- dbesc($signed_data),
- dbesc($author_signature_base64),
- dbesc($diaspora_handle)
- );
-
- // notify others
- proc_run('php','include/notifier.php','comment-import',$message_id);
- }
-
- return;
-}
-
-function diaspora_retraction($importer,$xml) {
-
-
- $guid = notags(unxmlify($xml->guid));
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
- $type = notags(unxmlify($xml->type));
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact)
- return;
-
- if($type === 'Person') {
- require_once('include/Contact.php');
- contact_remove($contact['id']);
- } elseif($type === 'StatusMessage') {
- $guid = notags(unxmlify($xml->post_guid));
-
- $r = q("SELECT * FROM `item` WHERE `guid` = '%s' AND `uid` = %d AND NOT `file` LIKE '%%[%%' LIMIT 1",
- dbesc($guid),
- intval($importer['uid'])
- );
- if(count($r)) {
- if(link_compare($r[0]['author-link'],$contact['url'])) {
- q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `id` = %d",
- dbesc(datetime_convert()),
- intval($r[0]['id'])
- );
- delete_thread($r[0]['id'], $r[0]['parent-uri']);
}
}
- } elseif($type === 'Post') {
- $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1",
- dbesc('guid'),
- intval($importer['uid'])
+ return false;
+ }
+
+ /**
+ * @brief Processes a reshare message
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ * @param string $xml The original XML of the message
+ *
+ * @return int the message id
+ */
+ private function receive_reshare($importer, $data, $xml) {
+ $root_author = notags(unxmlify($data->root_author));
+ $root_guid = notags(unxmlify($data->root_guid));
+ $guid = notags(unxmlify($data->guid));
+ $author = notags(unxmlify($data->author));
+ $public = notags(unxmlify($data->public));
+ $created_at = notags(unxmlify($data->created_at));
+
+ $contact = self::allowed_contact_by_handle($importer, $author, false);
+ if (!$contact)
+ return false;
+
+ $message_id = self::message_exists($importer["uid"], $guid);
+ if ($message_id)
+ return $message_id;
+
+ $original_item = self::original_item($root_guid, $root_author, $author);
+ if (!$original_item)
+ return false;
+
+ $orig_url = App::get_baseurl()."/display/".$original_item["guid"];
+
+ $datarray = array();
+
+ $datarray["uid"] = $importer["uid"];
+ $datarray["contact-id"] = $contact["id"];
+ $datarray["network"] = NETWORK_DIASPORA;
+
+ $datarray["author-name"] = $contact["name"];
+ $datarray["author-link"] = $contact["url"];
+ $datarray["author-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+
+ $datarray["owner-name"] = $datarray["author-name"];
+ $datarray["owner-link"] = $datarray["author-link"];
+ $datarray["owner-avatar"] = $datarray["author-avatar"];
+
+ $datarray["guid"] = $guid;
+ $datarray["uri"] = $datarray["parent-uri"] = $author.":".$guid;
+
+ $datarray["verb"] = ACTIVITY_POST;
+ $datarray["gravity"] = GRAVITY_PARENT;
+
+ $datarray["object"] = $xml;
+
+ $prefix = share_header($original_item["author-name"], $original_item["author-link"], $original_item["author-avatar"],
+ $original_item["guid"], $original_item["created"], $orig_url);
+ $datarray["body"] = $prefix.$original_item["body"]."[/share]";
+
+ $datarray["tag"] = $original_item["tag"];
+ $datarray["app"] = $original_item["app"];
+
+ $datarray["plink"] = self::plink($author, $guid);
+ $datarray["private"] = (($public == "false") ? 1 : 0);
+ $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
+
+ $datarray["object-type"] = $original_item["object-type"];
+
+ self::fetch_guid($datarray);
+ $message_id = item_store($datarray);
+
+ if ($message_id)
+ logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
+
+ return $message_id;
+ }
+
+ /**
+ * @brief Processes retractions
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact of the item owner
+ * @param object $data The message object
+ *
+ * @return bool success
+ */
+ private function item_retraction($importer, $contact, $data) {
+ $target_type = notags(unxmlify($data->target_type));
+ $target_guid = notags(unxmlify($data->target_guid));
+ $author = notags(unxmlify($data->author));
+
+ $person = self::person_by_handle($author);
+ if (!is_array($person)) {
+ logger("unable to find author detail for ".$author);
+ return false;
+ }
+
+ $r = q("SELECT `id`, `parent`, `parent-uri`, `author-link` FROM `item` WHERE `guid` = '%s' AND `uid` = %d AND NOT `file` LIKE '%%[%%' LIMIT 1",
+ dbesc($target_guid),
+ intval($importer["uid"])
);
- if(count($r)) {
- if(link_compare($r[0]['author-link'],$contact['url'])) {
- q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d",
- dbesc(datetime_convert()),
- intval($r[0]['id'])
- );
- delete_thread($r[0]['id'], $r[0]['parent-uri']);
+ if (!$r)
+ return false;
+
+ // Only delete it if the author really fits
+ if (!link_compare($r[0]["author-link"], $person["url"])) {
+ logger("Item author ".$r[0]["author-link"]." doesn't fit to expected contact ".$person["url"], LOGGER_DEBUG);
+ return false;
+ }
+
+ // Check if the sender is the thread owner
+ $p = q("SELECT `id`, `author-link`, `origin` FROM `item` WHERE `id` = %d",
+ intval($r[0]["parent"]));
+
+ // Only delete it if the parent author really fits
+ if (!link_compare($p[0]["author-link"], $contact["url"]) AND !link_compare($r[0]["author-link"], $contact["url"])) {
+ logger("Thread author ".$p[0]["author-link"]." and item author ".$r[0]["author-link"]." don't fit to expected contact ".$contact["url"], LOGGER_DEBUG);
+ return false;
+ }
+
+ // Currently we don't have a central deletion function that we could use in this case. The function "item_drop" doesn't work for that case
+ q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '' , `title` = '' WHERE `id` = %d",
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ intval($r[0]["id"])
+ );
+ delete_thread($r[0]["id"], $r[0]["parent-uri"]);
+
+ logger("Deleted target ".$target_guid." (".$r[0]["id"].") from user ".$importer["uid"]." parent: ".$p[0]["id"], LOGGER_DEBUG);
+
+ // Now check if the retraction needs to be relayed by us
+ if($p[0]["origin"]) {
+ // notify others
+ proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Receives retraction messages
+ *
+ * @param array $importer Array of the importer user
+ * @param string $sender The sender of the message
+ * @param object $data The message object
+ *
+ * @return bool Success
+ */
+ private function receive_retraction($importer, $sender, $data) {
+ $target_type = notags(unxmlify($data->target_type));
+
+ $contact = self::contact_by_handle($importer["uid"], $sender);
+ if (!$contact) {
+ logger("cannot find contact for sender: ".$sender." and user ".$importer["uid"]);
+ return false;
+ }
+
+ logger("Got retraction for ".$target_type.", sender ".$sender." and user ".$importer["uid"], LOGGER_DEBUG);
+
+ switch ($target_type) {
+ case "Comment":
+ case "Like":
+ case "Post": // "Post" will be supported in a future version
+ case "Reshare":
+ case "StatusMessage":
+ return self::item_retraction($importer, $contact, $data);;
+
+ case "Person":
+ /// @todo What should we do with an "unshare"?
+ // Removing the contact isn't correct since we still can read the public items
+ //contact_remove($contact["id"]);
+ return true;
+
+ default:
+ logger("Unknown target type ".$target_type);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @brief Receives status messages
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ * @param string $xml The original XML of the message
+ *
+ * @return int The message id of the newly created item
+ */
+ private function receive_status_message($importer, $data, $xml) {
+
+ $raw_message = unxmlify($data->raw_message);
+ $guid = notags(unxmlify($data->guid));
+ $author = notags(unxmlify($data->author));
+ $public = notags(unxmlify($data->public));
+ $created_at = notags(unxmlify($data->created_at));
+ $provider_display_name = notags(unxmlify($data->provider_display_name));
+
+ /// @todo enable support for polls
+ //if ($data->poll) {
+ // foreach ($data->poll AS $poll)
+ // print_r($poll);
+ // die("poll!\n");
+ //}
+ $contact = self::allowed_contact_by_handle($importer, $author, false);
+ if (!$contact)
+ return false;
+
+ $message_id = self::message_exists($importer["uid"], $guid);
+ if ($message_id)
+ return $message_id;
+
+ $address = array();
+ if ($data->location)
+ foreach ($data->location->children() AS $fieldname => $data)
+ $address[$fieldname] = notags(unxmlify($data));
+
+ $body = diaspora2bb($raw_message);
+
+ $datarray = array();
+
+ // Attach embedded pictures to the body
+ if ($data->photo) {
+ foreach ($data->photo AS $photo)
+ $body = "[img]".unxmlify($photo->remote_photo_path).
+ unxmlify($photo->remote_photo_name)."[/img]\n".$body;
+
+ $datarray["object-type"] = ACTIVITY_OBJ_PHOTO;
+ } else {
+ $datarray["object-type"] = ACTIVITY_OBJ_NOTE;
+
+ // Add OEmbed and other information to the body
+ if (!self::is_redmatrix($contact["url"]))
+ $body = add_page_info_to_body($body, false, true);
+ }
+
+ $datarray["uid"] = $importer["uid"];
+ $datarray["contact-id"] = $contact["id"];
+ $datarray["network"] = NETWORK_DIASPORA;
+
+ $datarray["author-name"] = $contact["name"];
+ $datarray["author-link"] = $contact["url"];
+ $datarray["author-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+
+ $datarray["owner-name"] = $datarray["author-name"];
+ $datarray["owner-link"] = $datarray["author-link"];
+ $datarray["owner-avatar"] = $datarray["author-avatar"];
+
+ $datarray["guid"] = $guid;
+ $datarray["uri"] = $datarray["parent-uri"] = $author.":".$guid;
+
+ $datarray["verb"] = ACTIVITY_POST;
+ $datarray["gravity"] = GRAVITY_PARENT;
+
+ $datarray["object"] = $xml;
+
+ $datarray["body"] = $body;
+
+ if ($provider_display_name != "")
+ $datarray["app"] = $provider_display_name;
+
+ $datarray["plink"] = self::plink($author, $guid);
+ $datarray["private"] = (($public == "false") ? 1 : 0);
+ $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
+
+ if (isset($address["address"]))
+ $datarray["location"] = $address["address"];
+
+ if (isset($address["lat"]) AND isset($address["lng"]))
+ $datarray["coord"] = $address["lat"]." ".$address["lng"];
+
+ self::fetch_guid($datarray);
+ $message_id = item_store($datarray);
+
+ if ($message_id)
+ logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
+
+ return $message_id;
+ }
+
+ /* ************************************************************************************** *
+ * Here are all the functions that are needed to transmit data with the Diaspora protocol *
+ * ************************************************************************************** */
+
+ /**
+ * @brief returnes the handle of a contact
+ *
+ * @param array $me contact array
+ *
+ * @return string the handle in the format user@domain.tld
+ */
+ private function my_handle($contact) {
+ if ($contact["addr"] != "")
+ return $contact["addr"];
+
+ // Normally we should have a filled "addr" field - but in the past this wasn't the case
+ // So - just in case - we build the the address here.
+ if ($contact["nickname"] != "")
+ $nick = $contact["nickname"];
+ else
+ $nick = $contact["nick"];
+
+ return $nick."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
+ }
+
+ /**
+ * @brief Creates the envelope for a public message
+ *
+ * @param string $msg The message that is to be transmitted
+ * @param array $user The record of the sender
+ * @param array $contact Target of the communication
+ * @param string $prvkey The private key of the sender
+ * @param string $pubkey The public key of the receiver
+ *
+ * @return string The envelope
+ */
+ private function build_public_message($msg, $user, $contact, $prvkey, $pubkey) {
+
+ logger("Message: ".$msg, LOGGER_DATA);
+
+ $handle = self::my_handle($user);
+
+ $b64url_data = base64url_encode($msg);
+
+ $data = str_replace(array("\n", "\r", " ", "\t"), array("", "", "", ""), $b64url_data);
+
+ $type = "application/xml";
+ $encoding = "base64url";
+ $alg = "RSA-SHA256";
+
+ $signable_data = $data.".".base64url_encode($type).".".base64url_encode($encoding).".".base64url_encode($alg);
+
+ $signature = rsa_sign($signable_data,$prvkey);
+ $sig = base64url_encode($signature);
+
+ $xmldata = array("diaspora" => array("header" => array("author_id" => $handle),
+ "me:env" => array("me:encoding" => "base64url",
+ "me:alg" => "RSA-SHA256",
+ "me:data" => $data,
+ "@attributes" => array("type" => "application/xml"),
+ "me:sig" => $sig)));
+
+ $namespaces = array("" => "https://joindiaspora.com/protocol",
+ "me" => "http://salmon-protocol.org/ns/magic-env");
+
+ $magic_env = xml::from_array($xmldata, $xml, false, $namespaces);
+
+ logger("magic_env: ".$magic_env, LOGGER_DATA);
+ return $magic_env;
+ }
+
+ /**
+ * @brief Creates the envelope for a private message
+ *
+ * @param string $msg The message that is to be transmitted
+ * @param array $user The record of the sender
+ * @param array $contact Target of the communication
+ * @param string $prvkey The private key of the sender
+ * @param string $pubkey The public key of the receiver
+ *
+ * @return string The envelope
+ */
+ private function build_private_message($msg, $user, $contact, $prvkey, $pubkey) {
+
+ logger("Message: ".$msg, LOGGER_DATA);
+
+ // without a public key nothing will work
+
+ if (!$pubkey) {
+ logger("pubkey missing: contact id: ".$contact["id"]);
+ return false;
+ }
+
+ $inner_aes_key = random_string(32);
+ $b_inner_aes_key = base64_encode($inner_aes_key);
+ $inner_iv = random_string(16);
+ $b_inner_iv = base64_encode($inner_iv);
+
+ $outer_aes_key = random_string(32);
+ $b_outer_aes_key = base64_encode($outer_aes_key);
+ $outer_iv = random_string(16);
+ $b_outer_iv = base64_encode($outer_iv);
+
+ $handle = self::my_handle($user);
+
+ $padded_data = pkcs5_pad($msg,16);
+ $inner_encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $padded_data, MCRYPT_MODE_CBC, $inner_iv);
+
+ $b64_data = base64_encode($inner_encrypted);
+
+
+ $b64url_data = base64url_encode($b64_data);
+ $data = str_replace(array("\n", "\r", " ", "\t"), array("", "", "", ""), $b64url_data);
+
+ $type = "application/xml";
+ $encoding = "base64url";
+ $alg = "RSA-SHA256";
+
+ $signable_data = $data.".".base64url_encode($type).".".base64url_encode($encoding).".".base64url_encode($alg);
+
+ $signature = rsa_sign($signable_data,$prvkey);
+ $sig = base64url_encode($signature);
+
+ $xmldata = array("decrypted_header" => array("iv" => $b_inner_iv,
+ "aes_key" => $b_inner_aes_key,
+ "author_id" => $handle));
+
+ $decrypted_header = xml::from_array($xmldata, $xml, true);
+ $decrypted_header = pkcs5_pad($decrypted_header,16);
+
+ $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $outer_aes_key, $decrypted_header, MCRYPT_MODE_CBC, $outer_iv);
+
+ $outer_json = json_encode(array("iv" => $b_outer_iv, "key" => $b_outer_aes_key));
+
+ $encrypted_outer_key_bundle = "";
+ openssl_public_encrypt($outer_json, $encrypted_outer_key_bundle, $pubkey);
+
+ $b64_encrypted_outer_key_bundle = base64_encode($encrypted_outer_key_bundle);
+
+ logger("outer_bundle: ".$b64_encrypted_outer_key_bundle." key: ".$pubkey, LOGGER_DATA);
+
+ $encrypted_header_json_object = json_encode(array("aes_key" => base64_encode($encrypted_outer_key_bundle),
+ "ciphertext" => base64_encode($ciphertext)));
+ $cipher_json = base64_encode($encrypted_header_json_object);
+
+ $xmldata = array("diaspora" => array("encrypted_header" => $cipher_json,
+ "me:env" => array("me:encoding" => "base64url",
+ "me:alg" => "RSA-SHA256",
+ "me:data" => $data,
+ "@attributes" => array("type" => "application/xml"),
+ "me:sig" => $sig)));
+
+ $namespaces = array("" => "https://joindiaspora.com/protocol",
+ "me" => "http://salmon-protocol.org/ns/magic-env");
+
+ $magic_env = xml::from_array($xmldata, $xml, false, $namespaces);
+
+ logger("magic_env: ".$magic_env, LOGGER_DATA);
+ return $magic_env;
+ }
+
+ /**
+ * @brief Create the envelope for a message
+ *
+ * @param string $msg The message that is to be transmitted
+ * @param array $user The record of the sender
+ * @param array $contact Target of the communication
+ * @param string $prvkey The private key of the sender
+ * @param string $pubkey The public key of the receiver
+ * @param bool $public Is the message public?
+ *
+ * @return string The message that will be transmitted to other servers
+ */
+ private function build_message($msg, $user, $contact, $prvkey, $pubkey, $public = false) {
+
+ if ($public)
+ $magic_env = self::build_public_message($msg,$user,$contact,$prvkey,$pubkey);
+ else
+ $magic_env = self::build_private_message($msg,$user,$contact,$prvkey,$pubkey);
+
+ // The data that will be transmitted is double encoded via "urlencode", strange ...
+ $slap = "xml=".urlencode(urlencode($magic_env));
+ return $slap;
+ }
+
+ /**
+ * @brief Creates a signature for a message
+ *
+ * @param array $owner the array of the owner of the message
+ * @param array $message The message that is to be signed
+ *
+ * @return string The signature
+ */
+ private function signature($owner, $message) {
+ $sigmsg = $message;
+ unset($sigmsg["author_signature"]);
+ unset($sigmsg["parent_author_signature"]);
+
+ $signed_text = implode(";", $sigmsg);
+
+ return base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+ }
+
+ /**
+ * @brief Transmit a message to a target server
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ * @param string $slap The message that is to be transmitted
+ * @param bool $public_batch Is it a public post?
+ * @param bool $queue_run Is the transmission called from the queue?
+ * @param string $guid message guid
+ *
+ * @return int Result of the transmission
+ */
+ public static function transmit($owner, $contact, $slap, $public_batch, $queue_run=false, $guid = "") {
+
+ $a = get_app();
+
+ $enabled = intval(get_config("system", "diaspora_enabled"));
+ if(!$enabled)
+ return 200;
+
+ $logid = random_string(4);
+ $dest_url = (($public_batch) ? $contact["batch"] : $contact["notify"]);
+ if (!$dest_url) {
+ logger("no url for contact: ".$contact["id"]." batch mode =".$public_batch);
+ return 0;
+ }
+
+ logger("transmit: ".$logid."-".$guid." ".$dest_url);
+
+ if (!$queue_run && was_recently_delayed($contact["id"])) {
+ $return_code = 0;
+ } else {
+ if (!intval(get_config("system", "diaspora_test"))) {
+ post_url($dest_url."/", $slap);
+ $return_code = $a->get_curl_code();
+ } else {
+ logger("test_mode");
+ return 200;
}
}
- }
- return 202;
- // NOTREACHED
-}
+ logger("transmit: ".$logid."-".$guid." returns: ".$return_code);
-function diaspora_signed_retraction($importer,$xml,$msg) {
+ if(!$return_code || (($return_code == 503) && (stristr($a->get_curl_headers(), "retry-after")))) {
+ logger("queue message");
-
- $guid = notags(unxmlify($xml->target_guid));
- $diaspora_handle = notags(unxmlify($xml->sender_handle));
- $type = notags(unxmlify($xml->target_type));
- $sig = notags(unxmlify($xml->target_author_signature));
-
- $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : '');
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact) {
- logger('diaspora_signed_retraction: no contact ' . $diaspora_handle . ' for ' . $importer['uid']);
- return;
- }
-
-
- $signed_data = $guid . ';' . $type ;
- $key = $msg['key'];
-
- /* How Diaspora performs relayable_retraction signature checking:
-
- - If an item has been sent by the item author to the top-level post owner to relay on
- to the rest of the contacts on the top-level post, the top-level post owner checks
- the author_signature, then creates a parent_author_signature before relaying the item on
- - If an item has been relayed on by the top-level post owner, the contacts who receive it
- check only the parent_author_signature. Basically, they trust that the top-level post
- owner has already verified the authenticity of anything he/she sends out
- - In either case, the signature that get checked is the signature created by the person
- who sent the salmon
- */
-
- if($parent_author_signature) {
-
- $parent_author_signature = base64_decode($parent_author_signature);
-
- if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
- logger('diaspora_signed_retraction: top-level post owner verification failed');
- return;
+ $r = q("SELECT `id` FROM `queue` WHERE `cid` = %d AND `network` = '%s' AND `content` = '%s' AND `batch` = %d LIMIT 1",
+ intval($contact["id"]),
+ dbesc(NETWORK_DIASPORA),
+ dbesc($slap),
+ intval($public_batch)
+ );
+ if($r) {
+ logger("add_to_queue ignored - identical item already in queue");
+ } else {
+ // queue message for redelivery
+ add_to_queue($contact["id"], NETWORK_DIASPORA, $slap, $public_batch);
+ }
}
- } else {
-
- $sig_decode = base64_decode($sig);
-
- if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) {
- logger('diaspora_signed_retraction: retraction owner verification failed.' . print_r($msg,true));
- return;
- }
+ return(($return_code) ? $return_code : (-1));
}
- if($type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') {
- $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1",
- dbesc($guid),
- intval($importer['uid'])
+
+ /**
+ * @brief Builds and transmit messages
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ * @param string $type The message type
+ * @param array $message The message data
+ * @param bool $public_batch Is it a public post?
+ * @param string $guid message guid
+ * @param bool $spool Should the transmission be spooled or transmitted?
+ *
+ * @return int Result of the transmission
+ */
+ private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "", $spool = false) {
+
+ $data = array("XML" => array("post" => array($type => $message)));
+
+ $msg = xml::from_array($data, $xml);
+
+ logger('message: '.$msg, LOGGER_DATA);
+ logger('send guid '.$guid, LOGGER_DEBUG);
+
+ $slap = self::build_message($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
+
+ if ($spool) {
+ add_to_queue($contact['id'], NETWORK_DIASPORA, $slap, $public_batch);
+ return true;
+ } else
+ $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $guid);
+
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
+ }
+
+ /**
+ * @brief Sends a "share" message
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_share($owner,$contact) {
+
+ $message = array("sender_handle" => self::my_handle($owner),
+ "recipient_handle" => $contact["addr"]);
+
+ return self::build_and_transmit($owner, $contact, "request", $message);
+ }
+
+ /**
+ * @brief sends an "unshare"
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_unshare($owner,$contact) {
+
+ $message = array("post_guid" => $owner["guid"],
+ "diaspora_handle" => self::my_handle($owner),
+ "type" => "Person");
+
+ return self::build_and_transmit($owner, $contact, "retraction", $message);
+ }
+
+ /**
+ * @brief Checks a message body if it is a reshare
+ *
+ * @param string $body The message body that is to be check
+ * @param bool $complete Should it be a complete check or a simple check?
+ *
+ * @return array|bool Reshare details or "false" if no reshare
+ */
+ public static function is_reshare($body, $complete = true) {
+ $body = trim($body);
+
+ // Skip if it isn't a pure repeated messages
+ // Does it start with a share?
+ if (strpos($body, "[share") > 0)
+ return(false);
+
+ // Does it end with a share?
+ if (strlen($body) > (strrpos($body, "[/share]") + 8))
+ return(false);
+
+ $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
+ // Skip if there is no shared message in there
+ if ($body == $attributes)
+ return(false);
+
+ // If we don't do the complete check we quit here
+ if (!$complete)
+ return true;
+
+ $guid = "";
+ preg_match("/guid='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $guid = $matches[1];
+
+ preg_match('/guid="(.*?)"/ism', $attributes, $matches);
+ if ($matches[1] != "")
+ $guid = $matches[1];
+
+ if ($guid != "") {
+ $r = q("SELECT `contact-id` FROM `item` WHERE `guid` = '%s' AND `network` IN ('%s', '%s') LIMIT 1",
+ dbesc($guid), NETWORK_DFRN, NETWORK_DIASPORA);
+ if ($r) {
+ $ret= array();
+ $ret["root_handle"] = self::handle_from_contact($r[0]["contact-id"]);
+ $ret["root_guid"] = $guid;
+ return($ret);
+ }
+ }
+
+ $profile = "";
+ preg_match("/profile='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $profile = $matches[1];
+
+ preg_match('/profile="(.*?)"/ism', $attributes, $matches);
+ if ($matches[1] != "")
+ $profile = $matches[1];
+
+ $ret= array();
+
+ $ret["root_handle"] = preg_replace("=https?://(.*)/u/(.*)=ism", "$2@$1", $profile);
+ if (($ret["root_handle"] == $profile) OR ($ret["root_handle"] == ""))
+ return(false);
+
+ $link = "";
+ preg_match("/link='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $link = $matches[1];
+
+ preg_match('/link="(.*?)"/ism', $attributes, $matches);
+ if ($matches[1] != "")
+ $link = $matches[1];
+
+ $ret["root_guid"] = preg_replace("=https?://(.*)/posts/(.*)=ism", "$2", $link);
+ if (($ret["root_guid"] == $link) OR (trim($ret["root_guid"]) == ""))
+ return(false);
+
+ return($ret);
+ }
+
+ /**
+ * @brief Sends a post
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ * @param bool $public_batch Is it a public post?
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_status($item, $owner, $contact, $public_batch = false) {
+
+ $myaddr = self::my_handle($owner);
+
+ $public = (($item["private"]) ? "false" : "true");
+
+ $created = datetime_convert("UTC", "UTC", $item["created"], 'Y-m-d H:i:s \U\T\C');
+
+ // Detect a share element and do a reshare
+ if (!$item['private'] AND ($ret = self::is_reshare($item["body"]))) {
+ $message = array("root_diaspora_id" => $ret["root_handle"],
+ "root_guid" => $ret["root_guid"],
+ "guid" => $item["guid"],
+ "diaspora_handle" => $myaddr,
+ "public" => $public,
+ "created_at" => $created,
+ "provider_display_name" => $item["app"]);
+
+ $type = "reshare";
+ } else {
+ $title = $item["title"];
+ $body = $item["body"];
+
+ // convert to markdown
+ $body = html_entity_decode(bb2diaspora($body));
+
+ // Adding the title
+ if(strlen($title))
+ $body = "## ".html_entity_decode($title)."\n\n".$body;
+
+ if ($item["attach"]) {
+ $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism', $item["attach"], $matches, PREG_SET_ORDER);
+ if(cnt) {
+ $body .= "\n".t("Attachments:")."\n";
+ foreach($matches as $mtch)
+ $body .= "[".$mtch[3]."](".$mtch[1].")\n";
+ }
+ }
+
+ $location = array();
+
+ if ($item["location"] != "")
+ $location["address"] = $item["location"];
+
+ if ($item["coord"] != "") {
+ $coord = explode(" ", $item["coord"]);
+ $location["lat"] = $coord[0];
+ $location["lng"] = $coord[1];
+ }
+
+ $message = array("raw_message" => $body,
+ "location" => $location,
+ "guid" => $item["guid"],
+ "diaspora_handle" => $myaddr,
+ "public" => $public,
+ "created_at" => $created,
+ "provider_display_name" => $item["app"]);
+
+ if (count($location) == 0)
+ unset($message["location"]);
+
+ $type = "status_message";
+ }
+
+ return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
+ }
+
+ /**
+ * @brief Creates a "like" object
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ *
+ * @return array The data for a "like"
+ */
+ private function construct_like($item, $owner) {
+
+ $p = q("SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1",
+ dbesc($item["thr-parent"]));
+ if(!$p)
+ return false;
+
+ $parent = $p[0];
+
+ $target_type = ($parent["uri"] === $parent["parent-uri"] ? "Post" : "Comment");
+ $positive = "true";
+
+ return(array("positive" => $positive,
+ "guid" => $item["guid"],
+ "target_type" => $target_type,
+ "parent_guid" => $parent["guid"],
+ "author_signature" => "",
+ "diaspora_handle" => self::my_handle($owner)));
+ }
+
+ /**
+ * @brief Creates the object for a comment
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ *
+ * @return array The data for a comment
+ */
+ private function construct_comment($item, $owner) {
+
+ $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
+ intval($item["parent"]),
+ intval($item["parent"])
);
- if(count($r)) {
- if(link_compare($r[0]['author-link'],$contact['url'])) {
- q("update item set `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '' , `title` = '' where `id` = %d",
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- intval($r[0]['id'])
- );
- delete_thread($r[0]['id'], $r[0]['parent-uri']);
- // Now check if the retraction needs to be relayed by us
- //
- // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always
- // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent.
- // The only item with `parent` and `id` as the parent id is the parent item.
- $p = q("SELECT `origin` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
- intval($r[0]['parent']),
- intval($r[0]['parent'])
- );
- if(count($p)) {
- if($p[0]['origin']) {
- q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- $r[0]['id'],
- dbesc($signed_data),
- dbesc($sig),
- dbesc($diaspora_handle)
- );
+ if (!$p)
+ return false;
- // the existence of parent_author_signature would have meant the parent_author or owner
- // is already relaying.
- logger('diaspora_signed_retraction: relaying relayable_retraction');
+ $parent = $p[0];
- proc_run('php','include/notifier.php','drop',$r[0]['id']);
+ $text = html_entity_decode(bb2diaspora($item["body"]));
+
+ return(array("guid" => $item["guid"],
+ "parent_guid" => $parent["guid"],
+ "author_signature" => "",
+ "text" => $text,
+ "diaspora_handle" => self::my_handle($owner)));
+ }
+
+ /**
+ * @brief Send a like or a comment
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ * @param bool $public_batch Is it a public post?
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_followup($item,$owner,$contact,$public_batch = false) {
+
+ if($item['verb'] === ACTIVITY_LIKE) {
+ $message = self::construct_like($item, $owner);
+ $type = "like";
+ } else {
+ $message = self::construct_comment($item, $owner);
+ $type = "comment";
+ }
+
+ if (!$message)
+ return false;
+
+ $message["author_signature"] = self::signature($owner, $message);
+
+ return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
+ }
+
+ /**
+ * @brief Creates a message from a signature record entry
+ *
+ * @param array $item The item that will be exported
+ * @param array $signature The entry of the "sign" record
+ *
+ * @return string The message
+ */
+ private function message_from_signature($item, $signature) {
+
+ // Split the signed text
+ $signed_parts = explode(";", $signature['signed_text']);
+
+ if ($item["deleted"])
+ $message = array("parent_author_signature" => "",
+ "target_guid" => $signed_parts[0],
+ "target_type" => $signed_parts[1],
+ "sender_handle" => $signature['signer'],
+ "target_author_signature" => $signature['signature']);
+ elseif ($item['verb'] === ACTIVITY_LIKE)
+ $message = array("positive" => $signed_parts[0],
+ "guid" => $signed_parts[1],
+ "target_type" => $signed_parts[2],
+ "parent_guid" => $signed_parts[3],
+ "parent_author_signature" => "",
+ "author_signature" => $signature['signature'],
+ "diaspora_handle" => $signed_parts[4]);
+ else {
+ // Remove the comment guid
+ $guid = array_shift($signed_parts);
+
+ // Remove the parent guid
+ $parent_guid = array_shift($signed_parts);
+
+ // Remove the handle
+ $handle = array_pop($signed_parts);
+
+ // Glue the parts together
+ $text = implode(";", $signed_parts);
+
+ $message = array("guid" => $guid,
+ "parent_guid" => $parent_guid,
+ "parent_author_signature" => "",
+ "author_signature" => $signature['signature'],
+ "text" => implode(";", $signed_parts),
+ "diaspora_handle" => $handle);
+ }
+ return $message;
+ }
+
+ /**
+ * @brief Relays messages (like, comment, retraction) to other servers if we are the thread owner
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ * @param bool $public_batch Is it a public post?
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_relay($item, $owner, $contact, $public_batch = false) {
+
+ if ($item["deleted"])
+ return self::send_retraction($item, $owner, $contact, $public_batch, true);
+ elseif ($item['verb'] === ACTIVITY_LIKE)
+ $type = "like";
+ else
+ $type = "comment";
+
+ logger("Got relayable data ".$type." for item ".$item["guid"]." (".$item["id"].")", LOGGER_DEBUG);
+
+ // fetch the original signature
+
+ $r = q("SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE `iid` = %d LIMIT 1",
+ intval($item["id"]));
+
+ if (!$r) {
+ logger("Couldn't fetch signatur for item ".$item["guid"]." (".$item["id"].")", LOGGER_DEBUG);
+ return false;
+ }
+
+ $signature = $r[0];
+
+ // Old way - is used by the internal Friendica functions
+ /// @todo Change all signatur storing functions to the new format
+ if ($signature['signed_text'] AND $signature['signature'] AND $signature['signer'])
+ $message = self::message_from_signature($item, $signature);
+ else {// New way
+ $msg = json_decode($signature['signed_text'], true);
+
+ $message = array();
+ if (is_array($msg)) {
+ foreach ($msg AS $field => $data) {
+ if (!$item["deleted"]) {
+ if ($field == "author")
+ $field = "diaspora_handle";
+ if ($field == "parent_type")
+ $field = "target_type";
+ }
+
+ $message[$field] = $data;
+ }
+ } else
+ logger("Signature text for item ".$item["guid"]." (".$item["id"].") couldn't be extracted: ".$signature['signed_text'], LOGGER_DEBUG);
+ }
+
+ $message["parent_author_signature"] = self::signature($owner, $message);
+
+ logger("Relayed data ".print_r($message, true), LOGGER_DEBUG);
+
+ return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
+ }
+
+ /**
+ * @brief Sends a retraction (deletion) of a message, like or comment
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact Target of the communication
+ * @param bool $public_batch Is it a public post?
+ * @param bool $relay Is the retraction transmitted from a relay?
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_retraction($item, $owner, $contact, $public_batch = false, $relay = false) {
+
+ $itemaddr = self::handle_from_contact($item["contact-id"], $item["gcontact-id"]);
+
+ // Check whether the retraction is for a top-level post or whether it's a relayable
+ if ($item["uri"] !== $item["parent-uri"]) {
+ $msg_type = "relayable_retraction";
+ $target_type = (($item["verb"] === ACTIVITY_LIKE) ? "Like" : "Comment");
+ } else {
+ $msg_type = "signed_retraction";
+ $target_type = "StatusMessage";
+ }
+
+ if ($relay AND ($item["uri"] !== $item["parent-uri"]))
+ $signature = "parent_author_signature";
+ else
+ $signature = "target_author_signature";
+
+ $signed_text = $item["guid"].";".$target_type;
+
+ $message = array("target_guid" => $item['guid'],
+ "target_type" => $target_type,
+ "sender_handle" => $itemaddr,
+ $signature => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
+
+ logger("Got message ".print_r($message, true), LOGGER_DEBUG);
+
+ return self::build_and_transmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]);
+ }
+
+ /**
+ * @brief Sends a mail
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner The owner
+ * @param array $contact Target of the communication
+ *
+ * @return int The result of the transmission
+ */
+ public static function send_mail($item, $owner, $contact) {
+
+ $myaddr = self::my_handle($owner);
+
+ $r = q("SELECT * FROM `conv` WHERE `id` = %d AND `uid` = %d LIMIT 1",
+ intval($item["convid"]),
+ intval($item["uid"])
+ );
+
+ if (!$r) {
+ logger("conversation not found.");
+ return;
+ }
+ $cnv = $r[0];
+
+ $conv = array(
+ "guid" => $cnv["guid"],
+ "subject" => $cnv["subject"],
+ "created_at" => datetime_convert("UTC", "UTC", $cnv['created'], 'Y-m-d H:i:s \U\T\C'),
+ "diaspora_handle" => $cnv["creator"],
+ "participant_handles" => $cnv["recips"]
+ );
+
+ $body = bb2diaspora($item["body"]);
+ $created = datetime_convert("UTC", "UTC", $item["created"], 'Y-m-d H:i:s \U\T\C');
+
+ $signed_text = $item["guid"].";".$cnv["guid"].";".$body.";".$created.";".$myaddr.";".$cnv['guid'];
+ $sig = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+
+ $msg = array(
+ "guid" => $item["guid"],
+ "parent_guid" => $cnv["guid"],
+ "parent_author_signature" => $sig,
+ "author_signature" => $sig,
+ "text" => $body,
+ "created_at" => $created,
+ "diaspora_handle" => $myaddr,
+ "conversation_guid" => $cnv["guid"]
+ );
+
+ if ($item["reply"]) {
+ $message = $msg;
+ $type = "message";
+ } else {
+ $message = array("guid" => $cnv["guid"],
+ "subject" => $cnv["subject"],
+ "created_at" => datetime_convert("UTC", "UTC", $cnv['created'], 'Y-m-d H:i:s \U\T\C'),
+ "message" => $msg,
+ "diaspora_handle" => $cnv["creator"],
+ "participant_handles" => $cnv["recips"]);
+
+ $type = "conversation";
+ }
+
+ return self::build_and_transmit($owner, $contact, $type, $message, false, $item["guid"]);
+ }
+
+ /**
+ * @brief Sends profile data
+ *
+ * @param int $uid The user id
+ */
+ public static function send_profile($uid) {
+
+ if (!$uid)
+ return;
+
+ $recips = q("SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s'
+ AND `uid` = %d AND `rel` != %d",
+ dbesc(NETWORK_DIASPORA),
+ intval($uid),
+ intval(CONTACT_IS_SHARING)
+ );
+ if (!$recips)
+ return;
+
+ $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.*, `user`.`prvkey` AS `uprvkey`, `contact`.`addr`
+ FROM `profile`
+ INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
+ INNER JOIN `contact` ON `profile`.`uid` = `contact`.`uid`
+ WHERE `user`.`uid` = %d AND `profile`.`is-default` AND `contact`.`self` LIMIT 1",
+ intval($uid)
+ );
+
+ if (!$r)
+ return;
+
+ $profile = $r[0];
+
+ $handle = $profile["addr"];
+ $first = ((strpos($profile['name'],' ')
+ ? trim(substr($profile['name'],0,strpos($profile['name'],' '))) : $profile['name']));
+ $last = (($first === $profile['name']) ? '' : trim(substr($profile['name'], strlen($first))));
+ $large = App::get_baseurl().'/photo/custom/300/'.$profile['uid'].'.jpg';
+ $medium = App::get_baseurl().'/photo/custom/100/'.$profile['uid'].'.jpg';
+ $small = App::get_baseurl().'/photo/custom/50/' .$profile['uid'].'.jpg';
+ $searchable = (($profile['publish'] && $profile['net-publish']) ? 'true' : 'false');
+
+ if ($searchable === 'true') {
+ $dob = '1000-00-00';
+
+ if (($profile['dob']) && ($profile['dob'] != '0000-00-00'))
+ $dob = ((intval($profile['dob'])) ? intval($profile['dob']) : '1000') .'-'. datetime_convert('UTC','UTC',$profile['dob'],'m-d');
+
+ $about = $profile['about'];
+ $about = strip_tags(bbcode($about));
+
+ $location = formatted_location($profile);
+ $tags = '';
+ if ($profile['pub_keywords']) {
+ $kw = str_replace(',',' ',$profile['pub_keywords']);
+ $kw = str_replace(' ',' ',$kw);
+ $arr = explode(' ',$profile['pub_keywords']);
+ if (count($arr)) {
+ for($x = 0; $x < 5; $x ++) {
+ if (trim($arr[$x]))
+ $tags .= '#'. trim($arr[$x]) .' ';
}
}
}
+ $tags = trim($tags);
}
- }
- else
- logger('diaspora_signed_retraction: unknown type: ' . $type);
- return 202;
- // NOTREACHED
-}
+ $message = array("diaspora_handle" => $handle,
+ "first_name" => $first,
+ "last_name" => $last,
+ "image_url" => $large,
+ "image_url_medium" => $medium,
+ "image_url_small" => $small,
+ "birthday" => $dob,
+ "gender" => $profile['gender'],
+ "bio" => $about,
+ "location" => $location,
+ "searchable" => $searchable,
+ "tag_string" => $tags);
-function diaspora_profile($importer,$xml,$msg) {
-
- $a = get_app();
- $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
-
-
- if($diaspora_handle != $msg['author']) {
- logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.');
- return 202;
+ foreach($recips as $recip)
+ self::build_and_transmit($profile, $recip, "profile", $message, false, "", true);
}
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact)
- return;
+ /**
+ * @brief Stores the signature for likes that are created on our system
+ *
+ * @param array $contact The contact array of the "like"
+ * @param int $post_id The post id of the "like"
+ *
+ * @return bool Success
+ */
+ public static function store_like_signature($contact, $post_id) {
- //if($contact['blocked']) {
- // logger('diaspora_post: Ignoring this author.');
- // return 202;
- //}
-
- $name = unxmlify($xml->first_name) . ((strlen($xml->last_name)) ? ' ' . unxmlify($xml->last_name) : '');
- $image_url = unxmlify($xml->image_url);
- $birthday = unxmlify($xml->birthday);
- $location = diaspora2bb(unxmlify($xml->location));
- $about = diaspora2bb(unxmlify($xml->bio));
- $gender = unxmlify($xml->gender);
- $searchable = (unxmlify($xml->searchable) == "true");
- $nsfw = (unxmlify($xml->nsfw) == "true");
- $tags = unxmlify($xml->tag_string);
-
- $tags = explode("#", $tags);
-
- $keywords = array();
- foreach ($tags as $tag) {
- $tag = trim(strtolower($tag));
- if ($tag != "")
- $keywords[] = $tag;
- }
-
- $keywords = implode(", ", $keywords);
-
- $handle_parts = explode("@", $diaspora_handle);
- $nick = $handle_parts[0];
-
- if($name === '') {
- $name = $handle_parts[0];
- }
-
- if( preg_match("|^https?://|", $image_url) === 0) {
- $image_url = "http://" . $handle_parts[1] . $image_url;
- }
-
-/* $r = q("SELECT DISTINCT ( `resource-id` ) FROM `photo` WHERE `uid` = %d AND `contact-id` = %d AND `album` = 'Contact Photos' ",
- intval($importer['uid']),
- intval($contact['id'])
- );
- $oldphotos = ((count($r)) ? $r : null);*/
-
- require_once('include/Photo.php');
-
- update_contact_avatar($image_url,$importer['uid'],$contact['id']);
-
- // Generic birthday. We don't know the timezone. The year is irrelevant.
-
- $birthday = str_replace('1000','1901',$birthday);
-
- if ($birthday != "")
- $birthday = datetime_convert('UTC','UTC',$birthday,'Y-m-d');
-
- // this is to prevent multiple birthday notifications in a single year
- // if we already have a stored birthday and the 'm-d' part hasn't changed, preserve the entry, which will preserve the notify year
-
- if(substr($birthday,5) === substr($contact['bd'],5))
- $birthday = $contact['bd'];
-
- /// @TODO Update name on item['author-name'] if the name changed. See consume_feed()
- /// (Not doing this currently because D* protocol is scheduled for revision soon).
-
- $r = q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `name-date` = '%s', `bd` = '%s',
- `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `id` = %d AND `uid` = %d",
- dbesc($name),
- dbesc($nick),
- dbesc($diaspora_handle),
- dbesc(datetime_convert()),
- dbesc($birthday),
- dbesc($location),
- dbesc($about),
- dbesc($keywords),
- dbesc($gender),
- intval($contact['id']),
- intval($importer['uid'])
- );
-
- if ($searchable) {
- require_once('include/socgraph.php');
- poco_check($contact['url'], $name, NETWORK_DIASPORA, $image_url, $about, $location, $gender, $keywords, "",
- datetime_convert(), 2, $contact['id'], $importer['uid']);
- }
-
- update_gcontact(array("url" => $contact['url'], "network" => NETWORK_DIASPORA, "generation" => 2,
- "photo" => $image_url, "name" => $name, "location" => $location,
- "about" => $about, "birthday" => $birthday, "gender" => $gender,
- "addr" => $diaspora_handle, "nick" => $nick, "keywords" => $keywords,
- "hide" => !$searchable, "nsfw" => $nsfw));
-
-/* if($r) {
- if($oldphotos) {
- foreach($oldphotos as $ph) {
- q("DELETE FROM `photo` WHERE `uid` = %d AND `contact-id` = %d AND `album` = 'Contact Photos' AND `resource-id` = '%s' ",
- intval($importer['uid']),
- intval($contact['id']),
- dbesc($ph['resource-id'])
- );
- }
+ $enabled = intval(get_config('system','diaspora_enabled'));
+ if (!$enabled) {
+ logger('Diaspora support disabled, not storing like signature', LOGGER_DEBUG);
+ return false;
}
- } */
- return;
-
-}
-
-function diaspora_share($me,$contact) {
- $a = get_app();
- $myaddr = $me['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
- $theiraddr = $contact['addr'];
-
- $tpl = get_markup_template('diaspora_share.tpl');
- $msg = replace_macros($tpl, array(
- '$sender' => $myaddr,
- '$recipient' => $theiraddr
- ));
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey'])));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey']));
-
- return(diaspora_transmit($owner,$contact,$slap, false));
-}
-
-function diaspora_unshare($me,$contact) {
-
- $a = get_app();
- $myaddr = $me['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-
- $tpl = get_markup_template('diaspora_retract.tpl');
- $msg = replace_macros($tpl, array(
- '$guid' => $me['guid'],
- '$type' => 'Person',
- '$handle' => $myaddr
- ));
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey'])));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey']));
-
- return(diaspora_transmit($owner,$contact,$slap, false));
-
-}
-
-
-function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
-
- $a = get_app();
- $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
- $theiraddr = $contact['addr'];
-
- $images = array();
-
- $title = $item['title'];
- $body = $item['body'];
-
-/*
- // We're trying to match Diaspora's split message/photo protocol but
- // all the photos are displayed on D* as links and not img's - even
- // though we're sending pretty much precisely what they send us when
- // doing the same operation.
- // Commented out for now, we'll use bb2diaspora to convert photos to markdown
- // which seems to get through intact.
-
- $cnt = preg_match_all('|\[img\](.*?)\[\/img\]|',$body,$matches,PREG_SET_ORDER);
- if($cnt) {
- foreach($matches as $mtch) {
- $detail = array();
- $detail['str'] = $mtch[0];
- $detail['path'] = dirname($mtch[1]) . '/';
- $detail['file'] = basename($mtch[1]);
- $detail['guid'] = $item['guid'];
- $detail['handle'] = $myaddr;
- $images[] = $detail;
- $body = str_replace($detail['str'],$mtch[1],$body);
+ // Is the contact the owner? Then fetch the private key
+ if (!$contact['self'] OR ($contact['uid'] == 0)) {
+ logger("No owner post, so not storing signature", LOGGER_DEBUG);
+ return false;
}
- }
-*/
- //if(strlen($title))
- // $body = "[b]".html_entity_decode($title)."[/b]\n\n".$body;
+ $r = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1", intval($contact['uid']));
+ if(!$r)
+ return false;
- // convert to markdown
- $body = xmlify(html_entity_decode(bb2diaspora($body)));
- //$body = bb2diaspora($body);
+ $contact["uprvkey"] = $r[0]['prvkey'];
- // Adding the title
- if(strlen($title))
- $body = "## ".html_entity_decode($title)."\n\n".$body;
+ $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($post_id));
+ if (!$r)
+ return false;
- if($item['attach']) {
- $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism',$item['attach'],$matches,PREG_SET_ORDER);
- if(cnt) {
- $body .= "\n" . t('Attachments:') . "\n";
- foreach($matches as $mtch) {
- $body .= '[' . $mtch[3] . '](' . $mtch[1] . ')' . "\n";
- }
- }
- }
+ if (!in_array($r[0]["verb"], array(ACTIVITY_LIKE, ACTIVITY_DISLIKE)))
+ return false;
+ $message = self::construct_like($r[0], $contact);
+ $message["author_signature"] = self::signature($contact, $message);
- $public = (($item['private']) ? 'false' : 'true');
+ // In the future we will store the signature more flexible to support new fields.
+ // Right now we cannot change this since old Friendica versions (prior to 3.5) can only handle this format.
+ // (We are transmitting this data here via DFRN)
- require_once('include/datetime.php');
- $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C');
+ $signed_text = $message["positive"].";".$message["guid"].";".$message["target_type"].";".
+ $message["parent_guid"].";".$message["diaspora_handle"];
- // Detect a share element and do a reshare
- // see: https://github.com/Raven24/diaspora-federation/blob/master/lib/diaspora-federation/entities/reshare.rb
- if (!$item['private'] AND ($ret = diaspora_is_reshare($item["body"]))) {
- $tpl = get_markup_template('diaspora_reshare.tpl');
- $msg = replace_macros($tpl, array(
- '$root_handle' => xmlify($ret['root_handle']),
- '$root_guid' => $ret['root_guid'],
- '$guid' => $item['guid'],
- '$handle' => xmlify($myaddr),
- '$public' => $public,
- '$created' => $created,
- '$provider' => $item["app"]
- ));
- } else {
- $tpl = get_markup_template('diaspora_post.tpl');
- $msg = replace_macros($tpl, array(
- '$body' => $body,
- '$guid' => $item['guid'],
- '$handle' => xmlify($myaddr),
- '$public' => $public,
- '$created' => $created,
- '$provider' => $item["app"]
- ));
- }
-
- logger('diaspora_send_status: '.$owner['username'].' -> '.$contact['name'].' base message: '.$msg, LOGGER_DATA);
- logger('send guid '.$item['guid'], LOGGER_DEBUG);
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch));
-
- $return_code = diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']);
-
- logger('diaspora_send_status: guid: '.$item['guid'].' result '.$return_code, LOGGER_DEBUG);
-
- if(count($images)) {
- diaspora_send_images($item,$owner,$contact,$images,$public_batch);
- }
-
- return $return_code;
-}
-
-function diaspora_is_reshare($body) {
- $body = trim($body);
-
- // Skip if it isn't a pure repeated messages
- // Does it start with a share?
- if (strpos($body, "[share") > 0)
- return(false);
-
- // Does it end with a share?
- if (strlen($body) > (strrpos($body, "[/share]") + 8))
- return(false);
-
- $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
- // Skip if there is no shared message in there
- if ($body == $attributes)
- return(false);
-
- $guid = "";
- preg_match("/guid='(.*?)'/ism", $attributes, $matches);
- if ($matches[1] != "")
- $guid = $matches[1];
-
- preg_match('/guid="(.*?)"/ism', $attributes, $matches);
- if ($matches[1] != "")
- $guid = $matches[1];
-
- if ($guid != "") {
- $r = q("SELECT `contact-id` FROM `item` WHERE `guid` = '%s' AND `network` IN ('%s', '%s') LIMIT 1",
- dbesc($guid), NETWORK_DFRN, NETWORK_DIASPORA);
- if ($r) {
- $ret= array();
- $ret["root_handle"] = diaspora_handle_from_contact($r[0]["contact-id"]);
- $ret["root_guid"] = $guid;
- return($ret);
- }
- }
-
- $profile = "";
- preg_match("/profile='(.*?)'/ism", $attributes, $matches);
- if ($matches[1] != "")
- $profile = $matches[1];
-
- preg_match('/profile="(.*?)"/ism', $attributes, $matches);
- if ($matches[1] != "")
- $profile = $matches[1];
-
- $ret= array();
-
- $ret["root_handle"] = preg_replace("=https?://(.*)/u/(.*)=ism", "$2@$1", $profile);
- if (($ret["root_handle"] == $profile) OR ($ret["root_handle"] == ""))
- return(false);
-
- $link = "";
- preg_match("/link='(.*?)'/ism", $attributes, $matches);
- if ($matches[1] != "")
- $link = $matches[1];
-
- preg_match('/link="(.*?)"/ism', $attributes, $matches);
- if ($matches[1] != "")
- $link = $matches[1];
-
- $ret["root_guid"] = preg_replace("=https?://(.*)/posts/(.*)=ism", "$2", $link);
- if (($ret["root_guid"] == $link) OR ($ret["root_guid"] == ""))
- return(false);
-
- return($ret);
-}
-
-function diaspora_send_images($item,$owner,$contact,$images,$public_batch = false) {
- $a = get_app();
- if(! count($images))
- return;
- $mysite = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://') + 3) . '/photo';
-
- $tpl = get_markup_template('diaspora_photo.tpl');
- foreach($images as $image) {
- if(! stristr($image['path'],$mysite))
- continue;
- $resource = str_replace('.jpg','',$image['file']);
- $resource = substr($resource,0,strpos($resource,'-'));
-
- $r = q("select * from photo where `resource-id` = '%s' and `uid` = %d limit 1",
- dbesc($resource),
- intval($owner['uid'])
+ q("INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s')",
+ intval($post_id),
+ dbesc($signed_text),
+ dbesc($message["author_signature"]),
+ dbesc($message["diaspora_handle"])
);
- if(! count($r))
- continue;
- $public = (($r[0]['allow_cid'] || $r[0]['allow_gid'] || $r[0]['deny_cid'] || $r[0]['deny_gid']) ? 'false' : 'true' );
- $msg = replace_macros($tpl,array(
- '$path' => xmlify($image['path']),
- '$filename' => xmlify($image['file']),
- '$msg_guid' => xmlify($image['guid']),
- '$guid' => xmlify($r[0]['guid']),
- '$handle' => xmlify($image['handle']),
- '$public' => xmlify($public),
- '$created_at' => xmlify(datetime_convert('UTC','UTC',$r[0]['created'],'Y-m-d H:i:s \U\T\C'))
- ));
+ // This here will replace the lines above, once Diaspora changed its protocol
+ //q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
+ // intval($message_id),
+ // dbesc(json_encode($message))
+ //);
- logger('diaspora_send_photo: base message: ' . $msg, LOGGER_DATA);
- logger('send guid '.$r[0]['guid'], LOGGER_DEBUG);
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch));
-
- diaspora_transmit($owner,$contact,$slap,$public_batch,false,$r[0]['guid']);
+ logger('Stored diaspora like signature');
+ return true;
}
-}
+ /**
+ * @brief Stores the signature for comments that are created on our system
+ *
+ * @param array $item The item array of the comment
+ * @param array $contact The contact array of the item owner
+ * @param string $uprvkey The private key of the sender
+ * @param int $message_id The message id of the comment
+ *
+ * @return bool Success
+ */
+ public static function store_comment_signature($item, $contact, $uprvkey, $message_id) {
-function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
+ if ($uprvkey == "") {
+ logger('No private key, so not storing comment signature', LOGGER_DEBUG);
+ return false;
+ }
- $a = get_app();
- $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-// $theiraddr = $contact['addr'];
+ $enabled = intval(get_config('system','diaspora_enabled'));
+ if (!$enabled) {
+ logger('Diaspora support disabled, not storing comment signature', LOGGER_DEBUG);
+ return false;
+ }
- // Diaspora doesn't support threaded comments, but some
- // versions of Diaspora (i.e. Diaspora-pistos) support
- // likes on comments
- if($item['verb'] === ACTIVITY_LIKE && $item['thr-parent']) {
- $p = q("select guid, type, uri, `parent-uri` from item where uri = '%s' limit 1",
- dbesc($item['thr-parent'])
- );
- }
- else {
- // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always
- // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent.
- // The only item with `parent` and `id` as the parent id is the parent item.
- $p = q("select guid, type, uri, `parent-uri` from item where parent = %d and id = %d limit 1",
- intval($item['parent']),
- intval($item['parent'])
+ $contact["uprvkey"] = $uprvkey;
+
+ $message = self::construct_comment($item, $contact);
+ $message["author_signature"] = self::signature($contact, $message);
+
+ // In the future we will store the signature more flexible to support new fields.
+ // Right now we cannot change this since old Friendica versions (prior to 3.5) can only handle this format.
+ // (We are transmitting this data here via DFRN)
+ $signed_text = $message["guid"].";".$message["parent_guid"].";".
+ $message["text"].";".$message["diaspora_handle"];
+
+ q("INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s')",
+ intval($message_id),
+ dbesc($signed_text),
+ dbesc($message["author_signature"]),
+ dbesc($message["diaspora_handle"])
);
+
+ // This here will replace the lines above, once Diaspora changed its protocol
+ //q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
+ // intval($message_id),
+ // dbesc(json_encode($message))
+ //);
+
+ logger('Stored diaspora comment signature');
+ return true;
}
- if(count($p))
- $parent = $p[0];
- else
- return;
-
- if($item['verb'] === ACTIVITY_LIKE) {
- $tpl = get_markup_template('diaspora_like.tpl');
- $like = true;
- $target_type = ( $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment');
-// $target_type = (strpos($parent['type'], 'comment') ? 'Comment' : 'Post');
-// $positive = (($item['deleted']) ? 'false' : 'true');
- $positive = 'true';
-
- if(($item['deleted']))
- logger('diaspora_send_followup: received deleted "like". Those should go to diaspora_send_retraction');
- }
- else {
- $tpl = get_markup_template('diaspora_comment.tpl');
- $like = false;
- }
-
- $text = html_entity_decode(bb2diaspora($item['body']));
-
- // sign it
-
- if($like)
- $signed_text = $positive . ';' . $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $myaddr;
- else
- $signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $myaddr;
-
- $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
-
- $msg = replace_macros($tpl,array(
- '$guid' => xmlify($item['guid']),
- '$parent_guid' => xmlify($parent['guid']),
- '$target_type' =>xmlify($target_type),
- '$authorsig' => xmlify($authorsig),
- '$body' => xmlify($text),
- '$positive' => xmlify($positive),
- '$handle' => xmlify($myaddr)
- ));
-
- logger('diaspora_followup: base message: ' . $msg, LOGGER_DATA);
- logger('send guid '.$item['guid'], LOGGER_DEBUG);
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch));
-
- return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
-}
-
-
-function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
-
-
- $a = get_app();
- $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-// $theiraddr = $contact['addr'];
-
- // Diaspora doesn't support threaded comments, but some
- // versions of Diaspora (i.e. Diaspora-pistos) support
- // likes on comments
- if($item['verb'] === ACTIVITY_LIKE && $item['thr-parent']) {
- $p = q("select guid, type, uri, `parent-uri` from item where uri = '%s' limit 1",
- dbesc($item['thr-parent'])
- );
- }
- else {
- // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always
- // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent.
- // The only item with `parent` and `id` as the parent id is the parent item.
- $p = q("select guid, type, uri, `parent-uri` from item where parent = %d and id = %d limit 1",
- intval($item['parent']),
- intval($item['parent'])
- );
- }
- if(count($p))
- $parent = $p[0];
- else
- return;
-
- $like = false;
- $relay_retract = false;
- $sql_sign_id = 'iid';
- if( $item['deleted']) {
- $relay_retract = true;
-
- $target_type = ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment');
-
- $sql_sign_id = 'retract_iid';
- $tpl = get_markup_template('diaspora_relayable_retraction.tpl');
- }
- elseif($item['verb'] === ACTIVITY_LIKE) {
- $like = true;
-
- $target_type = ( $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment');
-// $positive = (($item['deleted']) ? 'false' : 'true');
- $positive = 'true';
-
- $tpl = get_markup_template('diaspora_like_relay.tpl');
- }
- else { // item is a comment
- $tpl = get_markup_template('diaspora_comment_relay.tpl');
- }
-
-
- // fetch the original signature if the relayable was created by a Diaspora
- // or DFRN user. Relayables for other networks are not supported.
-
- $r = q("SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE " . $sql_sign_id . " = %d LIMIT 1",
- intval($item['id'])
- );
- if(count($r)) {
- $orig_sign = $r[0];
- $signed_text = $orig_sign['signed_text'];
- $authorsig = $orig_sign['signature'];
- $handle = $orig_sign['signer'];
-
- // Split the signed text
- $signed_parts = explode(";", $signed_text);
-
- // Remove the parent guid
- array_shift($signed_parts);
-
- // Remove the comment guid
- array_shift($signed_parts);
-
- // Remove the handle
- array_pop($signed_parts);
-
- // Glue the parts together
- $text = implode(";", $signed_parts);
- }
- else {
- // This part is meant for cases where we don't have the signatur. (Which shouldn't happen with posts from Diaspora and Friendica)
- // This means that the comment won't be accepted by newer Diaspora servers
-
- $body = $item['body'];
- $text = html_entity_decode(bb2diaspora($body));
-
- $handle = diaspora_handle_from_contact($item['contact-id']);
- if(! $handle)
- return;
-
- if($relay_retract)
- $signed_text = $item['guid'] . ';' . $target_type;
- elseif($like)
- $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $handle;
- else
- $signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $handle;
-
- $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
- }
-
- // Sign the relayable with the top-level owner's signature
- $parentauthorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
-
- $msg = replace_macros($tpl,array(
- '$guid' => xmlify($item['guid']),
- '$parent_guid' => xmlify($parent['guid']),
- '$target_type' =>xmlify($target_type),
- '$authorsig' => xmlify($authorsig),
- '$parentsig' => xmlify($parentauthorsig),
- '$body' => xmlify($text),
- '$positive' => xmlify($positive),
- '$handle' => xmlify($handle)
- ));
-
- logger('diaspora_send_relay: base message: ' . $msg, LOGGER_DATA);
- logger('send guid '.$item['guid'], LOGGER_DEBUG);
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch));
-
- return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
-
-}
-
-
-
-function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) {
-
- $a = get_app();
- $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-
- // Check whether the retraction is for a top-level post or whether it's a relayable
- if( $item['uri'] !== $item['parent-uri'] ) {
-
- $tpl = get_markup_template('diaspora_relay_retraction.tpl');
- $target_type = (($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment');
- }
- else {
-
- $tpl = get_markup_template('diaspora_signed_retract.tpl');
- $target_type = 'StatusMessage';
- }
-
- $signed_text = $item['guid'] . ';' . $target_type;
-
- $msg = replace_macros($tpl, array(
- '$guid' => xmlify($item['guid']),
- '$type' => xmlify($target_type),
- '$handle' => xmlify($myaddr),
- '$signature' => xmlify(base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')))
- ));
-
- logger('send guid '.$item['guid'], LOGGER_DEBUG);
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch));
-
- return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
-}
-
-function diaspora_send_mail($item,$owner,$contact) {
-
- $a = get_app();
- $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
-
- $r = q("select * from conv where id = %d and uid = %d limit 1",
- intval($item['convid']),
- intval($item['uid'])
- );
-
- if(! count($r)) {
- logger('diaspora_send_mail: conversation not found.');
- return;
- }
- $cnv = $r[0];
-
- $conv = array(
- 'guid' => xmlify($cnv['guid']),
- 'subject' => xmlify($cnv['subject']),
- 'created_at' => xmlify(datetime_convert('UTC','UTC',$cnv['created'],'Y-m-d H:i:s \U\T\C')),
- 'diaspora_handle' => xmlify($cnv['creator']),
- 'participant_handles' => xmlify($cnv['recips'])
- );
-
- $body = bb2diaspora($item['body']);
- $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C');
-
- $signed_text = $item['guid'] . ';' . $cnv['guid'] . ';' . $body . ';'
- . $created . ';' . $myaddr . ';' . $cnv['guid'];
-
- $sig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
-
- $msg = array(
- 'guid' => xmlify($item['guid']),
- 'parent_guid' => xmlify($cnv['guid']),
- 'parent_author_signature' => xmlify($sig),
- 'author_signature' => xmlify($sig),
- 'text' => xmlify($body),
- 'created_at' => xmlify($created),
- 'diaspora_handle' => xmlify($myaddr),
- 'conversation_guid' => xmlify($cnv['guid'])
- );
-
- if($item['reply']) {
- $tpl = get_markup_template('diaspora_message.tpl');
- $xmsg = replace_macros($tpl, array('$msg' => $msg));
- }
- else {
- $conv['messages'] = array($msg);
- $tpl = get_markup_template('diaspora_conversation.tpl');
- $xmsg = replace_macros($tpl, array('$conv' => $conv));
- }
-
- logger('diaspora_conversation: ' . print_r($xmsg,true), LOGGER_DATA);
- logger('send guid '.$item['guid'], LOGGER_DEBUG);
-
- $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],false)));
- //$slap = 'xml=' . urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],false));
-
- return(diaspora_transmit($owner,$contact,$slap,false,false,$item['guid']));
-
-
-}
-
-function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false,$guid = "") {
-
- $enabled = intval(get_config('system','diaspora_enabled'));
- if(! $enabled) {
- return 200;
- }
-
- $a = get_app();
- $logid = random_string(4);
- $dest_url = (($public_batch) ? $contact['batch'] : $contact['notify']);
- if(! $dest_url) {
- logger('diaspora_transmit: no url for contact: ' . $contact['id'] . ' batch mode =' . $public_batch);
- return 0;
- }
-
- logger('diaspora_transmit: '.$logid.'-'.$guid.' '.$dest_url);
-
- if( (! $queue_run) && (was_recently_delayed($contact['id'])) ) {
- $return_code = 0;
- }
- else {
- if (!intval(get_config('system','diaspora_test'))) {
- post_url($dest_url . '/', $slap);
- $return_code = $a->get_curl_code();
- } else {
- logger('diaspora_transmit: test_mode');
- return 200;
- }
- }
-
- logger('diaspora_transmit: '.$logid.'-'.$guid.' returns: '.$return_code);
-
- if((! $return_code) || (($return_code == 503) && (stristr($a->get_curl_headers(),'retry-after')))) {
- logger('diaspora_transmit: queue message');
-
- $r = q("SELECT id from queue where cid = %d and network = '%s' and content = '%s' and batch = %d limit 1",
- intval($contact['id']),
- dbesc(NETWORK_DIASPORA),
- dbesc($slap),
- intval($public_batch)
- );
- if(count($r)) {
- logger('diaspora_transmit: add_to_queue ignored - identical item already in queue');
- }
- else {
- // queue message for redelivery
- add_to_queue($contact['id'],NETWORK_DIASPORA,$slap,$public_batch);
- }
- }
-
-
- return(($return_code) ? $return_code : (-1));
-}
-
-function diaspora_fetch_relay() {
-
- $serverdata = get_config("system", "relay_server");
- if ($serverdata == "")
- return array();
-
- $relay = array();
-
- $servers = explode(",", $serverdata);
-
- foreach($servers AS $server) {
- $server = trim($server);
- $batch = $server."/receive/public";
-
- $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1", dbesc($batch));
-
- if (!$relais) {
- $addr = "relay@".str_replace("http://", "", normalise_link($server));
-
- $r = q("INSERT INTO `contact` (`uid`, `created`, `name`, `nick`, `addr`, `url`, `nurl`, `batch`, `network`, `rel`, `blocked`, `pending`, `writable`, `name-date`, `uri-date`, `avatar-date`)
- VALUES (0, '%s', '%s', 'relay', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, '%s', '%s', '%s')",
- datetime_convert(),
- dbesc($addr),
- dbesc($addr),
- dbesc($server),
- dbesc(normalise_link($server)),
- dbesc($batch),
- dbesc(NETWORK_DIASPORA),
- intval(CONTACT_IS_FOLLOWER),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc(datetime_convert())
- );
-
- $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1", dbesc($batch));
- if ($relais)
- $relay[] = $relais[0];
- } else
- $relay[] = $relais[0];
- }
-
- return $relay;
}
+?>
diff --git a/include/discover_poco.php b/include/discover_poco.php
index a8f670334b..0b468faea1 100644
--- a/include/discover_poco.php
+++ b/include/discover_poco.php
@@ -20,22 +20,14 @@ function discover_poco_run(&$argv, &$argc){
require_once('include/session.php');
require_once('include/datetime.php');
- require_once('include/pidfile.php');
load_config('config');
load_config('system');
- $maxsysload = intval(get_config('system','maxloadavg'));
- if($maxsysload < 1)
- $maxsysload = 50;
-
- $load = current_load();
- if($load) {
- if(intval($load) > $maxsysload) {
- logger('system: load ' . $load . ' too high. discover_poco deferred to next scheduled run.');
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run")
+ if (App::maxload_reached())
return;
- }
- }
if(($argc > 2) && ($argv[1] == "dirsearch")) {
$search = urldecode($argv[2]);
@@ -50,21 +42,10 @@ function discover_poco_run(&$argv, &$argc){
} else
die("Unknown or missing parameter ".$argv[1]."\n");
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'discover_poco'.$mode.urlencode($search));
- if($pidfile->is_already_running()) {
- logger("discover_poco: Already running");
- if ($pidfile->running_time() > 19*60) {
- $pidfile->kill();
- logger("discover_poco: killed stale process");
- // Calling a new instance
- if ($mode == 0)
- proc_run('php','include/discover_poco.php');
- }
- exit;
- }
- }
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run")
+ if (App::is_already_running('discover_poco'.$mode.urlencode($search), 'include/discover_poco.php', 1140))
+ return;
$a->set_baseurl(get_config('system','url'));
diff --git a/include/dsprphotoq.php b/include/dsprphotoq.php
deleted file mode 100644
index 0d8088d4bd..0000000000
--- a/include/dsprphotoq.php
+++ /dev/null
@@ -1,55 +0,0 @@
- 0, "page-flags" => PAGE_FREELOVE);
- else
- $r = q("SELECT * FROM user WHERE uid = %d",
- intval($dphoto['uid']));
-
- if(!$r) {
- logger("diaspora photo queue: user " . $dphoto['uid'] . " not found");
- return;
- }
-
- $ret = diaspora_dispatch($r[0],unserialize($dphoto['msg']),$dphoto['attempt']);
- q("DELETE FROM dsprphotoq WHERE id = %d",
- intval($dphoto['id'])
- );
- }
-}
-
-
-if (array_search(__file__,get_included_files())===0){
- dsprphotoq_run($_SERVER["argv"],$_SERVER["argc"]);
- killme();
-}
diff --git a/include/feed.php b/include/feed.php
index 04cfba75a6..293de3cc96 100644
--- a/include/feed.php
+++ b/include/feed.php
@@ -54,8 +54,10 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
if ($attributes->name == "href")
$author["author-link"] = $attributes->textContent;
+ $author["author-id"] = $xpath->evaluate('/atom:feed/atom:author/atom:uri/text()')->item(0)->nodeValue;
+
if ($author["author-link"] == "")
- $author["author-link"] = $xpath->evaluate('/atom:feed/atom:author/atom:uri/text()')->item(0)->nodeValue;
+ $author["author-link"] = $author["author-id"];
if ($author["author-link"] == "") {
$self = $xpath->query("atom:link[@rel='self']")->item(0)->attributes;
@@ -127,6 +129,7 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
// This is no field in the item table. So we have to unset it.
unset($author["author-nick"]);
+ unset($author["author-id"]);
}
$header = array();
diff --git a/include/follow.php b/include/follow.php
index 410e0e58aa..d0411a466a 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -258,12 +258,10 @@ function new_contact($uid,$url,$interactive = false) {
$contact_id = $r[0]['id'];
$result['cid'] = $contact_id;
- $g = q("select def_gid from user where uid = %d limit 1",
- intval($uid)
- );
- if($g && intval($g[0]['def_gid'])) {
+ $def_gid = get_default_group($uid, $contact["network"]);
+ if (intval($def_gid)) {
require_once('include/group.php');
- group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
+ group_add_member($uid, '', $contact_id, $def_gid);
}
require_once("include/Photo.php");
@@ -305,8 +303,8 @@ function new_contact($uid,$url,$interactive = false) {
}
if($contact['network'] == NETWORK_DIASPORA) {
require_once('include/diaspora.php');
- $ret = diaspora_share($a->user,$contact);
- logger('mod_follow: diaspora_share returns: ' . $ret);
+ $ret = diaspora::send_share($a->user,$contact);
+ logger('share returns: '.$ret);
}
}
diff --git a/include/group.php b/include/group.php
index 2b872f16a7..00b66ad586 100644
--- a/include/group.php
+++ b/include/group.php
@@ -188,7 +188,7 @@ function group_public_members($gid) {
}
-function mini_group_select($uid,$gid = 0) {
+function mini_group_select($uid,$gid = 0, $label = "") {
$grps = array();
$o = '';
@@ -205,8 +205,11 @@ function mini_group_select($uid,$gid = 0) {
}
logger('groups: ' . print_r($grps,true));
+ if ($label == "")
+ $label = t('Default privacy group for new contacts');
+
$o = replace_macros(get_markup_template('group_selection.tpl'), array(
- '$label' => t('Default privacy group for new contacts'),
+ '$label' => $label,
'$groups' => $grps
));
return $o;
@@ -375,3 +378,28 @@ function groups_count_unseen() {
return $r;
}
+
+/**
+ * @brief Returns the default group for a given user and network
+ *
+ * @param int $uid User id
+ * @param string $network network name
+ *
+ * @return int group id
+ */
+function get_default_group($uid, $network = "") {
+
+ $default_group = 0;
+
+ if ($network == NETWORK_OSTATUS)
+ $default_group = get_pconfig($uid, "ostatus", "default_group");
+
+ if ($default_group != 0)
+ return $default_group;
+
+ $g = q("SELECT `def_gid` FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
+ if($g && intval($g[0]["def_gid"]))
+ $default_group = $g[0]["def_gid"];
+
+ return $default_group;
+}
diff --git a/include/identity.php b/include/identity.php
index ec66225d0f..888a09ee6f 100644
--- a/include/identity.php
+++ b/include/identity.php
@@ -237,6 +237,7 @@ function profile_sidebar($profile, $block = 0) {
if ($connect AND ($profile['network'] != NETWORK_DFRN) AND !isset($profile['remoteconnect']))
$connect = false;
+ $remoteconnect = NULL;
if (isset($profile['remoteconnect']))
$remoteconnect = $profile['remoteconnect'];
@@ -292,9 +293,9 @@ function profile_sidebar($profile, $block = 0) {
// check if profile is a forum
if((intval($profile['page-flags']) == PAGE_COMMUNITY)
|| (intval($profile['page-flags']) == PAGE_PRVGROUP)
- || (intval($profile['forum']))
- || (intval($profile['prv']))
- || (intval($profile['community'])))
+ || (isset($profile['forum']) && intval($profile['forum']))
+ || (isset($profile['prv']) && intval($profile['prv']))
+ || (isset($profile['community']) && intval($profile['community'])))
$account_type = t('Forum');
else
$account_type = "";
@@ -332,9 +333,9 @@ function profile_sidebar($profile, $block = 0) {
'fullname' => $profile['name'],
'firstname' => $firstname,
'lastname' => $lastname,
- 'photo300' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg'),
- 'photo100' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg'),
- 'photo50' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg'),
+ 'photo300' => $a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg',
+ 'photo100' => $a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg',
+ 'photo50' => $a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg',
);
if (!$block){
diff --git a/include/items.php b/include/items.php
index 8d6b5b471c..4627b10ca2 100644
--- a/include/items.php
+++ b/include/items.php
@@ -383,9 +383,9 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
// Converting the plink
if ($arr['network'] == NETWORK_OSTATUS) {
if (isset($arr['plink']))
- $arr['plink'] = ostatus_convert_href($arr['plink']);
+ $arr['plink'] = ostatus::convert_href($arr['plink']);
elseif (isset($arr['uri']))
- $arr['plink'] = ostatus_convert_href($arr['uri']);
+ $arr['plink'] = ostatus::convert_href($arr['uri']);
}
if(x($arr, 'gravity'))
@@ -707,9 +707,9 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
if ($arr["uid"] == 0) {
$arr["global"] = true;
- q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($arr["guid"]));
+ q("UPDATE `item` SET `global` = 1 WHERE `uri` = '%s'", dbesc($arr["uri"]));
} else {
- $isglobal = q("SELECT `global` FROM `item` WHERE `uid` = 0 AND `guid` = '%s'", dbesc($arr["guid"]));
+ $isglobal = q("SELECT `global` FROM `item` WHERE `uid` = 0 AND `uri` = '%s'", dbesc($arr["uri"]));
$arr["global"] = (count($isglobal) > 0);
}
@@ -1243,7 +1243,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
//$tempfile = tempnam(get_temppath(), "ostatus2");
//file_put_contents($tempfile, $xml);
logger("Consume OStatus messages ", LOGGER_DEBUG);
- ostatus_import($xml,$importer,$contact, $hub);
+ ostatus::import($xml,$importer,$contact, $hub);
}
return;
}
@@ -1980,9 +1980,6 @@ function drop_item($id,$interactive = true) {
intval($r[0]['id'])
);
}
-
- // Add a relayable_retraction signature for Diaspora.
- store_diaspora_retract_sig($item, $a->user, $a->get_baseurl());
}
$drop_id = intval($item['id']);
@@ -2115,51 +2112,3 @@ function posted_date_widget($url,$uid,$wall) {
));
return $o;
}
-
-function store_diaspora_retract_sig($item, $user, $baseurl) {
- // Note that we can't add a target_author_signature
- // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting
- // the comment, that means we're the home of the post, and Diaspora will only
- // check the parent_author_signature of retractions that it doesn't have to relay further
- //
- // I don't think this function gets called for an "unlike," but I'll check anyway
-
- $enabled = intval(get_config('system','diaspora_enabled'));
- if(! $enabled) {
- logger('drop_item: diaspora support disabled, not storing retraction signature', LOGGER_DEBUG);
- return;
- }
-
- logger('drop_item: storing diaspora retraction signature');
-
- $signed_text = $item['guid'] . ';' . ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment');
-
- if(local_user() == $item['uid']) {
-
- $handle = $user['nickname'] . '@' . substr($baseurl, strpos($baseurl,'://') + 3);
- $authorsig = base64_encode(rsa_sign($signed_text,$user['prvkey'],'sha256'));
- }
- else {
- $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1",
- $item['contact-id'] // If this function gets called, drop_item() has already checked remote_user() == $item['contact-id']
- );
- if(count($r)) {
- // The below handle only works for NETWORK_DFRN. I think that's ok, because this function
- // only handles DFRN deletes
- $handle_baseurl_start = strpos($r['url'],'://') + 3;
- $handle_baseurl_length = strpos($r['url'],'/profile') - $handle_baseurl_start;
- $handle = $r['nick'] . '@' . substr($r['url'], $handle_baseurl_start, $handle_baseurl_length);
- $authorsig = '';
- }
- }
-
- if(isset($handle))
- q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- intval($item['id']),
- dbesc($signed_text),
- dbesc($authorsig),
- dbesc($handle)
- );
-
- return;
-}
diff --git a/include/like.php b/include/like.php
index 646e0727be..15633fc767 100644
--- a/include/like.php
+++ b/include/like.php
@@ -1,4 +1,5 @@
0)) {
- $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
- intval($contact['uid'])
- );
-
- if($r)
- $authorsig = base64_encode(rsa_sign($signed_text,$r[0]['prvkey'],'sha256'));
- }
-
- if(! isset($authorsig))
- $authorsig = '';
-
- q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- intval($like_item['id']),
- dbesc($signed_text),
- dbesc($authorsig),
- dbesc($diaspora_handle)
- );
- }
-
- return;
-}
-
-function store_diaspora_like_sig($activity, $post_type, $contact, $post_id) {
- // Note that we can only create a signature for a user of the local server. We don't have
- // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it
- // means we are the relay, and for relayable_retractions, Diaspora
- // only checks the parent_author_signature if it doesn't have to relay further
-
- $enabled = intval(get_config('system','diaspora_enabled'));
- if(! $enabled) {
- logger('mod_like: diaspora support disabled, not storing like signature', LOGGER_DEBUG);
- return;
- }
-
- logger('mod_like: storing diaspora like signature');
-
- if(($activity === ACTIVITY_LIKE) && ($post_type === t('status'))) {
- // Only works for NETWORK_DFRN
- $contact_baseurl_start = strpos($contact['url'],'://') + 3;
- $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start;
- $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length);
- $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl;
-
-
- // This code could never had worked (the return values form the queries were used in a wrong way.
- // Additionally it is needlessly complicated. Either the contact is owner or not. And we have this data already.
-/*
- // Get contact's private key if he's a user of the local Friendica server
- $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1",
- dbesc($contact['url'])
- );
-
- if( $r) {
- $contact_uid = $r['uid'];
- $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
- intval($contact_uid)
- );
-
- if( $r)
- $contact_uprvkey = $r['prvkey'];
- }
-*/
-
- // Is the contact the owner? Then fetch the private key
- if ($contact['self'] AND ($contact['uid'] > 0)) {
- $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
- intval($contact['uid'])
- );
-
- if($r)
- $contact_uprvkey = $r[0]['prvkey'];
- }
-
- $r = q("SELECT guid, parent FROM `item` WHERE id = %d LIMIT 1",
- intval($post_id)
- );
- if( $r) {
- $p = q("SELECT guid FROM `item` WHERE id = %d AND parent = %d LIMIT 1",
- intval($r[0]['parent']),
- intval($r[0]['parent'])
- );
- if( $p) {
- $signed_text = 'true;'.$r[0]['guid'].';Post;'.$p[0]['guid'].';'.$diaspora_handle;
-
- if(isset($contact_uprvkey))
- $authorsig = base64_encode(rsa_sign($signed_text,$contact_uprvkey,'sha256'));
- else
- $authorsig = '';
-
- q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- intval($post_id),
- dbesc($signed_text),
- dbesc($authorsig),
- dbesc($diaspora_handle)
- );
- }
- }
- }
-
- return;
-}
diff --git a/include/nav.php b/include/nav.php
index 6512d35609..0fa671a27d 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -82,7 +82,7 @@ function nav_info(&$a) {
// user info
$r = q("SELECT micro FROM contact WHERE uid=%d AND self=1", intval($a->user['uid']));
$userinfo = array(
- 'icon' => (count($r) ? $a->get_cached_avatar_image($r[0]['micro']) : $a->get_baseurl($ssl_state)."/images/person-48.jpg"),
+ 'icon' => (count($r) ? $a->remove_baseurl($r[0]['micro']) : "images/person-48.jpg"),
'name' => $a->user['username'],
);
@@ -107,7 +107,7 @@ function nav_info(&$a) {
if(($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user()))
$nav['register'] = array('register',t('Register'), "", t('Create an account'));
- $help_url = $a->get_baseurl($ssl_state) . '/help';
+ $help_url = 'help';
if(! get_config('system','hide_help'))
$nav['help'] = array($help_url, t('Help'), "", t('Help and documentation'));
diff --git a/include/network.php b/include/network.php
index c6379e407b..27459112d6 100644
--- a/include/network.php
+++ b/include/network.php
@@ -862,64 +862,6 @@ function parse_xml_string($s,$strict = true) {
return $x;
}}
-function add_fcontact($arr,$update = false) {
-
- if($update) {
- $r = q("UPDATE `fcontact` SET
- `name` = '%s',
- `photo` = '%s',
- `request` = '%s',
- `nick` = '%s',
- `addr` = '%s',
- `batch` = '%s',
- `notify` = '%s',
- `poll` = '%s',
- `confirm` = '%s',
- `alias` = '%s',
- `pubkey` = '%s',
- `updated` = '%s'
- WHERE `url` = '%s' AND `network` = '%s'",
- dbesc($arr['name']),
- dbesc($arr['photo']),
- dbesc($arr['request']),
- dbesc($arr['nick']),
- dbesc($arr['addr']),
- dbesc($arr['batch']),
- dbesc($arr['notify']),
- dbesc($arr['poll']),
- dbesc($arr['confirm']),
- dbesc($arr['alias']),
- dbesc($arr['pubkey']),
- dbesc(datetime_convert()),
- dbesc($arr['url']),
- dbesc($arr['network'])
- );
- }
- else {
- $r = q("insert into fcontact ( `url`,`name`,`photo`,`request`,`nick`,`addr`,
- `batch`, `notify`,`poll`,`confirm`,`network`,`alias`,`pubkey`,`updated` )
- values('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')",
- dbesc($arr['url']),
- dbesc($arr['name']),
- dbesc($arr['photo']),
- dbesc($arr['request']),
- dbesc($arr['nick']),
- dbesc($arr['addr']),
- dbesc($arr['batch']),
- dbesc($arr['notify']),
- dbesc($arr['poll']),
- dbesc($arr['confirm']),
- dbesc($arr['network']),
- dbesc($arr['alias']),
- dbesc($arr['pubkey']),
- dbesc(datetime_convert())
- );
- }
-
- return $r;
-}
-
-
function scale_external_images($srctext, $include_link = true, $scale_replace = false) {
// Suppress "view full size"
diff --git a/include/notifier.php b/include/notifier.php
index 6c42f19c6a..ffbb22e7bf 100644
--- a/include/notifier.php
+++ b/include/notifier.php
@@ -223,13 +223,13 @@ function notifier_run(&$argv, &$argc){
if(! ($mail || $fsuggest || $relocate)) {
- $slap = ostatus_salmon($target_item,$owner);
+ $slap = ostatus::salmon($target_item,$owner);
require_once('include/group.php');
$parent = $items[0];
- $thr_parent = q("SELECT `network` FROM `item` WHERE `uri` = '%s' AND `uid` = %d",
+ $thr_parent = q("SELECT `network`, `author-link`, `owner-link` FROM `item` WHERE `uri` = '%s' AND `uid` = %d",
dbesc($target_item["thr-parent"]), intval($target_item["uid"]));
logger('Parent is '.$parent['network'].'. Thread parent is '.$thr_parent[0]['network'], LOGGER_DEBUG);
@@ -390,6 +390,20 @@ function notifier_run(&$argv, &$argc){
logger('Some parent is OStatus for '.$target_item["guid"], LOGGER_DEBUG);
+ // Send a salmon to the parent author
+ $probed_contact = probe_url($thr_parent[0]['author-link']);
+ if ($probed_contact["notify"] != "") {
+ logger('Notify parent author '.$probed_contact["url"].': '.$probed_contact["notify"]);
+ $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
+ }
+
+ // Send a salmon to the parent owner
+ $probed_contact = probe_url($thr_parent[0]['owner-link']);
+ if ($probed_contact["notify"] != "") {
+ logger('Notify parent owner '.$probed_contact["url"].': '.$probed_contact["notify"]);
+ $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
+ }
+
// Send a salmon notification to every person we mentioned in the post
$arr = explode(',',$target_item['tag']);
foreach($arr as $x) {
@@ -536,7 +550,7 @@ function notifier_run(&$argv, &$argc){
if($public_message) {
if (!$followup AND $top_level)
- $r0 = diaspora_fetch_relay();
+ $r0 = diaspora::relay_list();
else
$r0 = array();
@@ -628,13 +642,6 @@ function notifier_run(&$argv, &$argc){
proc_run('php','include/pubsubpublish.php');
}
- // If the item was deleted, clean up the `sign` table
- if($target_item['deleted']) {
- $r = q("DELETE FROM sign where `retract_iid` = %d",
- intval($target_item['id'])
- );
- }
-
logger('notifier: calling hooks', LOGGER_DEBUG);
if($normal_mode)
diff --git a/include/onepoll.php b/include/onepoll.php
index 6fb191f73d..eb1045de14 100644
--- a/include/onepoll.php
+++ b/include/onepoll.php
@@ -31,7 +31,6 @@ function onepoll_run(&$argv, &$argc){
require_once('include/Contact.php');
require_once('include/email.php');
require_once('include/socgraph.php');
- require_once('include/pidfile.php');
require_once('include/queue_fn.php');
load_config('config');
@@ -60,18 +59,10 @@ function onepoll_run(&$argv, &$argc){
return;
}
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'onepoll'.$contact_id);
- if ($pidfile->is_already_running()) {
- logger("onepoll: Already running for contact ".$contact_id);
- if ($pidfile->running_time() > 9*60) {
- $pidfile->kill();
- logger("killed stale process");
- }
- exit;
- }
- }
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run")
+ if (App::is_already_running('onepoll'.$contact_id, '', 540))
+ return;
$d = datetime_convert();
diff --git a/include/ostatus.php b/include/ostatus.php
index 5c5016d0fc..b798a605f9 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -1,4 +1,8 @@
evaluate('atom:author/atom:uri/text()', $context)->item(0)->nodeValue;
+ $author["author-name"] = $xpath->evaluate('atom:author/atom:name/text()', $context)->item(0)->nodeValue;
- foreach ($r AS $contact) {
- ostatus_follow_friends($contact["uid"], $contact["v"]);
- set_pconfig($contact["uid"], "system", "ostatus_legacy_contact", "");
- }
-}
+ $aliaslink = $author["author-link"];
-// This function doesn't work reliable by now.
-function ostatus_follow_friends($uid, $url) {
- $contact = probe_url($url);
+ $alternate = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0)->attributes;
+ if (is_object($alternate))
+ foreach($alternate AS $attributes)
+ if ($attributes->name == "href")
+ $author["author-link"] = $attributes->textContent;
- if (!$contact)
- return;
+ $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'",
+ intval($importer["uid"]), dbesc(normalise_link($author["author-link"])),
+ dbesc(normalise_link($aliaslink)), dbesc(NETWORK_STATUSNET));
+ if ($r) {
+ $contact = $r[0];
+ $author["contact-id"] = $r[0]["id"];
+ } else
+ $author["contact-id"] = $contact["id"];
- $api = $contact["baseurl"]."/api/";
-
- // Fetching friends
- $data = z_fetch_url($api."statuses/friends.json?screen_name=".$contact["nick"]);
-
- if (!$data["success"])
- return;
-
- $friends = json_decode($data["body"]);
-
- foreach ($friends AS $friend) {
- $url = $friend->statusnet_profile_url;
- $r = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND
- (`nurl` = '%s' OR `alias` = '%s' OR `alias` = '%s') AND
- `network` != '%s' LIMIT 1",
- intval($uid), dbesc(normalise_link($url)),
- dbesc(normalise_link($url)), dbesc($url), dbesc(NETWORK_STATUSNET));
- if (!$r) {
- $data = probe_url($friend->statusnet_profile_url);
- if ($data["network"] == NETWORK_OSTATUS) {
- $result = new_contact($uid,$friend->statusnet_profile_url);
- if ($result["success"])
- logger($friend->name." ".$url." - success", LOGGER_DEBUG);
- else
- logger($friend->name." ".$url." - failed", LOGGER_DEBUG);
- } else
- logger($friend->name." ".$url." - not OStatus", LOGGER_DEBUG);
+ $avatarlist = array();
+ $avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context);
+ foreach($avatars AS $avatar) {
+ $href = "";
+ $width = 0;
+ foreach($avatar->attributes AS $attributes) {
+ if ($attributes->name == "href")
+ $href = $attributes->textContent;
+ if ($attributes->name == "width")
+ $width = $attributes->textContent;
+ }
+ if (($width > 0) AND ($href != ""))
+ $avatarlist[$width] = $href;
}
- }
-}
-
-function ostatus_fetchauthor($xpath, $context, $importer, &$contact, $onlyfetch) {
-
- $author = array();
- $author["author-link"] = $xpath->evaluate('atom:author/atom:uri/text()', $context)->item(0)->nodeValue;
- $author["author-name"] = $xpath->evaluate('atom:author/atom:name/text()', $context)->item(0)->nodeValue;
-
- // Preserve the value
- $authorlink = $author["author-link"];
-
- $alternate = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0)->attributes;
- if (is_object($alternate))
- foreach($alternate AS $attributes)
- if ($attributes->name == "href")
- $author["author-link"] = $attributes->textContent;
-
- $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'",
- intval($importer["uid"]), dbesc(normalise_link($author["author-link"])),
- dbesc(normalise_link($authorlink)), dbesc(NETWORK_STATUSNET));
- if ($r) {
- $contact = $r[0];
- $author["contact-id"] = $r[0]["id"];
- } else
- $author["contact-id"] = $contact["id"];
-
- $avatarlist = array();
- $avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context);
- foreach($avatars AS $avatar) {
- $href = "";
- $width = 0;
- foreach($avatar->attributes AS $attributes) {
- if ($attributes->name == "href")
- $href = $attributes->textContent;
- if ($attributes->name == "width")
- $width = $attributes->textContent;
- }
- if (($width > 0) AND ($href != ""))
- $avatarlist[$width] = $href;
- }
- if (count($avatarlist) > 0) {
- krsort($avatarlist);
- $author["author-avatar"] = current($avatarlist);
- }
-
- $displayname = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
- if ($displayname != "")
- $author["author-name"] = $displayname;
-
- $author["owner-name"] = $author["author-name"];
- $author["owner-link"] = $author["author-link"];
- $author["owner-avatar"] = $author["author-avatar"];
-
- // Only update the contacts if it is an OStatus contact
- if ($r AND !$onlyfetch AND ($contact["network"] == NETWORK_OSTATUS)) {
- // Update contact data
-
- $value = $xpath->query("atom:link[@rel='salmon']", $context)->item(0)->nodeValue;
- if ($value != "")
- $contact["notify"] = $value;
-
- $value = $xpath->evaluate('atom:author/uri/text()', $context)->item(0)->nodeValue;
- if ($value != "")
- $contact["alias"] = $value;
-
- $value = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
- if ($value != "")
- $contact["name"] = $value;
-
- $value = $xpath->evaluate('atom:author/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
- if ($value != "")
- $contact["nick"] = $value;
-
- $value = $xpath->evaluate('atom:author/poco:note/text()', $context)->item(0)->nodeValue;
- if ($value != "")
- $contact["about"] = html2bbcode($value);
-
- $value = $xpath->evaluate('atom:author/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
- if ($value != "")
- $contact["location"] = $value;
-
- if (($contact["name"] != $r[0]["name"]) OR ($contact["nick"] != $r[0]["nick"]) OR ($contact["about"] != $r[0]["about"]) OR ($contact["location"] != $r[0]["location"])) {
-
- logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG);
-
- q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', `name-date` = '%s' WHERE `id` = %d",
- dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["about"]), dbesc($contact["location"]),
- dbesc(datetime_convert()), intval($contact["id"]));
-
- poco_check($contact["url"], $contact["name"], $contact["network"], $author["author-avatar"], $contact["about"], $contact["location"],
- "", "", "", datetime_convert(), 2, $contact["id"], $contact["uid"]);
+ if (count($avatarlist) > 0) {
+ krsort($avatarlist);
+ $author["author-avatar"] = current($avatarlist);
}
- if (isset($author["author-avatar"]) AND ($author["author-avatar"] != $r[0]['avatar'])) {
- logger("Update profile picture for contact ".$contact["id"], LOGGER_DEBUG);
+ $displayname = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
+ if ($displayname != "")
+ $author["author-name"] = $displayname;
- update_contact_avatar($author["author-avatar"], $importer["uid"], $contact["id"]);
- }
+ $author["owner-name"] = $author["author-name"];
+ $author["owner-link"] = $author["author-link"];
+ $author["owner-avatar"] = $author["author-avatar"];
- $contact["generation"] = 2;
- $contact["photo"] = $author["author-avatar"];
- update_gcontact($contact);
- }
+ // Only update the contacts if it is an OStatus contact
+ if ($r AND !$onlyfetch AND ($contact["network"] == NETWORK_OSTATUS)) {
- return($author);
-}
+ // Update contact data
-function ostatus_salmon_author($xml, $importer) {
- $a = get_app();
+ // This query doesn't seem to work
+ // $value = $xpath->query("atom:link[@rel='salmon']", $context)->item(0)->nodeValue;
+ // if ($value != "")
+ // $contact["notify"] = $value;
- if ($xml == "")
- return;
+ // This query doesn't seem to work as well - I hate these queries
+ // $value = $xpath->query("atom:link[@rel='self' and @type='application/atom+xml']", $context)->item(0)->nodeValue;
+ // if ($value != "")
+ // $contact["poll"] = $value;
- $doc = new DOMDocument();
- @$doc->loadXML($xml);
+ $value = $xpath->evaluate('atom:author/atom:uri/text()', $context)->item(0)->nodeValue;
+ if ($value != "")
+ $contact["alias"] = $value;
- $xpath = new DomXPath($doc);
- $xpath->registerNamespace('atom', NAMESPACE_ATOM1);
- $xpath->registerNamespace('thr', NAMESPACE_THREAD);
- $xpath->registerNamespace('georss', NAMESPACE_GEORSS);
- $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY);
- $xpath->registerNamespace('media', NAMESPACE_MEDIA);
- $xpath->registerNamespace('poco', NAMESPACE_POCO);
- $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS);
- $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET);
+ $value = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
+ if ($value != "")
+ $contact["name"] = $value;
- $entries = $xpath->query('/atom:entry');
+ $value = $xpath->evaluate('atom:author/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
+ if ($value != "")
+ $contact["nick"] = $value;
- foreach ($entries AS $entry) {
- // fetch the author
- $author = ostatus_fetchauthor($xpath, $entry, $importer, $contact, true);
- return $author;
- }
-}
+ $value = $xpath->evaluate('atom:author/poco:note/text()', $context)->item(0)->nodeValue;
+ if ($value != "")
+ $contact["about"] = html2bbcode($value);
-function ostatus_import($xml,$importer,&$contact, &$hub) {
+ $value = $xpath->evaluate('atom:author/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
+ if ($value != "")
+ $contact["location"] = $value;
- $a = get_app();
+ if (($contact["name"] != $r[0]["name"]) OR ($contact["nick"] != $r[0]["nick"]) OR ($contact["about"] != $r[0]["about"]) OR
+ ($contact["alias"] != $r[0]["alias"]) OR ($contact["location"] != $r[0]["location"])) {
- logger("Import OStatus message", LOGGER_DEBUG);
+ logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG);
- if ($xml == "")
- return;
+ q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `alias` = '%s', `about` = '%s', `location` = '%s', `name-date` = '%s' WHERE `id` = %d",
+ dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["alias"]),
+ dbesc($contact["about"]), dbesc($contact["location"]),
+ dbesc(datetime_convert()), intval($contact["id"]));
- $doc = new DOMDocument();
- @$doc->loadXML($xml);
-
- $xpath = new DomXPath($doc);
- $xpath->registerNamespace('atom', NAMESPACE_ATOM1);
- $xpath->registerNamespace('thr', NAMESPACE_THREAD);
- $xpath->registerNamespace('georss', NAMESPACE_GEORSS);
- $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY);
- $xpath->registerNamespace('media', NAMESPACE_MEDIA);
- $xpath->registerNamespace('poco', NAMESPACE_POCO);
- $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS);
- $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET);
-
- $gub = "";
- $hub_attributes = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0)->attributes;
- if (is_object($hub_attributes))
- foreach($hub_attributes AS $hub_attribute)
- if ($hub_attribute->name == "href") {
- $hub = $hub_attribute->textContent;
- logger("Found hub ".$hub, LOGGER_DEBUG);
+ poco_check($contact["url"], $contact["name"], $contact["network"], $author["author-avatar"], $contact["about"], $contact["location"],
+ "", "", "", datetime_convert(), 2, $contact["id"], $contact["uid"]);
}
- $header = array();
- $header["uid"] = $importer["uid"];
- $header["network"] = NETWORK_OSTATUS;
- $header["type"] = "remote";
- $header["wall"] = 0;
- $header["origin"] = 0;
- $header["gravity"] = GRAVITY_PARENT;
+ if (isset($author["author-avatar"]) AND ($author["author-avatar"] != $r[0]['avatar'])) {
+ logger("Update profile picture for contact ".$contact["id"], LOGGER_DEBUG);
- // it could either be a received post or a post we fetched by ourselves
- // depending on that, the first node is different
- $first_child = $doc->firstChild->tagName;
+ update_contact_avatar($author["author-avatar"], $importer["uid"], $contact["id"]);
+ }
+
+ // Ensure that we are having this contact (with uid=0)
+ $cid = get_contact($author["author-link"], 0);
+
+ if ($cid) {
+ // Update it with the current values
+ q("UPDATE `contact` SET `url` = '%s', `name` = '%s', `nick` = '%s', `alias` = '%s',
+ `about` = '%s', `location` = '%s',
+ `success_update` = '%s', `last-update` = '%s'
+ WHERE `id` = %d",
+ dbesc($author["author-link"]), dbesc($contact["name"]), dbesc($contact["nick"]),
+ dbesc($contact["alias"]), dbesc($contact["about"]), dbesc($contact["location"]),
+ dbesc(datetime_convert()), dbesc(datetime_convert()), intval($cid));
+
+ // Update the avatar
+ update_contact_avatar($author["author-avatar"], 0, $cid);
+ }
+
+ $contact["generation"] = 2;
+ $contact["photo"] = $author["author-avatar"];
+ update_gcontact($contact);
+ }
+
+ return($author);
+ }
+
+ /**
+ * @brief Fetches author data from a given XML string
+ *
+ * @param string $xml The XML
+ * @param array $importer user record of the importing user
+ *
+ * @return array Array of author related entries for the item
+ */
+ public static function salmon_author($xml, $importer) {
+
+ if ($xml == "")
+ return;
+
+ $doc = new DOMDocument();
+ @$doc->loadXML($xml);
+
+ $xpath = new DomXPath($doc);
+ $xpath->registerNamespace('atom', NAMESPACE_ATOM1);
+ $xpath->registerNamespace('thr', NAMESPACE_THREAD);
+ $xpath->registerNamespace('georss', NAMESPACE_GEORSS);
+ $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY);
+ $xpath->registerNamespace('media', NAMESPACE_MEDIA);
+ $xpath->registerNamespace('poco', NAMESPACE_POCO);
+ $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS);
+ $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET);
- if ($first_child == "feed")
- $entries = $xpath->query('/atom:feed/atom:entry');
- else
$entries = $xpath->query('/atom:entry');
- $conversation = "";
- $conversationlist = array();
- $item_id = 0;
-
- // Reverse the order of the entries
- $entrylist = array();
-
- foreach ($entries AS $entry)
- $entrylist[] = $entry;
-
- foreach (array_reverse($entrylist) AS $entry) {
-
- $mention = false;
-
- // fetch the author
- if ($first_child == "feed")
- $author = ostatus_fetchauthor($xpath, $doc->firstChild, $importer, $contact, false);
- else
- $author = ostatus_fetchauthor($xpath, $entry, $importer, $contact, false);
-
- $value = $xpath->evaluate('atom:author/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
- if ($value != "")
- $nickname = $value;
- else
- $nickname = $author["author-name"];
-
- $item = array_merge($header, $author);
-
- // Now get the item
- $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue;
-
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
- intval($importer["uid"]), dbesc($item["uri"]));
- if ($r) {
- logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG);
- continue;
+ foreach ($entries AS $entry) {
+ // fetch the author
+ $author = self::fetchauthor($xpath, $entry, $importer, $contact, true);
+ return $author;
}
+ }
- $item["body"] = add_page_info_to_body(html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue));
- $item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
+ /**
+ * @brief Imports an XML string containing OStatus elements
+ *
+ * @param string $xml The XML
+ * @param array $importer user record of the importing user
+ * @param $contact
+ * @param array $hub Called by reference, returns the fetched hub data
+ */
+ public static function import($xml,$importer,&$contact, &$hub) {
+ /// @todo this function is too long. It has to be split in many parts
- if (($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) OR ($item["object-type"] == ACTIVITY_OBJ_EVENT)) {
- $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
- $item["body"] = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue;
- } elseif ($item["object-type"] == ACTIVITY_OBJ_QUESTION)
- $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
+ logger("Import OStatus message", LOGGER_DEBUG);
- $item["object"] = $xml;
- $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
+ if ($xml == "")
+ return;
- /// @TODO
- /// Delete a message
- if ($item["verb"] == "qvitter-delete-notice") {
- // ignore "Delete" messages (by now)
- logger("Ignore delete message ".print_r($item, true));
- continue;
- }
+ //$tempfile = tempnam(get_temppath(), "import");
+ //file_put_contents($tempfile, $xml);
- if ($item["verb"] == ACTIVITY_JOIN) {
- // ignore "Join" messages
- logger("Ignore join message ".print_r($item, true));
- continue;
- }
+ $doc = new DOMDocument();
+ @$doc->loadXML($xml);
- if ($item["verb"] == ACTIVITY_FOLLOW) {
- new_follower($importer, $contact, $item, $nickname);
- continue;
- }
+ $xpath = new DomXPath($doc);
+ $xpath->registerNamespace('atom', NAMESPACE_ATOM1);
+ $xpath->registerNamespace('thr', NAMESPACE_THREAD);
+ $xpath->registerNamespace('georss', NAMESPACE_GEORSS);
+ $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY);
+ $xpath->registerNamespace('media', NAMESPACE_MEDIA);
+ $xpath->registerNamespace('poco', NAMESPACE_POCO);
+ $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS);
+ $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET);
- if ($item["verb"] == NAMESPACE_OSTATUS."/unfollow") {
- lose_follower($importer, $contact, $item, $dummy);
- continue;
- }
-
- if ($item["verb"] == ACTIVITY_FAVORITE) {
- $orig_uri = $xpath->query("activity:object/atom:id", $entry)->item(0)->nodeValue;
- logger("Favorite ".$orig_uri." ".print_r($item, true));
-
- $item["verb"] = ACTIVITY_LIKE;
- $item["parent-uri"] = $orig_uri;
- $item["gravity"] = GRAVITY_LIKE;
- }
-
- if ($item["verb"] == NAMESPACE_OSTATUS."/unfavorite") {
- // Ignore "Unfavorite" message
- logger("Ignore unfavorite message ".print_r($item, true));
- continue;
- }
-
- // http://activitystrea.ms/schema/1.0/rsvp-yes
- if (!in_array($item["verb"], array(ACTIVITY_POST, ACTIVITY_LIKE, ACTIVITY_SHARE)))
- logger("Unhandled verb ".$item["verb"]." ".print_r($item, true));
-
- $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
- $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
- $conversation = $xpath->query('ostatus:conversation/text()', $entry)->item(0)->nodeValue;
-
- $related = "";
-
- $inreplyto = $xpath->query('thr:in-reply-to', $entry);
- if (is_object($inreplyto->item(0))) {
- foreach($inreplyto->item(0)->attributes AS $attributes) {
- if ($attributes->name == "ref")
- $item["parent-uri"] = $attributes->textContent;
- if ($attributes->name == "href")
- $related = $attributes->textContent;
- }
- }
-
- $georsspoint = $xpath->query('georss:point', $entry);
- if ($georsspoint)
- $item["coord"] = $georsspoint->item(0)->nodeValue;
-
- /// @TODO
- /// $item["location"] =
-
- $categories = $xpath->query('atom:category', $entry);
- if ($categories) {
- foreach ($categories AS $category) {
- foreach($category->attributes AS $attributes)
- if ($attributes->name == "term") {
- $term = $attributes->textContent;
- if(strlen($item["tag"]))
- $item["tag"] .= ',';
- $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]";
- }
- }
- }
-
- $self = "";
- $enclosure = "";
-
- $links = $xpath->query('atom:link', $entry);
- if ($links) {
- $rel = "";
- $href = "";
- $type = "";
- $length = "0";
- $title = "";
- foreach ($links AS $link) {
- foreach($link->attributes AS $attributes) {
- if ($attributes->name == "href")
- $href = $attributes->textContent;
- if ($attributes->name == "rel")
- $rel = $attributes->textContent;
- if ($attributes->name == "type")
- $type = $attributes->textContent;
- if ($attributes->name == "length")
- $length = $attributes->textContent;
- if ($attributes->name == "title")
- $title = $attributes->textContent;
+ $gub = "";
+ $hub_attributes = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0)->attributes;
+ if (is_object($hub_attributes))
+ foreach($hub_attributes AS $hub_attribute)
+ if ($hub_attribute->name == "href") {
+ $hub = $hub_attribute->textContent;
+ logger("Found hub ".$hub, LOGGER_DEBUG);
}
- if (($rel != "") AND ($href != ""))
- switch($rel) {
- case "alternate":
- $item["plink"] = $href;
- if (($item["object-type"] == ACTIVITY_OBJ_QUESTION) OR
- ($item["object-type"] == ACTIVITY_OBJ_EVENT))
- $item["body"] .= add_page_info($href);
- break;
- case "ostatus:conversation":
- $conversation = $href;
- break;
- case "enclosure":
- $enclosure = $href;
- if(strlen($item["attach"]))
- $item["attach"] .= ',';
- $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]';
- break;
- case "related":
- if ($item["object-type"] != ACTIVITY_OBJ_BOOKMARK) {
- if (!isset($item["parent-uri"]))
- $item["parent-uri"] = $href;
+ $header = array();
+ $header["uid"] = $importer["uid"];
+ $header["network"] = NETWORK_OSTATUS;
+ $header["type"] = "remote";
+ $header["wall"] = 0;
+ $header["origin"] = 0;
+ $header["gravity"] = GRAVITY_PARENT;
- if ($related == "")
- $related = $href;
- } else
- $item["body"] .= add_page_info($href);
- break;
- case "self":
- $self = $href;
- break;
- case "mentioned":
- // Notification check
- if ($importer["nurl"] == normalise_link($href))
- $mention = true;
- break;
- }
+ // it could either be a received post or a post we fetched by ourselves
+ // depending on that, the first node is different
+ $first_child = $doc->firstChild->tagName;
+
+ if ($first_child == "feed")
+ $entries = $xpath->query('/atom:feed/atom:entry');
+ else
+ $entries = $xpath->query('/atom:entry');
+
+ $conversation = "";
+ $conversationlist = array();
+ $item_id = 0;
+
+ // Reverse the order of the entries
+ $entrylist = array();
+
+ foreach ($entries AS $entry)
+ $entrylist[] = $entry;
+
+ foreach (array_reverse($entrylist) AS $entry) {
+
+ $mention = false;
+
+ // fetch the author
+ if ($first_child == "feed")
+ $author = self::fetchauthor($xpath, $doc->firstChild, $importer, $contact, false);
+ else
+ $author = self::fetchauthor($xpath, $entry, $importer, $contact, false);
+
+ $value = $xpath->evaluate('atom:author/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
+ if ($value != "")
+ $nickname = $value;
+ else
+ $nickname = $author["author-name"];
+
+ $item = array_merge($header, $author);
+
+ // Now get the item
+ $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue;
+
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
+ intval($importer["uid"]), dbesc($item["uri"]));
+ if ($r) {
+ logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG);
+ continue;
}
- }
- $local_id = "";
- $repeat_of = "";
+ $item["body"] = add_page_info_to_body(html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue));
+ $item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
- $notice_info = $xpath->query('statusnet:notice_info', $entry);
- if ($notice_info AND ($notice_info->length > 0)) {
- foreach($notice_info->item(0)->attributes AS $attributes) {
- if ($attributes->name == "source")
- $item["app"] = strip_tags($attributes->textContent);
- if ($attributes->name == "local_id")
- $local_id = $attributes->textContent;
- if ($attributes->name == "repeat_of")
- $repeat_of = $attributes->textContent;
+ if (($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) OR ($item["object-type"] == ACTIVITY_OBJ_EVENT)) {
+ $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
+ $item["body"] = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue;
+ } elseif ($item["object-type"] == ACTIVITY_OBJ_QUESTION)
+ $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
+
+ $item["object"] = $xml;
+ $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
+
+ /// @TODO
+ /// Delete a message
+ if ($item["verb"] == "qvitter-delete-notice") {
+ // ignore "Delete" messages (by now)
+ logger("Ignore delete message ".print_r($item, true));
+ continue;
}
- }
- // Is it a repeated post?
- if ($repeat_of != "") {
- $activityobjects = $xpath->query('activity:object', $entry)->item(0);
+ if ($item["verb"] == ACTIVITY_JOIN) {
+ // ignore "Join" messages
+ logger("Ignore join message ".print_r($item, true));
+ continue;
+ }
- if (is_object($activityobjects)) {
+ if ($item["verb"] == ACTIVITY_FOLLOW) {
+ new_follower($importer, $contact, $item, $nickname);
+ continue;
+ }
- $orig_uri = $xpath->query("activity:object/atom:id", $activityobjects)->item(0)->nodeValue;
- if (!isset($orig_uri))
- $orig_uri = $xpath->query('atom:id/text()', $activityobjects)->item(0)->nodeValue;
+ if ($item["verb"] == NAMESPACE_OSTATUS."/unfollow") {
+ lose_follower($importer, $contact, $item, $dummy);
+ continue;
+ }
- $orig_links = $xpath->query("activity:object/atom:link[@rel='alternate']", $activityobjects);
- if ($orig_links AND ($orig_links->length > 0))
- foreach($orig_links->item(0)->attributes AS $attributes)
+ if ($item["verb"] == ACTIVITY_FAVORITE) {
+ $orig_uri = $xpath->query("activity:object/atom:id", $entry)->item(0)->nodeValue;
+ logger("Favorite ".$orig_uri." ".print_r($item, true));
+
+ $item["verb"] = ACTIVITY_LIKE;
+ $item["parent-uri"] = $orig_uri;
+ $item["gravity"] = GRAVITY_LIKE;
+ }
+
+ if ($item["verb"] == NAMESPACE_OSTATUS."/unfavorite") {
+ // Ignore "Unfavorite" message
+ logger("Ignore unfavorite message ".print_r($item, true));
+ continue;
+ }
+
+ // http://activitystrea.ms/schema/1.0/rsvp-yes
+ if (!in_array($item["verb"], array(ACTIVITY_POST, ACTIVITY_LIKE, ACTIVITY_SHARE)))
+ logger("Unhandled verb ".$item["verb"]." ".print_r($item, true));
+
+ $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
+ $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
+ $conversation = $xpath->query('ostatus:conversation/text()', $entry)->item(0)->nodeValue;
+
+ $related = "";
+
+ $inreplyto = $xpath->query('thr:in-reply-to', $entry);
+ if (is_object($inreplyto->item(0))) {
+ foreach($inreplyto->item(0)->attributes AS $attributes) {
+ if ($attributes->name == "ref")
+ $item["parent-uri"] = $attributes->textContent;
+ if ($attributes->name == "href")
+ $related = $attributes->textContent;
+ }
+ }
+
+ $georsspoint = $xpath->query('georss:point', $entry);
+ if ($georsspoint)
+ $item["coord"] = $georsspoint->item(0)->nodeValue;
+
+ $categories = $xpath->query('atom:category', $entry);
+ if ($categories) {
+ foreach ($categories AS $category) {
+ foreach($category->attributes AS $attributes)
+ if ($attributes->name == "term") {
+ $term = $attributes->textContent;
+ if(strlen($item["tag"]))
+ $item["tag"] .= ',';
+ $item["tag"] .= "#[url=".App::get_baseurl()."/search?tag=".$term."]".$term."[/url]";
+ }
+ }
+ }
+
+ $self = "";
+ $enclosure = "";
+
+ $links = $xpath->query('atom:link', $entry);
+ if ($links) {
+ $rel = "";
+ $href = "";
+ $type = "";
+ $length = "0";
+ $title = "";
+ foreach ($links AS $link) {
+ foreach($link->attributes AS $attributes) {
if ($attributes->name == "href")
- $orig_link = $attributes->textContent;
+ $href = $attributes->textContent;
+ if ($attributes->name == "rel")
+ $rel = $attributes->textContent;
+ if ($attributes->name == "type")
+ $type = $attributes->textContent;
+ if ($attributes->name == "length")
+ $length = $attributes->textContent;
+ if ($attributes->name == "title")
+ $title = $attributes->textContent;
+ }
+ if (($rel != "") AND ($href != ""))
+ switch($rel) {
+ case "alternate":
+ $item["plink"] = $href;
+ if (($item["object-type"] == ACTIVITY_OBJ_QUESTION) OR
+ ($item["object-type"] == ACTIVITY_OBJ_EVENT))
+ $item["body"] .= add_page_info($href);
+ break;
+ case "ostatus:conversation":
+ $conversation = $href;
+ break;
+ case "enclosure":
+ $enclosure = $href;
+ if(strlen($item["attach"]))
+ $item["attach"] .= ',';
- if (!isset($orig_link))
- $orig_link = $xpath->query("atom:link[@rel='alternate']", $activityobjects)->item(0)->nodeValue;
+ $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]';
+ break;
+ case "related":
+ if ($item["object-type"] != ACTIVITY_OBJ_BOOKMARK) {
+ if (!isset($item["parent-uri"]))
+ $item["parent-uri"] = $href;
- if (!isset($orig_link))
- $orig_link = ostatus_convert_href($orig_uri);
+ if ($related == "")
+ $related = $href;
+ } else
+ $item["body"] .= add_page_info($href);
+ break;
+ case "self":
+ $self = $href;
+ break;
+ case "mentioned":
+ // Notification check
+ if ($importer["nurl"] == normalise_link($href))
+ $mention = true;
+ break;
+ }
+ }
+ }
- $orig_body = $xpath->query('activity:object/atom:content/text()', $activityobjects)->item(0)->nodeValue;
- if (!isset($orig_body))
- $orig_body = $xpath->query('atom:content/text()', $activityobjects)->item(0)->nodeValue;
+ $local_id = "";
+ $repeat_of = "";
- $orig_created = $xpath->query('atom:published/text()', $activityobjects)->item(0)->nodeValue;
+ $notice_info = $xpath->query('statusnet:notice_info', $entry);
+ if ($notice_info AND ($notice_info->length > 0)) {
+ foreach($notice_info->item(0)->attributes AS $attributes) {
+ if ($attributes->name == "source")
+ $item["app"] = strip_tags($attributes->textContent);
+ if ($attributes->name == "local_id")
+ $local_id = $attributes->textContent;
+ if ($attributes->name == "repeat_of")
+ $repeat_of = $attributes->textContent;
+ }
+ }
- $orig_contact = $contact;
- $orig_author = ostatus_fetchauthor($xpath, $activityobjects, $importer, $orig_contact, false);
+ // Is it a repeated post?
+ if ($repeat_of != "") {
+ $activityobjects = $xpath->query('activity:object', $entry)->item(0);
+
+ if (is_object($activityobjects)) {
+
+ $orig_uri = $xpath->query("activity:object/atom:id", $activityobjects)->item(0)->nodeValue;
+ if (!isset($orig_uri))
+ $orig_uri = $xpath->query('atom:id/text()', $activityobjects)->item(0)->nodeValue;
+
+ $orig_links = $xpath->query("activity:object/atom:link[@rel='alternate']", $activityobjects);
+ if ($orig_links AND ($orig_links->length > 0))
+ foreach($orig_links->item(0)->attributes AS $attributes)
+ if ($attributes->name == "href")
+ $orig_link = $attributes->textContent;
+
+ if (!isset($orig_link))
+ $orig_link = $xpath->query("atom:link[@rel='alternate']", $activityobjects)->item(0)->nodeValue;
+
+ if (!isset($orig_link))
+ $orig_link = self::convert_href($orig_uri);
+
+ $orig_body = $xpath->query('activity:object/atom:content/text()', $activityobjects)->item(0)->nodeValue;
+ if (!isset($orig_body))
+ $orig_body = $xpath->query('atom:content/text()', $activityobjects)->item(0)->nodeValue;
+
+ $orig_created = $xpath->query('atom:published/text()', $activityobjects)->item(0)->nodeValue;
+
+ $orig_contact = $contact;
+ $orig_author = self::fetchauthor($xpath, $activityobjects, $importer, $orig_contact, false);
- //if (!intval(get_config('system','wall-to-wall_share'))) {
- // $prefix = share_header($orig_author['author-name'], $orig_author['author-link'], $orig_author['author-avatar'], "", $orig_created, $orig_link);
- // $item["body"] = $prefix.add_page_info_to_body(html2bbcode($orig_body))."[/share]";
- //} else {
$item["author-name"] = $orig_author["author-name"];
$item["author-link"] = $orig_author["author-link"];
$item["author-avatar"] = $orig_author["author-avatar"];
@@ -498,1146 +504,1511 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
$item["uri"] = $orig_uri;
$item["plink"] = $orig_link;
- //}
- $item["verb"] = $xpath->query('activity:verb/text()', $activityobjects)->item(0)->nodeValue;
+ $item["verb"] = $xpath->query('activity:verb/text()', $activityobjects)->item(0)->nodeValue;
- $item["object-type"] = $xpath->query('activity:object/activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
- if (!isset($item["object-type"]))
- $item["object-type"] = $xpath->query('activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
- }
- }
-
- //if ($enclosure != "")
- // $item["body"] .= add_page_info($enclosure);
-
- if (isset($item["parent-uri"])) {
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
- intval($importer["uid"]), dbesc($item["parent-uri"]));
-
- if (!$r AND ($related != "")) {
- $reply_path = str_replace("/notice/", "/api/statuses/show/", $related).".atom";
-
- if ($reply_path != $related) {
- logger("Fetching related items for user ".$importer["uid"]." from ".$reply_path, LOGGER_DEBUG);
- $reply_xml = fetch_url($reply_path);
-
- $reply_contact = $contact;
- ostatus_import($reply_xml,$importer,$reply_contact, $reply_hub);
-
- // After the import try to fetch the parent item again
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
- intval($importer["uid"]), dbesc($item["parent-uri"]));
+ $item["object-type"] = $xpath->query('activity:object/activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
+ if (!isset($item["object-type"]))
+ $item["object-type"] = $xpath->query('activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
}
}
- if ($r) {
- $item["type"] = 'remote-comment';
- $item["gravity"] = GRAVITY_COMMENT;
- }
- } else
- $item["parent-uri"] = $item["uri"];
- $item_id = ostatus_completion($conversation, $importer["uid"], $item);
+ //if ($enclosure != "")
+ // $item["body"] .= add_page_info($enclosure);
- if (!$item_id) {
- logger("Error storing item", LOGGER_DEBUG);
- continue;
- }
+ if (isset($item["parent-uri"])) {
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
+ intval($importer["uid"]), dbesc($item["parent-uri"]));
- logger("Item was stored with id ".$item_id, LOGGER_DEBUG);
- }
-}
+ if (!$r AND ($related != "")) {
+ $reply_path = str_replace("/notice/", "/api/statuses/show/", $related).".atom";
-function ostatus_convert_href($href) {
- $elements = explode(":",$href);
+ if ($reply_path != $related) {
+ logger("Fetching related items for user ".$importer["uid"]." from ".$reply_path, LOGGER_DEBUG);
+ $reply_xml = fetch_url($reply_path);
- if ((count($elements) <= 2) OR ($elements[0] != "tag"))
- return $href;
+ $reply_contact = $contact;
+ self::import($reply_xml,$importer,$reply_contact, $reply_hub);
- $server = explode(",", $elements[1]);
- $conversation = explode("=", $elements[2]);
-
- if ((count($elements) == 4) AND ($elements[2] == "post"))
- return "http://".$server[0]."/notice/".$elements[3];
-
- if ((count($conversation) != 2) OR ($conversation[1] ==""))
- return $href;
-
- if ($elements[3] == "objectType=thread")
- return "http://".$server[0]."/conversation/".$conversation[1];
- else
- return "http://".$server[0]."/notice/".$conversation[1];
-
- return $href;
-}
-
-function check_conversations($mentions = false, $override = false) {
- $last = get_config('system','ostatus_last_poll');
-
- $poll_interval = intval(get_config('system','ostatus_poll_interval'));
- if(! $poll_interval)
- $poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
-
- // Don't poll if the interval is set negative
- if (($poll_interval < 0) AND !$override)
- return;
-
- if (!$mentions) {
- $poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
- if (!$poll_timeframe)
- $poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
- } else {
- $poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
- if (!$poll_timeframe)
- $poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS;
- }
-
-
- if ($last AND !$override) {
- $next = $last + ($poll_interval * 60);
- if ($next > time()) {
- logger('poll interval not reached');
- return;
- }
- }
-
- logger('cron_start');
-
- $start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
-
- if ($mentions)
- $conversations = q("SELECT `term`.`oid`, `term`.`url`, `term`.`uid` FROM `term`
- STRAIGHT_JOIN `thread` ON `thread`.`iid` = `term`.`oid` AND `thread`.`uid` = `term`.`uid`
- WHERE `term`.`type` = 7 AND `term`.`term` > '%s' AND `thread`.`mention`
- GROUP BY `term`.`url`, `term`.`uid` ORDER BY `term`.`term` DESC", dbesc($start));
- else
- $conversations = q("SELECT `oid`, `url`, `uid` FROM `term`
- WHERE `type` = 7 AND `term` > '%s'
- GROUP BY `url`, `uid` ORDER BY `term` DESC", dbesc($start));
-
- foreach ($conversations AS $conversation) {
- ostatus_completion($conversation['url'], $conversation['uid']);
- }
-
- logger('cron_end');
-
- set_config('system','ostatus_last_poll', time());
-}
-
-/**
- * @brief Updates the gcontact table with actor data from the conversation
- *
- * @param object $actor The actor object that contains the contact data
- */
-function ostatus_conv_fetch_actor($actor) {
-
- // We set the generation to "3" since the data here is not as reliable as the data we get on other occasions
- $contact = array("network" => NETWORK_OSTATUS, "generation" => 3);
-
- if (isset($actor->url))
- $contact["url"] = $actor->url;
-
- if (isset($actor->displayName))
- $contact["name"] = $actor->displayName;
-
- if (isset($actor->portablecontacts_net->displayName))
- $contact["name"] = $actor->portablecontacts_net->displayName;
-
- if (isset($actor->portablecontacts_net->preferredUsername))
- $contact["nick"] = $actor->portablecontacts_net->preferredUsername;
-
- if (isset($actor->id))
- $contact["alias"] = $actor->id;
-
- if (isset($actor->summary))
- $contact["about"] = $actor->summary;
-
- if (isset($actor->portablecontacts_net->note))
- $contact["about"] = $actor->portablecontacts_net->note;
-
- if (isset($actor->portablecontacts_net->addresses->formatted))
- $contact["location"] = $actor->portablecontacts_net->addresses->formatted;
-
-
- if (isset($actor->image->url))
- $contact["photo"] = $actor->image->url;
-
- if (isset($actor->image->width))
- $avatarwidth = $actor->image->width;
-
- if (is_array($actor->status_net->avatarLinks))
- foreach ($actor->status_net->avatarLinks AS $avatar) {
- if ($avatarsize < $avatar->width) {
- $contact["photo"] = $avatar->url;
- $avatarsize = $avatar->width;
- }
- }
-
- update_gcontact($contact);
-}
-
-
-function ostatus_completion($conversation_url, $uid, $item = array()) {
-
- $a = get_app();
-
- $item_stored = -1;
-
- $conversation_url = ostatus_convert_href($conversation_url);
-
- // If the thread shouldn't be completed then store the item and go away
- if ((intval(get_config('system','ostatus_poll_interval')) == -2) AND (count($item) > 0)) {
- //$arr["app"] .= " (OStatus-NoCompletion)";
- $item_stored = item_store($item, true);
- return($item_stored);
- }
-
- // Get the parent
- $parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
- (SELECT `parent` FROM `item` WHERE `id` IN
- (SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
- intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
-
- if ($parents)
- $parent = $parents[0];
- elseif (count($item) > 0) {
- $parent = $item;
- $parent["type"] = "remote";
- $parent["verb"] = ACTIVITY_POST;
- $parent["visible"] = 1;
- } else {
- // Preset the parent
- $r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
- if (!$r)
- return(-2);
-
- $parent = array();
- $parent["id"] = 0;
- $parent["parent"] = 0;
- $parent["uri"] = "";
- $parent["contact-id"] = $r[0]["id"];
- $parent["type"] = "remote";
- $parent["verb"] = ACTIVITY_POST;
- $parent["visible"] = 1;
- }
-
- $conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
- $pageno = 1;
- $items = array();
-
- logger('fetching conversation url '.$conv.' for user '.$uid);
-
- do {
- $conv_arr = z_fetch_url($conv."?page=".$pageno);
-
- // If it is a non-ssl site and there is an error, then try ssl or vice versa
- if (!$conv_arr["success"] AND (substr($conv, 0, 7) == "http://")) {
- $conv = str_replace("http://", "https://", $conv);
- $conv_as = fetch_url($conv."?page=".$pageno);
- } elseif (!$conv_arr["success"] AND (substr($conv, 0, 8) == "https://")) {
- $conv = str_replace("https://", "http://", $conv);
- $conv_as = fetch_url($conv."?page=".$pageno);
- } else
- $conv_as = $conv_arr["body"];
-
- $conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
- $conv_as = json_decode($conv_as);
-
- $no_of_items = sizeof($items);
-
- if (@is_array($conv_as->items))
- foreach ($conv_as->items AS $single_item)
- $items[$single_item->id] = $single_item;
-
- if ($no_of_items == sizeof($items))
- break;
-
- $pageno++;
-
- } while (true);
-
- logger('fetching conversation done. Found '.count($items).' items');
-
- if (!sizeof($items)) {
- if (count($item) > 0) {
- //$arr["app"] .= " (OStatus-NoConvFetched)";
- $item_stored = item_store($item, true);
-
- if ($item_stored) {
- logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
- ostatus_store_conversation($item_id, $conversation_url);
- }
-
- return($item_stored);
- } else
- return(-3);
- }
-
- $items = array_reverse($items);
-
- $r = q("SELECT `nurl` FROM `contact` WHERE `uid` = %d AND `self`", intval($uid));
- $importer = $r[0];
-
- foreach ($items as $single_conv) {
-
- // Update the gcontact table
- ostatus_conv_fetch_actor($single_conv->actor);
-
- // Test - remove before flight
- //$tempfile = tempnam(get_temppath(), "conversation");
- //file_put_contents($tempfile, json_encode($single_conv));
-
- $mention = false;
-
- if (isset($single_conv->object->id))
- $single_conv->id = $single_conv->object->id;
-
- $plink = ostatus_convert_href($single_conv->id);
- if (isset($single_conv->object->url))
- $plink = ostatus_convert_href($single_conv->object->url);
-
- if (@!$single_conv->id)
- continue;
-
- logger("Got id ".$single_conv->id, LOGGER_DEBUG);
-
- if ($first_id == "") {
- $first_id = $single_conv->id;
-
- // The first post of the conversation isn't our first post. There are three options:
- // 1. Our conversation hasn't the "real" thread starter
- // 2. This first post is a post inside our thread
- // 3. This first post is a post inside another thread
- if (($first_id != $parent["uri"]) AND ($parent["uri"] != "")) {
- $new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
- (SELECT `parent` FROM `item`
- WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1",
- intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
- if ($new_parents) {
- if ($new_parents[0]["parent"] == $parent["parent"]) {
- // Option 2: This post is already present inside our thread - but not as thread starter
- logger("Option 2: uri present in our thread: ".$first_id, LOGGER_DEBUG);
- $first_id = $parent["uri"];
- } else {
- // Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
- // For now just take the new parent.
- $parent = $new_parents[0];
- $first_id = $parent["uri"];
- logger("Option 3: mixed parents for uri ".$first_id, LOGGER_DEBUG);
+ // After the import try to fetch the parent item again
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
+ intval($importer["uid"]), dbesc($item["parent-uri"]));
}
- } else {
- // Option 1: We hadn't got the real thread starter
- // We have to clean up our existing messages.
- $parent["id"] = 0;
- $parent["uri"] = $first_id;
- logger("Option 1: we have a new parent: ".$first_id, LOGGER_DEBUG);
}
- } elseif ($parent["uri"] == "") {
- $parent["id"] = 0;
- $parent["uri"] = $first_id;
- }
- }
-
- $parent_uri = $parent["uri"];
-
- // "context" only seems to exist on older servers
- if (isset($single_conv->context->inReplyTo->id)) {
- $parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
- intval($uid), dbesc($single_conv->context->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
- if ($parent_exists)
- $parent_uri = $single_conv->context->inReplyTo->id;
- }
-
- // This is the current way
- if (isset($single_conv->object->inReplyTo->id)) {
- $parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
- intval($uid), dbesc($single_conv->object->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
- if ($parent_exists)
- $parent_uri = $single_conv->object->inReplyTo->id;
- }
-
- $message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
- intval($uid), dbesc($single_conv->id),
- dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
- if ($message_exists) {
- logger("Message ".$single_conv->id." already existed on the system", LOGGER_DEBUG);
-
- if ($parent["id"] != 0) {
- $existing_message = $message_exists[0];
-
- // We improved the way we fetch OStatus messages, this shouldn't happen very often now
- /// @TODO We have to change the shadow copies as well. This way here is really ugly.
- if ($existing_message["parent"] != $parent["id"]) {
- logger('updating id '.$existing_message["id"].' with parent '.$existing_message["parent"].' to parent '.$parent["id"].' uri '.$parent["uri"].' thread '.$parent_uri, LOGGER_DEBUG);
-
- // Update the parent id of the selected item
- $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `id` = %d",
- intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["id"]));
-
- // Update the parent uri in the thread - but only if it points to itself
- $r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE `id` = %d AND `uri` = `thr-parent`",
- dbesc($parent_uri), intval($existing_message["id"]));
-
- // try to change all items of the same parent
- $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d",
- intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["parent"]));
-
- // Update the parent uri in the thread - but only if it points to itself
- $r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE (`parent` = %d) AND (`uri` = `thr-parent`)",
- dbesc($parent["uri"]), intval($existing_message["parent"]));
-
- // Now delete the thread
- delete_thread($existing_message["parent"]);
+ if ($r) {
+ $item["type"] = 'remote-comment';
+ $item["gravity"] = GRAVITY_COMMENT;
}
+ } else
+ $item["parent-uri"] = $item["uri"];
+
+ $item_id = self::completion($conversation, $importer["uid"], $item, $self);
+
+ if (!$item_id) {
+ logger("Error storing item", LOGGER_DEBUG);
+ continue;
}
- // The item we are having on the system is the one that we wanted to store via the item array
- if (isset($item["uri"]) AND ($item["uri"] == $existing_message["uri"])) {
- $item = array();
- $item_stored = 0;
- }
-
- continue;
+ logger("Item was stored with id ".$item_id, LOGGER_DEBUG);
}
+ }
- if (is_array($single_conv->to))
- foreach($single_conv->to AS $to)
- if ($importer["nurl"] == normalise_link($to->id))
- $mention = true;
+ /**
+ * @brief Create an url out of an uri
+ *
+ * @param string $href URI in the format "parameter1:parameter1:..."
+ *
+ * @return string URL in the format http(s)://....
+ */
+ public static function convert_href($href) {
+ $elements = explode(":",$href);
- $actor = $single_conv->actor->id;
- if (isset($single_conv->actor->url))
- $actor = $single_conv->actor->url;
+ if ((count($elements) <= 2) OR ($elements[0] != "tag"))
+ return $href;
- $contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
- $uid, normalise_link($actor), NETWORK_STATUSNET);
+ $server = explode(",", $elements[1]);
+ $conversation = explode("=", $elements[2]);
- if (count($contact)) {
- logger("Found contact for url ".$actor, LOGGER_DEBUG);
- $contact_id = $contact[0]["id"];
+ if ((count($elements) == 4) AND ($elements[2] == "post"))
+ return "http://".$server[0]."/notice/".$elements[3];
+
+ if ((count($conversation) != 2) OR ($conversation[1] ==""))
+ return $href;
+
+ if ($elements[3] == "objectType=thread")
+ return "http://".$server[0]."/conversation/".$conversation[1];
+ else
+ return "http://".$server[0]."/notice/".$conversation[1];
+
+ return $href;
+ }
+
+ /**
+ * @brief Checks if there are entries in conversations that aren't present on our side
+ *
+ * @param bool $mentions Fetch conversations where we are mentioned
+ * @param bool $override Override the interval setting
+ */
+ public static function check_conversations($mentions = false, $override = false) {
+ $last = get_config('system','ostatus_last_poll');
+
+ $poll_interval = intval(get_config('system','ostatus_poll_interval'));
+ if(! $poll_interval)
+ $poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
+
+ // Don't poll if the interval is set negative
+ if (($poll_interval < 0) AND !$override)
+ return;
+
+ if (!$mentions) {
+ $poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
+ if (!$poll_timeframe)
+ $poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
} else {
- logger("No contact found for url ".$actor, LOGGER_DEBUG);
+ $poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
+ if (!$poll_timeframe)
+ $poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS;
+ }
+
+
+ if ($last AND !$override) {
+ $next = $last + ($poll_interval * 60);
+ if ($next > time()) {
+ logger('poll interval not reached');
+ return;
+ }
+ }
+
+ logger('cron_start');
+
+ $start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
+
+ if ($mentions)
+ $conversations = q("SELECT `term`.`oid`, `term`.`url`, `term`.`uid` FROM `term`
+ STRAIGHT_JOIN `thread` ON `thread`.`iid` = `term`.`oid` AND `thread`.`uid` = `term`.`uid`
+ WHERE `term`.`type` = 7 AND `term`.`term` > '%s' AND `thread`.`mention`
+ GROUP BY `term`.`url`, `term`.`uid` ORDER BY `term`.`term` DESC", dbesc($start));
+ else
+ $conversations = q("SELECT `oid`, `url`, `uid` FROM `term`
+ WHERE `type` = 7 AND `term` > '%s'
+ GROUP BY `url`, `uid` ORDER BY `term` DESC", dbesc($start));
+
+ foreach ($conversations AS $conversation) {
+ self::completion($conversation['url'], $conversation['uid']);
+ }
+
+ logger('cron_end');
+
+ set_config('system','ostatus_last_poll', time());
+ }
+
+ /**
+ * @brief Updates the gcontact table with actor data from the conversation
+ *
+ * @param object $actor The actor object that contains the contact data
+ */
+ private function conv_fetch_actor($actor) {
+
+ // We set the generation to "3" since the data here is not as reliable as the data we get on other occasions
+ $contact = array("network" => NETWORK_OSTATUS, "generation" => 3);
+
+ if (isset($actor->url))
+ $contact["url"] = $actor->url;
+
+ if (isset($actor->displayName))
+ $contact["name"] = $actor->displayName;
+
+ if (isset($actor->portablecontacts_net->displayName))
+ $contact["name"] = $actor->portablecontacts_net->displayName;
+
+ if (isset($actor->portablecontacts_net->preferredUsername))
+ $contact["nick"] = $actor->portablecontacts_net->preferredUsername;
+
+ if (isset($actor->id))
+ $contact["alias"] = $actor->id;
+
+ if (isset($actor->summary))
+ $contact["about"] = $actor->summary;
+
+ if (isset($actor->portablecontacts_net->note))
+ $contact["about"] = $actor->portablecontacts_net->note;
+
+ if (isset($actor->portablecontacts_net->addresses->formatted))
+ $contact["location"] = $actor->portablecontacts_net->addresses->formatted;
+
+
+ if (isset($actor->image->url))
+ $contact["photo"] = $actor->image->url;
+
+ if (isset($actor->image->width))
+ $avatarwidth = $actor->image->width;
+
+ if (is_array($actor->status_net->avatarLinks))
+ foreach ($actor->status_net->avatarLinks AS $avatar) {
+ if ($avatarsize < $avatar->width) {
+ $contact["photo"] = $avatar->url;
+ $avatarsize = $avatar->width;
+ }
+ }
+
+ update_gcontact($contact);
+ }
+
+ /**
+ * @brief Fetches the conversation url for a given item link or conversation id
+ *
+ * @param string $self The link to the posting
+ * @param string $conversation_id The conversation id
+ *
+ * @return string The conversation url
+ */
+ private function fetch_conversation($self, $conversation_id = "") {
+
+ if ($conversation_id != "") {
+ $elements = explode(":", $conversation_id);
+
+ if ((count($elements) <= 2) OR ($elements[0] != "tag"))
+ return $conversation_id;
+ }
+
+ if ($self == "")
+ return "";
+
+ $json = str_replace(".atom", ".json", $self);
+
+ $raw = fetch_url($json);
+ if ($raw == "")
+ return "";
+
+ $data = json_decode($raw);
+ if (!is_object($data))
+ return "";
+
+ $conversation_id = $data->statusnet_conversation_id;
+
+ $pos = strpos($self, "/api/statuses/show/");
+ $base_url = substr($self, 0, $pos);
+
+ return $base_url."/conversation/".$conversation_id;
+ }
+
+ /**
+ * @brief Fetches actor details of a given actor and user id
+ *
+ * @param string $actor The actor url
+ * @param int $uid The user id
+ * @param int $contact_id The default contact-id
+ *
+ * @return array Array with actor details
+ */
+ private function get_actor_details($actor, $uid, $contact_id) {
+
+ $details = array();
+
+ $contact = q("SELECT `id`, `rel`, `network` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
+ $uid, normalise_link($actor), NETWORK_STATUSNET);
+
+ if (!$contact)
+ $contact = q("SELECT `id`, `rel`, `network` FROM `contact` WHERE `uid` = %d AND `alias` IN ('%s', '%s') AND `network` != '%s'",
+ $uid, $actor, normalise_link($actor), NETWORK_STATUSNET);
+
+ if ($contact) {
+ logger("Found contact for url ".$actor, LOGGER_DEBUG);
+ $details["contact_id"] = $contact[0]["id"];
+ $details["network"] = $contact[0]["network"];
+
+ $details["not_following"] = !in_array($contact[0]["rel"], array(CONTACT_IS_SHARING, CONTACT_IS_FRIEND));
+ } else {
+ logger("No contact found for user ".$uid." and url ".$actor, LOGGER_DEBUG);
// Adding a global contact
/// @TODO Use this data for the post
- $global_contact_id = get_contact($actor, 0);
+ $details["global_contact_id"] = get_contact($actor, 0);
logger("Global contact ".$global_contact_id." found for url ".$actor, LOGGER_DEBUG);
- $contact_id = $parent["contact-id"];
+ $details["contact_id"] = $contact_id;
+ $details["network"] = NETWORK_OSTATUS;
+
+ $details["not_following"] = true;
}
- $arr = array();
- $arr["network"] = NETWORK_OSTATUS;
- $arr["uri"] = $single_conv->id;
- $arr["plink"] = $plink;
- $arr["uid"] = $uid;
- $arr["contact-id"] = $contact_id;
- $arr["parent-uri"] = $parent_uri;
- $arr["created"] = $single_conv->published;
- $arr["edited"] = $single_conv->published;
- $arr["owner-name"] = $single_conv->actor->displayName;
- if ($arr["owner-name"] == '')
- $arr["owner-name"] = $single_conv->actor->contact->displayName;
- if ($arr["owner-name"] == '')
- $arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
+ return $details;
+ }
- $arr["owner-link"] = $actor;
- $arr["owner-avatar"] = $single_conv->actor->image->url;
- $arr["author-name"] = $arr["owner-name"];
- $arr["author-link"] = $actor;
- $arr["author-avatar"] = $single_conv->actor->image->url;
- $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content));
+ /**
+ * @brief Stores an item and completes the thread
+ *
+ * @param string $conversation_url The URI of the conversation
+ * @param integer $uid The user id
+ * @param array $item Data of the item that is to be posted
+ *
+ * @return integer The item id of the posted item array
+ */
+ private function completion($conversation_url, $uid, $item = array(), $self = "") {
- if (isset($single_conv->status_net->notice_info->source))
- $arr["app"] = strip_tags($single_conv->status_net->notice_info->source);
- elseif (isset($single_conv->statusnet->notice_info->source))
- $arr["app"] = strip_tags($single_conv->statusnet->notice_info->source);
- elseif (isset($single_conv->statusnet_notice_info->source))
- $arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
- elseif (isset($single_conv->provider->displayName))
- $arr["app"] = $single_conv->provider->displayName;
- else
- $arr["app"] = "OStatus";
+ /// @todo This function is totally ugly and has to be rewritten totally
- //$arr["app"] .= " (Conversation)";
+ $item_stored = -1;
- $arr["object"] = json_encode($single_conv);
- $arr["verb"] = $parent["verb"];
- $arr["visible"] = $parent["visible"];
- $arr["location"] = $single_conv->location->displayName;
- $arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
+ $conversation_url = self::fetch_conversation($self, $conversation_url);
- // Is it a reshared item?
- if (isset($single_conv->verb) AND ($single_conv->verb == "share") AND isset($single_conv->object)) {
- if (is_array($single_conv->object))
- $single_conv->object = $single_conv->object[0];
+ // If the thread shouldn't be completed then store the item and go away
+ // Don't do a completion on liked content
+ if (((intval(get_config('system','ostatus_poll_interval')) == -2) AND (count($item) > 0)) OR
+ ($item["verb"] == ACTIVITY_LIKE) OR ($conversation_url == "")) {
+ $item_stored = item_store($item, true);
+ return($item_stored);
+ }
- logger("Found reshared item ".$single_conv->object->id);
+ // Get the parent
+ $parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
+ (SELECT `parent` FROM `item` WHERE `id` IN
+ (SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
+ intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
- // $single_conv->object->context->conversation;
+ if ($parents)
+ $parent = $parents[0];
+ elseif (count($item) > 0) {
+ $parent = $item;
+ $parent["type"] = "remote";
+ $parent["verb"] = ACTIVITY_POST;
+ $parent["visible"] = 1;
+ } else {
+ // Preset the parent
+ $r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
+ if (!$r)
+ return(-2);
- if (isset($single_conv->object->object->id))
- $arr["uri"] = $single_conv->object->object->id;
- else
- $arr["uri"] = $single_conv->object->id;
+ $parent = array();
+ $parent["id"] = 0;
+ $parent["parent"] = 0;
+ $parent["uri"] = "";
+ $parent["contact-id"] = $r[0]["id"];
+ $parent["type"] = "remote";
+ $parent["verb"] = ACTIVITY_POST;
+ $parent["visible"] = 1;
+ }
- if (isset($single_conv->object->object->url))
- $plink = ostatus_convert_href($single_conv->object->object->url);
- else
- $plink = ostatus_convert_href($single_conv->object->url);
+ $conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
+ $pageno = 1;
+ $items = array();
- if (isset($single_conv->object->object->content))
- $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content));
- else
- $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
+ logger('fetching conversation url '.$conv.' (Self: '.$self.') for user '.$uid);
+ do {
+ $conv_arr = z_fetch_url($conv."?page=".$pageno);
+
+ // If it is a non-ssl site and there is an error, then try ssl or vice versa
+ if (!$conv_arr["success"] AND (substr($conv, 0, 7) == "http://")) {
+ $conv = str_replace("http://", "https://", $conv);
+ $conv_as = fetch_url($conv."?page=".$pageno);
+ } elseif (!$conv_arr["success"] AND (substr($conv, 0, 8) == "https://")) {
+ $conv = str_replace("https://", "http://", $conv);
+ $conv_as = fetch_url($conv."?page=".$pageno);
+ } else
+ $conv_as = $conv_arr["body"];
+
+ $conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
+ $conv_as = json_decode($conv_as);
+
+ $no_of_items = sizeof($items);
+
+ if (@is_array($conv_as->items))
+ foreach ($conv_as->items AS $single_item)
+ $items[$single_item->id] = $single_item;
+
+ if ($no_of_items == sizeof($items))
+ break;
+
+ $pageno++;
+
+ } while (true);
+
+ logger('fetching conversation done. Found '.count($items).' items');
+
+ if (!sizeof($items)) {
+ if (count($item) > 0) {
+ $item_stored = item_store($item, true);
+
+ if ($item_stored) {
+ logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
+ self::store_conversation($item_id, $conversation_url);
+ }
+
+ return($item_stored);
+ } else
+ return(-3);
+ }
+
+ $items = array_reverse($items);
+
+ $r = q("SELECT `nurl` FROM `contact` WHERE `uid` = %d AND `self`", intval($uid));
+ $importer = $r[0];
+
+ $new_parent = true;
+
+ foreach ($items as $single_conv) {
+
+ // Update the gcontact table
+ self::conv_fetch_actor($single_conv->actor);
+
+ // Test - remove before flight
+ //$tempfile = tempnam(get_temppath(), "conversation");
+ //file_put_contents($tempfile, json_encode($single_conv));
+
+ $mention = false;
+
+ if (isset($single_conv->object->id))
+ $single_conv->id = $single_conv->object->id;
+
+ $plink = self::convert_href($single_conv->id);
+ if (isset($single_conv->object->url))
+ $plink = self::convert_href($single_conv->object->url);
+
+ if (@!$single_conv->id)
+ continue;
+
+ logger("Got id ".$single_conv->id, LOGGER_DEBUG);
+
+ if ($first_id == "") {
+ $first_id = $single_conv->id;
+
+ // The first post of the conversation isn't our first post. There are three options:
+ // 1. Our conversation hasn't the "real" thread starter
+ // 2. This first post is a post inside our thread
+ // 3. This first post is a post inside another thread
+ if (($first_id != $parent["uri"]) AND ($parent["uri"] != "")) {
+
+ $new_parent = true;
+
+ $new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
+ (SELECT `parent` FROM `item`
+ WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1",
+ intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+ if ($new_parents) {
+ if ($new_parents[0]["parent"] == $parent["parent"]) {
+ // Option 2: This post is already present inside our thread - but not as thread starter
+ logger("Option 2: uri present in our thread: ".$first_id, LOGGER_DEBUG);
+ $first_id = $parent["uri"];
+ } else {
+ // Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
+ // For now just take the new parent.
+ $parent = $new_parents[0];
+ $first_id = $parent["uri"];
+ logger("Option 3: mixed parents for uri ".$first_id, LOGGER_DEBUG);
+ }
+ } else {
+ // Option 1: We hadn't got the real thread starter
+ // We have to clean up our existing messages.
+ $parent["id"] = 0;
+ $parent["uri"] = $first_id;
+ logger("Option 1: we have a new parent: ".$first_id, LOGGER_DEBUG);
+ }
+ } elseif ($parent["uri"] == "") {
+ $parent["id"] = 0;
+ $parent["uri"] = $first_id;
+ }
+ }
+
+ $parent_uri = $parent["uri"];
+
+ // "context" only seems to exist on older servers
+ if (isset($single_conv->context->inReplyTo->id)) {
+ $parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+ intval($uid), dbesc($single_conv->context->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+ if ($parent_exists)
+ $parent_uri = $single_conv->context->inReplyTo->id;
+ }
+
+ // This is the current way
+ if (isset($single_conv->object->inReplyTo->id)) {
+ $parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+ intval($uid), dbesc($single_conv->object->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+ if ($parent_exists)
+ $parent_uri = $single_conv->object->inReplyTo->id;
+ }
+
+ $message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+ intval($uid), dbesc($single_conv->id),
+ dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+ if ($message_exists) {
+ logger("Message ".$single_conv->id." already existed on the system", LOGGER_DEBUG);
+
+ if ($parent["id"] != 0) {
+ $existing_message = $message_exists[0];
+
+ // We improved the way we fetch OStatus messages, this shouldn't happen very often now
+ /// @TODO We have to change the shadow copies as well. This way here is really ugly.
+ if ($existing_message["parent"] != $parent["id"]) {
+ logger('updating id '.$existing_message["id"].' with parent '.$existing_message["parent"].' to parent '.$parent["id"].' uri '.$parent["uri"].' thread '.$parent_uri, LOGGER_DEBUG);
+
+ // Update the parent id of the selected item
+ $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `id` = %d",
+ intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["id"]));
+
+ // Update the parent uri in the thread - but only if it points to itself
+ $r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE `id` = %d AND `uri` = `thr-parent`",
+ dbesc($parent_uri), intval($existing_message["id"]));
+
+ // try to change all items of the same parent
+ $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d",
+ intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["parent"]));
+
+ // Update the parent uri in the thread - but only if it points to itself
+ $r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE (`parent` = %d) AND (`uri` = `thr-parent`)",
+ dbesc($parent["uri"]), intval($existing_message["parent"]));
+
+ // Now delete the thread
+ delete_thread($existing_message["parent"]);
+ }
+ }
+
+ // The item we are having on the system is the one that we wanted to store via the item array
+ if (isset($item["uri"]) AND ($item["uri"] == $existing_message["uri"])) {
+ $item = array();
+ $item_stored = 0;
+ }
+
+ continue;
+ }
+
+ if (is_array($single_conv->to))
+ foreach($single_conv->to AS $to)
+ if ($importer["nurl"] == normalise_link($to->id))
+ $mention = true;
+
+ $actor = $single_conv->actor->id;
+ if (isset($single_conv->actor->url))
+ $actor = $single_conv->actor->url;
+
+ $details = self::get_actor_details($actor, $uid, $parent["contact-id"]);
+
+ // Do we only want to import threads that were started by our contacts?
+ if ($details["not_following"] AND $new_parent AND get_config('system','ostatus_full_threads')) {
+ logger("Don't import uri ".$first_id." because user ".$uid." doesn't follow the person ".$actor, LOGGER_DEBUG);
+ continue;
+ }
+
+ $arr = array();
+ $arr["network"] = $details["network"];
+ $arr["uri"] = $single_conv->id;
$arr["plink"] = $plink;
-
- $arr["created"] = $single_conv->object->published;
- $arr["edited"] = $single_conv->object->published;
-
- $arr["author-name"] = $single_conv->object->actor->displayName;
+ $arr["uid"] = $uid;
+ $arr["contact-id"] = $details["contact_id"];
+ $arr["parent-uri"] = $parent_uri;
+ $arr["created"] = $single_conv->published;
+ $arr["edited"] = $single_conv->published;
+ $arr["owner-name"] = $single_conv->actor->displayName;
if ($arr["owner-name"] == '')
- $arr["author-name"] = $single_conv->object->actor->contact->displayName;
+ $arr["owner-name"] = $single_conv->actor->contact->displayName;
+ if ($arr["owner-name"] == '')
+ $arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
- $arr["author-link"] = $single_conv->object->actor->url;
- $arr["author-avatar"] = $single_conv->object->actor->image->url;
+ $arr["owner-link"] = $actor;
+ $arr["owner-avatar"] = $single_conv->actor->image->url;
+ $arr["author-name"] = $arr["owner-name"];
+ $arr["author-link"] = $actor;
+ $arr["author-avatar"] = $single_conv->actor->image->url;
+ $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content));
- $arr["app"] = $single_conv->object->provider->displayName."#";
- //$arr["verb"] = $single_conv->object->verb;
+ if (isset($single_conv->status_net->notice_info->source))
+ $arr["app"] = strip_tags($single_conv->status_net->notice_info->source);
+ elseif (isset($single_conv->statusnet->notice_info->source))
+ $arr["app"] = strip_tags($single_conv->statusnet->notice_info->source);
+ elseif (isset($single_conv->statusnet_notice_info->source))
+ $arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
+ elseif (isset($single_conv->provider->displayName))
+ $arr["app"] = $single_conv->provider->displayName;
+ else
+ $arr["app"] = "OStatus";
- $arr["location"] = $single_conv->object->location->displayName;
- $arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
+
+ $arr["object"] = json_encode($single_conv);
+ $arr["verb"] = $parent["verb"];
+ $arr["visible"] = $parent["visible"];
+ $arr["location"] = $single_conv->location->displayName;
+ $arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
+
+ // Is it a reshared item?
+ if (isset($single_conv->verb) AND ($single_conv->verb == "share") AND isset($single_conv->object)) {
+ if (is_array($single_conv->object))
+ $single_conv->object = $single_conv->object[0];
+
+ logger("Found reshared item ".$single_conv->object->id);
+
+ // $single_conv->object->context->conversation;
+
+ if (isset($single_conv->object->object->id))
+ $arr["uri"] = $single_conv->object->object->id;
+ else
+ $arr["uri"] = $single_conv->object->id;
+
+ if (isset($single_conv->object->object->url))
+ $plink = self::convert_href($single_conv->object->object->url);
+ else
+ $plink = self::convert_href($single_conv->object->url);
+
+ if (isset($single_conv->object->object->content))
+ $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content));
+ else
+ $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
+
+ $arr["plink"] = $plink;
+
+ $arr["created"] = $single_conv->object->published;
+ $arr["edited"] = $single_conv->object->published;
+
+ $arr["author-name"] = $single_conv->object->actor->displayName;
+ if ($arr["owner-name"] == '')
+ $arr["author-name"] = $single_conv->object->actor->contact->displayName;
+
+ $arr["author-link"] = $single_conv->object->actor->url;
+ $arr["author-avatar"] = $single_conv->object->actor->image->url;
+
+ $arr["app"] = $single_conv->object->provider->displayName."#";
+ //$arr["verb"] = $single_conv->object->verb;
+
+ $arr["location"] = $single_conv->object->location->displayName;
+ $arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
+ }
+
+ if ($arr["location"] == "")
+ unset($arr["location"]);
+
+ if ($arr["coord"] == "")
+ unset($arr["coord"]);
+
+ // Copy fields from given item array
+ if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] == $single_conv->id))) {
+ $copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
+ "gravity", "body", "object-type", "object", "verb", "created", "edited", "coord", "tag",
+ "title", "attach", "app", "type", "location", "contact-id", "uri");
+ foreach ($copy_fields AS $field)
+ if (isset($item[$field]))
+ $arr[$field] = $item[$field];
+
+ }
+
+ $newitem = item_store($arr);
+ if (!$newitem) {
+ logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
+ continue;
+ }
+
+ if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
+ $item = array();
+ $item_stored = $newitem;
+ }
+
+ logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
+
+ // Add the conversation entry (but don't fetch the whole conversation)
+ self::store_conversation($newitem, $conversation_url);
+
+ // If the newly created item is the top item then change the parent settings of the thread
+ // This shouldn't happen anymore. This is supposed to be absolote.
+ if ($arr["uri"] == $first_id) {
+ logger('setting new parent to id '.$newitem);
+ $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
+ intval($uid), intval($newitem));
+ if ($new_parents)
+ $parent = $new_parents[0];
+ }
}
- if ($arr["location"] == "")
- unset($arr["location"]);
+ if (($item_stored < 0) AND (count($item) > 0)) {
- if ($arr["coord"] == "")
- unset($arr["coord"]);
+ if (get_config('system','ostatus_full_threads')) {
+ $details = self::get_actor_details($item["owner-link"], $uid, $item["contact-id"]);
+ if ($details["not_following"]) {
+ logger("Don't import uri ".$item["uri"]." because user ".$uid." doesn't follow the person ".$item["owner-link"], LOGGER_DEBUG);
+ return false;
+ }
+ }
- // Copy fields from given item array
- if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] == $single_conv->id))) {
- $copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
- "gravity", "body", "object-type", "object", "verb", "created", "edited", "coord", "tag",
- "title", "attach", "app", "type", "location", "contact-id", "uri");
- foreach ($copy_fields AS $field)
- if (isset($item[$field]))
- $arr[$field] = $item[$field];
-
- //$arr["app"] .= " (OStatus)";
+ $item_stored = item_store($item, true);
+ if ($item_stored) {
+ logger("Uri ".$item["uri"]." wasn't found in conversation ".$conversation_url, LOGGER_DEBUG);
+ self::store_conversation($item_stored, $conversation_url);
+ }
}
- $newitem = item_store($arr);
- if (!$newitem) {
- logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
- continue;
- }
+ return($item_stored);
+ }
- if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
- $item = array();
- $item_stored = $newitem;
- }
+ /**
+ * @brief Stores conversation data into the database
+ *
+ * @param integer $itemid The id of the item
+ * @param string $conversation_url The uri of the conversation
+ */
+ private function store_conversation($itemid, $conversation_url) {
- logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
+ $conversation_url = self::convert_href($conversation_url);
- // Add the conversation entry (but don't fetch the whole conversation)
- ostatus_store_conversation($newitem, $conversation_url);
+ $messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
+ if (!$messages)
+ return;
+ $message = $messages[0];
- // If the newly created item is the top item then change the parent settings of the thread
- // This shouldn't happen anymore. This is supposed to be absolote.
- if ($arr["uri"] == $first_id) {
- logger('setting new parent to id '.$newitem);
- $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
- intval($uid), intval($newitem));
- if ($new_parents)
- $parent = $new_parents[0];
+ // Store conversation url if not done before
+ $conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
+ intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
+
+ if (!$conversation) {
+ $r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
+ intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
+ dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
+ logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
}
}
- if (($item_stored < 0) AND (count($item) > 0)) {
- //$arr["app"] .= " (OStatus-NoConvFound)";
- $item_stored = item_store($item, true);
- if ($item_stored) {
- logger("Uri ".$item["uri"]." wasn't found in conversation ".$conversation_url, LOGGER_DEBUG);
- ostatus_store_conversation($item_stored, $conversation_url);
+ /**
+ * @brief Checks if the current post is a reshare
+ *
+ * @param array $item The item array of thw post
+ *
+ * @return string The guid if the post is a reshare
+ */
+ private function get_reshared_guid($item) {
+ $body = trim($item["body"]);
+
+ // Skip if it isn't a pure repeated messages
+ // Does it start with a share?
+ if (strpos($body, "[share") > 0)
+ return("");
+
+ // Does it end with a share?
+ if (strlen($body) > (strrpos($body, "[/share]") + 8))
+ return("");
+
+ $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
+ // Skip if there is no shared message in there
+ if ($body == $attributes)
+ return(false);
+
+ $guid = "";
+ preg_match("/guid='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $guid = $matches[1];
+
+ preg_match('/guid="(.*?)"/ism', $attributes, $matches);
+ if ($matches[1] != "")
+ $guid = $matches[1];
+
+ return $guid;
+ }
+
+ /**
+ * @brief Cleans the body of a post if it contains picture links
+ *
+ * @param string $body The body
+ *
+ * @return string The cleaned body
+ */
+ private function format_picture_post($body) {
+ $siteinfo = get_attached_data($body);
+
+ if (($siteinfo["type"] == "photo")) {
+ if (isset($siteinfo["preview"]))
+ $preview = $siteinfo["preview"];
+ else
+ $preview = $siteinfo["image"];
+
+ // Is it a remote picture? Then make a smaller preview here
+ $preview = proxy_url($preview, false, PROXY_SIZE_SMALL);
+
+ // Is it a local picture? Then make it smaller here
+ $preview = str_replace(array("-0.jpg", "-0.png"), array("-2.jpg", "-2.png"), $preview);
+ $preview = str_replace(array("-1.jpg", "-1.png"), array("-2.jpg", "-2.png"), $preview);
+
+ if (isset($siteinfo["url"]))
+ $url = $siteinfo["url"];
+ else
+ $url = $siteinfo["image"];
+
+ $body = trim($siteinfo["text"])." [url]".$url."[/url]\n[img]".$preview."[/img]";
}
+
+ return $body;
}
- return($item_stored);
-}
+ /**
+ * @brief Adds the header elements to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $owner Contact data of the poster
+ *
+ * @return object header root element
+ */
+ private function add_header($doc, $owner) {
-function ostatus_store_conversation($itemid, $conversation_url) {
- global $a;
+ $a = get_app();
- $conversation_url = ostatus_convert_href($conversation_url);
+ $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed');
+ $doc->appendChild($root);
- $messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
- if (!$messages)
- return;
- $message = $messages[0];
+ $root->setAttribute("xmlns:thr", NAMESPACE_THREAD);
+ $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
+ $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
+ $root->setAttribute("xmlns:media", NAMESPACE_MEDIA);
+ $root->setAttribute("xmlns:poco", NAMESPACE_POCO);
+ $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
+ $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
- // Store conversation url if not done before
- $conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
- intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
+ $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION);
+ xml::add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes);
+ xml::add_element($doc, $root, "id", App::get_baseurl()."/profile/".$owner["nick"]);
+ xml::add_element($doc, $root, "title", sprintf("%s timeline", $owner["name"]));
+ xml::add_element($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], $a->config["sitename"]));
+ xml::add_element($doc, $root, "logo", $owner["photo"]);
+ xml::add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
- if (!$conversation) {
- $r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
- intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
- dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
- logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
- }
-}
+ $author = self::add_author($doc, $owner);
+ $root->appendChild($author);
-function get_reshared_guid($item) {
- $body = trim($item["body"]);
+ $attributes = array("href" => $owner["url"], "rel" => "alternate", "type" => "text/html");
+ xml::add_element($doc, $root, "link", "", $attributes);
- // Skip if it isn't a pure repeated messages
- // Does it start with a share?
- if (strpos($body, "[share") > 0)
- return("");
+ /// @TODO We have to find out what this is
+ /// $attributes = array("href" => App::get_baseurl()."/sup",
+ /// "rel" => "http://api.friendfeed.com/2008/03#sup",
+ /// "type" => "application/json");
+ /// xml::add_element($doc, $root, "link", "", $attributes);
- // Does it end with a share?
- if (strlen($body) > (strrpos($body, "[/share]") + 8))
- return("");
+ self::hublinks($doc, $root);
- $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
- // Skip if there is no shared message in there
- if ($body == $attributes)
- return(false);
+ $attributes = array("href" => App::get_baseurl()."/salmon/".$owner["nick"], "rel" => "salmon");
+ xml::add_element($doc, $root, "link", "", $attributes);
- $guid = "";
- preg_match("/guid='(.*?)'/ism", $attributes, $matches);
- if ($matches[1] != "")
- $guid = $matches[1];
+ $attributes = array("href" => App::get_baseurl()."/salmon/".$owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-replies");
+ xml::add_element($doc, $root, "link", "", $attributes);
- preg_match('/guid="(.*?)"/ism', $attributes, $matches);
- if ($matches[1] != "")
- $guid = $matches[1];
+ $attributes = array("href" => App::get_baseurl()."/salmon/".$owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-mention");
+ xml::add_element($doc, $root, "link", "", $attributes);
- return $guid;
-}
+ $attributes = array("href" => App::get_baseurl()."/api/statuses/user_timeline/".$owner["nick"].".atom",
+ "rel" => "self", "type" => "application/atom+xml");
+ xml::add_element($doc, $root, "link", "", $attributes);
-function xml_create_element($doc, $element, $value = "", $attributes = array()) {
- $element = $doc->createElement($element, xmlify($value));
-
- foreach ($attributes AS $key => $value) {
- $attribute = $doc->createAttribute($key);
- $attribute->value = xmlify($value);
- $element->appendChild($attribute);
- }
- return $element;
-}
-
-function xml_add_element($doc, $parent, $element, $value = "", $attributes = array()) {
- $element = xml_create_element($doc, $element, $value, $attributes);
- $parent->appendChild($element);
-}
-
-function ostatus_format_picture_post($body) {
- $siteinfo = get_attached_data($body);
-
- if (($siteinfo["type"] == "photo")) {
- if (isset($siteinfo["preview"]))
- $preview = $siteinfo["preview"];
- else
- $preview = $siteinfo["image"];
-
- // Is it a remote picture? Then make a smaller preview here
- $preview = proxy_url($preview, false, PROXY_SIZE_SMALL);
-
- // Is it a local picture? Then make it smaller here
- $preview = str_replace(array("-0.jpg", "-0.png"), array("-2.jpg", "-2.png"), $preview);
- $preview = str_replace(array("-1.jpg", "-1.png"), array("-2.jpg", "-2.png"), $preview);
-
- if (isset($siteinfo["url"]))
- $url = $siteinfo["url"];
- else
- $url = $siteinfo["image"];
-
- $body = trim($siteinfo["text"])." [url]".$url."[/url]\n[img]".$preview."[/img]";
+ return $root;
}
- return $body;
-}
+ /**
+ * @brief Add the link to the push hubs to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $root XML root element where the hub links are added
+ */
+ public static function hublinks($doc, $root) {
+ $hub = get_config('system','huburl');
-function ostatus_add_header($doc, $owner) {
- $a = get_app();
-
- $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed');
- $doc->appendChild($root);
-
- $root->setAttribute("xmlns:thr", NAMESPACE_THREAD);
- $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
- $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
- $root->setAttribute("xmlns:media", NAMESPACE_MEDIA);
- $root->setAttribute("xmlns:poco", NAMESPACE_POCO);
- $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
- $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
-
- $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION);
- xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes);
- xml_add_element($doc, $root, "id", $a->get_baseurl()."/profile/".$owner["nick"]);
- xml_add_element($doc, $root, "title", sprintf("%s timeline", $owner["name"]));
- xml_add_element($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], $a->config["sitename"]));
- xml_add_element($doc, $root, "logo", $owner["photo"]);
- xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
-
- $author = ostatus_add_author($doc, $owner);
- $root->appendChild($author);
-
- $attributes = array("href" => $owner["url"], "rel" => "alternate", "type" => "text/html");
- xml_add_element($doc, $root, "link", "", $attributes);
-
- /// @TODO We have to find out what this is
- /// $attributes = array("href" => $a->get_baseurl()."/sup",
- /// "rel" => "http://api.friendfeed.com/2008/03#sup",
- /// "type" => "application/json");
- /// xml_add_element($doc, $root, "link", "", $attributes);
-
- ostatus_hublinks($doc, $root);
-
- $attributes = array("href" => $a->get_baseurl()."/salmon/".$owner["nick"], "rel" => "salmon");
- xml_add_element($doc, $root, "link", "", $attributes);
-
- $attributes = array("href" => $a->get_baseurl()."/salmon/".$owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-replies");
- xml_add_element($doc, $root, "link", "", $attributes);
-
- $attributes = array("href" => $a->get_baseurl()."/salmon/".$owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-mention");
- xml_add_element($doc, $root, "link", "", $attributes);
-
- $attributes = array("href" => $a->get_baseurl()."/api/statuses/user_timeline/".$owner["nick"].".atom",
- "rel" => "self", "type" => "application/atom+xml");
- xml_add_element($doc, $root, "link", "", $attributes);
-
- return $root;
-}
-
-function ostatus_hublinks($doc, $root) {
- $a = get_app();
- $hub = get_config('system','huburl');
-
- $hubxml = '';
- if(strlen($hub)) {
- $hubs = explode(',', $hub);
- if(count($hubs)) {
- foreach($hubs as $h) {
- $h = trim($h);
- if(! strlen($h))
- continue;
- if ($h === '[internal]')
- $h = $a->get_baseurl() . '/pubsubhubbub';
- xml_add_element($doc, $root, "link", "", array("href" => $h, "rel" => "hub"));
+ $hubxml = '';
+ if(strlen($hub)) {
+ $hubs = explode(',', $hub);
+ if(count($hubs)) {
+ foreach($hubs as $h) {
+ $h = trim($h);
+ if(! strlen($h))
+ continue;
+ if ($h === '[internal]')
+ $h = App::get_baseurl() . '/pubsubhubbub';
+ xml::add_element($doc, $root, "link", "", array("href" => $h, "rel" => "hub"));
+ }
}
}
}
-}
-function ostatus_get_attachment($doc, $root, $item) {
- $o = "";
- $siteinfo = get_attached_data($item["body"]);
+ /**
+ * @brief Adds attachement data to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $root XML root element where the hub links are added
+ * @param array $item Data of the item that is to be posted
+ */
+ private function get_attachment($doc, $root, $item) {
+ $o = "";
+ $siteinfo = get_attached_data($item["body"]);
- switch($siteinfo["type"]) {
- case 'link':
- $attributes = array("rel" => "enclosure",
- "href" => $siteinfo["url"],
- "type" => "text/html; charset=UTF-8",
- "length" => "",
- "title" => $siteinfo["title"]);
- xml_add_element($doc, $root, "link", "", $attributes);
- break;
- case 'photo':
- $imgdata = get_photo_info($siteinfo["image"]);
- $attributes = array("rel" => "enclosure",
- "href" => $siteinfo["image"],
- "type" => $imgdata["mime"],
- "length" => intval($imgdata["size"]));
- xml_add_element($doc, $root, "link", "", $attributes);
- break;
- case 'video':
- $attributes = array("rel" => "enclosure",
- "href" => $siteinfo["url"],
- "type" => "text/html; charset=UTF-8",
- "length" => "",
- "title" => $siteinfo["title"]);
- xml_add_element($doc, $root, "link", "", $attributes);
- break;
- default:
- break;
- }
-
- if (($siteinfo["type"] != "photo") AND isset($siteinfo["image"])) {
- $photodata = get_photo_info($siteinfo["image"]);
-
- $attributes = array("rel" => "preview", "href" => $siteinfo["image"], "media:width" => $photodata[0], "media:height" => $photodata[1]);
- xml_add_element($doc, $root, "link", "", $attributes);
- }
-
-
- $arr = explode('[/attach],',$item['attach']);
- if(count($arr)) {
- foreach($arr as $r) {
- $matches = false;
- $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches);
- if($cnt) {
+ switch($siteinfo["type"]) {
+ case 'link':
$attributes = array("rel" => "enclosure",
- "href" => $matches[1],
- "type" => $matches[3]);
+ "href" => $siteinfo["url"],
+ "type" => "text/html; charset=UTF-8",
+ "length" => "",
+ "title" => $siteinfo["title"]);
+ xml::add_element($doc, $root, "link", "", $attributes);
+ break;
+ case 'photo':
+ $imgdata = get_photo_info($siteinfo["image"]);
+ $attributes = array("rel" => "enclosure",
+ "href" => $siteinfo["image"],
+ "type" => $imgdata["mime"],
+ "length" => intval($imgdata["size"]));
+ xml::add_element($doc, $root, "link", "", $attributes);
+ break;
+ case 'video':
+ $attributes = array("rel" => "enclosure",
+ "href" => $siteinfo["url"],
+ "type" => "text/html; charset=UTF-8",
+ "length" => "",
+ "title" => $siteinfo["title"]);
+ xml::add_element($doc, $root, "link", "", $attributes);
+ break;
+ default:
+ break;
+ }
- if(intval($matches[2]))
- $attributes["length"] = intval($matches[2]);
+ if (($siteinfo["type"] != "photo") AND isset($siteinfo["image"])) {
+ $photodata = get_photo_info($siteinfo["image"]);
- if(trim($matches[4]) != "")
- $attributes["title"] = trim($matches[4]);
+ $attributes = array("rel" => "preview", "href" => $siteinfo["image"], "media:width" => $photodata[0], "media:height" => $photodata[1]);
+ xml::add_element($doc, $root, "link", "", $attributes);
+ }
- xml_add_element($doc, $root, "link", "", $attributes);
+
+ $arr = explode('[/attach],',$item['attach']);
+ if(count($arr)) {
+ foreach($arr as $r) {
+ $matches = false;
+ $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches);
+ if($cnt) {
+ $attributes = array("rel" => "enclosure",
+ "href" => $matches[1],
+ "type" => $matches[3]);
+
+ if(intval($matches[2]))
+ $attributes["length"] = intval($matches[2]);
+
+ if(trim($matches[4]) != "")
+ $attributes["title"] = trim($matches[4]);
+
+ xml::add_element($doc, $root, "link", "", $attributes);
+ }
}
}
}
-}
-function ostatus_add_author($doc, $owner) {
- $a = get_app();
+ /**
+ * @brief Adds the author element to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $owner Contact data of the poster
+ *
+ * @return object author element
+ */
+ private function add_author($doc, $owner) {
- $r = q("SELECT `homepage` FROM `profile` WHERE `uid` = %d AND `is-default` LIMIT 1", intval($owner["uid"]));
- if ($r)
- $profile = $r[0];
+ $r = q("SELECT `homepage` FROM `profile` WHERE `uid` = %d AND `is-default` LIMIT 1", intval($owner["uid"]));
+ if ($r)
+ $profile = $r[0];
- $author = $doc->createElement("author");
- xml_add_element($doc, $author, "activity:object-type", ACTIVITY_OBJ_PERSON);
- xml_add_element($doc, $author, "uri", $owner["url"]);
- xml_add_element($doc, $author, "name", $owner["name"]);
+ $author = $doc->createElement("author");
+ xml::add_element($doc, $author, "activity:object-type", ACTIVITY_OBJ_PERSON);
+ xml::add_element($doc, $author, "uri", $owner["url"]);
+ xml::add_element($doc, $author, "name", $owner["name"]);
+ xml::add_element($doc, $author, "summary", bbcode($owner["about"], false, false, 7));
- $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $owner["url"]);
- xml_add_element($doc, $author, "link", "", $attributes);
+ $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $owner["url"]);
+ xml::add_element($doc, $author, "link", "", $attributes);
- $attributes = array(
- "rel" => "avatar",
- "type" => "image/jpeg", // To-Do?
- "media:width" => 175,
- "media:height" => 175,
- "href" => $owner["photo"]);
- xml_add_element($doc, $author, "link", "", $attributes);
-
- if (isset($owner["thumb"])) {
$attributes = array(
"rel" => "avatar",
"type" => "image/jpeg", // To-Do?
- "media:width" => 80,
- "media:height" => 80,
- "href" => $owner["thumb"]);
- xml_add_element($doc, $author, "link", "", $attributes);
+ "media:width" => 175,
+ "media:height" => 175,
+ "href" => $owner["photo"]);
+ xml::add_element($doc, $author, "link", "", $attributes);
+
+ if (isset($owner["thumb"])) {
+ $attributes = array(
+ "rel" => "avatar",
+ "type" => "image/jpeg", // To-Do?
+ "media:width" => 80,
+ "media:height" => 80,
+ "href" => $owner["thumb"]);
+ xml::add_element($doc, $author, "link", "", $attributes);
+ }
+
+ xml::add_element($doc, $author, "poco:preferredUsername", $owner["nick"]);
+ xml::add_element($doc, $author, "poco:displayName", $owner["name"]);
+ xml::add_element($doc, $author, "poco:note", bbcode($owner["about"], false, false, 7));
+
+ if (trim($owner["location"]) != "") {
+ $element = $doc->createElement("poco:address");
+ xml::add_element($doc, $element, "poco:formatted", $owner["location"]);
+ $author->appendChild($element);
+ }
+
+ if (trim($profile["homepage"]) != "") {
+ $urls = $doc->createElement("poco:urls");
+ xml::add_element($doc, $urls, "poco:type", "homepage");
+ xml::add_element($doc, $urls, "poco:value", $profile["homepage"]);
+ xml::add_element($doc, $urls, "poco:primary", "true");
+ $author->appendChild($urls);
+ }
+
+ if (count($profile)) {
+ xml::add_element($doc, $author, "followers", "", array("url" => App::get_baseurl()."/viewcontacts/".$owner["nick"]));
+ xml::add_element($doc, $author, "statusnet:profile_info", "", array("local_id" => $owner["uid"]));
+ }
+
+ return $author;
}
- xml_add_element($doc, $author, "poco:preferredUsername", $owner["nick"]);
- xml_add_element($doc, $author, "poco:displayName", $owner["name"]);
- xml_add_element($doc, $author, "poco:note", $owner["about"]);
+ /**
+ * @TODO Picture attachments should look like this:
+ * https://status.pirati.ca/attachment/572819
+ *
+ */
- if (trim($owner["location"]) != "") {
- $element = $doc->createElement("poco:address");
- xml_add_element($doc, $element, "poco:formatted", $owner["location"]);
- $author->appendChild($element);
+ /**
+ * @brief Returns the given activity if present - otherwise returns the "post" activity
+ *
+ * @param array $item Data of the item that is to be posted
+ *
+ * @return string activity
+ */
+ function construct_verb($item) {
+ if ($item['verb'])
+ return $item['verb'];
+ return ACTIVITY_POST;
}
- if (trim($profile["homepage"]) != "") {
- $urls = $doc->createElement("poco:urls");
- xml_add_element($doc, $urls, "poco:type", "homepage");
- xml_add_element($doc, $urls, "poco:value", $profile["homepage"]);
- xml_add_element($doc, $urls, "poco:primary", "true");
- $author->appendChild($urls);
+ /**
+ * @brief Returns the given object type if present - otherwise returns the "note" object type
+ *
+ * @param array $item Data of the item that is to be posted
+ *
+ * @return string Object type
+ */
+ function construct_objecttype($item) {
+ if (in_array($item['object-type'], array(ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_COMMENT)))
+ return $item['object-type'];
+ return ACTIVITY_OBJ_NOTE;
}
- if (count($profile)) {
- xml_add_element($doc, $author, "followers", "", array("url" => $a->get_baseurl()."/viewcontacts/".$owner["nick"]));
- xml_add_element($doc, $author, "statusnet:profile_info", "", array("local_id" => $owner["uid"]));
+ /**
+ * @brief Adds an entry element to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param bool $toplevel
+ *
+ * @return object Entry element
+ */
+ private function entry($doc, $item, $owner, $toplevel = false) {
+ $repeated_guid = self::get_reshared_guid($item);
+ if ($repeated_guid != "")
+ $xml = self::reshare_entry($doc, $item, $owner, $repeated_guid, $toplevel);
+
+ if ($xml)
+ return $xml;
+
+ if ($item["verb"] == ACTIVITY_LIKE)
+ return self::like_entry($doc, $item, $owner, $toplevel);
+ else
+ return self::note_entry($doc, $item, $owner, $toplevel);
}
- return $author;
-}
+ /**
+ * @brief Adds a source entry to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $contact Array of the contact that is added
+ *
+ * @return object Source element
+ */
+ private function source_entry($doc, $contact) {
+ $source = $doc->createElement("source");
+ xml::add_element($doc, $source, "id", $contact["poll"]);
+ xml::add_element($doc, $source, "title", $contact["name"]);
+ xml::add_element($doc, $source, "link", "", array("rel" => "alternate",
+ "type" => "text/html",
+ "href" => $contact["alias"]));
+ xml::add_element($doc, $source, "link", "", array("rel" => "self",
+ "type" => "application/atom+xml",
+ "href" => $contact["poll"]));
+ xml::add_element($doc, $source, "icon", $contact["photo"]);
+ xml::add_element($doc, $source, "updated", datetime_convert("UTC","UTC",$contact["success_update"]."+00:00",ATOM_TIME));
-/**
- * @TODO Picture attachments should look like this:
- * https://status.pirati.ca/attachment/572819
- *
-*/
-
-function ostatus_entry($doc, $item, $owner, $toplevel = false, $repeat = false) {
- $a = get_app();
-
- if (($item["id"] != $item["parent"]) AND (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) {
- logger("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", LOGGER_DEBUG);
+ return $source;
}
- $is_repeat = false;
+ /**
+ * @brief Fetches contact data from the contact or the gcontact table
+ *
+ * @param string $url URL of the contact
+ * @param array $owner Contact data of the poster
+ *
+ * @return array Contact array
+ */
+ private function contact_entry($url, $owner) {
-/* if (!$repeat) {
- $repeated_guid = get_reshared_guid($item);
+ $r = q("SELECT * FROM `contact` WHERE `nurl` = '%s' AND `uid` IN (0, %d) ORDER BY `uid` DESC LIMIT 1",
+ dbesc(normalise_link($url)), intval($owner["uid"]));
+ if ($r) {
+ $contact = $r[0];
+ $contact["uid"] = -1;
+ }
- if ($repeated_guid != "") {
- $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($owner["uid"]), dbesc($repeated_guid));
+ if (!$r) {
+ $r = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
+ dbesc(normalise_link($url)));
if ($r) {
- $repeated_item = $r[0];
- $is_repeat = true;
+ $contact = $r[0];
+ $contact["uid"] = -1;
+ $contact["success_update"] = $contact["updated"];
}
}
- }
-*/
- if (!$toplevel AND !$repeat) {
- $entry = $doc->createElement("entry");
- $title = sprintf("New note by %s", $owner["nick"]);
- } elseif (!$toplevel AND $repeat) {
- $entry = $doc->createElement("activity:object");
- $title = sprintf("New note by %s", $owner["nick"]);
- } else {
- $entry = $doc->createElementNS(NAMESPACE_ATOM1, "entry");
- $entry->setAttribute("xmlns:thr", NAMESPACE_THREAD);
- $entry->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
- $entry->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
- $entry->setAttribute("xmlns:media", NAMESPACE_MEDIA);
- $entry->setAttribute("xmlns:poco", NAMESPACE_POCO);
- $entry->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
- $entry->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
+ if (!$r)
+ $contact = owner;
- $author = ostatus_add_author($doc, $owner);
- $entry->appendChild($author);
+ if (!isset($contact["poll"])) {
+ $data = probe_url($url);
+ $contact["poll"] = $data["poll"];
- $title = sprintf("New comment by %s", $owner["nick"]);
- }
-
- // To use the object-type "bookmark" we have to implement these elements:
- //
- // http://activitystrea.ms/schema/1.0/bookmark
- // Historic Rocket Landing
- // Nur ein Testbeitrag.
- //
- //
- //
- // But: it seems as if it doesn't federate well between the GS servers
- // So we just set it to "note" to be sure that it reaches their target systems
-
- if (!$repeat)
- xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_NOTE);
- else
- xml_add_element($doc, $entry, "activity:object-type", NAMESPACE_ACTIVITY_SCHEMA.'activity');
-
- xml_add_element($doc, $entry, "id", $item["uri"]);
- xml_add_element($doc, $entry, "title", $title);
-
- if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
- $body = fix_private_photos($item['body'],$owner['uid'],$item, 0);
- else
- $body = $item['body'];
-
- $body = ostatus_format_picture_post($body);
-
- if ($item['title'] != "")
- $body = "[b]".$item['title']."[/b]\n\n".$body;
-
- //$body = bb_remove_share_information($body);
- $body = bbcode($body, false, false, 7);
-
- xml_add_element($doc, $entry, "content", $body, array("type" => "html"));
-
- xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html",
- "href" => $a->get_baseurl()."/display/".$item["guid"]));
-
- xml_add_element($doc, $entry, "status_net", "", array("notice_id" => $item["id"]));
-
- if (!$is_repeat)
- xml_add_element($doc, $entry, "activity:verb", construct_verb($item));
- else
- xml_add_element($doc, $entry, "activity:verb", ACTIVITY_SHARE);
-
- xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME));
- xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME));
-
- if ($is_repeat) {
- $repeated_owner = array();
- $repeated_owner["name"] = $repeated_item["author-name"];
- $repeated_owner["url"] = $repeated_item["author-link"];
- $repeated_owner["photo"] = $repeated_item["author-avatar"];
- $repeated_owner["nick"] = $repeated_owner["name"];
- $repeated_owner["location"] = "";
- $repeated_owner["about"] = "";
- $repeated_owner["uid"] = 0;
-
- // Fetch the missing data from the global contacts
- $r =q("SELECT * FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($repeated_item["author-link"]));
- if ($r) {
- if ($r[0]["nick"] != "")
- $repeated_owner["nick"] = $r[0]["nick"];
-
- $repeated_owner["location"] = $r[0]["location"];
- $repeated_owner["about"] = $r[0]["about"];
+ if (!$contact["alias"])
+ $contact["alias"] = $data["alias"];
}
- $entry_repeat = ostatus_entry($doc, $repeated_item, $repeated_owner, false, true);
- $entry->appendChild($entry_repeat);
- } elseif ($repeat) {
- $author = ostatus_add_author($doc, $owner);
- $entry->appendChild($author);
+ if (!isset($contact["alias"]))
+ $contact["alias"] = $contact["url"];
+
+ return $contact;
}
- $mentioned = array();
+ /**
+ * @brief Adds an entry element with reshared content
+ *
+ * @param object $doc XML document
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param $repeated_guid
+ * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)?
+ *
+ * @return object Entry element
+ */
+ private function reshare_entry($doc, $item, $owner, $repeated_guid, $toplevel) {
+
+ if (($item["id"] != $item["parent"]) AND (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) {
+ logger("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", LOGGER_DEBUG);
+ }
+
+ $title = self::entry_header($doc, $entry, $owner, $toplevel);
+
+ $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' AND NOT `private` AND `network` IN ('%s', '%s', '%s') LIMIT 1",
+ intval($owner["uid"]), dbesc($repeated_guid),
+ dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS));
+ if ($r)
+ $repeated_item = $r[0];
+ else
+ return false;
+
+ $contact = self::contact_entry($repeated_item['author-link'], $owner);
- if (($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) {
- $parent = q("SELECT `guid`, `author-link`, `owner-link` FROM `item` WHERE `id` = %d", intval($item["parent"]));
$parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
- $attributes = array(
- "ref" => $parent_item,
- "type" => "text/html",
- "href" => $a->get_baseurl()."/display/".$parent[0]["guid"]);
- xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes);
+ $title = $owner["nick"]." repeated a notice by ".$contact["nick"];
- $attributes = array(
- "rel" => "related",
- "href" => $a->get_baseurl()."/display/".$parent[0]["guid"]);
- xml_add_element($doc, $entry, "link", "", $attributes);
+ self::entry_content($doc, $entry, $item, $owner, $title, ACTIVITY_SHARE, false);
- $mentioned[$parent[0]["author-link"]] = $parent[0]["author-link"];
- $mentioned[$parent[0]["owner-link"]] = $parent[0]["owner-link"];
+ $as_object = $doc->createElement("activity:object");
- $thrparent = q("SELECT `guid`, `author-link`, `owner-link` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
+ xml::add_element($doc, $as_object, "activity:object-type", NAMESPACE_ACTIVITY_SCHEMA."activity");
+
+ self::entry_content($doc, $as_object, $repeated_item, $owner, "", "", false);
+
+ $author = self::add_author($doc, $contact);
+ $as_object->appendChild($author);
+
+ $as_object2 = $doc->createElement("activity:object");
+
+ xml::add_element($doc, $as_object2, "activity:object-type", self::construct_objecttype($repeated_item));
+
+ $title = sprintf("New comment by %s", $contact["nick"]);
+
+ self::entry_content($doc, $as_object2, $repeated_item, $owner, $title);
+
+ $as_object->appendChild($as_object2);
+
+ self::entry_footer($doc, $as_object, $item, $owner, false);
+
+ $source = self::source_entry($doc, $contact);
+
+ $as_object->appendChild($source);
+
+ $entry->appendChild($as_object);
+
+ self::entry_footer($doc, $entry, $item, $owner);
+
+ return $entry;
+ }
+
+ /**
+ * @brief Adds an entry element with a "like"
+ *
+ * @param object $doc XML document
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)?
+ *
+ * @return object Entry element with "like"
+ */
+ private function like_entry($doc, $item, $owner, $toplevel) {
+
+ if (($item["id"] != $item["parent"]) AND (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) {
+ logger("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", LOGGER_DEBUG);
+ }
+
+ $title = self::entry_header($doc, $entry, $owner, $toplevel);
+
+ $verb = NAMESPACE_ACTIVITY_SCHEMA."favorite";
+ self::entry_content($doc, $entry, $item, $owner, "Favorite", $verb, false);
+
+ $as_object = $doc->createElement("activity:object");
+
+ $parent = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d",
+ dbesc($item["thr-parent"]), intval($item["uid"]));
+ $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
+
+ xml::add_element($doc, $as_object, "activity:object-type", self::construct_objecttype($parent[0]));
+
+ self::entry_content($doc, $as_object, $parent[0], $owner, "New entry");
+
+ $entry->appendChild($as_object);
+
+ self::entry_footer($doc, $entry, $item, $owner);
+
+ return $entry;
+ }
+
+ /**
+ * @brief Adds a regular entry element
+ *
+ * @param object $doc XML document
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)?
+ *
+ * @return object Entry element
+ */
+ private function note_entry($doc, $item, $owner, $toplevel) {
+
+ if (($item["id"] != $item["parent"]) AND (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) {
+ logger("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", LOGGER_DEBUG);
+ }
+
+ $title = self::entry_header($doc, $entry, $owner, $toplevel);
+
+ xml::add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_NOTE);
+
+ self::entry_content($doc, $entry, $item, $owner, $title);
+
+ self::entry_footer($doc, $entry, $item, $owner);
+
+ return $entry;
+ }
+
+ /**
+ * @brief Adds a header element to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $entry The entry element where the elements are added
+ * @param array $owner Contact data of the poster
+ * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)?
+ *
+ * @return string The title for the element
+ */
+ private function entry_header($doc, &$entry, $owner, $toplevel) {
+ /// @todo Check if this title stuff is really needed (I guess not)
+ if (!$toplevel) {
+ $entry = $doc->createElement("entry");
+ $title = sprintf("New note by %s", $owner["nick"]);
+ } else {
+ $entry = $doc->createElementNS(NAMESPACE_ATOM1, "entry");
+
+ $entry->setAttribute("xmlns:thr", NAMESPACE_THREAD);
+ $entry->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
+ $entry->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
+ $entry->setAttribute("xmlns:media", NAMESPACE_MEDIA);
+ $entry->setAttribute("xmlns:poco", NAMESPACE_POCO);
+ $entry->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
+ $entry->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
+
+ $author = self::add_author($doc, $owner);
+ $entry->appendChild($author);
+
+ $title = sprintf("New comment by %s", $owner["nick"]);
+ }
+ return $title;
+ }
+
+ /**
+ * @brief Adds elements to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $entry Entry element where the content is added
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param string $title Title for the post
+ * @param string $verb The activity verb
+ * @param bool $complete Add the "status_net" element?
+ */
+ private function entry_content($doc, $entry, $item, $owner, $title, $verb = "", $complete = true) {
+
+ if ($verb == "")
+ $verb = self::construct_verb($item);
+
+ xml::add_element($doc, $entry, "id", $item["uri"]);
+ xml::add_element($doc, $entry, "title", $title);
+
+ $body = self::format_picture_post($item['body']);
+
+ if ($item['title'] != "")
+ $body = "[b]".$item['title']."[/b]\n\n".$body;
+
+ $body = bbcode($body, false, false, 7);
+
+ xml::add_element($doc, $entry, "content", $body, array("type" => "html"));
+
+ xml::add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html",
+ "href" => App::get_baseurl()."/display/".$item["guid"]));
+
+ if ($complete)
+ xml::add_element($doc, $entry, "status_net", "", array("notice_id" => $item["id"]));
+
+ xml::add_element($doc, $entry, "activity:verb", $verb);
+
+ xml::add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME));
+ xml::add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME));
+ }
+
+ /**
+ * @brief Adds the elements at the foot of an entry to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $entry The entry element where the elements are added
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param $complete
+ */
+ private function entry_footer($doc, $entry, $item, $owner, $complete = true) {
+
+ $mentioned = array();
+
+ if (($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) {
+ $parent = q("SELECT `guid`, `author-link`, `owner-link` FROM `item` WHERE `id` = %d", intval($item["parent"]));
+ $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
+
+ $attributes = array(
+ "ref" => $parent_item,
+ "type" => "text/html",
+ "href" => App::get_baseurl()."/display/".$parent[0]["guid"]);
+ xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes);
+
+ $attributes = array(
+ "rel" => "related",
+ "href" => App::get_baseurl()."/display/".$parent[0]["guid"]);
+ xml::add_element($doc, $entry, "link", "", $attributes);
+
+ $mentioned[$parent[0]["author-link"]] = $parent[0]["author-link"];
+ $mentioned[$parent[0]["owner-link"]] = $parent[0]["owner-link"];
+
+ $thrparent = q("SELECT `guid`, `author-link`, `owner-link` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
+ intval($owner["uid"]),
+ dbesc($parent_item));
+ if ($thrparent) {
+ $mentioned[$thrparent[0]["author-link"]] = $thrparent[0]["author-link"];
+ $mentioned[$thrparent[0]["owner-link"]] = $thrparent[0]["owner-link"];
+ }
+ }
+
+ xml::add_element($doc, $entry, "link", "", array("rel" => "ostatus:conversation",
+ "href" => App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]));
+ xml::add_element($doc, $entry, "ostatus:conversation", App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]);
+
+ $tags = item_getfeedtags($item);
+
+ if(count($tags))
+ foreach($tags as $t)
+ if ($t[0] == "@")
+ $mentioned[$t[1]] = $t[1];
+
+ // Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS)
+ $newmentions = array();
+ foreach ($mentioned AS $mention) {
+ $newmentions[str_replace("http://", "https://", $mention)] = str_replace("http://", "https://", $mention);
+ $newmentions[str_replace("https://", "http://", $mention)] = str_replace("https://", "http://", $mention);
+ }
+ $mentioned = $newmentions;
+
+ foreach ($mentioned AS $mention) {
+ $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'",
intval($owner["uid"]),
- dbesc($parent_item));
- if ($thrparent) {
- $mentioned[$thrparent[0]["author-link"]] = $thrparent[0]["author-link"];
- $mentioned[$thrparent[0]["owner-link"]] = $thrparent[0]["owner-link"];
+ dbesc(normalise_link($mention)));
+ if ($r[0]["forum"] OR $r[0]["prv"])
+ xml::add_element($doc, $entry, "link", "", array("rel" => "mentioned",
+ "ostatus:object-type" => ACTIVITY_OBJ_GROUP,
+ "href" => $mention));
+ else
+ xml::add_element($doc, $entry, "link", "", array("rel" => "mentioned",
+ "ostatus:object-type" => ACTIVITY_OBJ_PERSON,
+ "href" => $mention));
+ }
+
+ if (!$item["private"]) {
+ xml::add_element($doc, $entry, "link", "", array("rel" => "ostatus:attention",
+ "href" => "http://activityschema.org/collection/public"));
+ xml::add_element($doc, $entry, "link", "", array("rel" => "mentioned",
+ "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/collection",
+ "href" => "http://activityschema.org/collection/public"));
+ }
+
+ if(count($tags))
+ foreach($tags as $t)
+ if ($t[0] != "@")
+ xml::add_element($doc, $entry, "category", "", array("term" => $t[2]));
+
+ self::get_attachment($doc, $entry, $item);
+
+ if ($complete) {
+ $app = $item["app"];
+ if ($app == "")
+ $app = "web";
+
+ $attributes = array("local_id" => $item["id"], "source" => $app);
+
+ if (isset($parent["id"]))
+ $attributes["repeat_of"] = $parent["id"];
+
+ if ($item["coord"] != "")
+ xml::add_element($doc, $entry, "georss:point", $item["coord"]);
+
+ xml::add_element($doc, $entry, "statusnet:notice_info", "", $attributes);
}
}
- xml_add_element($doc, $entry, "link", "", array("rel" => "ostatus:conversation",
- "href" => $a->get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]));
- xml_add_element($doc, $entry, "ostatus:conversation", $a->get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]);
+ /**
+ * @brief Creates the XML feed for a given nickname
+ *
+ * @param app $a The application class
+ * @param string $owner_nick Nickname of the feed owner
+ * @param string $last_update Date of the last update
+ *
+ * @return string XML feed
+ */
+ public static function feed(&$a, $owner_nick, $last_update) {
- $tags = item_getfeedtags($item);
+ $r = q("SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`
+ FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
+ WHERE `contact`.`self` AND `user`.`nickname` = '%s' LIMIT 1",
+ dbesc($owner_nick));
+ if (!$r)
+ return;
- if(count($tags))
- foreach($tags as $t)
- if ($t[0] == "@")
- $mentioned[$t[1]] = $t[1];
+ $owner = $r[0];
- // Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS)
- $newmentions = array();
- foreach ($mentioned AS $mention) {
- $newmentions[str_replace("http://", "https://", $mention)] = str_replace("http://", "https://", $mention);
- $newmentions[str_replace("https://", "http://", $mention)] = str_replace("https://", "http://", $mention);
- }
- $mentioned = $newmentions;
+ if(!strlen($last_update))
+ $last_update = 'now -30 days';
- foreach ($mentioned AS $mention) {
- $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'",
- intval($owner["uid"]),
- dbesc(normalise_link($mention)));
- if ($r[0]["forum"] OR $r[0]["prv"])
- xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
- "ostatus:object-type" => ACTIVITY_OBJ_GROUP,
- "href" => $mention));
- else
- xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
- "ostatus:object-type" => ACTIVITY_OBJ_PERSON,
- "href" => $mention));
+ $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
+
+ $items = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id` FROM `item`
+ INNER JOIN `thread` ON `thread`.`iid` = `item`.`parent`
+ LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid`
+ WHERE `item`.`uid` = %d AND `item`.`received` > '%s' AND NOT `item`.`private` AND NOT `item`.`deleted`
+ AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = ''
+ AND ((`item`.`wall` AND (`item`.`parent` = `item`.`id`))
+ OR (`item`.`network` = '%s' AND ((`thread`.`network` IN ('%s', '%s')) OR (`thritem`.`network` IN ('%s', '%s')))) AND `thread`.`mention`)
+ AND ((`item`.`owner-link` IN ('%s', '%s') AND (`item`.`parent` = `item`.`id`))
+ OR (`item`.`author-link` IN ('%s', '%s')))
+ ORDER BY `item`.`received` DESC
+ LIMIT 0, 300",
+ intval($owner["uid"]), dbesc($check_date), dbesc(NETWORK_DFRN),
+ //dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
+ //dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
+ dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN),
+ dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN),
+ dbesc($owner["nurl"]), dbesc(str_replace("http://", "https://", $owner["nurl"])),
+ dbesc($owner["nurl"]), dbesc(str_replace("http://", "https://", $owner["nurl"]))
+ );
+
+ $doc = new DOMDocument('1.0', 'utf-8');
+ $doc->formatOutput = true;
+
+ $root = self::add_header($doc, $owner);
+
+ foreach ($items AS $item) {
+ $entry = self::entry($doc, $item, $owner);
+ $root->appendChild($entry);
+ }
+
+ return(trim($doc->saveXML()));
}
- if (!$item["private"])
- xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned",
- "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/collection",
- "href" => "http://activityschema.org/collection/public"));
+ /**
+ * @brief Creates the XML for a salmon message
+ *
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ *
+ * @return string XML for the salmon
+ */
+ public static function salmon($item,$owner) {
- if(count($tags))
- foreach($tags as $t)
- if ($t[0] != "@")
- xml_add_element($doc, $entry, "category", "", array("term" => $t[2]));
+ $doc = new DOMDocument('1.0', 'utf-8');
+ $doc->formatOutput = true;
- ostatus_get_attachment($doc, $entry, $item);
+ $entry = self::entry($doc, $item, $owner, true);
- /// @TODO
- /// The API call has yet to be implemented
- //$attributes = array("href" => $a->get_baseurl()."/api/statuses/show/".$item["id"].".atom",
- // "rel" => "self", "type" => "application/atom+xml");
- //xml_add_element($doc, $entry, "link", "", $attributes);
+ $doc->appendChild($entry);
- //$attributes = array("href" => $a->get_baseurl()."/api/statuses/show/".$item["id"].".atom",
- // "rel" => "edit", "type" => "application/atom+xml");
- //xml_add_element($doc, $entry, "link", "", $attributes);
-
- $app = $item["app"];
- if ($app == "")
- $app = "web";
-
-
- $attributes = array("local_id" => $item["id"], "source" => $app);
- if ($is_repeat)
- $attributes["repeat_of"] = $repeated_item["id"];
-
- xml_add_element($doc, $entry, "statusnet:notice_info", "", $attributes);
-
- return $entry;
-}
-
-function ostatus_feed(&$a, $owner_nick, $last_update) {
-
- $r = q("SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`
- FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
- WHERE `contact`.`self` AND `user`.`nickname` = '%s' LIMIT 1",
- dbesc($owner_nick));
- if (!$r)
- return;
-
- $owner = $r[0];
-
- if(!strlen($last_update))
- $last_update = 'now -30 days';
-
- $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
-
- $items = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id` FROM `item`
- INNER JOIN `thread` ON `thread`.`iid` = `item`.`parent`
- LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid`
- WHERE `item`.`uid` = %d AND `item`.`received` > '%s' AND NOT `item`.`private` AND NOT `item`.`deleted`
- AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = ''
- AND ((`item`.`wall` AND (`item`.`parent` = `item`.`id`))
- OR (`item`.`network` = '%s' AND ((`thread`.`network` IN ('%s', '%s')) OR (`thritem`.`network` IN ('%s', '%s')))) AND `thread`.`mention`)
- AND ((`item`.`owner-link` IN ('%s', '%s') AND (`item`.`parent` = `item`.`id`))
- OR (`item`.`author-link` IN ('%s', '%s')))
- ORDER BY `item`.`received` DESC
- LIMIT 0, 300",
- intval($owner["uid"]), dbesc($check_date), dbesc(NETWORK_DFRN),
- //dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
- //dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
- dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN),
- dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN),
- dbesc($owner["nurl"]), dbesc(str_replace("http://", "https://", $owner["nurl"])),
- dbesc($owner["nurl"]), dbesc(str_replace("http://", "https://", $owner["nurl"]))
- );
-
- $doc = new DOMDocument('1.0', 'utf-8');
- $doc->formatOutput = true;
-
- $root = ostatus_add_header($doc, $owner);
-
- foreach ($items AS $item) {
- $entry = ostatus_entry($doc, $item, $owner);
- $root->appendChild($entry);
+ return(trim($doc->saveXML()));
}
-
- return(trim($doc->saveXML()));
-}
-
-function ostatus_salmon($item,$owner) {
-
- $doc = new DOMDocument('1.0', 'utf-8');
- $doc->formatOutput = true;
-
- $entry = ostatus_entry($doc, $item, $owner, true);
-
- $doc->appendChild($entry);
-
- return(trim($doc->saveXML()));
}
?>
diff --git a/include/plaintext.php b/include/plaintext.php
index 05431bee2d..a2b2c56522 100644
--- a/include/plaintext.php
+++ b/include/plaintext.php
@@ -132,7 +132,19 @@ function shortenmsg($msg, $limit, $twitter = false) {
return($msg);
}
-function plaintext($a, $b, $limit = 0, $includedlinks = false, $htmlmode = 2) {
+/**
+ * @brief Convert a message into plaintext for connectors to other networks
+ *
+ * @param App $a The application class
+ * @param array $b The message array that is about to be posted
+ * @param int $limit The maximum number of characters when posting to that network
+ * @param bool $includedlinks Has an attached link to be included into the message?
+ * @param int $htmlmode This triggers the behaviour of the bbcode conversion
+ * @param string $target_network Name of the network where the post should go to.
+ *
+ * @return string The converted message
+ */
+function plaintext($a, $b, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = "") {
require_once("include/bbcode.php");
require_once("include/html2plain.php");
require_once("include/network.php");
@@ -144,6 +156,9 @@ function plaintext($a, $b, $limit = 0, $includedlinks = false, $htmlmode = 2) {
// Add an URL element if the text contains a raw link
$body = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2[/url]', $body);
+ // Remove the abstract
+ $body = remove_abstract($body);
+
// At first look at data that is attached via "type-..." stuff
// This will hopefully replaced with a dedicated bbcode later
//$post = get_attached_data($b["body"]);
@@ -154,6 +169,44 @@ function plaintext($a, $b, $limit = 0, $includedlinks = false, $htmlmode = 2) {
elseif ($b["title"] != "")
$post["text"] = trim($b["title"]);
+ $abstract = "";
+
+ // Fetch the abstract from the given target network
+ if ($target_network != "") {
+ $default_abstract = fetch_abstract($b["body"]);
+ $abstract = fetch_abstract($b["body"], $target_network);
+
+ // If we post to a network with no limit we only fetch
+ // an abstract exactly for this network
+ if (($limit == 0) AND ($abstract == $default_abstract))
+ $abstract = "";
+
+ } else // Try to guess the correct target network
+ switch ($htmlmode) {
+ case 8:
+ $abstract = fetch_abstract($b["body"], NETWORK_TWITTER);
+ break;
+ case 7:
+ $abstract = fetch_abstract($b["body"], NETWORK_STATUSNET);
+ break;
+ case 6:
+ $abstract = fetch_abstract($b["body"], NETWORK_APPNET);
+ break;
+ default: // We don't know the exact target.
+ // We fetch an abstract since there is a posting limit.
+ if ($limit > 0)
+ $abstract = fetch_abstract($b["body"]);
+ }
+
+ if ($abstract != "") {
+ $post["text"] = $abstract;
+
+ if ($post["type"] == "text") {
+ $post["type"] = "link";
+ $post["url"] = $b["plink"];
+ }
+ }
+
$html = bbcode($post["text"], false, false, $htmlmode);
$msg = html2plain($html, 0, true);
$msg = trim(html_entity_decode($msg,ENT_QUOTES,'UTF-8'));
diff --git a/include/poller.php b/include/poller.php
index 90e94ede9e..7ffd47aa68 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -29,17 +29,8 @@ function poller_run(&$argv, &$argc){
if (poller_max_connections_reached())
return;
- $load = current_load();
- if($load) {
- $maxsysload = intval(get_config('system','maxloadavg'));
- if($maxsysload < 1)
- $maxsysload = 50;
-
- if(intval($load) > $maxsysload) {
- logger('system: load ' . $load . ' too high. poller deferred to next scheduled run.');
- return;
- }
- }
+ if (App::maxload_reached())
+ return;
// Checking the number of workers
if (poller_too_much_workers(1)) {
@@ -205,6 +196,12 @@ function poller_max_connections_reached() {
*/
function poller_kill_stale_workers() {
$r = q("SELECT `pid`, `executed` FROM `workerqueue` WHERE `executed` != '0000-00-00 00:00:00'");
+
+ if (!is_array($r) || count($r) == 0) {
+ // No processing here needed
+ return;
+ }
+
foreach($r AS $pid)
if (!posix_kill($pid["pid"], 0))
q("UPDATE `workerqueue` SET `executed` = '0000-00-00 00:00:00', `pid` = 0 WHERE `pid` = %d",
diff --git a/include/post_update.php b/include/post_update.php
new file mode 100644
index 0000000000..2bdfe1f6fd
--- /dev/null
+++ b/include/post_update.php
@@ -0,0 +1,141 @@
+= 1192)
+ return true;
+
+ // Check if the first step is done (Setting "gcontact-id" in the item table)
+ $r = q("SELECT `author-link`, `author-name`, `author-avatar`, `uid`, `network` FROM `item` WHERE `gcontact-id` = 0 LIMIT 1000");
+ if (!$r) {
+ // Are there unfinished entries in the thread table?
+ $r = q("SELECT COUNT(*) AS `total` FROM `thread`
+ INNER JOIN `item` ON `item`.`id` =`thread`.`iid`
+ WHERE `thread`.`gcontact-id` = 0 AND
+ (`thread`.`uid` IN (SELECT `uid` from `user`) OR `thread`.`uid` = 0)");
+
+ if ($r AND ($r[0]["total"] == 0)) {
+ set_config("system", "post_update_version", 1192);
+ return true;
+ }
+
+ // Update the thread table from the item table
+ q("UPDATE `thread` INNER JOIN `item` ON `item`.`id`=`thread`.`iid`
+ SET `thread`.`gcontact-id` = `item`.`gcontact-id`
+ WHERE `thread`.`gcontact-id` = 0 AND
+ (`thread`.`uid` IN (SELECT `uid` from `user`) OR `thread`.`uid` = 0)");
+
+ return false;
+ }
+
+ $item_arr = array();
+ foreach ($r AS $item) {
+ $index = $item["author-link"]."-".$item["uid"];
+ $item_arr[$index] = array("author-link" => $item["author-link"],
+ "uid" => $item["uid"],
+ "network" => $item["network"]);
+ }
+
+ // Set the "gcontact-id" in the item table and add a new gcontact entry if needed
+ foreach($item_arr AS $item) {
+ $gcontact_id = get_gcontact_id(array("url" => $item['author-link'], "network" => $item['network'],
+ "photo" => $item['author-avatar'], "name" => $item['author-name']));
+ q("UPDATE `item` SET `gcontact-id` = %d WHERE `uid` = %d AND `author-link` = '%s' AND `gcontact-id` = 0",
+ intval($gcontact_id), intval($item["uid"]), dbesc($item["author-link"]));
+ }
+ return false;
+}
+
+/**
+ * @brief Updates the "global" field in the item table
+ *
+ * @return bool "true" when the job is done
+ */
+function post_update_1194() {
+
+ // Was the script completed?
+ if (get_config("system", "post_update_version") >= 1194)
+ return true;
+
+ logger("Start", LOGGER_DEBUG);
+
+ $end_id = get_config("system", "post_update_1194_end");
+ if (!$end_id) {
+ $r = q("SELECT `id` FROM `item` WHERE `uid` != 0 ORDER BY `id` DESC LIMIT 1");
+ if ($r) {
+ set_config("system", "post_update_1194_end", $r[0]["id"]);
+ $end_id = get_config("system", "post_update_1194_end");
+ }
+ }
+
+ logger("End ID: ".$end_id, LOGGER_DEBUG);
+
+ $start_id = get_config("system", "post_update_1194_start");
+
+ $query1 = "SELECT `item`.`id` FROM `item` ";
+
+ $query2 = "INNER JOIN `item` AS `shadow` ON `item`.`uri` = `shadow`.`uri` AND `shadow`.`uid` = 0 ";
+
+ $query3 = "WHERE `item`.`uid` != 0 AND `item`.`id` >= %d AND `item`.`id` <= %d
+ AND `item`.`visible` AND NOT `item`.`private`
+ AND NOT `item`.`deleted` AND NOT `item`.`moderated`
+ AND `item`.`network` IN ('%s', '%s', '%s', '')
+ AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = ''
+ AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = ''
+ AND NOT `item`.`global`";
+
+ $r = q($query1.$query2.$query3." ORDER BY `item`.`id` LIMIT 1",
+ intval($start_id), intval($end_id),
+ dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS));
+ if (!$r) {
+ set_config("system", "post_update_version", 1194);
+ logger("Update is done", LOGGER_DEBUG);
+ return true;
+ } else {
+ set_config("system", "post_update_1194_start", $r[0]["id"]);
+ $start_id = get_config("system", "post_update_1194_start");
+ }
+
+ logger("Start ID: ".$start_id, LOGGER_DEBUG);
+
+ $r = q($query1.$query2.$query3." ORDER BY `item`.`id` LIMIT 1000,1",
+ intval($start_id), intval($end_id),
+ dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS));
+ if ($r)
+ $pos_id = $r[0]["id"];
+ else
+ $pos_id = $end_id;
+
+ logger("Progress: Start: ".$start_id." position: ".$pos_id." end: ".$end_id, LOGGER_DEBUG);
+
+ $r = q("UPDATE `item` ".$query2." SET `item`.`global` = 1 ".$query3,
+ intval($start_id), intval($pos_id),
+ dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS));
+
+ logger("Done", LOGGER_DEBUG);
+}
+?>
diff --git a/include/profile_update.php b/include/profile_update.php
index 7cc72cc866..399150f21c 100644
--- a/include/profile_update.php
+++ b/include/profile_update.php
@@ -1,96 +1,6 @@
get_baseurl() . '/profile/' . $a->user['nickname'];
-// if($url && strlen(get_config('system','directory')))
-// proc_run('php',"include/directory.php","$url");
-
- $recips = q("SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s'
- AND `uid` = %d AND `rel` != %d ",
- dbesc(NETWORK_DIASPORA),
- intval(local_user()),
- intval(CONTACT_IS_SHARING)
- );
- if(! count($recips))
- return;
-
- $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.* FROM `profile`
- INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
- WHERE `user`.`uid` = %d AND `profile`.`is-default` = 1 LIMIT 1",
- intval(local_user())
- );
-
- if(! count($r))
- return;
- $profile = $r[0];
-
- $handle = xmlify($a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3));
- $first = xmlify(((strpos($profile['name'],' '))
- ? trim(substr($profile['name'],0,strpos($profile['name'],' '))) : $profile['name']));
- $last = xmlify((($first === $profile['name']) ? '' : trim(substr($profile['name'],strlen($first)))));
- $large = xmlify($a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg');
- $medium = xmlify($a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg');
- $small = xmlify($a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg');
- $searchable = xmlify((($profile['publish'] && $profile['net-publish']) ? 'true' : 'false' ));
-// $searchable = 'true';
-
- if($searchable === 'true') {
- $dob = '1000-00-00';
-
- if(($profile['dob']) && ($profile['dob'] != '0000-00-00'))
- $dob = ((intval($profile['dob'])) ? intval($profile['dob']) : '1000') . '-' . datetime_convert('UTC','UTC',$profile['dob'],'m-d');
- $gender = xmlify($profile['gender']);
- $about = xmlify($profile['about']);
- require_once('include/bbcode.php');
- $about = xmlify(strip_tags(bbcode($about)));
- $location = formatted_location($profile);
- $location = xmlify($location);
- $tags = '';
- if($profile['pub_keywords']) {
- $kw = str_replace(',',' ',$profile['pub_keywords']);
- $kw = str_replace(' ',' ',$kw);
- $arr = explode(' ',$profile['pub_keywords']);
- if(count($arr)) {
- for($x = 0; $x < 5; $x ++) {
- if(trim($arr[$x]))
- $tags .= '#' . trim($arr[$x]) . ' ';
- }
- }
- }
- $tags = xmlify(trim($tags));
- }
-
- $tpl = get_markup_template('diaspora_profile.tpl');
-
- $msg = replace_macros($tpl,array(
- '$handle' => $handle,
- '$first' => $first,
- '$last' => $last,
- '$large' => $large,
- '$medium' => $medium,
- '$small' => $small,
- '$dob' => $dob,
- '$gender' => $gender,
- '$about' => $about,
- '$location' => $location,
- '$searchable' => $searchable,
- '$tags' => $tags
- ));
- logger('profile_change: ' . $msg, LOGGER_ALL);
-
- foreach($recips as $recip) {
- $msgtosend = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$a->user,$recip,$a->user['prvkey'],$recip['pubkey'],false)));
- add_to_queue($recip['id'],NETWORK_DIASPORA,$msgtosend,false);
- }
+ diaspora::send_profile(local_user());
}
diff --git a/include/pubsubpublish.php b/include/pubsubpublish.php
index 0ac50aaaa7..625eefc261 100644
--- a/include/pubsubpublish.php
+++ b/include/pubsubpublish.php
@@ -16,7 +16,7 @@ function handle_pubsubhubbub() {
logger("Generate feed for user ".$rr['nickname']." - last updated ".$rr['last_update'], LOGGER_DEBUG);
- $params = ostatus_feed($a, $rr['nickname'], $rr['last_update']);
+ $params = ostatus::feed($a, $rr['nickname'], $rr['last_update']);
$hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
$headers = array("Content-type: application/atom+xml",
@@ -74,25 +74,14 @@ function pubsubpublish_run(&$argv, &$argc){
};
require_once('include/items.php');
- require_once('include/pidfile.php');
load_config('config');
load_config('system');
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'pubsubpublish');
- if($pidfile->is_already_running()) {
- logger("Already running");
- if ($pidfile->running_time() > 9*60) {
- $pidfile->kill();
- logger("killed stale process");
- // Calling a new instance
- proc_run('php',"include/pubsubpublish.php");
- }
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run")
+ if (App::is_already_running("pubsubpublish", "include/pubsubpublish.php", 540))
return;
- }
- }
$a->set_baseurl(get_config('system','url'));
diff --git a/include/queue.php b/include/queue.php
index 1525ca3abf..878c149731 100644
--- a/include/queue.php
+++ b/include/queue.php
@@ -22,26 +22,15 @@ function queue_run(&$argv, &$argc){
require_once("include/datetime.php");
require_once('include/items.php');
require_once('include/bbcode.php');
- require_once('include/pidfile.php');
require_once('include/socgraph.php');
load_config('config');
load_config('system');
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'queue');
- if($pidfile->is_already_running()) {
- logger("queue: Already running");
- if ($pidfile->running_time() > 9*60) {
- $pidfile->kill();
- logger("queue: killed stale process");
- // Calling a new instance
- proc_run('php',"include/queue.php");
- }
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run")
+ if (App::is_already_running('queue', 'include/queue.php', 540))
return;
- }
- }
$a->set_baseurl(get_config('system','url'));
@@ -204,7 +193,7 @@ function queue_run(&$argv, &$argc){
case NETWORK_DIASPORA:
if($contact['notify']) {
logger('queue: diaspora_delivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
- $deliver_status = diaspora_transmit($owner,$contact,$data,$public,true);
+ $deliver_status = diaspora::transmit($owner,$contact,$data,$public,true);
if($deliver_status == (-1)) {
update_queue_time($q_item['id']);
diff --git a/include/session.php b/include/session.php
index 11641d6cea..12551efc42 100644
--- a/include/session.php
+++ b/include/session.php
@@ -69,7 +69,7 @@ function ref_session_destroy ($id) {
if(! function_exists('ref_session_gc')) {
function ref_session_gc($expire) {
q("DELETE FROM `session` WHERE `expire` < %d", dbesc(time()));
- q("OPTIMIZE TABLE `sess_data`");
+ //q("OPTIMIZE TABLE `sess_data`");
return true;
}}
diff --git a/include/socgraph.php b/include/socgraph.php
index bd5b1817f0..33d62dc5b9 100644
--- a/include/socgraph.php
+++ b/include/socgraph.php
@@ -438,44 +438,47 @@ function poco_last_updated($profile, $force = false) {
$noscrape = json_decode($noscraperet["body"], true);
- $contact = array("url" => $profile,
- "network" => $server[0]["network"],
- "generation" => $gcontacts[0]["generation"]);
+ if (is_array($noscrape)) {
+ $contact = array("url" => $profile,
+ "network" => $server[0]["network"],
+ "generation" => $gcontacts[0]["generation"]);
- $contact["name"] = $noscrape["fn"];
- $contact["community"] = $noscrape["comm"];
+ $contact["name"] = $noscrape["fn"];
+ $contact["community"] = $noscrape["comm"];
- if (isset($noscrape["tags"])) {
- $keywords = implode(" ", $noscrape["tags"]);
- if ($keywords != "")
- $contact["keywords"] = $keywords;
+ if (isset($noscrape["tags"])) {
+ $keywords = implode(" ", $noscrape["tags"]);
+ if ($keywords != "")
+ $contact["keywords"] = $keywords;
+ }
+
+ $location = formatted_location($noscrape);
+ if ($location)
+ $contact["location"] = $location;
+
+ $contact["notify"] = $noscrape["dfrn-notify"];
+
+ // Remove all fields that are not present in the gcontact table
+ unset($noscrape["fn"]);
+ unset($noscrape["key"]);
+ unset($noscrape["homepage"]);
+ unset($noscrape["comm"]);
+ unset($noscrape["tags"]);
+ unset($noscrape["locality"]);
+ unset($noscrape["region"]);
+ unset($noscrape["country-name"]);
+ unset($noscrape["contacts"]);
+ unset($noscrape["dfrn-request"]);
+ unset($noscrape["dfrn-confirm"]);
+ unset($noscrape["dfrn-notify"]);
+ unset($noscrape["dfrn-poll"]);
+
+ $contact = array_merge($contact, $noscrape);
+
+ update_gcontact($contact);
+
+ return $noscrape["updated"];
}
-
- $location = formatted_location($noscrape);
- if ($location)
- $contact["location"] = $location;
-
- $contact["notify"] = $noscrape["dfrn-notify"];
-
- // Remove all fields that are not present in the gcontact table
- unset($noscrape["fn"]);
- unset($noscrape["key"]);
- unset($noscrape["homepage"]);
- unset($noscrape["comm"]);
- unset($noscrape["tags"]);
- unset($noscrape["locality"]);
- unset($noscrape["region"]);
- unset($noscrape["country-name"]);
- unset($noscrape["contacts"]);
- unset($noscrape["dfrn-request"]);
- unset($noscrape["dfrn-confirm"]);
- unset($noscrape["dfrn-notify"]);
- unset($noscrape["dfrn-poll"]);
-
- $contact = array_merge($contact, $noscrape);
- update_gcontact($contact);
-
- return $noscrape["updated"];
}
}
}
@@ -719,7 +722,8 @@ function poco_check_server($server_url, $network = "", $force = false) {
// Will also return data for Friendica and GNU Social - but it will be overwritten later
// The "not implemented" is a special treatment for really, really old Friendica versions
$serverret = z_fetch_url($server_url."/api/statusnet/version.json");
- if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND ($serverret["body"] != '') AND (strlen($serverret["body"]) < 250)) {
+ if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND
+ ($serverret["body"] != '') AND (strlen($serverret["body"]) < 30)) {
$platform = "StatusNet";
$version = trim($serverret["body"], '"');
$network = NETWORK_OSTATUS;
@@ -727,7 +731,8 @@ function poco_check_server($server_url, $network = "", $force = false) {
// Test for GNU Social
$serverret = z_fetch_url($server_url."/api/gnusocial/version.json");
- if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND ($serverret["body"] != '') AND (strlen($serverret["body"]) < 250)) {
+ if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND
+ ($serverret["body"] != '') AND (strlen($serverret["body"]) < 30)) {
$platform = "GNU Social";
$version = trim($serverret["body"], '"');
$network = NETWORK_OSTATUS;
@@ -854,6 +859,11 @@ function poco_check_server($server_url, $network = "", $force = false) {
// Check again if the server exists
$servers = q("SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s'", dbesc(normalise_link($server_url)));
+ $version = strip_tags($version);
+ $site_name = strip_tags($site_name);
+ $info = strip_tags($info);
+ $platform = strip_tags($platform);
+
if ($servers)
q("UPDATE `gserver` SET `url` = '%s', `version` = '%s', `site_name` = '%s', `info` = '%s', `register_policy` = %d, `poco` = '%s', `noscrape` = '%s',
`network` = '%s', `platform` = '%s', `last_contact` = '%s', `last_failure` = '%s' WHERE `nurl` = '%s'",
diff --git a/include/text.php b/include/text.php
index c7681a4d58..c868499cc6 100644
--- a/include/text.php
+++ b/include/text.php
@@ -285,7 +285,7 @@ function paginate_data(&$a, $count=null) {
if (($a->page_offset != "") AND !preg_match('/[?&].offset=/', $stripped))
$stripped .= "&offset=".urlencode($a->page_offset);
- $url = z_root() . '/' . $stripped;
+ $url = $stripped;
$data = array();
function _l(&$d, $name, $url, $text, $class="") {
@@ -923,7 +923,7 @@ function micropro($contact, $redirect = false, $class = '', $textmode = false) {
if($redirect) {
$a = get_app();
- $redirect_url = z_root() . '/redir/' . $contact['id'];
+ $redirect_url = 'redir/' . $contact['id'];
if(local_user() && ($contact['uid'] == local_user()) && ($contact['network'] === NETWORK_DFRN)) {
$redir = true;
$url = $redirect_url;
@@ -964,13 +964,13 @@ if(! function_exists('search')) {
* @param string $url search url
* @param boolean $savedsearch show save search button
*/
-function search($s,$id='search-box',$url='/search',$save = false, $aside = true) {
+function search($s,$id='search-box',$url='search',$save = false, $aside = true) {
$a = get_app();
$values = array(
'$s' => $s,
'$id' => $id,
- '$action_url' => $a->get_baseurl((stristr($url,'network')) ? true : false) . $url,
+ '$action_url' => $url,
'$search_label' => t('Search'),
'$save_label' => t('Save'),
'$savedsearch' => feature_enabled(local_user(),'savedsearch'),
@@ -1148,41 +1148,41 @@ function smilies($s, $sample = false) {
);
$icons = array(
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '~friendica ',
- 'redmatrix',
- 'redmatrix'
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '~friendica ',
+ 'redmatrix',
+ 'redmatrix'
);
$params = array('texts' => $texts, 'icons' => $icons, 'string' => $s);
@@ -1305,7 +1305,7 @@ function redir_private_images($a, &$item) {
if((local_user() == $item['uid']) && ($item['private'] != 0) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == NETWORK_DFRN)) {
//logger("redir_private_images: redir");
- $img_url = z_root() . '/redir?f=1&quiet=1&url=' . $mtch[1] . '&conurl=' . $item['author-link'];
+ $img_url = 'redir?f=1&quiet=1&url=' . $mtch[1] . '&conurl=' . $item['author-link'];
$item['body'] = str_replace($mtch[0], "[img]".$img_url."[/img]", $item['body']);
}
}
@@ -1421,7 +1421,7 @@ function prepare_body(&$item,$attach = false, $preview = false) {
$mime = $mtch[3];
if((local_user() == $item['uid']) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == NETWORK_DFRN))
- $the_url = z_root() . '/redir/' . $item['contact-id'] . '?f=1&url=' . $mtch[1];
+ $the_url = 'redir/' . $item['contact-id'] . '?f=1&url=' . $mtch[1];
else
$the_url = $mtch[1];
@@ -1596,7 +1596,7 @@ function get_cats_and_terms($item) {
$categories[] = array(
'name' => xmlify(file_tag_decode($mtch[1])),
'url' => "#",
- 'removeurl' => ((local_user() == $item['uid'])?z_root() . '/filerm/' . $item['id'] . '?f=&cat=' . xmlify(file_tag_decode($mtch[1])):""),
+ 'removeurl' => ((local_user() == $item['uid'])?'filerm/' . $item['id'] . '?f=&cat=' . xmlify(file_tag_decode($mtch[1])):""),
'first' => $first,
'last' => false
);
@@ -1614,7 +1614,7 @@ function get_cats_and_terms($item) {
$folders[] = array(
'name' => xmlify(file_tag_decode($mtch[1])),
'url' => "#",
- 'removeurl' => ((local_user() == $item['uid'])?z_root() . '/filerm/' . $item['id'] . '?f=&term=' . xmlify(file_tag_decode($mtch[1])):""),
+ 'removeurl' => ((local_user() == $item['uid'])?'filerm/' . $item['id'] . '?f=&term=' . xmlify(file_tag_decode($mtch[1])):""),
'first' => $first,
'last' => false
);
@@ -1639,15 +1639,15 @@ function get_plink($item) {
if ($a->user['nickname'] != "") {
$ret = array(
- //'href' => z_root()."/display/".$a->user['nickname']."/".$item['id'],
- 'href' => z_root()."/display/".$item['guid'],
- 'orig' => z_root()."/display/".$item['guid'],
+ //'href' => "display/".$a->user['nickname']."/".$item['id'],
+ 'href' => "display/".$item['guid'],
+ 'orig' => "display/".$item['guid'],
'title' => t('View on separate page'),
'orig_title' => t('view on separate page'),
);
if (x($item,'plink')) {
- $ret["href"] = $item['plink'];
+ $ret["href"] = $a->remove_baseurl($item['plink']);
$ret["title"] = t('link to source');
}
diff --git a/include/update_gcontact.php b/include/update_gcontact.php
index b5ea30a0a4..88e1817f0b 100644
--- a/include/update_gcontact.php
+++ b/include/update_gcontact.php
@@ -16,7 +16,6 @@ function update_gcontact_run(&$argv, &$argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
- require_once('include/pidfile.php');
require_once('include/Scrape.php');
require_once("include/socgraph.php");
@@ -37,18 +36,10 @@ function update_gcontact_run(&$argv, &$argc){
return;
}
- $lockpath = get_lockpath();
- if ($lockpath != '') {
- $pidfile = new pidfile($lockpath, 'update_gcontact'.$contact_id);
- if ($pidfile->is_already_running()) {
- logger("update_gcontact: Already running for contact ".$contact_id);
- if ($pidfile->running_time() > 9*60) {
- $pidfile->kill();
- logger("killed stale process");
- }
- exit;
- }
- }
+ // Don't check this stuff if the function is called by the poller
+ if (App::callstack() != "poller_run")
+ if (App::is_already_running('update_gcontact'.$contact_id, '', 540))
+ return;
$r = q("SELECT * FROM `gcontact` WHERE `id` = %d", intval($contact_id));
diff --git a/include/xml.php b/include/xml.php
new file mode 100644
index 0000000000..76ad88cf48
--- /dev/null
+++ b/include/xml.php
@@ -0,0 +1,131 @@
+ $value) {
+ foreach ($namespaces AS $nskey => $nsvalue)
+ $key .= " xmlns".($nskey == "" ? "":":").$nskey.'="'.$nsvalue.'"';
+
+ $root = new SimpleXMLElement("<".$key."/>");
+ self::from_array($value, $root, $remove_header, $namespaces, false);
+
+ $dom = dom_import_simplexml($root)->ownerDocument;
+ $dom->formatOutput = true;
+ $xml = $dom;
+
+ $xml_text = $dom->saveXML();
+
+ if ($remove_header)
+ $xml_text = trim(substr($xml_text, 21));
+
+ return $xml_text;
+ }
+ }
+
+ foreach($array as $key => $value) {
+ if ($key == "@attributes") {
+ if (!isset($element) OR !is_array($value))
+ continue;
+
+ foreach ($value as $attr_key => $attr_value) {
+ $element_parts = explode(":", $attr_key);
+ if ((count($element_parts) > 1) AND isset($namespaces[$element_parts[0]]))
+ $namespace = $namespaces[$element_parts[0]];
+ else
+ $namespace = NULL;
+
+ $element->addAttribute ($attr_key, $attr_value, $namespace);
+ }
+
+ continue;
+ }
+
+ $element_parts = explode(":", $key);
+ if ((count($element_parts) > 1) AND isset($namespaces[$element_parts[0]]))
+ $namespace = $namespaces[$element_parts[0]];
+ else
+ $namespace = NULL;
+
+ if (!is_array($value))
+ $element = $xml->addChild($key, xmlify($value), $namespace);
+ elseif (is_array($value)) {
+ $element = $xml->addChild($key, NULL, $namespace);
+ self::from_array($value, $element, $remove_header, $namespaces, false);
+ }
+ }
+ }
+
+ /**
+ * @brief Copies an XML object
+ *
+ * @param object $source The XML source
+ * @param object $target The XML target
+ * @param string $elementname Name of the XML element of the target
+ */
+ public static function copy(&$source, &$target, $elementname) {
+ if (count($source->children()) == 0)
+ $target->addChild($elementname, xmlify($source));
+ else {
+ $child = $target->addChild($elementname);
+ foreach ($source->children() AS $childfield => $childentry)
+ self::copy($childentry, $child, $childfield);
+ }
+ }
+
+ /**
+ * @brief Create an XML element
+ *
+ * @param object $doc XML root
+ * @param string $element XML element name
+ * @param string $value XML value
+ * @param array $attributes array containing the attributes
+ *
+ * @return object XML element object
+ */
+ public static function create_element($doc, $element, $value = "", $attributes = array()) {
+ $element = $doc->createElement($element, xmlify($value));
+
+ foreach ($attributes AS $key => $value) {
+ $attribute = $doc->createAttribute($key);
+ $attribute->value = xmlify($value);
+ $element->appendChild($attribute);
+ }
+ return $element;
+ }
+
+ /**
+ * @brief Create an XML and append it to the parent object
+ *
+ * @param object $doc XML root
+ * @param object $parent parent object
+ * @param string $element XML element name
+ * @param string $value XML value
+ * @param array $attributes array containing the attributes
+ */
+ public static function add_element($doc, $parent, $element, $value = "", $attributes = array()) {
+ $element = self::create_element($doc, $element, $value, $attributes);
+ $parent->appendChild($element);
+ }
+}
+?>
diff --git a/index.php b/index.php
index 8471735d01..625c2d82dc 100644
--- a/index.php
+++ b/index.php
@@ -72,7 +72,8 @@ if(!$install) {
(intval(get_config('system','ssl_policy')) == SSL_POLICY_FULL) AND
(substr($a->get_baseurl(), 0, 8) == "https://")) {
header("HTTP/1.1 302 Moved Temporarily");
- header("location: ".$a->get_baseurl()."/".$a->query_string);
+ header("Location: ".$a->get_baseurl()."/".$a->query_string);
+ exit();
}
require_once("include/session.php");
@@ -371,7 +372,7 @@ $a->init_page_end();
if(x($_SESSION,'visitor_home'))
$homebase = $_SESSION['visitor_home'];
elseif(local_user())
- $homebase = $a->get_baseurl() . '/profile/' . $a->user['nickname'];
+ $homebase = 'profile/' . $a->user['nickname'];
if(isset($homebase))
$a->page['content'] .= '';
@@ -423,10 +424,10 @@ if($a->module != 'install' && $a->module != 'maintenance') {
if($a->is_mobile || $a->is_tablet) {
if(isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) {
- $link = $a->get_baseurl() . '/toggle_mobile?address=' . curPageURL();
+ $link = 'toggle_mobile?address=' . curPageURL();
}
else {
- $link = $a->get_baseurl() . '/toggle_mobile?off=1&address=' . curPageURL();
+ $link = 'toggle_mobile?off=1&address=' . curPageURL();
}
$a->page['footer'] = replace_macros(get_markup_template("toggle_mobile_footer.tpl"), array(
'$toggle_link' => $link,
diff --git a/mod/admin.php b/mod/admin.php
index 7f9000807b..2fc9c48a78 100644
--- a/mod/admin.php
+++ b/mod/admin.php
@@ -55,13 +55,13 @@ function admin_post(&$a){
$func($a);
}
}
- goaway($a->get_baseurl(true) . '/admin/plugins/' . $a->argv[2] );
+ goaway('admin/plugins/'.$a->argv[2]);
return; // NOTREACHED
break;
case 'themes':
if($a->argc < 2) {
if(is_ajax()) return;
- goaway($a->get_baseurl(true) . '/admin/' );
+ goaway('admin/');
return;
}
@@ -92,7 +92,7 @@ function admin_post(&$a){
info(t('Theme settings updated.'));
if(is_ajax()) return;
- goaway($a->get_baseurl(true) . '/admin/themes/' . $theme );
+ goaway('admin/themes/'.$theme);
return;
break;
case 'features':
@@ -107,7 +107,7 @@ function admin_post(&$a){
}
}
- goaway($a->get_baseurl(true) . '/admin' );
+ goaway('admin');
return; // NOTREACHED
}
@@ -150,17 +150,17 @@ function admin_content(&$a) {
* Side bar links
*/
$aside_tools = array();
- // array( url, name, extra css classes )
+ // array(url, name, extra css classes)
// not part of $aside to make the template more adjustable
$aside_sub = array(
- 'site' => array($a->get_baseurl(true)."/admin/site/", t("Site") , "site"),
- 'users' => array($a->get_baseurl(true)."/admin/users/", t("Users") , "users"),
- 'plugins'=> array($a->get_baseurl(true)."/admin/plugins/", t("Plugins") , "plugins"),
- 'themes' => array($a->get_baseurl(true)."/admin/themes/", t("Themes") , "themes"),
- 'features' => array($a->get_baseurl(true)."/admin/features/", t("Additional features") , "features"),
- 'dbsync' => array($a->get_baseurl(true)."/admin/dbsync/", t('DB updates'), "dbsync"),
- 'queue' => array($a->get_baseurl(true)."/admin/queue/", t('Inspect Queue'), "queue"),
- 'federation' => array($a->get_baseurl(true)."/admin/federation/", t('Federation Statistics'), "federation"),
+ 'site' => array("admin/site/", t("Site") , "site"),
+ 'users' => array("admin/users/", t("Users") , "users"),
+ 'plugins'=> array("admin/plugins/", t("Plugins") , "plugins"),
+ 'themes' => array("admin/themes/", t("Themes") , "themes"),
+ 'features' => array("admin/features/", t("Additional features") , "features"),
+ 'dbsync' => array("admin/dbsync/", t('DB updates'), "dbsync"),
+ 'queue' => array("admin/queue/", t('Inspect Queue'), "queue"),
+ 'federation' => array("admin/federation/", t('Federation Statistics'), "federation"),
);
/* get plugins admin page */
@@ -169,18 +169,18 @@ function admin_content(&$a) {
$aside_tools['plugins_admin']=array();
foreach ($r as $h){
$plugin =$h['name'];
- $aside_tools['plugins_admin'][] = array($a->get_baseurl(true)."/admin/plugins/".$plugin, $plugin, "plugin");
+ $aside_tools['plugins_admin'][] = array("admin/plugins/".$plugin, $plugin, "plugin");
// temp plugins with admin
$a->plugins_admin[] = $plugin;
}
- $aside_tools['logs'] = array($a->get_baseurl(true)."/admin/logs/", t("Logs"), "logs");
- $aside_tools['viewlogs'] = array($a->get_baseurl(true)."/admin/viewlogs/", t("View Logs"), 'viewlogs');
- $aside_tools['diagnostics_probe'] = array($a->get_baseurl(true).'/probe/', t('probe address'), 'probe');
- $aside_tools['diagnostics_webfinger'] = array($a->get_baseurl(true).'/webfinger/', t('check webfinger'), 'webfinger');
+ $aside_tools['logs'] = array("admin/logs/", t("Logs"), "logs");
+ $aside_tools['viewlogs'] = array("admin/viewlogs/", t("View Logs"), 'viewlogs');
+ $aside_tools['diagnostics_probe'] = array('probe/', t('probe address'), 'probe');
+ $aside_tools['diagnostics_webfinger'] = array('webfinger/', t('check webfinger'), 'webfinger');
$t = get_markup_template("admin_aside.tpl");
- $a->page['aside'] .= replace_macros( $t, array(
+ $a->page['aside'] .= replace_macros($t, array(
'$admin' => $aside_tools,
'$subpages' => $aside_sub,
'$admtxt' => t('Admin'),
@@ -188,7 +188,7 @@ function admin_content(&$a) {
'$logtxt' => t('Logs'),
'$diagnosticstxt' => t('diagnostics'),
'$h_pending' => t('User registrations waiting for confirmation'),
- '$admurl'=> $a->get_baseurl(true)."/admin/"
+ '$admurl'=> "admin/"
));
@@ -231,7 +231,7 @@ function admin_content(&$a) {
$o = admin_page_federation($a);
break;
default:
- notice( t("Item not found.") );
+ notice(t("Item not found."));
}
} else {
$o = admin_page_summary($a);
@@ -270,6 +270,12 @@ function admin_page_federation(&$a) {
// Add more platforms if you like, when one returns 0 known nodes it is not
// displayed on the stats page.
$platforms = array('Friendica', 'Diaspora', '%%red%%', 'Hubzilla', 'GNU Social', 'StatusNet');
+ $colors = array('Friendica' => '#ffc018', // orange from the logo
+ 'Diaspora' => '#a1a1a1', // logo is black and white, makes a gray
+ '%%red%%' => '#c50001', // fire red from the logo
+ 'Hubzilla' => '#43488a', // blue from the logo
+ 'GNU Social'=> '#a22430', // dark red from the logo
+ 'StatusNet' => '#789240'); // the green from the logo (red and blue have already others
$counts = array();
$total = 0;
@@ -277,14 +283,14 @@ function admin_page_federation(&$a) {
// get a total count for the platform, the name and version of the
// highest version and the protocol tpe
$c = q('SELECT count(*) AS total, platform, network, version FROM gserver
- WHERE platform LIKE "%s" AND last_contact > last_failure
+ WHERE platform LIKE "%s" AND last_contact > last_failure AND `version` != ""
ORDER BY version ASC;', $p);
$total = $total + $c[0]['total'];
// what versions for that platform do we know at all?
// again only the active nodes
$v = q('SELECT count(*) AS total, version FROM gserver
- WHERE last_contact > last_failure AND platform LIKE "%s"
+ WHERE last_contact > last_failure AND platform LIKE "%s" AND `version` != ""
GROUP BY version
ORDER BY version;', $p);
@@ -338,9 +344,12 @@ function admin_page_federation(&$a) {
$v = $newVv;
}
+ foreach ($v as $key => $vv)
+ $v[$key]["version"] = trim(strip_tags($vv["version"]));
+
// the 3rd array item is needed for the JavaScript graphs as JS does
// not like some characters in the names of variables...
- $counts[$p]=array($c[0], $v, str_replace(array(' ','%'),'',$p));
+ $counts[$p]=array($c[0], $v, str_replace(array(' ','%'),'',$p), $colors[$p]);
}
// some helpful text
@@ -409,18 +418,18 @@ function admin_page_queue(&$a) {
function admin_page_summary(&$a) {
$r = q("SELECT `page-flags`, COUNT(uid) as `count` FROM `user` GROUP BY `page-flags`");
$accounts = array(
- array( t('Normal Account'), 0),
- array( t('Soapbox Account'), 0),
- array( t('Community/Celebrity Account'), 0),
- array( t('Automatic Friend Account'), 0),
- array( t('Blog Account'), 0),
- array( t('Private Forum'), 0)
+ array(t('Normal Account'), 0),
+ array(t('Soapbox Account'), 0),
+ array(t('Community/Celebrity Account'), 0),
+ array(t('Automatic Friend Account'), 0),
+ array(t('Blog Account'), 0),
+ array(t('Private Forum'), 0)
);
$users=0;
foreach ($r as $u){ $accounts[$u['page-flags']][1] = $u['count']; $users+= $u['count']; }
- logger('accounts: ' . print_r($accounts,true),LOGGER_DATA);
+ logger('accounts: '.print_r($accounts,true),LOGGER_DATA);
$r = q("SELECT COUNT(id) as `count` FROM `register`");
$pending = $r[0]['count'];
@@ -433,7 +442,7 @@ function admin_page_summary(&$a) {
// We can do better, but this is a quick queue status
- $queues = array( 'label' => t('Message queues'), 'deliverq' => $deliverq, 'queue' => $queue );
+ $queues = array('label' => t('Message queues'), 'deliverq' => $deliverq, 'queue' => $queue);
$t = get_markup_template("admin_summary.tpl");
@@ -441,15 +450,15 @@ function admin_page_summary(&$a) {
'$title' => t('Administration'),
'$page' => t('Summary'),
'$queues' => $queues,
- '$users' => array( t('Registered users'), $users),
+ '$users' => array(t('Registered users'), $users),
'$accounts' => $accounts,
- '$pending' => array( t('Pending registrations'), $pending),
- '$version' => array( t('Version'), FRIENDICA_VERSION),
+ '$pending' => array(t('Pending registrations'), $pending),
+ '$version' => array(t('Version'), FRIENDICA_VERSION),
'$baseurl' => $a->get_baseurl(),
'$platform' => FRIENDICA_PLATFORM,
'$codename' => FRIENDICA_CODENAME,
'$build' => get_config('system','build'),
- '$plugins' => array( t('Active plugins'), $a->plugins )
+ '$plugins' => array(t('Active plugins'), $a->plugins)
));
}
@@ -473,7 +482,7 @@ function admin_page_site_post(&$a) {
$parsed = @parse_url($new_url);
if(!$parsed || (!x($parsed,'host') || !x($parsed,'scheme'))) {
notice(t("Can not parse base url. Must have at least ://"));
- goaway($a->get_baseurl(true) . '/admin/site' );
+ goaway('admin/site');
}
/* steps:
@@ -483,6 +492,10 @@ function admin_page_site_post(&$a) {
$old_url = $a->get_baseurl(true);
+ // Generate host names for relocation the addresses in the format user@address.tld
+ $new_host = str_replace("http://", "@", normalise_link($new_url));
+ $old_host = str_replace("http://", "@", normalise_link($old_url));
+
function update_table($table_name, $fields, $old_url, $new_url) {
global $db, $a;
@@ -501,17 +514,22 @@ function admin_page_site_post(&$a) {
$q = sprintf("UPDATE %s SET %s;", $table_name, $upds);
$r = q($q);
if(!$r) {
- notice( "Failed updating '$table_name': " . $db->error );
- goaway($a->get_baseurl(true) . '/admin/site' );
+ notice("Failed updating '$table_name': ".$db->error);
+ goaway('admin/site');
}
}
// update tables
+ // update profile links in the format "http://server.tld"
update_table("profile", array('photo', 'thumb'), $old_url, $new_url);
update_table("term", array('url'), $old_url, $new_url);
- update_table("contact", array('photo','thumb','micro','url','nurl','request','notify','poll','confirm','poco'), $old_url, $new_url);
- update_table("gcontact", array('photo','url','nurl','server_url'), $old_url, $new_url);
- update_table("item", array('owner-link','owner-avatar','author-name','author-link','author-avatar','body','plink','tag'), $old_url, $new_url);
+ update_table("contact", array('photo','thumb','micro','url','nurl','alias','request','notify','poll','confirm','poco', 'avatar'), $old_url, $new_url);
+ update_table("gcontact", array('url','nurl','photo','server_url','notify','alias'), $old_url, $new_url);
+ update_table("item", array('owner-link','owner-avatar','author-link','author-avatar','body','plink','tag'), $old_url, $new_url);
+
+ // update profile addresses in the format "user@server.tld"
+ update_table("contact", array('addr'), $old_host, $new_host);
+ update_table("gcontact", array('connect','addr'), $old_host, $new_host);
// update config
$a->set_baseurl($new_url);
@@ -526,7 +544,7 @@ function admin_page_site_post(&$a) {
info("Relocation started. Could take a while to complete.");
- goaway($a->get_baseurl(true) . '/admin/site' );
+ goaway('admin/site');
}
// end relocate
@@ -589,6 +607,7 @@ function admin_page_site_post(&$a) {
$dfrn_only = ((x($_POST,'dfrn_only')) ? True : False);
$ostatus_disabled = !((x($_POST,'ostatus_disabled')) ? True : False);
$ostatus_poll_interval = ((x($_POST,'ostatus_poll_interval')) ? intval(trim($_POST['ostatus_poll_interval'])) : 0);
+ $ostatus_full_threads = ((x($_POST,'ostatus_full_threads')) ? True : False);
$diaspora_enabled = ((x($_POST,'diaspora_enabled')) ? True : False);
$ssl_policy = ((x($_POST,'ssl_policy')) ? intval($_POST['ssl_policy']) : 0);
$force_ssl = ((x($_POST,'force_ssl')) ? True : False);
@@ -609,6 +628,9 @@ function admin_page_site_post(&$a) {
$only_tag_search = ((x($_POST,'only_tag_search')) ? True : False);
$rino = ((x($_POST,'rino')) ? intval($_POST['rino']) : 0);
$embedly = ((x($_POST,'embedly')) ? notags(trim($_POST['embedly'])) : '');
+ $worker = ((x($_POST,'worker')) ? True : False);
+ $worker_queues = ((x($_POST,'worker_queues')) ? intval($_POST['worker_queues']) : 4);
+ $worker_dont_fork = ((x($_POST,'worker_dont_fork')) ? True : False);
if($a->get_path() != "")
$diaspora_enabled = false;
@@ -695,12 +717,12 @@ function admin_page_site_post(&$a) {
set_config('system','language', $language);
set_config('system','theme', $theme);
- if( $theme_mobile === '---' ) {
+ if($theme_mobile === '---') {
del_config('system','mobile-theme');
} else {
set_config('system','mobile-theme', $theme_mobile);
}
- if( $singleuser === '---' ) {
+ if($singleuser === '---') {
del_config('system','singleuser');
} else {
set_config('system','singleuser', $singleuser);
@@ -737,6 +759,7 @@ function admin_page_site_post(&$a) {
set_config('system','dfrn_only', $dfrn_only);
set_config('system','ostatus_disabled', $ostatus_disabled);
set_config('system','ostatus_poll_interval', $ostatus_poll_interval);
+ set_config('system','ostatus_full_threads', $ostatus_full_threads);
set_config('system','diaspora_enabled', $diaspora_enabled);
set_config('config','private_addons', $private_addons);
@@ -754,7 +777,9 @@ function admin_page_site_post(&$a) {
set_config('system','proxy_disabled', $proxy_disabled);
set_config('system','old_pager', $old_pager);
set_config('system','only_tag_search', $only_tag_search);
-
+ set_config('system','worker', $worker);
+ set_config('system','worker_queues', $worker_queues);
+ set_config('system','worker_dont_fork', $worker_dont_fork);
if($rino==2 and !function_exists('mcrypt_create_iv')) {
notice(t("RINO2 needs mcrypt php extension to work."));
@@ -765,8 +790,8 @@ function admin_page_site_post(&$a) {
set_config('system','embedly', $embedly);
- info( t('Site settings updated.') . EOL);
- goaway($a->get_baseurl(true) . '/admin/site' );
+ info(t('Site settings updated.').EOL);
+ goaway('admin/site');
return; // NOTREACHED
}
@@ -797,12 +822,12 @@ function admin_page_site(&$a) {
$files = glob('view/theme/*');
if($files) {
foreach($files as $file) {
- if(intval(file_exists($file . '/unsupported')))
+ if(intval(file_exists($file.'/unsupported')))
continue;
$f = basename($file);
- $theme_name = ((file_exists($file . '/experimental')) ? sprintf("%s - \x28Experimental\x29", $f) : $f);
- if(file_exists($file . '/mobile')) {
+ $theme_name = ((file_exists($file.'/experimental')) ? sprintf("%s - \x28Experimental\x29", $f) : $f);
+ if(file_exists($file.'/mobile')) {
$theme_choices_mobile[$f] = $theme_name;
} else {
$theme_choices[$f] = $theme_name;
@@ -893,6 +918,7 @@ function admin_page_site(&$a) {
'$advanced' => t('Advanced'),
'$portable_contacts' => t('Auto Discovered Contact Directory'),
'$performance' => t('Performance'),
+ '$worker_title' => t('Worker'),
'$relocate'=> t('Relocate - WARNING: advanced function. Could make this server unreachable.'),
'$baseurl' => $a->get_baseurl(true),
// name, label, value, help string, extra data...
@@ -938,6 +964,7 @@ function admin_page_site(&$a) {
'$max_author_posts_community_page' => array('max_author_posts_community_page', t("Posts per user on community page"), get_config('system','max_author_posts_community_page'), t("The maximum number of posts per user on the community page. (Not valid for 'Global Community')")),
'$ostatus_disabled' => array('ostatus_disabled', t("Enable OStatus support"), !get_config('system','ostatus_disabled'), t("Provide built-in OStatus \x28StatusNet, GNU Social etc.\x29 compatibility. All communications in OStatus are public, so privacy warnings will be occasionally displayed.")),
'$ostatus_poll_interval' => array('ostatus_poll_interval', t("OStatus conversation completion interval"), (string) intval(get_config('system','ostatus_poll_interval')), t("How often shall the poller check for new entries in OStatus conversations? This can be a very ressource task."), $ostatus_poll_choices),
+ '$ostatus_full_threads' => array('ostatus_full_threads', t("Only import OStatus threads from our contacts"), get_config('system','ostatus_full_threads'), t("Normally we import every content from our OStatus contacts. With this option we only store threads that are started by a contact that is known on our system.")),
'$ostatus_not_able' => t("OStatus support can only be enabled if threading is enabled."),
'$diaspora_able' => $diaspora_able,
'$diaspora_not_able' => t("Diaspora support can't be enabled because Friendica was installed into a sub directory."),
@@ -980,6 +1007,10 @@ function admin_page_site(&$a) {
'$rino' => array('rino', t("RINO Encryption"), intval(get_config('system','rino_encrypt')), t("Encryption layer between nodes."), array("Disabled", "RINO1 (deprecated)", "RINO2")),
'$embedly' => array('embedly', t("Embedly API key"), get_config('system','embedly'), t("Embedly is used to fetch additional data for web pages. This is an optional parameter.")),
+ '$worker' => array('worker', t("Enable 'worker' background processing"), get_config('system','worker'), t("The worker background processing limits the number of parallel background jobs to a maximum number and respects the system load.")),
+ '$worker_queues' => array('worker_queues', t("Maximum number of parallel workers"), get_config('system','worker_queues'), t("On shared hosters set this to 2. On larger systems, values of 10 are great. Default value is 4.")),
+ '$worker_dont_fork' => array('worker_dont_fork', t("Don't use 'proc_open' with the worker"), get_config('system','worker_dont_fork'), t("Enable this if your system doesn't allow the use of 'proc_open'. This can happen on shared hosters. If this is enabled you should increase the frequency of poller calls in your crontab.")),
+
'$form_security_token' => get_form_security_token("admin_site")
));
@@ -1003,12 +1034,12 @@ function admin_page_dbsync(&$a) {
$o = '';
if($a->argc > 3 && intval($a->argv[3]) && $a->argv[2] === 'mark') {
- set_config('database', 'update_' . intval($a->argv[3]), 'success');
+ set_config('database', 'update_'.intval($a->argv[3]), 'success');
$curr = get_config('system','build');
if(intval($curr) == intval($a->argv[3]))
set_config('system','build',intval($curr) + 1);
- info( t('Update has been marked successful') . EOL);
- goaway($a->get_baseurl(true) . '/admin/dbsync');
+ info(t('Update has been marked successful').EOL);
+ goaway('admin/dbsync');
}
if(($a->argc > 2) AND (intval($a->argv[2]) OR ($a->argv[2] === 'check'))) {
@@ -1026,7 +1057,7 @@ function admin_page_dbsync(&$a) {
if($a->argc > 2 && intval($a->argv[2])) {
require_once('update.php');
- $func = 'update_' . intval($a->argv[2]);
+ $func = 'update_'.intval($a->argv[2]);
if(function_exists($func)) {
$retval = $func();
if($retval === UPDATE_FAILED) {
@@ -1082,18 +1113,18 @@ function admin_page_dbsync(&$a) {
* @param App $a
*/
function admin_page_users_post(&$a){
- $pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
- $users = ( x($_POST, 'user') ? $_POST['user'] : array() );
- $nu_name = ( x($_POST, 'new_user_name') ? $_POST['new_user_name'] : '');
- $nu_nickname = ( x($_POST, 'new_user_nickname') ? $_POST['new_user_nickname'] : '');
- $nu_email = ( x($_POST, 'new_user_email') ? $_POST['new_user_email'] : '');
+ $pending = (x($_POST, 'pending') ? $_POST['pending'] : array());
+ $users = (x($_POST, 'user') ? $_POST['user'] : array());
+ $nu_name = (x($_POST, 'new_user_name') ? $_POST['new_user_name'] : '');
+ $nu_nickname = (x($_POST, 'new_user_nickname') ? $_POST['new_user_nickname'] : '');
+ $nu_email = (x($_POST, 'new_user_email') ? $_POST['new_user_email'] : '');
check_form_security_token_redirectOnErr('/admin/users', 'admin_users');
if(!($nu_name==="") && !($nu_email==="") && !($nu_nickname==="")) {
require_once('include/user.php');
- $result = create_user( array('username'=>$nu_name, 'email'=>$nu_email, 'nickname'=>$nu_nickname, 'verified'=>1) );
+ $result = create_user(array('username'=>$nu_name, 'email'=>$nu_email, 'nickname'=>$nu_nickname, 'verified'=>1));
if(! $result['success']) {
notice($result['message']);
return;
@@ -1134,7 +1165,7 @@ function admin_page_users_post(&$a){
notification(array(
'type' => "SYSTEM_EMAIL",
'to_email' => $nu['email'],
- 'subject'=> sprintf( t('Registration details for %s'), $a->config['sitename']),
+ 'subject'=> sprintf(t('Registration details for %s'), $a->config['sitename']),
'preamble'=> $preamble,
'body' => $body));
@@ -1143,17 +1174,17 @@ function admin_page_users_post(&$a){
if(x($_POST,'page_users_block')) {
foreach($users as $uid){
q("UPDATE `user` SET `blocked`=1-`blocked` WHERE `uid`=%s",
- intval( $uid )
+ intval($uid)
);
}
- notice( sprintf( tt("%s user blocked/unblocked", "%s users blocked/unblocked", count($users)), count($users)) );
+ notice(sprintf(tt("%s user blocked/unblocked", "%s users blocked/unblocked", count($users)), count($users)));
}
if(x($_POST,'page_users_delete')) {
require_once("include/Contact.php");
foreach($users as $uid){
user_remove($uid);
}
- notice( sprintf( tt("%s user deleted", "%s users deleted", count($users)), count($users)) );
+ notice(sprintf(tt("%s user deleted", "%s users deleted", count($users)), count($users)));
}
if(x($_POST,'page_users_approve')) {
@@ -1168,7 +1199,7 @@ function admin_page_users_post(&$a){
user_deny($hash);
}
}
- goaway($a->get_baseurl(true) . '/admin/users' );
+ goaway('admin/users');
return; // NOTREACHED
}
@@ -1189,8 +1220,8 @@ function admin_page_users(&$a){
$uid = $a->argv[3];
$user = q("SELECT username, blocked FROM `user` WHERE `uid`=%d", intval($uid));
if(count($user)==0) {
- notice( 'User not found' . EOL);
- goaway($a->get_baseurl(true) . '/admin/users' );
+ notice('User not found'.EOL);
+ goaway('admin/users');
return ''; // NOTREACHED
}
switch($a->argv[2]){
@@ -1200,18 +1231,18 @@ function admin_page_users(&$a){
require_once("include/Contact.php");
user_remove($uid);
- notice( sprintf(t("User '%s' deleted"), $user[0]['username']) . EOL);
+ notice(sprintf(t("User '%s' deleted"), $user[0]['username']).EOL);
}; break;
case "block":{
check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't');
q("UPDATE `user` SET `blocked`=%d WHERE `uid`=%s",
- intval( 1-$user[0]['blocked'] ),
- intval( $uid )
+ intval(1-$user[0]['blocked']),
+ intval($uid)
);
- notice( sprintf( ($user[0]['blocked']?t("User '%s' unblocked"):t("User '%s' blocked")) , $user[0]['username']) . EOL);
+ notice(sprintf(($user[0]['blocked']?t("User '%s' unblocked"):t("User '%s' blocked")) , $user[0]['username']).EOL);
}; break;
}
- goaway($a->get_baseurl(true) . '/admin/users' );
+ goaway('admin/users');
return ''; // NOTREACHED
}
@@ -1230,7 +1261,7 @@ function admin_page_users(&$a){
$a->set_pager_itemspage(100);
}
- $users = q("SELECT `user` . * , `contact`.`name` , `contact`.`url` , `contact`.`micro`, `lastitem`.`lastitem_date`, `user`.`account_expired`
+ $users = q("SELECT `user`.* , `contact`.`name` , `contact`.`url` , `contact`.`micro`, `lastitem`.`lastitem_date`, `user`.`account_expired`
FROM
(SELECT MAX(`item`.`changed`) as `lastitem_date`, `item`.`uid`
FROM `item`
@@ -1277,7 +1308,7 @@ function admin_page_users(&$a){
while(count($users)) {
$new_user = array();
- foreach( array_pop($users) as $k => $v) {
+ foreach(array_pop($users) as $k => $v) {
$k = str_replace('-','_',$k);
$new_user[$k] = $v;
}
@@ -1303,7 +1334,7 @@ function admin_page_users(&$a){
'$select_all' => t('select all'),
'$h_pending' => t('User registrations waiting for confirm'),
'$h_deleted' => t('User waiting for permanent deletion'),
- '$th_pending' => array( t('Request date'), t('Name'), t('Email') ),
+ '$th_pending' => array(t('Request date'), t('Name'), t('Email')),
'$no_pending' => t('No registrations.'),
'$approve' => t('Approve'),
'$deny' => t('Deny'),
@@ -1315,8 +1346,8 @@ function admin_page_users(&$a){
'$h_users' => t('Users'),
'$h_newuser' => t('New User'),
- '$th_deleted' => array( t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Deleted since') ),
- '$th_users' => array( t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Account') ),
+ '$th_deleted' => array(t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Deleted since')),
+ '$th_users' => array(t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Account')),
'$confirm_delete_multi' => t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'),
@@ -1362,7 +1393,7 @@ function admin_page_plugins(&$a){
if($a->argc == 3) {
$plugin = $a->argv[2];
if(!is_file("addon/$plugin/$plugin.php")) {
- notice( t("Item not found.") );
+ notice(t("Item not found."));
return '';
}
@@ -1374,14 +1405,14 @@ function admin_page_plugins(&$a){
if($idx !== false) {
unset($a->plugins[$idx]);
uninstall_plugin($plugin);
- info( sprintf( t("Plugin %s disabled."), $plugin ) );
+ info(sprintf(t("Plugin %s disabled."), $plugin));
} else {
$a->plugins[] = $plugin;
install_plugin($plugin);
- info( sprintf( t("Plugin %s enabled."), $plugin ) );
+ info(sprintf(t("Plugin %s enabled."), $plugin));
}
set_config("system","addon", implode(", ",$a->plugins));
- goaway($a->get_baseurl(true) . '/admin/plugins' );
+ goaway('admin/plugins');
return ''; // NOTREACHED
}
@@ -1480,7 +1511,7 @@ function admin_page_plugins(&$a){
'$function' => 'plugins',
'$plugins' => $plugins,
'$pcount' => count($plugins),
- '$noplugshint' => sprintf( t('There are currently no plugins available on your node. You can find the official plugin repository at %1$s and might find other interesting plugins in the open plugin registry at %2$s'), 'https://github.com/friendica/friendica-addons', 'http://addons.friendi.ca'),
+ '$noplugshint' => sprintf(t('There are currently no plugins available on your node. You can find the official plugin repository at %1$s and might find other interesting plugins in the open plugin registry at %2$s'), 'https://github.com/friendica/friendica-addons', 'http://addons.friendi.ca'),
'$form_security_token' => get_form_security_token("admin_themes"),
));
}
@@ -1575,8 +1606,8 @@ function admin_page_themes(&$a){
if($files) {
foreach($files as $file) {
$f = basename($file);
- $is_experimental = intval(file_exists($file . '/experimental'));
- $is_supported = 1-(intval(file_exists($file . '/unsupported')));
+ $is_experimental = intval(file_exists($file.'/experimental'));
+ $is_supported = 1-(intval(file_exists($file.'/unsupported')));
$is_allowed = intval(in_array($f,$allowed_themes));
if($is_allowed OR $is_supported OR get_config("system", "show_unsupported_themes"))
@@ -1585,7 +1616,7 @@ function admin_page_themes(&$a){
}
if(! count($themes)) {
- notice( t('No themes found.'));
+ notice(t('No themes found.'));
return '';
}
@@ -1596,7 +1627,7 @@ function admin_page_themes(&$a){
if($a->argc == 3) {
$theme = $a->argv[2];
if(! is_dir("view/theme/$theme")) {
- notice( t("Item not found.") );
+ notice(t("Item not found."));
return '';
}
@@ -1609,15 +1640,15 @@ function admin_page_themes(&$a){
$s = rebuild_theme_table($themes);
if($result) {
install_theme($theme);
- info( sprintf('Theme %s enabled.',$theme));
+ info(sprintf('Theme %s enabled.',$theme));
}
else {
uninstall_theme($theme);
- info( sprintf('Theme %s disabled.',$theme));
+ info(sprintf('Theme %s disabled.',$theme));
}
set_config('system','allowed_themes',$s);
- goaway($a->get_baseurl(true) . '/admin/themes' );
+ goaway('admin/themes');
return ''; // NOTREACHED
}
@@ -1663,7 +1694,7 @@ function admin_page_themes(&$a){
$admin_form = __get_theme_admin_form($a, $theme);
}
- $screenshot = array( get_theme_screenshot($theme), t('Screenshot'));
+ $screenshot = array(get_theme_screenshot($theme), t('Screenshot'));
if(! stristr($screenshot[0],$theme))
$screenshot = null;
@@ -1754,8 +1785,8 @@ function admin_page_logs_post(&$a) {
set_config('system','loglevel', $loglevel);
}
- info( t("Log settings updated.") );
- goaway($a->get_baseurl(true) . '/admin/logs' );
+ info(t("Log settings updated."));
+ goaway('admin/logs');
return; // NOTREACHED
}
@@ -1803,7 +1834,7 @@ function admin_page_logs(&$a){
'$form_security_token' => get_form_security_token("admin_logs"),
'$phpheader' => t("PHP logging"),
'$phphint' => t("To enable logging of PHP errors and warnings you can add the following to the .htconfig.php file of your installation. The filename set in the 'error_log' line is relative to the friendica top-level directory and must be writeable by the web server. The option '1' for 'log_errors' and 'display_errors' is to enable these options, set to '0' to disable them."),
- '$phplogcode' => "error_reporting(E_ERROR | E_WARNING | E_PARSE );\nini_set('error_log','php.out');\nini_set('log_errors','1');\nini_set('display_errors', '1');",
+ '$phplogcode' => "error_reporting(E_ERROR | E_WARNING | E_PARSE);\nini_set('error_log','php.out');\nini_set('log_errors','1');\nini_set('display_errors', '1');",
));
}
@@ -1871,7 +1902,7 @@ function admin_page_features_post(&$a) {
check_form_security_token_redirectOnErr('/admin/features', 'admin_manage_features');
- logger('postvars: ' . print_r($_POST,true),LOGGER_DATA);
+ logger('postvars: '.print_r($_POST,true),LOGGER_DATA);
$arr = array();
$features = get_features(false);
@@ -1879,11 +1910,11 @@ function admin_page_features_post(&$a) {
foreach($features as $fname => $fdata) {
foreach(array_slice($fdata,1) as $f) {
$feature = $f[0];
- $feature_state = 'feature_' . $feature;
- $featurelock = 'featurelock_' . $feature;
+ $feature_state = 'feature_'.$feature;
+ $featurelock = 'featurelock_'.$feature;
if(x($_POST[$feature_state]))
- $val = intval($_POST['feature_' . $feature]);
+ $val = intval($_POST['feature_'.$feature]);
else
$val = 0;
set_config('feature',$feature,$val);
@@ -1895,7 +1926,7 @@ function admin_page_features_post(&$a) {
}
}
- goaway($a->get_baseurl(true) . '/admin/features' );
+ goaway('admin/features');
return; // NOTREACHED
}
@@ -1929,7 +1960,7 @@ function admin_page_features(&$a) {
$set = $f[3];
$arr[$fname][1][] = array(
array('feature_' .$f[0],$f[1],$set,$f[2],array(t('Off'),t('On'))),
- array('featurelock_' .$f[0],sprintf( t('Lock feature %s'),$f[1]),(($f[4] !== false) ? "1" : ''),'',array(t('Off'),t('On')))
+ array('featurelock_' .$f[0],sprintf(t('Lock feature %s'),$f[1]),(($f[4] !== false) ? "1" : ''),'',array(t('Off'),t('On')))
);
}
}
diff --git a/mod/common.php b/mod/common.php
index c9409b3ef1..62a5185fed 100644
--- a/mod/common.php
+++ b/mod/common.php
@@ -40,7 +40,7 @@ function common_content(&$a) {
$vcard_widget .= replace_macros(get_markup_template("vcard-widget.tpl"),array(
'$name' => htmlentities($c[0]['name']),
'$photo' => $c[0]['photo'],
- 'url' => z_root() . '/contacts/' . $cid
+ 'url' => 'contacts/' . $cid
));
if(! x($a->page,'aside'))
diff --git a/mod/contacts.php b/mod/contacts.php
index 0b421433e0..4897663a05 100644
--- a/mod/contacts.php
+++ b/mod/contacts.php
@@ -44,7 +44,7 @@ function contacts_init(&$a) {
$vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"),array(
'$name' => htmlentities($a->data['contact']['name']),
'$photo' => $a->data['contact']['photo'],
- '$url' => ($a->data['contact']['network'] == NETWORK_DFRN) ? z_root()."/redir/".$a->data['contact']['id'] : $a->data['contact']['url'],
+ '$url' => ($a->data['contact']['network'] == NETWORK_DFRN) ? "redir/".$a->data['contact']['id'] : $a->data['contact']['url'],
'$addr' => (($a->data['contact']['addr'] != "") ? ($a->data['contact']['addr']) : ""),
'$network_name' => $networkname,
'$network' => t('Network:'),
@@ -129,9 +129,9 @@ function contacts_batch_actions(&$a){
}
if(x($_SESSION,'return_url'))
- goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
+ goaway('' . $_SESSION['return_url']);
else
- goaway($a->get_baseurl(true) . '/contacts');
+ goaway('contacts');
}
@@ -157,7 +157,7 @@ function contacts_post(&$a) {
if(! count($orig_record)) {
notice( t('Could not access contact record.') . EOL);
- goaway($a->get_baseurl(true) . '/contacts');
+ goaway('contacts');
return; // NOTREACHED
}
@@ -366,19 +366,19 @@ function contacts_content(&$a) {
if(! count($orig_record)) {
notice( t('Could not access contact record.') . EOL);
- goaway($a->get_baseurl(true) . '/contacts');
+ goaway('contacts');
return; // NOTREACHED
}
if($cmd === 'update') {
_contact_update($contact_id);
- goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
+ goaway('contacts/' . $contact_id);
// NOTREACHED
}
if($cmd === 'updateprofile') {
_contact_update_profile($contact_id);
- goaway($a->get_baseurl(true) . '/crepair/' . $contact_id);
+ goaway('crepair/' . $contact_id);
// NOTREACHED
}
@@ -389,7 +389,7 @@ function contacts_content(&$a) {
info((($blocked) ? t('Contact has been blocked') : t('Contact has been unblocked')).EOL);
}
- goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
+ goaway('contacts/' . $contact_id);
return; // NOTREACHED
}
@@ -400,7 +400,7 @@ function contacts_content(&$a) {
info((($readonly) ? t('Contact has been ignored') : t('Contact has been unignored')).EOL);
}
- goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
+ goaway('contacts/' . $contact_id);
return; // NOTREACHED
}
@@ -412,7 +412,7 @@ function contacts_content(&$a) {
info((($archived) ? t('Contact has been archived') : t('Contact has been unarchived')).EOL);
}
- goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
+ goaway('contacts/' . $contact_id);
return; // NOTREACHED
}
@@ -447,17 +447,17 @@ function contacts_content(&$a) {
// Now check how the user responded to the confirmation query
if($_REQUEST['canceled']) {
if(x($_SESSION,'return_url'))
- goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
+ goaway('' . $_SESSION['return_url']);
else
- goaway($a->get_baseurl(true) . '/contacts');
+ goaway('contacts');
}
_contact_drop($contact_id, $orig_record[0]);
info( t('Contact has been removed.') . EOL );
if(x($_SESSION,'return_url'))
- goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
+ goaway('' . $_SESSION['return_url']);
else
- goaway($a->get_baseurl(true) . '/contacts');
+ goaway('contacts');
return; // NOTREACHED
}
if($cmd === 'posts') {
@@ -565,6 +565,9 @@ function contacts_content(&$a) {
($contact['rel'] == CONTACT_IS_FOLLOWER))
$follow = $a->get_baseurl(true)."/follow?url=".urlencode($contact["url"]);
+ // Load contactact related actions like hide, suggest, delete and others
+ $contact_actions = contact_actions($contact);
+
$o .= replace_macros($tpl, array(
//'$header' => t('Contact Editor'),
@@ -575,7 +578,7 @@ function contacts_content(&$a) {
'$lbl_info1' => t('Contact Information / Notes'),
'$infedit' => t('Edit contact notes'),
'$common_text' => $common_text,
- '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_user() . '/' . $contact['id'],
+ '$common_link' => 'common/loc/' . local_user() . '/' . $contact['id'],
'$all_friends' => $all_friends,
'$relation_text' => $relation_text,
'$visit' => sprintf( t('Visit %s\'s profile [%s]'),$contact['name'],$contact['url']),
@@ -584,7 +587,7 @@ function contacts_content(&$a) {
'$lblcrepair' => t("Repair URL settings"),
'$lblrecent' => t('View conversations'),
'$lblsuggest' => $lblsuggest,
- '$delete' => t('Delete contact'),
+ //'$delete' => t('Delete contact'),
'$nettype' => $nettype,
'$poll_interval' => $poll_interval,
'$poll_enabled' => $poll_enabled,
@@ -622,7 +625,11 @@ function contacts_content(&$a) {
'$about' => bbcode($contact["about"], false, false),
'$about_label' => t("About:"),
'$keywords' => $contact["keywords"],
- '$keywords_label' => t("Tags:")
+ '$keywords_label' => t("Tags:"),
+ '$contact_action_button' => t("Actions"),
+ '$contact_actions' => $contact_actions,
+ '$contact_status' => t("Status"),
+ '$contact_settings_label' => t('Contact Settings'),
));
@@ -668,7 +675,7 @@ function contacts_content(&$a) {
$tabs = array(
array(
'label' => t('Suggestions'),
- 'url' => $a->get_baseurl(true) . '/suggest',
+ 'url' => 'suggest',
'sel' => '',
'title' => t('Suggest potential friends'),
'id' => 'suggestions-tab',
@@ -676,7 +683,7 @@ function contacts_content(&$a) {
),
array(
'label' => t('All Contacts'),
- 'url' => $a->get_baseurl(true) . '/contacts/all',
+ 'url' => 'contacts/all',
'sel' => ($all) ? 'active' : '',
'title' => t('Show all contacts'),
'id' => 'showall-tab',
@@ -684,7 +691,7 @@ function contacts_content(&$a) {
),
array(
'label' => t('Unblocked'),
- 'url' => $a->get_baseurl(true) . '/contacts',
+ 'url' => 'contacts',
'sel' => ((! $all) && (! $blocked) && (! $hidden) && (! $search) && (! $nets) && (! $ignored) && (! $archived)) ? 'active' : '',
'title' => t('Only show unblocked contacts'),
'id' => 'showunblocked-tab',
@@ -693,7 +700,7 @@ function contacts_content(&$a) {
array(
'label' => t('Blocked'),
- 'url' => $a->get_baseurl(true) . '/contacts/blocked',
+ 'url' => 'contacts/blocked',
'sel' => ($blocked) ? 'active' : '',
'title' => t('Only show blocked contacts'),
'id' => 'showblocked-tab',
@@ -702,7 +709,7 @@ function contacts_content(&$a) {
array(
'label' => t('Ignored'),
- 'url' => $a->get_baseurl(true) . '/contacts/ignored',
+ 'url' => 'contacts/ignored',
'sel' => ($ignored) ? 'active' : '',
'title' => t('Only show ignored contacts'),
'id' => 'showignored-tab',
@@ -711,7 +718,7 @@ function contacts_content(&$a) {
array(
'label' => t('Archived'),
- 'url' => $a->get_baseurl(true) . '/contacts/archived',
+ 'url' => 'contacts/archived',
'sel' => ($archived) ? 'active' : '',
'title' => t('Only show archived contacts'),
'id' => 'showarchived-tab',
@@ -720,7 +727,7 @@ function contacts_content(&$a) {
array(
'label' => t('Hidden'),
- 'url' => $a->get_baseurl(true) . '/contacts/hidden',
+ 'url' => 'contacts/hidden',
'sel' => ($hidden) ? 'active' : '',
'title' => t('Only show hidden contacts'),
'id' => 'showhidden-tab',
@@ -800,6 +807,17 @@ function contacts_content(&$a) {
return $o;
}
+/**
+ * @brief List of pages for the Contact TabBar
+ *
+ * Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends'
+ *
+ * @param app $a
+ * @param int $contact_id The ID of the contact
+ * @param int $active_tab 1 if tab should be marked as active
+ *
+ * @return array with with contact TabBar data
+ */
function contacts_tab($a, $contact_id, $active_tab) {
// tabs
$tabs = array(
@@ -821,6 +839,7 @@ function contacts_tab($a, $contact_id, $active_tab) {
)
);
+ // Show this tab only if there is visible friend list
$x = count_all_friends(local_user(), $contact_id);
if ($x)
$tabs[] = array('label'=>t('Contacts'),
@@ -830,6 +849,7 @@ function contacts_tab($a, $contact_id, $active_tab) {
'id' => 'allfriends-tab',
'accesskey' => 't');
+ // Show this tab only if there is visible common friend list
$common = count_common_friends(local_user(),$contact_id);
if ($common)
$tabs[] = array('label'=>t('Common Friends'),
@@ -839,35 +859,13 @@ function contacts_tab($a, $contact_id, $active_tab) {
'id' => 'common-loc-tab',
'accesskey' => 'd');
- $tabs[] = array('label' => t('Repair'),
- 'url' => $a->get_baseurl(true) . '/crepair/' . $contact_id,
+ $tabs[] = array('label' => t('Advanced'),
+ 'url' => 'crepair/' . $contact_id,
'sel' => (($active_tab == 5)?'active':''),
'title' => t('Advanced Contact Settings'),
- 'id' => 'repair-tab',
+ 'id' => 'advanced-tab',
'accesskey' => 'r');
-
- $tabs[] = array('label' => (($contact['blocked']) ? t('Unblock') : t('Block') ),
- 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/block',
- 'sel' => '',
- 'title' => t('Toggle Blocked status'),
- 'id' => 'toggle-block-tab',
- 'accesskey' => 'b');
-
- $tabs[] = array('label' => (($contact['readonly']) ? t('Unignore') : t('Ignore') ),
- 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/ignore',
- 'sel' => '',
- 'title' => t('Toggle Ignored status'),
- 'id' => 'toggle-ignore-tab',
- 'accesskey' => 'i');
-
- $tabs[] = array('label' => (($contact['archive']) ? t('Unarchive') : t('Archive') ),
- 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/archive',
- 'sel' => '',
- 'title' => t('Toggle Archive status'),
- 'id' => 'toggle-archive-tab',
- 'accesskey' => 'v');
-
$tab_tpl = get_markup_template('common_tabs.tpl');
$tab_str = replace_macros($tab_tpl, array('$tabs' => $tabs));
@@ -954,3 +952,72 @@ function _contact_detail_for_template($rr){
);
}
+
+/**
+ * @brief Gives a array with actions which can performed to a given contact
+ *
+ * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others
+ *
+ * @param array $contact Data about the Contact
+ * @return array with contact related actions
+ */
+function contact_actions($contact) {
+
+ $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2));
+ $contact_action = array();
+
+ // Provide friend suggestion only for Friendica contacts
+ if($contact['network'] === NETWORK_DFRN) {
+ $contact_actions['suggest'] = array(
+ 'label' => t('Suggest friends'),
+ 'url' => 'fsuggest/' . $contact['id'],
+ 'title' => '',
+ 'sel' => '',
+ 'id' => 'suggest',
+ );
+ }
+
+ if($poll_enabled) {
+ $contact_actions['update'] = array(
+ 'label' => t('Update now'),
+ 'url' => 'contacts/' . $contact['id'] . '/update',
+ 'title' => '',
+ 'sel' => '',
+ 'id' => 'update',
+ );
+ }
+
+ $contact_actions['block'] = array(
+ 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ),
+ 'url' => 'contacts/' . $contact['id'] . '/block',
+ 'title' => t('Toggle Blocked status'),
+ 'sel' => (intval($contact['blocked']) ? 'active' : ''),
+ 'id' => 'toggle-block',
+ );
+
+ $contact_actions['ignore'] = array(
+ 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ),
+ 'url' => 'contacts/' . $contact['id'] . '/ignore',
+ 'title' => t('Toggle Ignored status'),
+ 'sel' => (intval($contact['readonly']) ? 'active' : ''),
+ 'id' => 'toggle-ignore',
+ );
+
+ $contact_actions['archive'] = array(
+ 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ),
+ 'url' => 'contacts/' . $contact['id'] . '/archive',
+ 'title' => t('Toggle Archive status'),
+ 'sel' => (intval($contact['archive']) ? 'active' : ''),
+ 'id' => 'toggle-archive',
+ );
+
+ $contact_actions['delete'] = array(
+ 'label' => t('Delete'),
+ 'url' => 'contacts/' . $contact['id'] . '/drop',
+ 'title' => t('Delete contact'),
+ 'sel' => '',
+ 'id' => 'delete',
+ );
+
+ return $contact_actions;
+}
diff --git a/mod/content.php b/mod/content.php
index c5a5556116..49cff74d2d 100644
--- a/mod/content.php
+++ b/mod/content.php
@@ -420,7 +420,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) {
if(($normalised != 'mailbox') && (x($a->contacts[$normalised])))
$profile_avatar = $a->contacts[$normalised]['thumb'];
else
- $profile_avatar = ((strlen($item['author-avatar'])) ? $a->get_cached_avatar_image($item['author-avatar']) : $item['thumb']);
+ $profile_avatar = $a->remove_baseurl(((strlen($item['author-avatar'])) ? $item['author-avatar'] : $item['thumb']));
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
call_hooks('render_location',$locate);
@@ -615,7 +615,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) {
$comment_lastcollapsed = true;
}
- $redirect_url = $a->get_baseurl($ssl_state) . '/redir/' . $item['cid'] ;
+ $redirect_url = 'redir/' . $item['cid'] ;
$lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
@@ -791,7 +791,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) {
if(($normalised != 'mailbox') && (x($a->contacts,$normalised)))
$profile_avatar = $a->contacts[$normalised]['thumb'];
else
- $profile_avatar = (((strlen($item['author-avatar'])) && $diff_author) ? $item['author-avatar'] : $a->get_cached_avatar_image($thumb));
+ $profile_avatar = $a->remove_baseurl(((strlen($item['author-avatar']) && $diff_author) ? $item['author-avatar'] : $thumb));
$like = ((x($alike,$item['uri'])) ? format_like($alike[$item['uri']],$alike[$item['uri'] . '-l'],'like',$item['uri']) : '');
$dislike = ((x($dlike,$item['uri'])) ? format_like($dlike[$item['uri']],$dlike[$item['uri'] . '-l'],'dislike',$item['uri']) : '');
diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php
index 27c04a908d..5e0e5c85c5 100644
--- a/mod/dfrn_confirm.php
+++ b/mod/dfrn_confirm.php
@@ -427,8 +427,8 @@ function dfrn_confirm_post(&$a,$handsfree = null) {
if(($contact) && ($contact['network'] === NETWORK_DIASPORA)) {
require_once('include/diaspora.php');
- $ret = diaspora_share($user[0],$r[0]);
- logger('mod_follow: diaspora_share returns: ' . $ret);
+ $ret = diaspora::send_share($user[0],$r[0]);
+ logger('share returns: ' . $ret);
}
// Send a new friend post if we are allowed to...
@@ -448,6 +448,7 @@ function dfrn_confirm_post(&$a,$handsfree = null) {
if(count($self)) {
$arr = array();
+ $arr['guid'] = get_guid(32);
$arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $uid);
$arr['uid'] = $uid;
$arr['contact-id'] = $self[0]['id'];
@@ -466,7 +467,7 @@ function dfrn_confirm_post(&$a,$handsfree = null) {
$BPhoto = '[url=' . $contact['url'] . ']' . '[img]' . $contact['thumb'] . '[/img][/url]';
$arr['verb'] = ACTIVITY_FRIEND;
- $arr['object-type'] = ACTIVITY_OBJ_PERSON;
+ $arr['object-type'] = ACTIVITY_OBJ_PERSON;
$arr['body'] = sprintf( t('%1$s is now friends with %2$s'), $A, $B)."\n\n\n".$BPhoto;
$arr['object'] = '