From 16e4e94b293035ab73e00c5d6cd68f54797e23cd Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Tue, 19 Jan 2016 18:11:40 +0100 Subject: [PATCH 001/485] rework autocomplete: initial commit --- js/autocomplete.js | 192 +++ js/fk.autocomplete.js | 2 +- js/main.js | 2 +- library/jquery-textcomplete/LICENSE | 21 + .../jquery.textcomplete.js | 1104 +++++++++++++++++ view/templates/display-head.tpl | 4 +- view/templates/head.tpl | 4 +- view/templates/jot-header.tpl | 2 +- 8 files changed, 1325 insertions(+), 6 deletions(-) create mode 100644 js/autocomplete.js create mode 100644 library/jquery-textcomplete/LICENSE create mode 100644 library/jquery-textcomplete/jquery.textcomplete.js diff --git a/js/autocomplete.js b/js/autocomplete.js new file mode 100644 index 0000000000..aa4494b714 --- /dev/null +++ b/js/autocomplete.js @@ -0,0 +1,192 @@ +/** + * Red people autocomplete + * + * require jQuery, jquery.textcomplete + */ +function contact_search(term, callback, backend_url, type) { + + // Check if there is a cached result that contains the same information we would get with a full server-side search + var bt = backend_url+type; + if(!(bt in contact_search.cache)) contact_search.cache[bt] = {}; + + var lterm = term.toLowerCase(); // Ignore case + for(var t in contact_search.cache[bt]) { + if(lterm.indexOf(t) >= 0) { // A more broad search has been performed already, so use those results + // Filter old results locally + var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || (typeof x.nick !== 'undefined' && x.nick.toLowerCase().indexOf(lterm) >= 0)); }); // Need to check that nick exists because groups don't have one + matching.unshift({taggable:false, text: term, replace: term}); + setTimeout(function() { callback(matching); } , 1); // Use "pseudo-thread" to avoid some problems + return; + } + } + + var postdata = { + start:0, + count:100, + search:term, + type:type, + }; + + + $.ajax({ + type:'POST', + url: backend_url, + data: postdata, + dataType: 'json', + success: function(data){ + // Cache results if we got them all (more information would not improve results) + // data.count represents the maximum number of items + if(data.items.length -1 < data.count) { + contact_search.cache[bt][lterm] = data.items; + } + var items = data.items.slice(0); + items.unshift({taggable:false, text: term, replace: term}); + callback(items); + }, + }).fail(function () {callback([]); }); // Callback must be invoked even if something went wrong. +} +contact_search.cache = {}; + + +function contact_format(item) { + // Show contact information if not explicitly told to show something else + if(typeof item.text === 'undefined') { + var desc = ((item.label) ? item.nick + ' ' + item.label : item.nick); + if(typeof desc === 'undefined') desc = ''; + if(desc) desc = ' ('+desc+')'; + return "
(.*?)<\/pre>/ism','self::smile_encode',$s);
+ $s = preg_replace_callback('/(.*?)<\/code>/ism','self::smile_encode',$s);
+
+ $params = self::list_smilies();
+ $params['string'] = $s;
+
+ if($sample) {
+ $s = '';
+ for($x = 0; $x < count($params['texts']); $x ++) {
+ $s .= '- ' . $params['texts'][$x] . '
- ' . $params['icons'][$x] . '
';
+ }
+ }
+ else {
+ $params['string'] = preg_replace_callback('/<(3+)/','self::preg_heart',$params['string']);
+ $s = str_replace($params['texts'],$params['icons'],$params['string']);
+ }
+
+ $s = preg_replace_callback('/(.*?)<\/pre>/ism','self::smile_decode',$s);
+ $s = preg_replace_callback('/(.*?)<\/code>/ism','self::smile_decode',$s);
+
+ return $s;
+ }
+
+ private function smile_encode($m) {
+ return(str_replace($m[1],base64url_encode($m[1]),$m[0]));
+ }
+
+ private function smile_decode($m) {
+ return(str_replace($m[1],base64url_decode($m[1]),$m[0]));
+ }
+
+
+ /**
+ * @brief expand <3333 to the correct number of hearts
+ *
+ * @param string $x
+ * @return string
+ */
+ private function preg_heart($x) {
+ if(strlen($x[1]) == 1)
+ return $x[0];
+ $t = '';
+ for($cnt = 0; $cnt < strlen($x[1]); $cnt ++)
+ $t .= '';
+ $r = str_replace($x[0],$t,$x[0]);
+ return $r;
+ }
+
+}
diff --git a/include/text.php b/include/text.php
index 4f3af5aee8..eb8dde40cb 100644
--- a/include/text.php
+++ b/include/text.php
@@ -2,6 +2,7 @@
require_once("include/template_processor.php");
require_once("include/friendica_smarty.php");
+require_once("include/smilies.php");
require_once("include/map.php");
require_once("mod/proxy.php");
@@ -1079,160 +1080,6 @@ function get_mood_verbs() {
return $arr;
}
-
-
-if(! function_exists('smilies')) {
-/**
- * Replaces text emoticons with graphical images
- *
- * It is expected that this function will be called using HTML text.
- * We will escape text between HTML pre and code blocks from being
- * processed.
- *
- * At a higher level, the bbcode [nosmile] tag can be used to prevent this
- * function from being executed by the prepare_text() routine when preparing
- * bbcode source for HTML display
- *
- * @param string $s
- * @param boolean $sample
- * @return string
- * @hook smilie ('texts' => smilies texts array, 'icons' => smilies html array, 'string' => $s)
- */
-function smilies($s, $sample = false) {
- $a = get_app();
-
- if(intval(get_config('system','no_smilies'))
- || (local_user() && intval(get_pconfig(local_user(),'system','no_smilies'))))
- return $s;
-
- $s = preg_replace_callback('/(.*?)<\/pre>/ism','smile_encode',$s);
- $s = preg_replace_callback('/(.*?)<\/code>/ism','smile_encode',$s);
-
- $texts = array(
- '<3',
- '</3',
- '<\\3',
- ':-)',
- ';-)',
- ':-(',
- ':-P',
- ':-p',
- ':-"',
- ':-"',
- ':-x',
- ':-X',
- ':-D',
- '8-|',
- '8-O',
- ':-O',
- '\\o/',
- 'o.O',
- 'O.o',
- 'o_O',
- 'O_o',
- ":'(",
- ":-!",
- ":-/",
- ":-[",
- "8-)",
- ':beer',
- ':homebrew',
- ':coffee',
- ':facepalm',
- ':like',
- ':dislike',
- '~friendica',
- 'red#',
- 'red#matrix'
-
- );
-
- $icons = array(
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '~friendica ',
- 'redmatrix',
- 'redmatrix'
- );
-
- $params = array('texts' => $texts, 'icons' => $icons, 'string' => $s);
- call_hooks('smilie', $params);
-
- if($sample) {
- $s = '';
- for($x = 0; $x < count($params['texts']); $x ++) {
- $s .= '- ' . $params['texts'][$x] . '
- ' . $params['icons'][$x] . '
';
- }
- }
- else {
- $params['string'] = preg_replace_callback('/<(3+)/','preg_heart',$params['string']);
- $s = str_replace($params['texts'],$params['icons'],$params['string']);
- }
-
- $s = preg_replace_callback('/(.*?)<\/pre>/ism','smile_decode',$s);
- $s = preg_replace_callback('/(.*?)<\/code>/ism','smile_decode',$s);
-
- return $s;
-
-}}
-
-function smile_encode($m) {
- return(str_replace($m[1],base64url_encode($m[1]),$m[0]));
-}
-
-function smile_decode($m) {
- return(str_replace($m[1],base64url_decode($m[1]),$m[0]));
-}
-
-
-/**
- * expand <3333 to the correct number of hearts
- *
- * @param string $x
- * @return string
- */
-function preg_heart($x) {
- $a = get_app();
- if(strlen($x[1]) == 1)
- return $x[0];
- $t = '';
- for($cnt = 0; $cnt < strlen($x[1]); $cnt ++)
- $t .= '';
- $r = str_replace($x[0],$t,$x[0]);
- return $r;
-}
-
-
if(! function_exists('day_translate')) {
/**
* Translate days and months names
@@ -1549,7 +1396,7 @@ function prepare_text($text) {
if(stristr($text,'[nosmile]'))
$s = bbcode($text);
else
- $s = smilies(bbcode($text));
+ $s = smilies::replace(bbcode($text));
return trim($s);
}}
diff --git a/mod/smilies.php b/mod/smilies.php
index c47f95da76..5a157e3686 100644
--- a/mod/smilies.php
+++ b/mod/smilies.php
@@ -1,3 +1,21 @@
argv[1]==="json"){
+ $tmp = smilies::list_smilies();
+ $results = array();
+ for($i = 0; $i < count($tmp['texts']); $i++) {
+ $results[] = array('text' => $tmp['texts'][$i], 'icon' => $tmp['icons'][$i]);
+ }
+ json_return_and_die($results);
+ }
+ else {
+ return smilies('',true);
+ }
+}
From aee94b38c174f0e182d6d14309ef3f4aef2563b0 Mon Sep 17 00:00:00 2001
From: rabuzarus <>
Date: Mon, 1 Feb 2016 18:21:29 +0100
Subject: [PATCH 008/485] rework autocomplete: add class dir and static
function
---
include/acl_selectors.php | 4 +-
include/dir_fns.php | 74 +++++++++++++++++---------------
view/templates/contacts-head.tpl | 12 ------
3 files changed, 42 insertions(+), 48 deletions(-)
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 46f737e4c2..b5c43e38e6 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -659,7 +659,7 @@ function acl_lookup(&$a, $out_type = 'json') {
* @brief Searching for global contacts for autocompletion
*
* @param App $a
- * @return type
+ * @return array
*/
function navbar_complete(&$a) {
@@ -682,7 +682,7 @@ function navbar_complete(&$a) {
$search = substr($search,1);
if($localsearch) {
- $x = dirsearch_global_by_name($search);
+ $x = dir::global_search_by_name($search);
return $x;
}
diff --git a/include/dir_fns.php b/include/dir_fns.php
index 2e39e7ddbf..b85cb5b2d0 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -2,45 +2,51 @@
/**
* @file include/dir_fns.php
- * @brief Functions for directory
*/
+
/**
- * @brief Search global contact table by nick or name
- * *
- * @param string $search
- * @return array
+ * @brief This class handels directory related functions
*/
-function dirsearch_global_by_name($search) {
+class dir {
- if($search) {
- // check supported networks
- if (get_config('system','diaspora_enabled'))
- $diaspora = NETWORK_DIASPORA;
- else
- $diaspora = NETWORK_DFRN;
+ /**
+ * @brief Search global contact table by nick or name
+ * *
+ * @param string $search Name or nick
+ * @return array
+ */
+ public static function global_search_by_name($search) {
- if (!get_config('system','ostatus_disabled'))
- $ostatus = NETWORK_OSTATUS;
- else
- $ostatus = NETWORK_DFRN;
+ if($search) {
+ // check supported networks
+ if (get_config('system','diaspora_enabled'))
+ $diaspora = NETWORK_DIASPORA;
+ else
+ $diaspora = NETWORK_DFRN;
+
+ if (!get_config('system','ostatus_disabled'))
+ $ostatus = NETWORK_OSTATUS;
+ else
+ $ostatus = NETWORK_DFRN;
+
+ $results = q("SELECT `contact`.`id` AS `cid`, `gcontact`.`url`, `gcontact`.`name`, `gcontact`.`nick`, `gcontact`.`photo`,
+ `gcontact`.`network`, `gcontact`.`keywords`, `gcontact`.`addr`
+ FROM `gcontact`
+ LEFT JOIN `contact` ON `contact`.`nurl` = `gcontact`.`nurl`
+ AND `contact`.`uid` = %d AND NOT `contact`.`blocked`
+ AND NOT `contact`.`pending` AND `contact`.`rel` IN ('%s', '%s')
+ WHERE (`contact`.`id` > 0 OR (NOT `gcontact`.`hide` AND `gcontact`.`network` IN ('%s', '%s', '%s') AND
+ ((`gcontact`.`last_contact` >= `gcontact`.`last_failure`) OR (`gcontact`.`updated` >= `gcontact`.`last_failure`)))) AND
+ (`gcontact`.`url` REGEXP '%s' OR `gcontact`.`name` REGEXP '%s' OR `gcontact`.`nick` REGEXP '%s'
+ )
+ GROUP BY `gcontact`.`nurl`
+ ORDER BY `gcontact`.`updated` DESC ",
+ intval(local_user()), dbesc(CONTACT_IS_SHARING), dbesc(CONTACT_IS_FRIEND),
+ dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora),
+ dbesc(escape_tags($search)), dbesc(escape_tags($search)), dbesc(escape_tags($search)));
+ return $results;
+ }
- $results = q("SELECT `contact`.`id` AS `cid`, `gcontact`.`url`, `gcontact`.`name`, `gcontact`.`nick`, `gcontact`.`photo`,
- `gcontact`.`network`, `gcontact`.`keywords`, `gcontact`.`addr`
- FROM `gcontact`
- LEFT JOIN `contact` ON `contact`.`nurl` = `gcontact`.`nurl`
- AND `contact`.`uid` = %d AND NOT `contact`.`blocked`
- AND NOT `contact`.`pending` AND `contact`.`rel` IN ('%s', '%s')
- WHERE (`contact`.`id` > 0 OR (NOT `gcontact`.`hide` AND `gcontact`.`network` IN ('%s', '%s', '%s') AND
- ((`gcontact`.`last_contact` >= `gcontact`.`last_failure`) OR (`gcontact`.`updated` >= `gcontact`.`last_failure`)))) AND
- (`gcontact`.`url` REGEXP '%s' OR `gcontact`.`name` REGEXP '%s' OR `gcontact`.`nick` REGEXP '%s'
- )
- GROUP BY `gcontact`.`nurl`
- ORDER BY `gcontact`.`updated` DESC ",
- intval(local_user()), dbesc(CONTACT_IS_SHARING), dbesc(CONTACT_IS_FRIEND),
- dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora),
- dbesc(escape_tags($search)), dbesc(escape_tags($search)), dbesc(escape_tags($search)));
- return $results;
}
-
-}
\ No newline at end of file
+}
diff --git a/view/templates/contacts-head.tpl b/view/templates/contacts-head.tpl
index 25055d405b..ea562233f4 100644
--- a/view/templates/contacts-head.tpl
+++ b/view/templates/contacts-head.tpl
@@ -2,18 +2,6 @@
From 00e319faa269801e9ffe1f60ad1b4d74946522c7 Mon Sep 17 00:00:00 2001
From: rabuzarus <>
Date: Mon, 1 Feb 2016 18:22:26 +0100
Subject: [PATCH 009/485] rework autocomplete: add bbcode autocompletion to
editor
---
js/autocomplete.js | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/js/autocomplete.js b/js/autocomplete.js
index 1f7df011d3..6c75f17ca6 100644
--- a/js/autocomplete.js
+++ b/js/autocomplete.js
@@ -1,8 +1,15 @@
/**
- * Friendica people autocomplete
+ * @brief Friendica people autocomplete
*
* require jQuery, jquery.textcomplete
+ *
+ * for further documentation look at:
+ * http://yuku-t.com/jquery-textcomplete/
+ *
+ * https://github.com/yuku-t/jquery-textcomplete/blob/master/doc/how_to_use.md
*/
+
+
function contact_search(term, callback, backend_url, type) {
// Check if there is a conversation id to include the unkonwn contacts of the conversation
@@ -107,6 +114,9 @@ function submit_form(e) {
(function( $ ) {
$.fn.editor_autocomplete = function(backend_url) {
+ // list of supported bbtags
+ var bbelements = ['b', 'u', 'i', 'img', 'url', 'quote', 'code', 'spoiler', 'audio', 'video', 'youtube', 'map', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 's', 'o', 'list', 'center', 'nosmile', 'vimeo' ];
+
// Autocomplete contacts
contacts = {
match: /(^|\s)(@\!*)([^ \n]+)$/,
@@ -119,12 +129,19 @@ function submit_form(e) {
smilies = {
match: /(^|\s)(:[a-z]{2,})$/,
index: 2,
- search: function(term, callback) { $.getJSON('/smilies/json').done(function(data) { callback($.map(data, function(entry) { return entry.text.indexOf(term) === 0 ? entry : null; })); }); },
- template: function(item) { return item.icon + item.text; },
+ search: function(term, callback) { $.getJSON('smilies/json').done(function(data) { callback($.map(data, function(entry) { return entry.text.indexOf(term) === 0 ? entry : null; })); }); },
+ template: function(item) { return item.icon + ' ' + item.text; },
replace: function(item) { return "$1" + item.text + ' '; },
};
+
+ bbtags = {
+ match: /\[(\w*)$/,
+ index: 1,
+ search: function (term, callback) { callback($.map(bbelements, function (element) { return element.indexOf(term) === 0 ? element : null; })); },
+ replace: function (element) { return ['[' + element + ']', '[/' + element + ']']; },
+ };
this.attr('autocomplete','off');
- this.textcomplete([contacts,smilies], {className:'acpopup', zIndex:1020});
+ this.textcomplete([contacts,smilies, bbtags], {className:'acpopup', zIndex:1020});
};
})( jQuery );
From aff775e55c51fa2745656bb2e2607f1c5710e56f Mon Sep 17 00:00:00 2001
From: rabuzarus <>
Date: Tue, 2 Feb 2016 22:33:14 +0100
Subject: [PATCH 010/485] rework autocomplete: add NavBar forum search
---
include/acl_selectors.php | 14 ++++++++------
include/dir_fns.php | 14 ++++++++++----
js/autocomplete.js | 21 +++++++++++++++++----
3 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index b5c43e38e6..9e1a2642a4 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -395,11 +395,12 @@ function acl_lookup(&$a, $out_type = 'json') {
if(!local_user())
return "";
- $start = (x($_REQUEST,'start')?$_REQUEST['start']:0);
- $count = (x($_REQUEST,'count')?$_REQUEST['count']:100);
- $search = (x($_REQUEST,'search')?$_REQUEST['search']:"");
- $type = (x($_REQUEST,'type')?$_REQUEST['type']:"");
- $conv_id = (x($_REQUEST,'conversation')?$_REQUEST['conversation']:null);
+ $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
+ $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
+ $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : "");
+ $type = (x($_REQUEST,'type') ? $_REQUEST['type'] : "");
+ $mode = (x($_REQUEST,'mode') ? $_REQUEST['mode'] : "");
+ $conv_id = (x($_REQUEST,'conversation') ? $_REQUEST['conversation'] : null);
// For use with jquery.textcomplete for private mail completion
@@ -673,6 +674,7 @@ function navbar_complete(&$a) {
$localsearch = get_config('system','poco_local_search');
$search = $prefix.notags(trim($_REQUEST['search']));
+ $mode = $_REQUEST['mode'];
// don't search if search term has less than 2 characters
if(! $search || mb_strlen($search) < 2)
@@ -682,7 +684,7 @@ function navbar_complete(&$a) {
$search = substr($search,1);
if($localsearch) {
- $x = dir::global_search_by_name($search);
+ $x = dir::global_search_by_name($search, $mode);
return $x;
}
diff --git a/include/dir_fns.php b/include/dir_fns.php
index b85cb5b2d0..d258058763 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -14,9 +14,10 @@ class dir {
* @brief Search global contact table by nick or name
* *
* @param string $search Name or nick
+ * @param string $mode Search mode
* @return array
*/
- public static function global_search_by_name($search) {
+ public static function global_search_by_name($search, $mode = '') {
if($search) {
// check supported networks
@@ -30,6 +31,12 @@ class dir {
else
$ostatus = NETWORK_DFRN;
+ // check if fo
+ if($mode === "community")
+ $extra_sql = " AND `community`";
+ else
+ $extra_sql = "";
+
$results = q("SELECT `contact`.`id` AS `cid`, `gcontact`.`url`, `gcontact`.`name`, `gcontact`.`nick`, `gcontact`.`photo`,
`gcontact`.`network`, `gcontact`.`keywords`, `gcontact`.`addr`
FROM `gcontact`
@@ -38,13 +45,12 @@ class dir {
AND NOT `contact`.`pending` AND `contact`.`rel` IN ('%s', '%s')
WHERE (`contact`.`id` > 0 OR (NOT `gcontact`.`hide` AND `gcontact`.`network` IN ('%s', '%s', '%s') AND
((`gcontact`.`last_contact` >= `gcontact`.`last_failure`) OR (`gcontact`.`updated` >= `gcontact`.`last_failure`)))) AND
- (`gcontact`.`url` REGEXP '%s' OR `gcontact`.`name` REGEXP '%s' OR `gcontact`.`nick` REGEXP '%s'
- )
+ (`gcontact`.`name` REGEXP '%s' OR `gcontact`.`nick` REGEXP '%s') $extra_sql
GROUP BY `gcontact`.`nurl`
ORDER BY `gcontact`.`updated` DESC ",
intval(local_user()), dbesc(CONTACT_IS_SHARING), dbesc(CONTACT_IS_FRIEND),
dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora),
- dbesc(escape_tags($search)), dbesc(escape_tags($search)), dbesc(escape_tags($search)));
+ dbesc(escape_tags($search)), dbesc(escape_tags($search)));
return $results;
}
diff --git a/js/autocomplete.js b/js/autocomplete.js
index 6c75f17ca6..aa8b6836c5 100644
--- a/js/autocomplete.js
+++ b/js/autocomplete.js
@@ -10,12 +10,11 @@
*/
-function contact_search(term, callback, backend_url, type) {
+function contact_search(term, callback, backend_url, type, mode) {
// Check if there is a conversation id to include the unkonwn contacts of the conversation
var conv_id = document.activeElement.id.match(/\d+$/);
-
// Check if there is a cached result that contains the same information we would get with a full server-side search
var bt = backend_url+type;
if(!(bt in contact_search.cache)) contact_search.cache[bt] = {};
@@ -41,6 +40,9 @@ function contact_search(term, callback, backend_url, type) {
if(conv_id !== null)
postdata['conversation'] = conv_id[0];
+ if(mode !== null)
+ postdata['mode'] = mode;
+
$.ajax({
type:'POST',
@@ -126,6 +128,7 @@ function submit_form(e) {
template: contact_format,
};
+ // Autocomplete smilies e.g. ":like"
smilies = {
match: /(^|\s)(:[a-z]{2,})$/,
index: 2,
@@ -134,6 +137,7 @@ function submit_form(e) {
replace: function(item) { return "$1" + item.text + ' '; },
};
+ // Autocomplete BBTags
bbtags = {
match: /\[(\w*)$/,
index: 1,
@@ -154,12 +158,21 @@ function submit_form(e) {
contacts = {
match: /(^@)([^\n]{2,})$/,
index: 2,
- search: function(term, callback) { contact_search(term, callback, backend_url, 'x'); },
+ search: function(term, callback) { contact_search(term, callback, backend_url, 'x', 'contact'); },
+ replace: basic_replace,
+ template: contact_format,
+ };
+
+ // Autocomplete forum accounts
+ community = {
+ match: /(^!)([^\n]{2,})$/,
+ index: 2,
+ search: function(term, callback) { contact_search(term, callback, backend_url, 'x', 'community'); },
replace: basic_replace,
template: contact_format,
};
this.attr('autocomplete', 'off');
- var a = this.textcomplete([contacts], {className:'acpopup', maxCount:100, zIndex: 1020, appendTo:'nav'});
+ var a = this.textcomplete([contacts, community], {className:'acpopup', maxCount:100, zIndex: 1020, appendTo:'#nav-search-box'});
a.on('textComplete:select', function(e, value, strategy) { submit_form(this); });
};
})( jQuery );
From ad5be2901e131ec28356c7bdbb3cd0f748ffaa54 Mon Sep 17 00:00:00 2001
From: rabuzarus <>
Date: Wed, 3 Feb 2016 00:25:33 +0100
Subject: [PATCH 011/485] rework autocomplete: some styling if contact is forum
---
include/acl_selectors.php | 11 +++++++----
include/dir_fns.php | 2 +-
js/autocomplete.js | 5 +++--
view/theme/vier/style.css | 11 +++++++++++
4 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 9e1a2642a4..99848aa193 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -509,7 +509,7 @@ function acl_lookup(&$a, $out_type = 'json') {
if ($type==''){
- $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum` FROM `contact`
+ $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 AND `notify` != ''
AND NOT (`network` IN ('%s', '%s'))
$sql_extra2
@@ -520,7 +520,7 @@ function acl_lookup(&$a, $out_type = 'json') {
}
elseif ($type=='c'){
- $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum` FROM `contact`
+ $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 AND `notify` != ''
AND NOT (`network` IN ('%s'))
$sql_extra2
@@ -542,7 +542,7 @@ function acl_lookup(&$a, $out_type = 'json') {
);
}
elseif($type == 'a') {
- $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag` FROM `contact`
+ $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND `pending` = 0
$sql_extra2
ORDER BY `name` ASC ",
@@ -559,6 +559,9 @@ function acl_lookup(&$a, $out_type = 'json') {
"photo" => $g['photo'],
"name" => $g['name'],
"nick" => (x($g['addr']) ? $g['addr'] : $g['url']),
+ "network" => $g['network'],
+ "link" => $g['url'],
+ "forum" => (x($g['community']) ? 1 : 0),
);
}
}
@@ -584,7 +587,7 @@ function acl_lookup(&$a, $out_type = 'json') {
"network" => $g['network'],
"link" => $g['url'],
"nick" => htmlentities(($g['attag']) ? $g['attag'] : $g['nick']),
- "forum" => $g['forum']
+ "forum" => ((x($g['forum']) || x($g['prv'])) ? 1 : 0),
);
}
}
diff --git a/include/dir_fns.php b/include/dir_fns.php
index d258058763..5f018ed8cf 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -38,7 +38,7 @@ class dir {
$extra_sql = "";
$results = q("SELECT `contact`.`id` AS `cid`, `gcontact`.`url`, `gcontact`.`name`, `gcontact`.`nick`, `gcontact`.`photo`,
- `gcontact`.`network`, `gcontact`.`keywords`, `gcontact`.`addr`
+ `gcontact`.`network`, `gcontact`.`keywords`, `gcontact`.`addr`, `gcontact`.`community`
FROM `gcontact`
LEFT JOIN `contact` ON `contact`.`nurl` = `gcontact`.`nurl`
AND `contact`.`uid` = %d AND NOT `contact`.`blocked`
diff --git a/js/autocomplete.js b/js/autocomplete.js
index aa8b6836c5..f31161ff83 100644
--- a/js/autocomplete.js
+++ b/js/autocomplete.js
@@ -24,7 +24,7 @@ function contact_search(term, callback, backend_url, type, mode) {
if(lterm.indexOf(t) >= 0) { // A more broad search has been performed already, so use those results
// Filter old results locally
var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || (typeof x.nick !== 'undefined' && x.nick.toLowerCase().indexOf(lterm) >= 0)); }); // Need to check that nick exists because groups don't have one
- matching.unshift({taggable:false, text: term, replace: term});
+ matching.unshift({forum:false, text: term, replace: term});
setTimeout(function() { callback(matching); } , 1); // Use "pseudo-thread" to avoid some problems
return;
}
@@ -68,9 +68,10 @@ function contact_format(item) {
// Show contact information if not explicitly told to show something else
if(typeof item.text === 'undefined') {
var desc = ((item.label) ? item.nick + ' ' + item.label : item.nick);
+ var forum = ((item.forum) ? 'forum' : '');
if(typeof desc === 'undefined') desc = '';
if(desc) desc = ' ('+desc+')';
- return "{2}{3}".format(item.taggable, item.photo, item.name, desc, item.link);
+ return "{2}{3}".format(forum, item.photo, item.name, desc, item.link);
}
else
return "" + item.text + "";
diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css
index a7b15c581b..7a73e03e83 100644
--- a/view/theme/vier/style.css
+++ b/view/theme/vier/style.css
@@ -935,8 +935,19 @@ nav .acpopup {
color: #737373;
}
.textcomplete-item a:hover {
+ color: #000;
padding: 3px 20px;
}
+.textcomplete-item a .forum, .forum .acpopup-sub-text {
+ color: #36C;
+ opacity: 0.8;
+}
+.textcomplete-item a .forum:hover {
+ opacity: 1.0;
+}
+img.acpopup-img {
+ border-radius: 4px;
+}
#nav-notifications-menu {
width: 400px;
From 30c375d238af79795937b8df046abe9f0ee63db9 Mon Sep 17 00:00:00 2001
From: rabuzarus <>
Date: Fri, 5 Feb 2016 14:26:22 +0100
Subject: [PATCH 012/485] rework autocomplete: polishing class and methods
naming
---
include/{dir_fns.php => DirSearch.php} | 4 ++--
include/{smilies.php => Smilies.php} | 18 +++++++++---------
include/acl_selectors.php | 4 ++--
include/text.php | 4 ++--
mod/smilies.php | 4 ++--
5 files changed, 17 insertions(+), 17 deletions(-)
rename include/{dir_fns.php => DirSearch.php} (97%)
rename include/{smilies.php => Smilies.php} (92%)
diff --git a/include/dir_fns.php b/include/DirSearch.php
similarity index 97%
rename from include/dir_fns.php
rename to include/DirSearch.php
index 5f018ed8cf..a6a0b59fcb 100644
--- a/include/dir_fns.php
+++ b/include/DirSearch.php
@@ -1,14 +1,14 @@
smilies texts array, 'icons' => smilies html array)
*/
- public static function list_smilies() {
+ public static function get_list() {
$texts = array(
'<3',
@@ -128,10 +128,10 @@ class smilies {
|| (local_user() && intval(get_pconfig(local_user(),'system','no_smilies'))))
return $s;
- $s = preg_replace_callback('/(.*?)<\/pre>/ism','self::smile_encode',$s);
- $s = preg_replace_callback('/(.*?)<\/code>/ism','self::smile_encode',$s);
+ $s = preg_replace_callback('/(.*?)<\/pre>/ism','self::encode',$s);
+ $s = preg_replace_callback('/(.*?)<\/code>/ism','self::encode',$s);
- $params = self::list_smilies();
+ $params = self::get_list();
$params['string'] = $s;
if($sample) {
@@ -145,17 +145,17 @@ class smilies {
$s = str_replace($params['texts'],$params['icons'],$params['string']);
}
- $s = preg_replace_callback('/(.*?)<\/pre>/ism','self::smile_decode',$s);
- $s = preg_replace_callback('/(.*?)<\/code>/ism','self::smile_decode',$s);
+ $s = preg_replace_callback('/(.*?)<\/pre>/ism','self::decode',$s);
+ $s = preg_replace_callback('/(.*?)<\/code>/ism','self::decode',$s);
return $s;
}
- private function smile_encode($m) {
+ private function encode($m) {
return(str_replace($m[1],base64url_encode($m[1]),$m[0]));
}
- private function smile_decode($m) {
+ private function decode($m) {
return(str_replace($m[1],base64url_decode($m[1]),$m[0]));
}
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index 99848aa193..4a35fd0f08 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -6,7 +6,7 @@
require_once("include/contact_selectors.php");
require_once("include/contact_widgets.php");
-require_once("include/dir_fns.php");
+require_once("include/DirSearch.php");
require_once("include/features.php");
require_once("mod/proxy.php");
@@ -687,7 +687,7 @@ function navbar_complete(&$a) {
$search = substr($search,1);
if($localsearch) {
- $x = dir::global_search_by_name($search, $mode);
+ $x = DirSearch::global_search_by_name($search, $mode);
return $x;
}
diff --git a/include/text.php b/include/text.php
index eb8dde40cb..e14930b102 100644
--- a/include/text.php
+++ b/include/text.php
@@ -2,7 +2,7 @@
require_once("include/template_processor.php");
require_once("include/friendica_smarty.php");
-require_once("include/smilies.php");
+require_once("include/Smilies.php");
require_once("include/map.php");
require_once("mod/proxy.php");
@@ -1396,7 +1396,7 @@ function prepare_text($text) {
if(stristr($text,'[nosmile]'))
$s = bbcode($text);
else
- $s = smilies::replace(bbcode($text));
+ $s = Smilies::replace(bbcode($text));
return trim($s);
}}
diff --git a/mod/smilies.php b/mod/smilies.php
index 5a157e3686..b3d86cb3fe 100644
--- a/mod/smilies.php
+++ b/mod/smilies.php
@@ -4,11 +4,11 @@
* @file mod/smilies.php
*/
-require_once("include/smilies.php");
+require_once("include/Smilies.php");
function smilies_content(&$a) {
if ($a->argv[1]==="json"){
- $tmp = smilies::list_smilies();
+ $tmp = Smilies::get_list();
$results = array();
for($i = 0; $i < count($tmp['texts']); $i++) {
$results[] = array('text' => $tmp['texts'][$i], 'icon' => $tmp['icons'][$i]);
From e5c7a0cf9369f39abcd8ef75e6edfb6c2b2b241a Mon Sep 17 00:00:00 2001
From: Olivier Mehani
Date: Tue, 9 Feb 2016 10:04:48 +0000
Subject: [PATCH 013/485] Enable SSL on standard and well-known HTTP headers
Look for the `Forwarded` header with `proto=https`, as specified
in RFC7239 (strictly expecting no whitespace around the = sign).
This also add similar support for `X-Forwarded-Proto: https`,
`Front-End-Https: on` and `X-Forwarded-Ssl: on` (all case-sensitive).
Also add some documentation about this, and an NginX configuration
example, in INSTALL.txt
This should fix #757.
Signed-off-by: Olivier Mehani
---
INSTALL.txt | 31 ++++++++++++++++++++++++++++++-
boot.php | 11 ++++++++---
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/INSTALL.txt b/INSTALL.txt
index 7726bdb0d7..71671af3f1 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -136,8 +136,37 @@ $a->config['system']['addon'] = 'js_upload,poormancron';
and save your changes.
+9. (Optional) Reverse-proxying and HTTPS
+
+Friendica looks for some well-known HTTP headers indicating a reverse-proxy
+terminating an HTTPS connection. While the standard from RFC 7239 specifies
+the use of the `Forwaded` header.
+
+ Forwarded: for=192.0.2.1; proto=https; by=192.0.2.2
+
+Friendica also supports a number on non-standard headers in common use.
+
+
+ X-Forwarded-Proto: https
+
+ Front-End-Https: on
+
+ X-Forwarded-Ssl: on
+
+It is however preferable to use the standard approach if configuring a new server.
+In Nginx, this can be done as follows (assuming Friendica runs on port 8080).
+
+ location / {
+ if ( $scheme != https ) { # Force Redirect to HTTPS
+ return 302 https://$host$uri;
+ }
+ proxy_pass http://localhost:8080;
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Forwarded "for=$proxy_add_x_forwarded_for; proto=$scheme";
+ }
-
#####################################################################
If things don't work...
diff --git a/boot.php b/boot.php
index dd70040c64..6a2acaa35e 100644
--- a/boot.php
+++ b/boot.php
@@ -582,10 +582,15 @@ class App {
$this->scheme = 'http';
- if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS'])
- $this->scheme = 'https';
- elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443))
+ if((x($_SERVER,'HTTPS') && $_SERVER['HTTPS']) ||
+ (x($_SERVER['HTTP_FORWARDED']) && preg_match("/proto=https/", $_SERVER['HTTP_FORWARDED'])) ||
+ (x($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') ||
+ (x($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') ||
+ (x($_SERVER['FRONT_END_HTTPS']) && $_SERVER['FRONT_END_HTTPS'] == 'on') ||
+ (x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443)) // XXX: reasonable assumption, but isn't this hardcoding too much?
+ ) {
$this->scheme = 'https';
+ }
if(x($_SERVER,'SERVER_NAME')) {
$this->hostname = $_SERVER['SERVER_NAME'];
From 69865ea843ac346a89d5ba428015b324b074e91e Mon Sep 17 00:00:00 2001
From: rabuzarus
Date: Wed, 17 Feb 2016 19:33:23 +0100
Subject: [PATCH 014/485] Initial commit
---
LICENSE | 661 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
README.md | 2 +
2 files changed, 663 insertions(+)
create mode 100644 LICENSE
create mode 100644 README.md
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000..dbbe355815
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+ .
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..dfba0278ee
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# frio
+A bootstrap based theme for friendica
From a3960bda371c8083bad2ed422169282fed004d24 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sat, 27 Feb 2016 23:54:17 +0100
Subject: [PATCH 015/485] New Diaspora code
---
include/diaspora.php | 37 +++
include/diaspora2.php | 638 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 675 insertions(+)
create mode 100644 include/diaspora2.php
diff --git a/include/diaspora.php b/include/diaspora.php
index 93fe2a472f..9dbbeabbcf 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -58,6 +58,8 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
return;
}
+ $data = $msg;
+
// php doesn't like dashes in variable names
$msg['message'] = str_replace(
@@ -74,48 +76,83 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
if($xmlbase->request) {
+ $tempfile = tempnam(get_temppath(), "diaspora-request");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_request($importer,$xmlbase->request);
}
elseif($xmlbase->status_message) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-status_message");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_post($importer,$xmlbase->status_message,$msg);
}
elseif($xmlbase->profile) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-profile");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_profile($importer,$xmlbase->profile,$msg);
}
elseif($xmlbase->comment) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-comment");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_comment($importer,$xmlbase->comment,$msg);
}
elseif($xmlbase->like) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-like");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_like($importer,$xmlbase->like,$msg);
}
elseif($xmlbase->asphoto) {
+ $tempfile = tempnam(get_temppath(), "diaspora-asphoto");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg);
}
elseif($xmlbase->reshare) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-reshare");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_reshare($importer,$xmlbase->reshare,$msg);
}
elseif($xmlbase->retraction) {
+ $tempfile = tempnam(get_temppath(), "diaspora-retraction");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
}
elseif($xmlbase->signed_retraction) {
+ $tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
}
elseif($xmlbase->relayable_retraction) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-relayable_retraction");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
}
elseif($xmlbase->photo) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-photo");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_photo($importer,$xmlbase->photo,$msg,$attempt);
}
elseif($xmlbase->conversation) {
+ $tempfile = tempnam(get_temppath(), "diaspora-conversation");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_conversation($importer,$xmlbase->conversation,$msg);
}
elseif($xmlbase->message) {
+ $tempfile = tempnam(get_temppath(), "diaspora-message");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_message($importer,$xmlbase->message,$msg);
}
elseif($xmlbase->participation) {
+ //$tempfile = tempnam(get_temppath(), "diaspora-participation");
+ //file_put_contents($tempfile, json_encode($data));
+ $ret = diaspora_participation($importer,$xmlbase->participation);
+ }
+ elseif($xmlbase->poll_participation) {
+ $tempfile = tempnam(get_temppath(), "diaspora-poll_participation");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_participation($importer,$xmlbase->participation);
}
else {
+ $tempfile = tempnam(get_temppath(), "diaspora-unknown");
+ file_put_contents($tempfile, json_encode($data));
logger('diaspora_dispatch: unknown message type: ' . print_r($xmlbase,true));
}
return $ret;
diff --git a/include/diaspora2.php b/include/diaspora2.php
new file mode 100644
index 0000000000..690e54aa41
--- /dev/null
+++ b/include/diaspora2.php
@@ -0,0 +1,638 @@
+ $value) {
+ $root = new SimpleXMLElement('<'.$key.'/>');
+ array_to_xml($value, $root);
+
+ $dom = dom_import_simplexml($root)->ownerDocument;
+ $dom->formatOutput = true;
+ return $dom->saveXML();
+ }
+ }
+
+ foreach($array as $key => $value) {
+ if (!is_array($value) AND !is_numeric($key))
+ $xml->addChild($key, $value);
+ elseif (is_array($value))
+ array_to_xml($value, $xml->addChild($key));
+ }
+}
+
+/**
+ * @brief This class contain functions to create and send DFRN XML files
+ *
+ */
+class diaspora {
+
+ 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);
+ 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(count($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));
+ }
+
+ 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();
+
+ switch ($type) {
+ case "account_deletion":
+ return self::import_account_deletion($importer, $fields);
+
+ case "comment":
+ return self::import_comment($importer, $sender, $fields);
+
+ case "conversation":
+ return self::import_conversation($importer, $fields);
+
+ case "like":
+ return self::import_like($importer, $sender, $fields);
+
+ case "message":
+ return self::import_message($importer, $fields);
+
+ case "participation":
+ return self::import_participation($importer, $fields);
+
+ case "photo":
+ return self::import_photo($importer, $fields);
+
+ case "poll_participation":
+ return self::import_poll_participation($importer, $fields);
+
+ case "profile":
+ return self::import_profile($importer, $fields);
+
+ case "request":
+ return self::import_request($importer, $fields);
+
+ case "reshare":
+ return self::import_reshare($importer, $fields);
+
+ case "retraction":
+ return self::import_retraction($importer, $fields);
+
+ case "status_message":
+ return self::import_status_message($importer, $fields);
+
+ 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
+ *
+ * @return bool Is the posting valid?
+ */
+ private function valid_posting($msg, &$fields) {
+
+ $data = parse_xml_string($msg->message, false);
+
+ $first_child = $data->getName();
+
+ if ($data->getName() == "XML") {
+ $oldXML = true;
+ foreach ($data->post->children() as $child)
+ $element = $child;
+ } else {
+ $oldXML = false;
+ $element = $data;
+ }
+
+ $type = $element->getName();
+
+ if (in_array($type, array("signed_retraction", "relayable_retraction")))
+ $type = "retraction";
+
+ $fields = new SimpleXMLElement("<".$type."/>");
+
+ $signed_data = "";
+
+ foreach ($element->children() AS $fieldname => $data) {
+
+ 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($data);
+ elseif ($fieldname == "parent_author_signature")
+ $parent_author_signature = base64_decode($data);
+ elseif ($fieldname != "target_author_signature") {
+ if ($signed_data != "") {
+ $signed_data .= ";";
+ $signed_data_parent .= ";";
+ }
+
+ $signed_data .= $data;
+ $fields->$fieldname = $data;
+ }
+ }
+
+ if (in_array($type, array("status_message", "reshare")))
+ if ($msg->author != $fields->author) {
+ logger("Message handle is not the same as envelope sender. Quitting this message.");
+ return false;
+ }
+
+ if (!in_array($type, array("comment", "conversation", "message", "like")))
+ return true;
+
+ if (!isset($author_signature))
+ return false;
+
+ if (isset($parent_author_signature)) {
+ $key = self::get_key($msg->author);
+
+ if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256"))
+ return false;
+ }
+
+ $key = self::get_key($fields->author);
+
+ return rsa_verify($signed_data, $author_signature, $key, "sha256");
+ }
+
+ private function get_key($handle) {
+ logger("Fetching diaspora key for: ".$handle);
+
+ $r = self::get_person_by_handle($handle);
+ if($r)
+ return $r["pubkey"];
+
+ return "";
+ }
+
+ private function get_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)) {
+ $person = $r[0];
+ 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"))
+ $update = true;
+ }
+
+ if (!$person OR $update) {
+ logger("create or refresh", LOGGER_DEBUG);
+ $r = probe_url($handle, PROBE_DIASPORA);
+
+ // Note that Friendica contacts will return a "Diaspora person"
+ // if Diaspora connectivity is enabled on their server
+ if (count($r) AND ($r["network"] === NETWORK_DIASPORA)) {
+ self::add_fcontact($r, $update);
+ $person = $r;
+ }
+ }
+ return $person;
+ }
+
+ private function add_fcontact($arr, $update = false) {
+ /// @todo Remove this function from include/network.php
+
+ 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;
+ }
+
+ private function get_contact_by_handle($uid, $handle) {
+ $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `addr` = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($handle)
+ );
+
+ if ($r AND count($r))
+ return $r[0];
+
+ $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 AND count($r))
+ return $r[0];
+
+ return false;
+ }
+
+/*
+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);
+ 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 ($datarray['contact-id'] == 0)
+ return false;
+
+ DiasporaFetchGuid($datarray);
+ $message_id = item_store($datarray);
+
+ /// @TODO
+ /// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
+
+ return $message_id;
+}
+*/
+
+ private function import_account_deletion($importer, $data) {
+ return true;
+ }
+
+ private function import_comment($importer, $sender, $data) {
+ $guid = notags(unxmlify($data->guid));
+ $parent_guid = notags(unxmlify($data->parent_guid));
+ $text = unxmlify($data->text);
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::get_contact_by_handle($importer["uid"], $sender);
+ if (!$contact) {
+ logger("cannot find contact for sender: ".$sender);
+ return false;
+ }
+/*
+ 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']);
+ }
+
+ 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_comment: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid);
+ return;
+ }
+ $parent_item = $r[0];
+
+ // 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 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 true;
+ }
+
+ private function import_conversation($importer, $data) {
+ return true;
+ }
+
+ private function import_like($importer, $sender, $data) {
+ return true;
+ }
+
+ private function import_message($importer, $data) {
+ return true;
+ }
+
+ private function import_participation($importer, $data) {
+ return true;
+ }
+
+ private function import_photo($importer, $data) {
+ return true;
+ }
+
+ private function import_poll_participation($importer, $data) {
+ return true;
+ }
+
+ private function import_profile($importer, $data) {
+ return true;
+ }
+
+ private function import_request($importer, $data) {
+ return true;
+ }
+
+ private function import_reshare($importer, $data) {
+ return true;
+ }
+
+ private function import_retraction($importer, $data) {
+ return true;
+ }
+
+ private function import_status_message($importer, $data) {
+ return true;
+ }
+}
+?>
From c02b54997e84667f195ee3ddf0c809a863fab294 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 28 Feb 2016 19:05:23 +0100
Subject: [PATCH 016/485] Like and Comment could work (partially)
---
include/diaspora2.php | 589 ++++++++++++++++++++++++++----------------
1 file changed, 372 insertions(+), 217 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 690e54aa41..e6e2d74bf6 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -4,8 +4,9 @@
* @brief The implementation of the diaspora protocol
*/
-require_once("include/diaspora.php");
+require_once("include/bb2diaspora.php");
require_once("include/Scrape.php");
+require_once("include/Contact.php");
function array_to_xml($array, &$xml) {
@@ -66,7 +67,7 @@ class diaspora {
// 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;
+ $sender = $msg["author"];
if (!diaspora::valid_posting($msg, $fields)) {
logger("Invalid posting");
@@ -80,12 +81,14 @@ class diaspora {
return self::import_account_deletion($importer, $fields);
case "comment":
- return self::import_comment($importer, $sender, $fields);
+ return true;
+ // return self::import_comment($importer, $sender, $fields);
case "conversation":
return self::import_conversation($importer, $fields);
case "like":
+ // return true;
return self::import_like($importer, $sender, $fields);
case "message":
@@ -136,7 +139,7 @@ class diaspora {
*/
private function valid_posting($msg, &$fields) {
- $data = parse_xml_string($msg->message, false);
+ $data = parse_xml_string($msg["message"], false);
$first_child = $data->getName();
@@ -202,12 +205,13 @@ class diaspora {
}
$signed_data .= $data;
- $fields->$fieldname = $data;
}
+ if (!in_array($fieldname, array("parent_author_signature", "target_author_signature")))
+ $fields->$fieldname = $data;
}
if (in_array($type, array("status_message", "reshare")))
- if ($msg->author != $fields->author) {
+ if ($msg["author"] != $fields->author) {
logger("Message handle is not the same as envelope sender. Quitting this message.");
return false;
}
@@ -219,7 +223,7 @@ class diaspora {
return false;
if (isset($parent_author_signature)) {
- $key = self::get_key($msg->author);
+ $key = self::get_key($msg["author"]);
if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256"))
return false;
@@ -349,104 +353,166 @@ class diaspora {
return false;
}
+ 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"]);
+ }
+
+ private function fetch_guid_sub($match, $item) {
+ $a = get_app();
+
+ if (!self::store_by_guid($match[1], $item["author-link"]))
+ self::store_by_guid($match[1], $item["owner-link"]);
+ }
+
+ 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);
+
+/// @todo $item = self::fetch_message($guid, $server);
+
+ if (!$item)
+ return false;
+
+ logger("Successfully fetched item ".$guid." from ".$server, LOGGER_DEBUG);
+
+// @todo - neue Funktion import_status... nutzen
+print_r($item);
+die();
+ return self::import_status_message($importer, $data);
+
/*
-function DiasporaFetchGuid($item) {
- preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
- function ($match) use ($item){
- return(DiasporaFetchGuidSub($match, $item));
- },$item["body"]);
-}
+ $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"];
-function DiasporaFetchGuidSub($match, $item) {
- $a = get_app();
+ $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"];
- if (!diaspora_store_by_guid($match[1], $item["author-link"]))
- diaspora_store_by_guid($match[1], $item["owner-link"]);
-}
+ $person = self::get_person_by_handle($author);
-function diaspora_store_by_guid($guid, $server, $uid = 0) {
- require_once("include/Contact.php");
+ $contact_id = get_contact($person["url"], $uid);
- $serverparts = parse_url($server);
- $server = $serverparts["scheme"]."://".$serverparts["host"];
+ $contacts = q("SELECT * FROM `contact` WHERE `id` = %d", intval($contact_id));
+ $importers = q("SELECT * FROM `user` WHERE `uid` = %d", intval($uid));
- logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
+ if ($contacts AND $importers)
+ if (!self::post_allow($importers[0],$contacts[0], false)) {
+ logger("Ignoring author ".$person["url"]." for uid ".$uid);
+ return false;
+ } else
+ logger("Author ".$person["url"]." is allowed for uid ".$uid);
- $item = diaspora_fetch_message($guid, $server);
+ $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"] = $author.":".$guid;
+ $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert('UTC','UTC',$created);
+ $datarray["private"] = $private;
+ $datarray["parent"] = 0;
+ $datarray["plink"] = self::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 (!$item)
- return false;
+ if ($datarray["contact-id"] == 0)
+ return false;
- logger("Successfully fetched item ".$guid." from ".$server, LOGGER_DEBUG);
+ self::fetch_guid($datarray);
+ $message_id = item_store($datarray);
- $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"];
+ /// @TODO
+ /// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
- $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);
- 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 ($datarray['contact-id'] == 0)
- return false;
-
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
-
- /// @TODO
- /// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
-
- return $message_id;
-}
+ return $message_id;
*/
+ }
+
+ 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.
+ // 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("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)
+ return true;
+
+ // Messages for the global users are always accepted
+ if ($importer["uid"] == 0)
+ return true;
+
+ return false;
+ }
+
+ private function fetch_parent_item($uid, $guid, $author, $contact) {
+ $r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `owner-name`, `owner-link`, `owner-avatar`, `origin`
+ FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($uid), dbesc($guid));
+
+ if(!count($r)) {
+ $result = self::store_by_guid($guid, $contact["url"], $uid);
+
+ if (!$result) {
+ $person = self::get_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`,
+ `owner-name`, `owner-link`, `owner-avatar`, `origin`
+ FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($uid), dbesc($guid));
+ }
+ }
+
+ if (!count($r)) {
+ logger("parent item not found: parent: ".$guid." item: ".$guid);
+ return false;
+ } else
+ return $r[0];
+ }
private function import_account_deletion($importer, $data) {
return true;
@@ -463,132 +529,93 @@ function diaspora_store_by_guid($guid, $server, $uid = 0) {
logger("cannot find contact for sender: ".$sender);
return false;
}
+
+ if (!self::post_allow($importer,$contact, true)) {
+ logger("Ignoring the author ".$sender);
+ return false;
+ }
/*
- 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']);
- }
-
- 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_comment: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid);
- return;
- }
- $parent_item = $r[0];
-
- // 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 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);
- }
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($guid)
+ );
+ if(count($r)) {
+ logger("The comment already exists: ".$guid);
+ return;
+ }
*/
- return true;
+ $parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
+ if (!$parent_item)
+ return false;
+
+ $person = self::get_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
+ $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);
+
+ $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"] = $author.":".$guid;
+ $datarray["parent-uri"] = $parent_item["uri"];
+
+ // The old Diaspora protocol doesn't have a timestamp for comments
+ $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert();
+ $datarray["private"] = $parent_item["private"];
+
+ $datarray["owner-name"] = $contact["name"];
+ $datarray["owner-link"] = $contact["url"];
+ $datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+
+ $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($data);
+ $datarray["object-type"] = ACTIVITY_OBJ_COMMENT;
+
+ self::fetch_guid($datarray);
+
+// $message_id = item_store($datarray);
+print_r($datarray);
+ $datarray["id"] = $message_id;
+
+ // 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.
+ // The new Diaspora protocol can have variable fields. We now store the data in correct order in a single field.
+ 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;
}
private function import_conversation($importer, $data) {
@@ -596,6 +623,134 @@ function diaspora_store_by_guid($guid, $server, $uid = 0) {
}
private function import_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
+ if ($parent_type !== "Post")
+ return false;
+
+ // "positive" = "false" doesn't seem to be supported by Diaspora
+ if ($positive === "false") {
+ logger("Received a like with positive set to 'false' - this shouldn't exist at all");
+ return false;
+ }
+
+ $contact = self::get_contact_by_handle($importer["uid"], $sender);
+ if (!$contact) {
+ logger("cannot find contact for sender: ".$sender);
+ return false;
+ }
+
+ if (!self::post_allow($importer,$contact, true)) {
+ logger("Ignoring the author ".$sender);
+ return false;
+ }
+/*
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($guid)
+ );
+ if(count($r)) {
+ logger("The like already exists: ".$guid);
+ return false;
+ }
+*/
+ $parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
+ if (!$parent_item)
+ return false;
+
+ $person = self::get_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
+ $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;
+ }
+
+// ------------------------------------------------
+ $objtype = ACTIVITY_OBJ_NOTE;
+ $link = xmlify(''."\n") ;
+ $parent_body = $parent_item["body"];
+
+ $obj = <<< EOT
+
+
+EOT;
+ $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]";
+ $body = sprintf($bodyverb, $ulink, $alink, $plink);
+// ------------------------------------------------
+
+ $datarray = array();
+
+ $datarray["uri"] = $author.":".$guid;
+ $datarray["uid"] = $importer["uid"];
+ $datarray["guid"] = $guid;
+ $datarray["network"] = $network;
+ $datarray["contact-id"] = $cid;
+ $datarray["type"] = "activity";
+ $datarray["wall"] = $parent_item["wall"];
+ $datarray["gravity"] = GRAVITY_LIKE;
+ $datarray["parent"] = $parent_item["id"];
+ $datarray["parent-uri"] = $parent_item["uri"];
+
+ $datarray["owner-name"] = $contact["name"];
+ $datarray["owner-link"] = $contact["url"];
+ $datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+
+ $datarray["author-name"] = $person["name"];
+ $datarray["author-link"] = $person["url"];
+ $datarray["author-avatar"] = ((x($person,"thumb")) ? $person["thumb"] : $person["photo"]);
+
+ $datarray["body"] = $body;
+ $datarray["private"] = $parent_item["private"];
+ $datarray["verb"] = ACTIVITY_LIKE;
+ $datarray["object-type"] = $objtype;
+ $datarray["object"] = $obj;
+ $datarray["visible"] = 1;
+ $datarray["unseen"] = 1;
+ $datarray["last-child"] = 0;
+
+print_r($datarray);
+// $message_id = item_store($datarray);
+
+ // 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.
+ // The new Diaspora protocol can have variable fields. We now store the data in correct order in a single field.
+ 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 true;
}
From 6d3581dac8dc5a27a18a39709fa3ae38c080c490 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 29 Feb 2016 08:02:50 +0100
Subject: [PATCH 017/485] "profile". "like" and "comment" could work, status
messages only partly.
---
include/diaspora.php | 4 +-
include/diaspora2.php | 1055 +++++++++++++++++++++++++++++++++--------
2 files changed, 856 insertions(+), 203 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 9dbbeabbcf..4ec7489ca4 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -116,8 +116,8 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
$ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
}
elseif($xmlbase->signed_retraction) {
- $tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
- file_put_contents($tempfile, json_encode($data));
+ //$tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
}
elseif($xmlbase->relayable_retraction) {
diff --git a/include/diaspora2.php b/include/diaspora2.php
index e6e2d74bf6..578a496c0a 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -7,30 +7,43 @@
require_once("include/bb2diaspora.php");
require_once("include/Scrape.php");
require_once("include/Contact.php");
+require_once("include/Photo.php");
+require_once("include/socgraph.php");
-function array_to_xml($array, &$xml) {
+class xml {
+ function from_array($array, &$xml) {
+
+ if (!is_object($xml)) {
+ foreach($array as $key => $value) {
+ $root = new SimpleXMLElement('<'.$key.'/>');
+ array_to_xml($value, $root);
+
+ $dom = dom_import_simplexml($root)->ownerDocument;
+ $dom->formatOutput = true;
+ return $dom->saveXML();
+ }
+ }
- if (!is_object($xml)) {
foreach($array as $key => $value) {
- $root = new SimpleXMLElement('<'.$key.'/>');
- array_to_xml($value, $root);
-
- $dom = dom_import_simplexml($root)->ownerDocument;
- $dom->formatOutput = true;
- return $dom->saveXML();
+ if (!is_array($value) AND !is_numeric($key))
+ $xml->addChild($key, $value);
+ elseif (is_array($value))
+ array_to_xml($value, $xml->addChild($key));
}
}
- foreach($array as $key => $value) {
- if (!is_array($value) AND !is_numeric($key))
- $xml->addChild($key, $value);
- elseif (is_array($value))
- array_to_xml($value, $xml->addChild($key));
+ function copy(&$source, &$target, $elementname) {
+ if (count($source->children()) == 0)
+ $target->addChild($elementname, $source);
+ else {
+ $child = $target->addChild($elementname);
+ foreach ($source->children() AS $childfield => $childentry)
+ self::copy($childentry, $child, $childfield);
+ }
}
}
-
/**
- * @brief This class contain functions to create and send DFRN XML files
+ * @brief This class contain functions to create and send Diaspora XML files
*
*/
class diaspora {
@@ -39,7 +52,7 @@ class diaspora {
$enabled = intval(get_config("system", "diaspora_enabled"));
if (!$enabled) {
- logger('diaspora is disabled');
+ logger("diaspora is disabled");
return false;
}
@@ -69,7 +82,7 @@ class diaspora {
// This will often be different with relayed messages (for example "like" and "comment")
$sender = $msg["author"];
- if (!diaspora::valid_posting($msg, $fields)) {
+ if (!diaspora::valid_posting($msg, $fields, $data2)) {
logger("Invalid posting");
return false;
}
@@ -77,34 +90,36 @@ class diaspora {
$type = $fields->getName();
switch ($type) {
- case "account_deletion":
+ case "account_deletion": // Not implemented
return self::import_account_deletion($importer, $fields);
case "comment":
return true;
- // return self::import_comment($importer, $sender, $fields);
+ //return self::import_comment($importer, $sender, $fields);
case "conversation":
return self::import_conversation($importer, $fields);
case "like":
- // return true;
- return self::import_like($importer, $sender, $fields);
+ return true;
+ //return self::import_like($importer, $sender, $fields);
case "message":
- return self::import_message($importer, $fields);
+ return true;
+ //return self::import_message($importer, $fields);
- case "participation":
+ case "participation": // Not implemented
return self::import_participation($importer, $fields);
case "photo":
return self::import_photo($importer, $fields);
- case "poll_participation":
+ case "poll_participation": // Not implemented
return self::import_poll_participation($importer, $fields);
case "profile":
- return self::import_profile($importer, $fields);
+ return true;
+ //return self::import_profile($importer, $fields);
case "request":
return self::import_request($importer, $fields);
@@ -116,7 +131,7 @@ class diaspora {
return self::import_retraction($importer, $fields);
case "status_message":
- return self::import_status_message($importer, $fields);
+ return self::import_status_message($importer, $fields, $msg, $data2);
default:
logger("Unknown message type ".$type);
@@ -133,16 +148,20 @@ class diaspora {
* 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
+ * @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) {
+ private function valid_posting($msg, &$fields, &$element) {
$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)
@@ -154,6 +173,8 @@ class diaspora {
$type = $element->getName();
+ // 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";
@@ -161,8 +182,7 @@ class diaspora {
$signed_data = "";
- foreach ($element->children() AS $fieldname => $data) {
-
+ foreach ($element->children() AS $fieldname => $entry) {
if ($oldXML) {
// Translation for the old XML structure
if ($fieldname == "diaspora_handle")
@@ -195,30 +215,33 @@ class diaspora {
}
if ($fieldname == "author_signature")
- $author_signature = base64_decode($data);
+ $author_signature = base64_decode($entry);
elseif ($fieldname == "parent_author_signature")
- $parent_author_signature = base64_decode($data);
+ $parent_author_signature = base64_decode($entry);
elseif ($fieldname != "target_author_signature") {
if ($signed_data != "") {
$signed_data .= ";";
$signed_data_parent .= ";";
}
- $signed_data .= $data;
+ $signed_data .= $entry;
}
if (!in_array($fieldname, array("parent_author_signature", "target_author_signature")))
- $fields->$fieldname = $data;
+ xml::copy($entry, $fields, $fieldname);
}
- if (in_array($type, array("status_message", "reshare")))
+ // 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", "conversation", "message", "like")))
return true;
+ // No author_signature? This is a must, so we quit.
if (!isset($author_signature))
return false;
@@ -373,85 +396,57 @@ class diaspora {
logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
-/// @todo $item = self::fetch_message($guid, $server);
+ $msg = self::fetch_message($guid, $server);
- if (!$item)
+ if (!$msg)
return false;
logger("Successfully fetched item ".$guid." from ".$server, LOGGER_DEBUG);
-// @todo - neue Funktion import_status... nutzen
-print_r($item);
-die();
- return self::import_status_message($importer, $data);
+ // Now call the dispatcher
+ return self::dispatch_public($msg);
+ }
-/*
- $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"];
+ private function fetch_message($guid, $server, $level = 0) {
- $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 = self::get_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 (!self::post_allow($importers[0],$contacts[0], false)) {
- logger("Ignoring author ".$person["url"]." for uid ".$uid);
- 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"] = $author.":".$guid;
- $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert('UTC','UTC',$created);
- $datarray["private"] = $private;
- $datarray["parent"] = 0;
- $datarray["plink"] = self::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 ($datarray["contact-id"] == 0)
+ if ($level > 5)
return false;
- self::fetch_guid($datarray);
- $message_id = item_store($datarray);
+ // 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;
- /// @TODO
- /// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
+ /// @todo - should maybe solved by the dispatcher
+ $source_xml = parse_xml_string($x, false);
- return $message_id;
-*/
+ if (!is_object($source_xml))
+ return false;
+
+ if ($source_xml->post->reshare) {
+ // Reshare of a reshare - old Diaspora version
+ return self::fetch_message($source_xml->post->reshare->root_guid, $server, ++$level);
+ } elseif ($source_xml->getName() == "reshare") {
+ // Reshare of a reshare - new Diaspora version
+ return self::fetch_message($source_xml->root_guid, $server, ++$level);
+ }
+
+ // 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)
+ $author = (string)$source_xml->author;
+
+ if (!$author)
+ return false;
+
+ $msg = array("message" => $x, "author" => $author);
+
+ // We don't really need this, but until the work is unfinished we better will keep this
+ $msg["key"] = self::get_key($msg["author"]);
+
+ return $msg;
}
private function post_allow($importer, $contact, $is_comment = false) {
@@ -485,7 +480,9 @@ die();
}
private function fetch_parent_item($uid, $guid, $author, $contact) {
- $r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `owner-name`, `owner-link`, `owner-avatar`, `origin`
+ $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));
@@ -500,8 +497,9 @@ die();
if ($result) {
logger("Fetched missing item ".$guid." - result: ".$result, LOGGER_DEBUG);
- $r = q("SELECT `id`, `body`, `wall`, `uri`, `private`,
- `owner-name`, `owner-link`, `owner-avatar`, `origin`
+ $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));
}
@@ -514,7 +512,49 @@ die();
return $r[0];
}
+ private function get_author_contact_by_url($contact, $person, $uid) {
+
+ $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;
+ }
+
+ return (array("cid" => $cid, "network" => $network));
+ }
+
+ public static function is_redmatrix($url) {
+ return(strstr($url, "/channel/"));
+ }
+
+ private function 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 (self::is_redmatrix($r[0]["url"]))
+ return $r[0]["url"]."/?f=&mid=".$guid;
+
+ return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
+ }
+
private function import_account_deletion($importer, $data) {
+ // Not supported by now. We are waiting for sample data
return true;
}
@@ -534,16 +574,16 @@ die();
logger("Ignoring the author ".$sender);
return false;
}
-/*
+
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer["uid"]),
dbesc($guid)
);
if(count($r)) {
logger("The comment already exists: ".$guid);
- return;
+ return false;
}
-*/
+
$parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item)
return false;
@@ -555,51 +595,39 @@ die();
}
// 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);
+ $author_contact = self::get_author_contact_by_url($contact, $person, $importer["uid"]);
$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"] = $author.":".$guid;
- $datarray["parent-uri"] = $parent_item["uri"];
+ $datarray["contact-id"] = $author_contact["cid"];
+ $datarray["network"] = $author_contact["network"];
- // The old Diaspora protocol doesn't have a timestamp for comments
- $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert();
- $datarray["private"] = $parent_item["private"];
+ $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["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($data);
+ $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"] = json_encode($data);
+
+ $datarray["body"] = diaspora2bb($text);
self::fetch_guid($datarray);
-// $message_id = item_store($datarray);
-print_r($datarray);
- $datarray["id"] = $message_id;
+ $message_id = item_store($datarray);
+ // print_r($datarray);
// If we are the origin of the parent we store the original data and notify our followers
if($message_id AND $parent_item["origin"]) {
@@ -622,6 +650,36 @@ print_r($datarray);
return true;
}
+ 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);
+ }
+
+ private function construct_like_object($importer, $parent_item) {
+ $objtype = ACTIVITY_OBJ_NOTE;
+ $link = xmlify(''."\n") ;
+ $parent_body = $parent_item["body"];
+
+ $obj = <<< EOT
+
+
+EOT;
+
+ return $obj;
+ }
+
private function import_like($importer, $sender, $data) {
$positive = notags(unxmlify($data->positive));
$guid = notags(unxmlify($data->guid));
@@ -649,7 +707,7 @@ print_r($datarray);
logger("Ignoring the author ".$sender);
return false;
}
-/*
+
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer["uid"]),
dbesc($guid)
@@ -658,7 +716,7 @@ print_r($datarray);
logger("The like already exists: ".$guid);
return false;
}
-*/
+
$parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item)
return false;
@@ -670,72 +728,37 @@ print_r($datarray);
}
// 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;
- }
-
-// ------------------------------------------------
- $objtype = ACTIVITY_OBJ_NOTE;
- $link = xmlify(''."\n") ;
- $parent_body = $parent_item["body"];
-
- $obj = <<< EOT
-
-
-EOT;
- $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]";
- $body = sprintf($bodyverb, $ulink, $alink, $plink);
-// ------------------------------------------------
+ $author_contact = self::get_author_contact_by_url($contact, $person, $importer["uid"]);
$datarray = array();
- $datarray["uri"] = $author.":".$guid;
$datarray["uid"] = $importer["uid"];
- $datarray["guid"] = $guid;
- $datarray["network"] = $network;
- $datarray["contact-id"] = $cid;
- $datarray["type"] = "activity";
- $datarray["wall"] = $parent_item["wall"];
- $datarray["gravity"] = GRAVITY_LIKE;
- $datarray["parent"] = $parent_item["id"];
- $datarray["parent-uri"] = $parent_item["uri"];
-
- $datarray["owner-name"] = $contact["name"];
- $datarray["owner-link"] = $contact["url"];
- $datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
+ $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["body"] = $body;
- $datarray["private"] = $parent_item["private"];
- $datarray["verb"] = ACTIVITY_LIKE;
- $datarray["object-type"] = $objtype;
- $datarray["object"] = $obj;
- $datarray["visible"] = 1;
- $datarray["unseen"] = 1;
- $datarray["last-child"] = 0;
+ $datarray["owner-name"] = $contact["name"];
+ $datarray["owner-link"] = $contact["url"];
+ $datarray["owner-avatar"] = ((x($contact,"thumb")) ? $contact["thumb"] : $contact["photo"]);
-print_r($datarray);
-// $message_id = item_store($datarray);
+ $datarray["guid"] = $guid;
+ $datarray["uri"] = $author.":".$guid;
+
+ $datarray["type"] = "activity";
+ $datarray["verb"] = ACTIVITY_LIKE;
+ $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);
+ //print_r($datarray);
// If we are the origin of the parent we store the original data and notify our followers
if($message_id AND $parent_item["origin"]) {
@@ -751,10 +774,86 @@ print_r($datarray);
proc_run("php", "include/notifier.php", "comment-import", $message_id);
}
- return true;
+ return $message_id;
}
private function import_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));
+
+ $parent_uri = $author.":".$parent_guid;
+
+ $contact = self::get_contact_by_handle($importer["uid"], $author);
+ if (!$contact) {
+ logger("cannot find contact: ".$author);
+ return false;
+ }
+
+ if(($contact["rel"] == CONTACT_IS_FOLLOWER) || ($contact["blocked"]) || ($contact["readonly"])) {
+ logger("Ignoring this author.");
+ return false;
+ }
+
+ $conversation = null;
+
+ $c = q("SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($conversation_guid)
+ );
+ if(count($c))
+ $conversation = $c[0];
+ else {
+ logger("conversation not available.");
+ return false;
+ }
+
+ $reply = 0;
+
+ $body = diaspora2bb($text);
+ $message_id = $author.":".$guid;
+
+ $person = self::get_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_id),
+ intval($importer["uid"])
+ );
+ if(count($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_id),
+ dbesc($parent_uri),
+ dbesc($created_at)
+ );
+
+ q("UPDATE `conv` SET `updated` = '%s' WHERE `id` = %d",
+ dbesc(datetime_convert()),
+ intval($conversation["id"])
+ );
+
return true;
}
@@ -771,14 +870,445 @@ print_r($datarray);
}
private function import_profile($importer, $data) {
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::get_contact_by_handle($importer["uid"], $author);
+ if (!$contact)
+ return;
+
+ $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);
+
return true;
}
private function import_request($importer, $data) {
+print_r($data);
+/*
+ $author = unxmlify($xml->author);
+ $recipient = unxmlify($xml->recipient);
+
+ if (!$author || !$recipient)
+ return;
+
+ $contact = self::get_contact_by_handle($importer["uid"],$author);
+
+ if($contact) {
+
+ // 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))) {
+ 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((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");
+
+ }
+
+ }
+
+ return;
+ }
+
+ $ret = self::get_person_by_handle($author);
+
+
+ if((! count($ret)) || ($ret["network"] != NETWORK_DIASPORA)) {
+ logger('diaspora_request: Cannot resolve diaspora handle ' . $author . ' for ' . $recipient);
+ 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"],$author);
+
+ 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 true;
}
private function import_reshare($importer, $data) {
+/*
+ $guid = notags(unxmlify($xml->guid));
+ $author = notags(unxmlify($xml->author));
+
+
+ if($author != $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"],$author);
+ if(! $contact)
+ return;
+
+ if(! diaspora_post_allow($importer,$contact, false)) {
+ logger('diaspora_reshare: Ignoring this author: ' . $author . ' ' . print_r($xml,true));
+ return 202;
+ }
+
+ $message_id = $author . ':' . $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;
+ }
+
+ $orig_author = notags(unxmlify($xml->root_diaspora_id));
+ $orig_guid = notags(unxmlify($xml->root_guid));
+ $orig_url = $a->get_baseurl()."/display/".$orig_guid;
+
+ $create_original_post = 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.');
+
+ // 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"];
+ }
+ }
+
+ if (!count($r)) {
+ $body = "";
+ $str_tags = "";
+ $app = "";
+
+ $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($author,strpos($author,'@')+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($author,strpos($author,'@')+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);
+ }
+
+ 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"];
+ }
+ }
+
+ $plink = diaspora_plink($author, $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"]);
+ $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]";
+
+ $datarray["object"] = json_encode($xml);
+ $datarray["object-type"] = $objecttype;
+
+ $datarray["tag"] = $str_tags;
+ $datarray["app"] = $app;
+
+ // 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);
+
+ // Store the original item of a reshare
+ if ($create_original_post) {
+ require_once("include/Contact.php");
+
+ $datarray2 = $datarray;
+
+ $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);
+ }
+
+ DiasporaFetchGuid($datarray);
+ $message_id = item_store($datarray);
+*/
return true;
}
@@ -786,8 +1316,131 @@ print_r($datarray);
return true;
}
- private function import_status_message($importer, $data) {
- return true;
+ private function import_status_message($importer, $data, $msg, $data2) {
+
+ $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));
+
+ foreach ($data->children() AS $name => $entry)
+ if (count($entry->children()))
+ if (!in_array($name, array("location", "photo", "poll")))
+ die("Kinder: ".$name."\n");
+/*
+ if ($data->location) {
+ print_r($location);
+ foreach ($data->location->children() AS $fieldname => $data)
+ echo $fieldname." - ".$data."\n";
+ die("Location!\n");
+ }
+*/
+/*
+ if ($data->photo) {
+ print_r($data->photo);
+ foreach ($data->photo->children() AS $fieldname => $data)
+ echo $fieldname." - ".$data."\n";
+ die("Photo!\n");
+ }
+*/
+
+ if ($data->poll) {
+ print_r($data2);
+ print_r($data);
+ die("poll!\n");
+ }
+
+
+ $contact = self::get_contact_by_handle($importer["uid"], $author);
+ if (!$contact) {
+ logger("A Contact for handle ".$author." and user ".$importer["uid"]." was not found");
+ return false;
+ }
+
+ if (!self::post_allow($importer, $contact, false)) {
+ logger("Ignoring this author.");
+ return false;
+ }
+/*
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($guid)
+ );
+ if(count($r)) {
+ logger("message exists: ".$guid);
+ return false;
+ }
+*/
+ $private = (($public == "false") ? 1 : 0);
+
+ $body = diaspora2bb($raw_message);
+
+ $datarray = array();
+
+ if($data->photo->remote_photo_path AND $data->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 (!self::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 = self::plink($author, $guid);
+
+ $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"] = json_encode($data);
+
+ $datarray["body"] = $body;
+
+ $datarray["tag"] = $str_tags;
+ if ($provider_display_name != "")
+ $datarray["app"] = $provider_display_name;
+
+ $datarray["plink"] = $plink;
+ $datarray["private"] = $private;
+ $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
+
+ // 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);
+
+ self::fetch_guid($datarray);
+ //$message_id = item_store($datarray);
+ print_r($datarray);
+
+ logger("Stored item with message id ".$message_id, LOGGER_DEBUG);
+
+ return $message_id;
}
}
?>
From 8bcbff30e0984f35bb3d36c22a2edbce437d6369 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 29 Feb 2016 23:54:25 +0100
Subject: [PATCH 018/485] Account deletion should work, status messages works -
reshares are half done.
---
include/diaspora2.php | 519 ++++++++++++++++++++++++++----------------
1 file changed, 328 insertions(+), 191 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 578a496c0a..59514ebc76 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -58,7 +58,7 @@ class diaspora {
// Use a dummy importer to import the data for the public copy
$importer = array("uid" => 0, "page-flags" => PAGE_FREELOVE);
- self::dispatch($importer,$msg);
+ $item_id = self::dispatch($importer,$msg);
// Now distribute it to the followers
$r = q("SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
@@ -74,6 +74,8 @@ class diaspora {
}
} else
logger("No subscribers for ".$msg["author"]." ".print_r($msg, true));
+
+ return $item_id;
}
public static function dispatch($importer, $msg) {
@@ -82,7 +84,7 @@ class diaspora {
// This will often be different with relayed messages (for example "like" and "comment")
$sender = $msg["author"];
- if (!diaspora::valid_posting($msg, $fields, $data2)) {
+ if (!diaspora::valid_posting($msg, $fields)) {
logger("Invalid posting");
return false;
}
@@ -90,8 +92,9 @@ class diaspora {
$type = $fields->getName();
switch ($type) {
- case "account_deletion": // Not implemented
- return self::import_account_deletion($importer, $fields);
+ case "account_deletion":
+ return true;
+ //return self::import_account_deletion($importer, $fields);
case "comment":
return true;
@@ -131,7 +134,8 @@ class diaspora {
return self::import_retraction($importer, $fields);
case "status_message":
- return self::import_status_message($importer, $fields, $msg, $data2);
+ return true;
+ //return self::import_status_message($importer, $fields, $msg, $data2);
default:
logger("Unknown message type ".$type);
@@ -152,7 +156,7 @@ class diaspora {
*
* @return bool Is the posting valid?
*/
- private function valid_posting($msg, &$fields, &$element) {
+ private function valid_posting($msg, &$fields) {
$data = parse_xml_string($msg["message"], false);
@@ -554,7 +558,16 @@ class diaspora {
}
private function import_account_deletion($importer, $data) {
- // Not supported by now. We are waiting for sample data
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::get_contact_by_handle($importer["uid"], $author);
+ if (!$contact) {
+ logger("cannot find contact for sender: ".$sender);
+ return false;
+ }
+
+ // We now remove the contact
+ contact_remove($contact["id"]);
return true;
}
@@ -647,6 +660,167 @@ class diaspora {
}
private function import_conversation($importer, $data) {
+/*
+ $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) {
+
+ $reply = 0;
+
+ $msg_guid = notags(unxmlify($mesg->guid));
+ $msg_parent_guid = notags(unxmlify($mesg->parent_guid));
+ $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_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;
+ }
+
+ $body = diaspora2bb($msg_text);
+ $message_id = $msg_diaspora_handle . ':' . $msg_guid;
+
+ $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid;
+
+ $author_signature = base64_decode($msg_author_signature);
+
+ if(strcasecmp($msg_diaspora_handle,$msg['author']) == 0) {
+ $person = $contact;
+ $key = $msg['key'];
+ }
+ else {
+ $person = find_diaspora_person_by_handle($msg_diaspora_handle);
+
+ if(is_array($person) && x($person,'pubkey'))
+ $key = $person['pubkey'];
+ else {
+ logger('diaspora_conversation: unable to find author details');
+ continue;
+ }
+ }
+
+ if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) {
+ logger('diaspora_conversation: verification failed.');
+ continue;
+ }
+
+ 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;
+
+ $parent_author_signature = base64_decode($msg_parent_author_signature);
+
+ $key = $msg['key'];
+
+ if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) {
+ logger('diaspora_conversation: owner verification failed.');
+ continue;
+ }
+ }
+
+ $r = q("select id from mail where `uri` = '%s' limit 1",
+ dbesc($message_id)
+ );
+ if(count($r)) {
+ logger('diaspora_conversation: duplicate message already delivered.', LOGGER_DEBUG);
+ continue;
+ }
+
+ 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($subject),
+ dbesc($body),
+ 0,
+ 0,
+ 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'])
+ );
+
+ 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'
+ ));
+ }
+*/
return true;
}
@@ -858,14 +1032,17 @@ EOT;
}
private function import_participation($importer, $data) {
+ // I'm not sure if we can fully support this message type
return true;
}
private function import_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;
}
private function import_poll_participation($importer, $data) {
+ // We don't support polls by now
return true;
}
@@ -1138,185 +1315,156 @@ print_r($data);
}
private function import_reshare($importer, $data) {
+ $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::get_contact_by_handle($importer["uid"], $author);
+ if (!$contact)
+ return false;
+
+ if (!self::post_allow($importer, $contact, false)) {
+ logger("Ignoring this author: ".$author." ".print_r($data,true));
+ return false;
+ }
/*
- $guid = notags(unxmlify($xml->guid));
- $author = notags(unxmlify($xml->author));
-
-
- if($author != $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"],$author);
- if(! $contact)
- return;
-
- if(! diaspora_post_allow($importer,$contact, false)) {
- logger('diaspora_reshare: Ignoring this author: ' . $author . ' ' . print_r($xml,true));
- return 202;
- }
-
- $message_id = $author . ':' . $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;
- }
-
- $orig_author = notags(unxmlify($xml->root_diaspora_id));
- $orig_guid = notags(unxmlify($xml->root_guid));
- $orig_url = $a->get_baseurl()."/display/".$orig_guid;
-
- $create_original_post = 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.');
-
- // 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"];
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($importer["uid"]),
+ dbesc($guid)
+ );
+ if(count($r)) {
+ logger("message exists: ".$guid);
+ return;
}
- }
+*/
+ $orig_author = $root_author;
+ $orig_guid = $root_guid;
+ $orig_url = App::get_baseurl()."/display/".$guid;
- if (!count($r)) {
- $body = "";
- $str_tags = "";
- $app = "";
+ $create_original_post = false;
- $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);
+ // 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.");
- if (!$item) {
- $server = 'https://'.substr($author,strpos($author,'@')+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($author,strpos($author,'@')+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);
+ // 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"];
+ }
}
- 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"];
+/* @todo
+ if (!count($r)) {
+ $body = "";
+ $str_tags = "";
+ $app = "";
+
+ $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 = self::fetch_message($orig_guid, $server);
+
+ if (!$item) {
+ $server = 'https://'.substr($author,strpos($author,'@')+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($author,strpos($author,'@')+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);
+ }
+
+ 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"];
+ }
}
- }
+*/
+ $plink = self::plink($author, $guid);
- $plink = diaspora_plink($author, $guid);
+ $person = self::get_person_by_handle($orig_author);
- $person = find_diaspora_person_by_handle($orig_author);
+ $private = (($public == "false") ? 1 : 0);
- $created = unxmlify($xml->created_at);
- $private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
+ $datarray = array();
- $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"]);
- $prefix = share_header($person["name"], $person["url"], ((x($person,'thumb')) ? $person["thumb"] : $person["photo"]), $orig_guid, $orig_created, $orig_url);
+ $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"] = $contact["thumb"];
+ $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"] = json_encode($data);
+
+ $prefix = share_header($person["name"], $person["url"], ((x($person,'thumb')) ? $person["thumb"] : $person["photo"]),
+ $orig_guid, $orig_created, $orig_url);
$datarray["body"] = $prefix.$body."[/share]";
- $datarray["object"] = json_encode($xml);
- $datarray["object-type"] = $objecttype;
+ $datarray["tag"] = $str_tags;
+ $datarray["app"] = $app;
- $datarray["tag"] = $str_tags;
- $datarray["app"] = $app;
+ $datarray["plink"] = $plink;
+ $datarray["private"] = $private;
+ $datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
- // 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);
+ $datarray["object-type"] = $objecttype;
- // Store the original item of a reshare
- if ($create_original_post) {
- require_once("include/Contact.php");
+ self::fetch_guid($datarray);
+ //$message_id = item_store($datarray);
+ print_r($datarray);
- $datarray2 = $datarray;
-
- $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);
- }
-
- DiasporaFetchGuid($datarray);
- $message_id = item_store($datarray);
-*/
- return true;
+ return $message_id;
}
private function import_retraction($importer, $data) {
return true;
}
- private function import_status_message($importer, $data, $msg, $data2) {
+ private function import_status_message($importer, $data) {
$raw_message = unxmlify($data->raw_message);
$guid = notags(unxmlify($data->guid));
@@ -1325,34 +1473,6 @@ print_r($data);
$created_at = notags(unxmlify($data->created_at));
$provider_display_name = notags(unxmlify($data->provider_display_name));
- foreach ($data->children() AS $name => $entry)
- if (count($entry->children()))
- if (!in_array($name, array("location", "photo", "poll")))
- die("Kinder: ".$name."\n");
-/*
- if ($data->location) {
- print_r($location);
- foreach ($data->location->children() AS $fieldname => $data)
- echo $fieldname." - ".$data."\n";
- die("Location!\n");
- }
-*/
-/*
- if ($data->photo) {
- print_r($data->photo);
- foreach ($data->photo->children() AS $fieldname => $data)
- echo $fieldname." - ".$data."\n";
- die("Photo!\n");
- }
-*/
-
- if ($data->poll) {
- print_r($data2);
- print_r($data);
- die("poll!\n");
- }
-
-
$contact = self::get_contact_by_handle($importer["uid"], $author);
if (!$contact) {
logger("A Contact for handle ".$author." and user ".$importer["uid"]." was not found");
@@ -1363,7 +1483,7 @@ print_r($data);
logger("Ignoring this author.");
return false;
}
-/*
+
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer["uid"]),
dbesc($guid)
@@ -1372,11 +1492,26 @@ print_r($data);
logger("message exists: ".$guid);
return false;
}
-*/
+
+ /// @todo enable support for polls
+ // if ($data->poll) {
+ // print_r($data->poll);
+ // die("poll!\n");
+ // }
+
+ $address = array();
+ if ($data->location)
+ foreach ($data->location->children() AS $fieldname => $data)
+ $address[$fieldname] = notags(unxmlify($data));
+
$private = (($public == "false") ? 1 : 0);
$body = diaspora2bb($raw_message);
+ if ($data->photo)
+ for ($i = 0; $i < count($data->photo); $i++)
+ $body = "[img]".$data->photo[$i]->remote_photo_path.$data->photo[$i]->remote_photo_name."[/img]\n".$body;
+
$datarray = array();
if($data->photo->remote_photo_path AND $data->photo->remote_photo_name)
@@ -1430,9 +1565,11 @@ print_r($data);
$datarray["private"] = $private;
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = datetime_convert("UTC", "UTC", $created_at);
- // if empty content it might be a photo that hasn't arrived yet. If a photo arrives, we'll make it visible.
+ if (isset($address["address"]))
+ $datarray["location"] = $address["address"];
- $datarray["visible"] = ((strlen($body)) ? 1 : 0);
+ if (isset($address["lat"]) AND isset($address["lng"]))
+ $datarray["coord"] = $address["lat"]." ".$address["lng"];
self::fetch_guid($datarray);
//$message_id = item_store($datarray);
From cb900c5742628ad437b7fc2d06d10e9999a06aaf Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 1 Mar 2016 07:57:26 +0100
Subject: [PATCH 019/485] Reshares could work now, code is cleaned
---
include/diaspora2.php | 356 +++++++++++++++++-------------------------
1 file changed, 147 insertions(+), 209 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 59514ebc76..a1297c5193 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -4,11 +4,14 @@
* @brief The implementation of the diaspora protocol
*/
+require_once("include/items.php");
require_once("include/bb2diaspora.php");
require_once("include/Scrape.php");
require_once("include/Contact.php");
require_once("include/Photo.php");
require_once("include/socgraph.php");
+require_once("include/group.php");
+require_once("include/api.php");
class xml {
function from_array($array, &$xml) {
@@ -380,6 +383,64 @@ class diaspora {
return false;
}
+ 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.
+ // 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("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)
+ return true;
+
+ // Messages for the global users are always accepted
+ if ($importer["uid"] == 0)
+ return true;
+
+ return false;
+ }
+
+ private function get_allowed_contact_by_handle($importer, $handle, $is_comment = false) {
+ $contact = self::get_contact_by_handle($importer["uid"], $handle);
+ if (!$contact) {
+ logger("A Contact for handle ".$handle." and user ".$importer["uid"]." was not found");
+ return false;
+ }
+
+ if (!self::post_allow($importer, $contact, false)) {
+ logger("The handle: ".$handle." is not allowed to post to user ".$importer["uid"]);
+ return false;
+ }
+ return $contact;
+ }
+
+ private function message_exists($uid, $guid) {
+ $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+ intval($uid),
+ dbesc($guid)
+ );
+
+ if(count($r)) {
+ logger("message ".$guid." already exists for user ".$uid);
+ return false;
+ }
+
+ return true;
+ }
+
private function fetch_guid($item) {
preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
function ($match) use ($item){
@@ -388,8 +449,6 @@ class diaspora {
}
private function fetch_guid_sub($match, $item) {
- $a = get_app();
-
if (!self::store_by_guid($match[1], $item["author-link"]))
self::store_by_guid($match[1], $item["owner-link"]);
}
@@ -453,36 +512,6 @@ class diaspora {
return $msg;
}
- 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.
- // 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("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)
- return true;
-
- // Messages for the global users are always accepted
- if ($importer["uid"] == 0)
- return true;
-
- return false;
- }
-
private function fetch_parent_item($uid, $guid, $author, $contact) {
$r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
`author-name`, `author-link`, `author-avatar`,
@@ -562,7 +591,7 @@ class diaspora {
$contact = self::get_contact_by_handle($importer["uid"], $author);
if (!$contact) {
- logger("cannot find contact for sender: ".$sender);
+ logger("cannot find contact for author: ".$author);
return false;
}
@@ -577,25 +606,12 @@ class diaspora {
$text = unxmlify($data->text);
$author = notags(unxmlify($data->author));
- $contact = self::get_contact_by_handle($importer["uid"], $sender);
- if (!$contact) {
- logger("cannot find contact for sender: ".$sender);
+ $contact = self::get_allowed_contact_by_handle($importer, $sender, true);
+ if (!$contact)
return false;
- }
- if (!self::post_allow($importer,$contact, true)) {
- logger("Ignoring the author ".$sender);
+ if (self::message_exists($importer["uid"], $guid))
return false;
- }
-
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer["uid"]),
- dbesc($guid)
- );
- if(count($r)) {
- logger("The comment already exists: ".$guid);
- return false;
- }
$parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item)
@@ -676,16 +692,9 @@ class diaspora {
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;
- }
+ $contact = self::get_allowed_contact_by_handle($importer, $sender, true)
+ if (!$contact)
+ return false;
$conversation = null;
@@ -871,25 +880,12 @@ EOT;
return false;
}
- $contact = self::get_contact_by_handle($importer["uid"], $sender);
- if (!$contact) {
- logger("cannot find contact for sender: ".$sender);
+ $contact = self::get_allowed_contact_by_handle($importer, $sender, true);
+ if (!$contact)
return false;
- }
- if (!self::post_allow($importer,$contact, true)) {
- logger("Ignoring the author ".$sender);
+ if (self::message_exists($importer["uid"], $guid))
return false;
- }
-
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer["uid"]),
- dbesc($guid)
- );
- if(count($r)) {
- logger("The like already exists: ".$guid);
- return false;
- }
$parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item)
@@ -961,16 +957,9 @@ EOT;
$parent_uri = $author.":".$parent_guid;
- $contact = self::get_contact_by_handle($importer["uid"], $author);
- if (!$contact) {
- logger("cannot find contact: ".$author);
+ $contact = self::get_allowed_contact_by_handle($importer, $author, true);
+ if (!$contact)
return false;
- }
-
- if(($contact["rel"] == CONTACT_IS_FOLLOWER) || ($contact["blocked"]) || ($contact["readonly"])) {
- logger("Ignoring this author.");
- return false;
- }
$conversation = null;
@@ -1159,7 +1148,6 @@ print_r($data);
);
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"])
@@ -1170,7 +1158,7 @@ print_r($data);
if(count($self) && $contact["rel"] == CONTACT_IS_FOLLOWER) {
$arr = array();
- $arr["uri"] = $arr["parent-uri"] = item_new_uri($a->get_hostname(), $importer["uid"]);
+ $arr["uri"] = $arr["parent-uri"] = item_new_uri(App::get_hostname(), $importer["uid"]);
$arr["uid"] = $importer["uid"];
$arr["contact-id"] = $self[0]["id"];
$arr["wall"] = 1;
@@ -1256,7 +1244,6 @@ print_r($data);
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"]);
}
@@ -1279,8 +1266,6 @@ print_r($data);
// 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),
@@ -1314,6 +1299,60 @@ print_r($data);
return true;
}
+ private function get_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(count($r)) {
+ logger("reshared message ".$guid." already exists on system.");
+
+ // 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
+ if (api_share_as_retweet($r[0]))
+ $r = array();
+ else
+ return $r[0];
+ }
+
+ if (!count($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 = 'https://'.substr($author,strpos($author,'@')+1);
+ logger("2nd try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
+ $item = self::store_by_guid($guid, $server);
+ }
+ if (!$item_id) {
+ $server = 'http://'.substr($orig_author,strpos($orig_author,'@')+1);
+ logger("3rd try: reshared message ".$guid." will be fetched from original server: ".$server);
+ $item = 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 = self::store_by_guid($guid, $server);
+ }
+
+ 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));
+
+ if ($r)
+ return $r[0];
+
+ }
+ }
+ return false;
+ }
+
private function import_reshare($importer, $data) {
$root_author = notags(unxmlify($data->root_author));
$root_guid = notags(unxmlify($data->root_guid));
@@ -1322,101 +1361,16 @@ print_r($data);
$public = notags(unxmlify($data->public));
$created_at = notags(unxmlify($data->created_at));
- $contact = self::get_contact_by_handle($importer["uid"], $author);
+ $contact = self::get_allowed_contact_by_handle($importer, $author, false);
if (!$contact)
return false;
- if (!self::post_allow($importer, $contact, false)) {
- logger("Ignoring this author: ".$author." ".print_r($data,true));
+// if (self::message_exists($importer["uid"], $guid))
+// return false;
+
+ $original_item = self::get_original_item($root_guid, $root_author, $author);
+ if (!$original_item)
return false;
- }
-/*
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer["uid"]),
- dbesc($guid)
- );
- if(count($r)) {
- logger("message exists: ".$guid);
- return;
- }
-*/
- $orig_author = $root_author;
- $orig_guid = $root_guid;
- $orig_url = App::get_baseurl()."/display/".$guid;
-
- $create_original_post = 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.");
-
- // 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"];
- }
- }
-
-/* @todo
- if (!count($r)) {
- $body = "";
- $str_tags = "";
- $app = "";
-
- $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 = self::fetch_message($orig_guid, $server);
-
- if (!$item) {
- $server = 'https://'.substr($author,strpos($author,'@')+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($author,strpos($author,'@')+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);
- }
-
- 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"];
- }
- }
-*/
- $plink = self::plink($author, $guid);
-
- $person = self::get_person_by_handle($orig_author);
-
- $private = (($public == "false") ? 1 : 0);
$datarray = array();
@@ -1440,18 +1394,18 @@ print_r($data);
$datarray["object"] = json_encode($data);
- $prefix = share_header($person["name"], $person["url"], ((x($person,'thumb')) ? $person["thumb"] : $person["photo"]),
- $orig_guid, $orig_created, $orig_url);
- $datarray["body"] = $prefix.$body."[/share]";
+ $prefix = share_header($original_item["author-name"], $original_item["author-link"], $original_item["author-avatar"],
+ $original_item["guid"], $original_item["created"], $original_item["uri"]);
+ $datarray["body"] = $prefix.$original_item["body"]."[/share]";
- $datarray["tag"] = $str_tags;
- $datarray["app"] = $app;
+ $datarray["tag"] = $original_item["tag"];
+ $datarray["app"] = $original_item["app"];
- $datarray["plink"] = $plink;
- $datarray["private"] = $private;
+ $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"] = $objecttype;
+ $datarray["object-type"] = $original_item["object-type"];
self::fetch_guid($datarray);
//$message_id = item_store($datarray);
@@ -1473,25 +1427,12 @@ print_r($data);
$created_at = notags(unxmlify($data->created_at));
$provider_display_name = notags(unxmlify($data->provider_display_name));
- $contact = self::get_contact_by_handle($importer["uid"], $author);
- if (!$contact) {
- logger("A Contact for handle ".$author." and user ".$importer["uid"]." was not found");
+ $contact = self::get_allowed_contact_by_handle($importer, $author, false);
+ if (!$contact)
return false;
- }
- if (!self::post_allow($importer, $contact, false)) {
- logger("Ignoring this author.");
+ if (self::message_exists($importer["uid"], $guid))
return false;
- }
-
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($importer["uid"]),
- dbesc($guid)
- );
- if(count($r)) {
- logger("message exists: ".$guid);
- return false;
- }
/// @todo enable support for polls
// if ($data->poll) {
@@ -1504,8 +1445,6 @@ print_r($data);
foreach ($data->location->children() AS $fieldname => $data)
$address[$fieldname] = notags(unxmlify($data));
- $private = (($public == "false") ? 1 : 0);
-
$body = diaspora2bb($raw_message);
if ($data->photo)
@@ -1533,7 +1472,6 @@ print_r($data);
$str_tags .= "@[url=".$mtch[1]."[/url]";
}
}
- $plink = self::plink($author, $guid);
$datarray["uid"] = $importer["uid"];
$datarray["contact-id"] = $contact["id"];
@@ -1561,8 +1499,8 @@ print_r($data);
if ($provider_display_name != "")
$datarray["app"] = $provider_display_name;
- $datarray["plink"] = $plink;
- $datarray["private"] = $private;
+ $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"]))
From 009cadf63beada12c3e53f5d60a5542321a3f470 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 1 Mar 2016 19:10:35 +0100
Subject: [PATCH 020/485] Just another commit message :-)
---
include/diaspora.php | 6 +++---
include/diaspora2.php | 8 +++++---
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 4ec7489ca4..9db9e6056e 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -146,9 +146,9 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
$ret = diaspora_participation($importer,$xmlbase->participation);
}
elseif($xmlbase->poll_participation) {
- $tempfile = tempnam(get_temppath(), "diaspora-poll_participation");
- file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_participation($importer,$xmlbase->participation);
+ //$tempfile = tempnam(get_temppath(), "diaspora-poll_participation");
+ //file_put_contents($tempfile, json_encode($data));
+ $ret = diaspora_participation($importer,$xmlbase->poll_participation);
}
else {
$tempfile = tempnam(get_temppath(), "diaspora-unknown");
diff --git a/include/diaspora2.php b/include/diaspora2.php
index a1297c5193..e8ed80ee80 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -131,7 +131,8 @@ class diaspora {
return self::import_request($importer, $fields);
case "reshare":
- return self::import_reshare($importer, $fields);
+ return true;
+ //return self::import_reshare($importer, $fields);
case "retraction":
return self::import_retraction($importer, $fields);
@@ -676,6 +677,8 @@ class diaspora {
}
private function import_conversation($importer, $data) {
+ print_r($data);
+ die();
/*
$guid = notags(unxmlify($xml->guid));
$subject = notags(unxmlify($xml->subject));
@@ -874,9 +877,8 @@ EOT;
if ($parent_type !== "Post")
return false;
- // "positive" = "false" doesn't seem to be supported by Diaspora
+ // "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora
if ($positive === "false") {
- logger("Received a like with positive set to 'false' - this shouldn't exist at all");
return false;
}
From f1dae26df8a9f46d683716b48b9b739f02824302 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 1 Mar 2016 23:21:56 +0100
Subject: [PATCH 021/485] Likes would now work with unlikes and with likes on
comments.
---
include/diaspora2.php | 48 +++++++++++++++++++++++--------------------
1 file changed, 26 insertions(+), 22 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index e8ed80ee80..97d22b4b97 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -104,7 +104,8 @@ class diaspora {
//return self::import_comment($importer, $sender, $fields);
case "conversation":
- return self::import_conversation($importer, $fields);
+ return true;
+ //return self::import_conversation($importer, $fields);
case "like":
return true;
@@ -138,8 +139,8 @@ class diaspora {
return self::import_retraction($importer, $fields);
case "status_message":
- return true;
- //return self::import_status_message($importer, $fields, $msg, $data2);
+ //return true;
+ return self::import_status_message($importer, $fields);
default:
logger("Unknown message type ".$type);
@@ -246,7 +247,7 @@ class diaspora {
}
// Only some message types have signatures. So we quit here for the other types.
- if (!in_array($type, array("comment", "conversation", "message", "like")))
+ if (!in_array($type, array("comment", "message", "like")))
return true;
// No author_signature? This is a must, so we quit.
@@ -691,7 +692,7 @@ class diaspora {
$messages = $xml->message;
if(! count($messages)) {
- logger('diaspora_conversation: empty conversation');
+ logger('empty conversation');
return;
}
@@ -874,14 +875,10 @@ EOT;
$author = notags(unxmlify($data->author));
// likes on comments aren't supported by Diaspora - only on posts
- if ($parent_type !== "Post")
+ // But maybe this will be supported in the future, so we will accept it.
+ if (!in_array($parent_type, array("Post", "Comment")))
return false;
- // "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora
- if ($positive === "false") {
- return false;
- }
-
$contact = self::get_allowed_contact_by_handle($importer, $sender, true);
if (!$contact)
return false;
@@ -902,6 +899,13 @@ EOT;
// Fetch the contact id - if we know this contact
$author_contact = self::get_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"];
@@ -920,7 +924,7 @@ EOT;
$datarray["uri"] = $author.":".$guid;
$datarray["type"] = "activity";
- $datarray["verb"] = ACTIVITY_LIKE;
+ $datarray["verb"] = $verb;
$datarray["gravity"] = GRAVITY_LIKE;
$datarray["parent-uri"] = $parent_item["uri"];
@@ -1429,18 +1433,18 @@ print_r($data);
$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::get_allowed_contact_by_handle($importer, $author, false);
if (!$contact)
return false;
- if (self::message_exists($importer["uid"], $guid))
- return false;
-
- /// @todo enable support for polls
- // if ($data->poll) {
- // print_r($data->poll);
- // die("poll!\n");
- // }
+ //if (self::message_exists($importer["uid"], $guid))
+ // return false;
$address = array();
if ($data->location)
@@ -1450,8 +1454,8 @@ print_r($data);
$body = diaspora2bb($raw_message);
if ($data->photo)
- for ($i = 0; $i < count($data->photo); $i++)
- $body = "[img]".$data->photo[$i]->remote_photo_path.$data->photo[$i]->remote_photo_name."[/img]\n".$body;
+ foreach ($data->photo AS $photo)
+ $body = "[img]".$photo->remote_photo_path.$photo->remote_photo_name."[/img]\n".$body;
$datarray = array();
From 66919761ab9ab60f1e6d3cac0810a6846e1e3a47 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 2 Mar 2016 23:28:20 +0100
Subject: [PATCH 022/485] Some work at the retractions.
---
include/diaspora.php | 8 +-
include/diaspora2.php | 381 +++++++++++++++++++++++++-----------------
2 files changed, 230 insertions(+), 159 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 9db9e6056e..0e0a860311 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -116,13 +116,13 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
$ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
}
elseif($xmlbase->signed_retraction) {
- //$tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
- //file_put_contents($tempfile, json_encode($data));
+ $tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
}
elseif($xmlbase->relayable_retraction) {
- //$tempfile = tempnam(get_temppath(), "diaspora-relayable_retraction");
- //file_put_contents($tempfile, json_encode($data));
+ $tempfile = tempnam(get_temppath(), "diaspora-relayable_retraction");
+ file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
}
elseif($xmlbase->photo) {
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 97d22b4b97..baf117b102 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -95,11 +95,11 @@ class diaspora {
$type = $fields->getName();
switch ($type) {
- case "account_deletion":
+ case "account_deletion": // Done
return true;
//return self::import_account_deletion($importer, $fields);
- case "comment":
+ case "comment": // Done
return true;
//return self::import_comment($importer, $sender, $fields);
@@ -107,40 +107,40 @@ class diaspora {
return true;
//return self::import_conversation($importer, $fields);
- case "like":
+ case "like": // Done
return true;
//return self::import_like($importer, $sender, $fields);
- case "message":
+ case "message": // Done
return true;
//return self::import_message($importer, $fields);
case "participation": // Not implemented
return self::import_participation($importer, $fields);
- case "photo":
+ case "photo": // Not needed
return self::import_photo($importer, $fields);
case "poll_participation": // Not implemented
return self::import_poll_participation($importer, $fields);
- case "profile":
+ case "profile": // Done
return true;
//return self::import_profile($importer, $fields);
case "request":
return self::import_request($importer, $fields);
- case "reshare":
+ case "reshare": // Done
return true;
//return self::import_reshare($importer, $fields);
case "retraction":
return self::import_retraction($importer, $fields);
- case "status_message":
- //return true;
- return self::import_status_message($importer, $fields);
+ case "status_message": // Done
+ return true;
+ //return self::import_status_message($importer, $fields);
default:
logger("Unknown message type ".$type);
@@ -567,25 +567,25 @@ class diaspora {
}
private function plink($addr, $guid) {
- $r = q("SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", dbesc($addr));
+ $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;
+ // 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"];
+ // 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 ($r[0]["network"] == NETWORK_DFRN)
+ return(str_replace("/profile/".$r[0]["nick"]."/", "/display/".$guid, $r[0]["url"]."/"));
- if (self::is_redmatrix($r[0]["url"]))
- return $r[0]["url"]."/?f=&mid=".$guid;
+ if (self::is_redmatrix($r[0]["url"]))
+ return $r[0]["url"]."/?f=&mid=".$guid;
- return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
+ return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
}
private function import_account_deletion($importer, $data) {
@@ -681,158 +681,158 @@ class diaspora {
print_r($data);
die();
/*
- $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)));
+ $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;
+ $parent_uri = $diaspora_handle . ':' . $guid;
- $messages = $xml->message;
+ $messages = $xml->message;
- if(! count($messages)) {
- logger('empty conversation');
- return;
- }
+ if(! count($messages)) {
+ logger('empty conversation');
+ return;
+ }
$contact = self::get_allowed_contact_by_handle($importer, $sender, true)
if (!$contact)
return false;
- $conversation = null;
+ $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;
- }
+ $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) {
+ foreach($messages as $mesg) {
- $reply = 0;
+ $reply = 0;
- $msg_guid = notags(unxmlify($mesg->guid));
- $msg_parent_guid = notags(unxmlify($mesg->parent_guid));
- $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_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;
- }
+ $msg_guid = notags(unxmlify($mesg->guid));
+ $msg_parent_guid = notags(unxmlify($mesg->parent_guid));
+ $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_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;
+ }
- $body = diaspora2bb($msg_text);
- $message_id = $msg_diaspora_handle . ':' . $msg_guid;
+ $body = diaspora2bb($msg_text);
+ $message_id = $msg_diaspora_handle . ':' . $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_diaspora_handle . ';' . $msg_conversation_guid;
- $author_signature = base64_decode($msg_author_signature);
+ $author_signature = base64_decode($msg_author_signature);
- if(strcasecmp($msg_diaspora_handle,$msg['author']) == 0) {
- $person = $contact;
- $key = $msg['key'];
- }
- else {
- $person = find_diaspora_person_by_handle($msg_diaspora_handle);
+ if(strcasecmp($msg_diaspora_handle,$msg["author"]) == 0) {
+ $person = $contact;
+ $key = $msg["key"];
+ }
+ else {
+ $person = find_diaspora_person_by_handle($msg_diaspora_handle);
- if(is_array($person) && x($person,'pubkey'))
- $key = $person['pubkey'];
- else {
- logger('diaspora_conversation: unable to find author details');
- continue;
- }
- }
+ if(is_array($person) && x($person,'pubkey'))
+ $key = $person["pubkey"];
+ else {
+ logger('diaspora_conversation: unable to find author details');
+ continue;
+ }
+ }
- 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('diaspora_conversation: verification failed.');
+ continue;
+ }
- 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;
+ 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;
- $parent_author_signature = base64_decode($msg_parent_author_signature);
+ $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('diaspora_conversation: owner verification failed.');
+ continue;
+ }
+ }
- $r = q("select id from mail where `uri` = '%s' limit 1",
- dbesc($message_id)
- );
- if(count($r)) {
- logger('diaspora_conversation: duplicate message already delivered.', LOGGER_DEBUG);
- continue;
- }
+ $r = q("select id from mail where `uri` = '%s' limit 1",
+ dbesc($message_id)
+ );
+ if(count($r)) {
+ logger('diaspora_conversation: duplicate message already delivered.', LOGGER_DEBUG);
+ continue;
+ }
- 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($subject),
- dbesc($body),
- 0,
- 0,
- dbesc($message_id),
- dbesc($parent_uri),
- dbesc($msg_created_at)
- );
+ 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($subject),
+ dbesc($body),
+ 0,
+ 0,
+ 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'])
- );
+ q("update conv set updated = '%s' where id = %d",
+ dbesc(datetime_convert()),
+ 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'
- ));
- }
+ 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'
+ ));
+ }
*/
return true;
}
@@ -1420,7 +1420,78 @@ print_r($data);
return $message_id;
}
+ private function item_retraction($importer, $contact, $data) {
+ $target_guid = notags(unxmlify($data->target_guid));
+
+ $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 (!$r)
+ return false;
+
+ // Only delete it if the author really fits
+ if (!link_compare($r[0]["author-link"],$contact["url"]))
+ 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"]);
+
+ // 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"]) {
+
+ // Formerly we stored the signed text, the signature and the author in different fields.
+ // The new Diaspora protocol can have variable fields. We now store the data in correct order in a single field.
+ q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
+ intval($r[0]["id"]),
+ dbesc(json_encode($data))
+ );
+
+ // the existence of parent_author_signature would have meant the parent_author or owner
+ // is already relaying.
+ logger("relaying retraction");
+
+ proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
+ }
+ }
+ }
+
private function import_retraction($importer, $data) {
+ $target_type = notags(unxmlify($data->target_type));
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::get_contact_by_handle($importer["uid"], $author);
+ if (!$contact) {
+ logger("cannot find contact for author: ".$author);
+ return false;
+ }
+
+ switch ($target_type) {
+ case "Comment": case "Like": case "StatusMessage":
+ self::item_retraction($importer, $contact, $data);
+ break;
+
+ case "Person":
+ contact_remove($contact["id"]);
+ return true;
+
+ default:
+ logger("Unknown target type ".$target_type);
+ }
return true;
}
@@ -1434,11 +1505,11 @@ print_r($data);
$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");
- }
+ //if ($data->poll) {
+ // foreach ($data->poll AS $poll)
+ // print_r($poll);
+ // die("poll!\n");
+ //}
$contact = self::get_allowed_contact_by_handle($importer, $author, false);
if (!$contact)
return false;
From 5adecf5b50e11fb6016cc089426f74b8f930ed0b Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 2 Mar 2016 23:39:50 +0100
Subject: [PATCH 023/485] Some beautification
---
include/diaspora2.php | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index baf117b102..4d0e4c2cb8 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -1524,16 +1524,16 @@ print_r($data);
$body = diaspora2bb($raw_message);
- if ($data->photo)
+ $datarray = array();
+
+ if ($data->photo) {
foreach ($data->photo AS $photo)
$body = "[img]".$photo->remote_photo_path.$photo->remote_photo_name."[/img]\n".$body;
- $datarray = array();
-
- if($data->photo->remote_photo_path AND $data->photo->remote_photo_name)
$datarray["object-type"] = ACTIVITY_OBJ_PHOTO;
- else {
+ } 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);
@@ -1541,6 +1541,7 @@ print_r($data);
$str_tags = "";
+ // This doesn't work. @todo Check if the "tag" field is filled in the "item_store" function.
$cnt = preg_match_all("/@\[url=(.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
From 2edf4548dca3ff2df4765be957766af91c4930d2 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Thu, 3 Mar 2016 23:34:17 +0100
Subject: [PATCH 024/485] Retractions could work now.
---
include/diaspora2.php | 170 ++++++++++++++++++++++++++----------------
1 file changed, 105 insertions(+), 65 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 4d0e4c2cb8..59a5c372db 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -13,6 +13,10 @@ require_once("include/socgraph.php");
require_once("include/group.php");
require_once("include/api.php");
+/**
+ * @brief This class contain functions to work with XML data
+ *
+ */
class xml {
function from_array($array, &$xml) {
@@ -45,12 +49,20 @@ class xml {
}
}
}
+
/**
* @brief This class contain functions to create and send Diaspora XML files
*
*/
class diaspora {
+ /**
+ * @brief Dispatches public messages and find the fitting receivers
+ *
+ * @param array $msg The post that will be dispatched
+ *
+ * @return bool Was the message accepted?
+ */
public static function dispatch_public($msg) {
$enabled = intval(get_config("system", "diaspora_enabled"));
@@ -81,6 +93,14 @@ class diaspora {
return $item_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 bool Was the message accepted?
+ */
public static function dispatch($importer, $msg) {
// The sender is the handle of the contact that sent the message.
@@ -104,8 +124,8 @@ class diaspora {
//return self::import_comment($importer, $sender, $fields);
case "conversation":
- return true;
- //return self::import_conversation($importer, $fields);
+ //return true;
+ return self::import_conversation($importer, $fields);
case "like": // Done
return true;
@@ -129,18 +149,20 @@ class diaspora {
//return self::import_profile($importer, $fields);
case "request":
+ //return true;
return self::import_request($importer, $fields);
case "reshare": // Done
return true;
//return self::import_reshare($importer, $fields);
- case "retraction":
- return self::import_retraction($importer, $fields);
-
- case "status_message": // Done
+ case "retraction": // Done
return true;
- //return self::import_status_message($importer, $fields);
+ //return self::import_retraction($importer, $sender, $fields);
+
+ case "status_message":
+ //return true;
+ return self::import_status_message($importer, $fields);
default:
logger("Unknown message type ".$type);
@@ -181,6 +203,7 @@ class diaspora {
}
$type = $element->getName();
+ $orig_type = $type;
// All retractions are handled identically from now on.
// In the new version there will only be "retraction".
@@ -235,7 +258,8 @@ class diaspora {
$signed_data .= $entry;
}
- if (!in_array($fieldname, array("parent_author_signature", "target_author_signature")))
+ if (!in_array($fieldname, array("parent_author_signature", "target_author_signature")) OR
+ ($orig_type == "relayable_retraction"))
xml::copy($entry, $fields, $fieldname);
}
@@ -266,6 +290,13 @@ class diaspora {
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 get_key($handle) {
logger("Fetching diaspora key for: ".$handle);
@@ -276,6 +307,13 @@ class diaspora {
return "";
}
+ /**
+ * @brief Fetches data for a given handle
+ *
+ * @param string $handle The handle
+ *
+ * @return array the queried data
+ */
private function get_person_by_handle($handle) {
$r = q("SELECT * FROM `fcontact` WHERE `network` = '%s' AND `addr` = '%s' LIMIT 1",
@@ -306,6 +344,14 @@ class diaspora {
return $person;
}
+ /**
+ * @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) {
/// @todo Remove this function from include/network.php
@@ -477,13 +523,12 @@ class diaspora {
if ($level > 5)
return false;
- // This will not work if the server is not a Diaspora server
+ // This will work for Diaspora and newer Friendica servers
$source_url = $server."/p/".$guid.".xml";
$x = fetch_url($source_url);
if(!$x)
return false;
- /// @todo - should maybe solved by the dispatcher
$source_xml = parse_xml_string($x, false);
if (!is_object($source_xml))
@@ -664,7 +709,7 @@ class diaspora {
if($message_id AND $parent_item["origin"]) {
// Formerly we stored the signed text, the signature and the author in different fields.
- // The new Diaspora protocol can have variable fields. We now store the data in correct order in a single field.
+ // 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))
@@ -678,6 +723,7 @@ class diaspora {
}
private function import_conversation($importer, $data) {
+ // @todo
print_r($data);
die();
/*
@@ -934,13 +980,13 @@ EOT;
$datarray["body"] = self::construct_like_body($contact, $parent_item, $guid);
$message_id = item_store($datarray);
- //print_r($datarray);
+ // print_r($datarray);
// 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.
- // The new Diaspora protocol can have variable fields. We now store the data in correct order in a single field.
+ // 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))
@@ -1125,7 +1171,8 @@ EOT;
}
private function import_request($importer, $data) {
-print_r($data);
+ // @todo
+ print_r($data);
/*
$author = unxmlify($xml->author);
$recipient = unxmlify($xml->recipient);
@@ -1371,8 +1418,8 @@ print_r($data);
if (!$contact)
return false;
-// if (self::message_exists($importer["uid"], $guid))
-// return false;
+ if (self::message_exists($importer["uid"], $guid))
+ return false;
$original_item = self::get_original_item($root_guid, $root_author, $author);
if (!$original_item)
@@ -1414,14 +1461,22 @@ print_r($data);
$datarray["object-type"] = $original_item["object-type"];
self::fetch_guid($datarray);
- //$message_id = item_store($datarray);
- print_r($datarray);
+ $message_id = item_store($datarray);
+ // print_r($datarray);
return $message_id;
}
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::get_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),
@@ -1431,7 +1486,15 @@ print_r($data);
return false;
// Only delete it if the author really fits
- if (!link_compare($r[0]["author-link"],$contact["url"]))
+ if (!link_compare($r[0]["author-link"],$person["url"]))
+ return false;
+
+ // Check if the sender is the thread owner
+ $p = q("SELECT `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"]))
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
@@ -1443,47 +1506,36 @@ print_r($data);
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"]) {
+ if($p[0]["origin"]) {
- // Formerly we stored the signed text, the signature and the author in different fields.
- // The new Diaspora protocol can have variable fields. We now store the data in correct order in a single field.
- q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
- intval($r[0]["id"]),
- dbesc(json_encode($data))
- );
+ // 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($r[0]["id"]),
+ dbesc(json_encode($data))
+ );
- // the existence of parent_author_signature would have meant the parent_author or owner
- // is already relaying.
- logger("relaying retraction");
-
- proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
- }
+ // notify others
+ proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
}
}
- private function import_retraction($importer, $data) {
+ private function import_retraction($importer, $sender, $data) {
$target_type = notags(unxmlify($data->target_type));
- $author = notags(unxmlify($data->author));
- $contact = self::get_contact_by_handle($importer["uid"], $author);
+ $contact = self::get_contact_by_handle($importer["uid"], $sender);
if (!$contact) {
- logger("cannot find contact for author: ".$author);
+ logger("cannot find contact for sender: ".$sender." and user ".$importer["uid"]);
return false;
}
switch ($target_type) {
- case "Comment": case "Like": case "StatusMessage":
- self::item_retraction($importer, $contact, $data);
- break;
+ 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":
contact_remove($contact["id"]);
@@ -1491,6 +1543,7 @@ print_r($data);
default:
logger("Unknown target type ".$target_type);
+ return false;
}
return true;
}
@@ -1514,8 +1567,8 @@ print_r($data);
if (!$contact)
return false;
- //if (self::message_exists($importer["uid"], $guid))
- // return false;
+ if (self::message_exists($importer["uid"], $guid))
+ return false;
$address = array();
if ($data->location)
@@ -1539,18 +1592,6 @@ print_r($data);
$body = add_page_info_to_body($body, false, true);
}
- $str_tags = "";
-
- // This doesn't work. @todo Check if the "tag" field is filled in the "item_store" function.
- $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]";
- }
- }
-
$datarray["uid"] = $importer["uid"];
$datarray["contact-id"] = $contact["id"];
$datarray["network"] = NETWORK_DIASPORA;
@@ -1573,7 +1614,6 @@ print_r($data);
$datarray["body"] = $body;
- $datarray["tag"] = $str_tags;
if ($provider_display_name != "")
$datarray["app"] = $provider_display_name;
@@ -1588,8 +1628,8 @@ print_r($data);
$datarray["coord"] = $address["lat"]." ".$address["lng"];
self::fetch_guid($datarray);
- //$message_id = item_store($datarray);
- print_r($datarray);
+ $message_id = item_store($datarray);
+ // print_r($datarray);
logger("Stored item with message id ".$message_id, LOGGER_DEBUG);
From ef3620c191add50b212fc5479abc0a6d1f04db6c Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Fri, 4 Mar 2016 23:28:43 +0100
Subject: [PATCH 025/485] Conversations should work now too.
---
include/diaspora2.php | 282 +++++++++++++++++++++---------------------
1 file changed, 141 insertions(+), 141 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 59a5c372db..b834e3deb9 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -22,7 +22,7 @@ class xml {
if (!is_object($xml)) {
foreach($array as $key => $value) {
- $root = new SimpleXMLElement('<'.$key.'/>');
+ $root = new SimpleXMLElement("<".$key."/>");
array_to_xml($value, $root);
$dom = dom_import_simplexml($root)->ownerDocument;
@@ -82,7 +82,7 @@ class diaspora {
dbesc(NETWORK_DIASPORA),
dbesc($msg["author"])
);
- if(count($r)) {
+ if($r) {
foreach($r as $rr) {
logger("delivering to: ".$rr["username"]);
self::dispatch($rr,$msg);
@@ -125,7 +125,7 @@ class diaspora {
case "conversation":
//return true;
- return self::import_conversation($importer, $fields);
+ return self::import_conversation($importer, $msg, $fields);
case "like": // Done
return true;
@@ -320,7 +320,7 @@ class diaspora {
dbesc(NETWORK_DIASPORA),
dbesc($handle)
);
- if (count($r)) {
+ if ($r) {
$person = $r[0];
logger("In cache ".print_r($r,true), LOGGER_DEBUG);
@@ -336,7 +336,7 @@ class diaspora {
// Note that Friendica contacts will return a "Diaspora person"
// if Diaspora connectivity is enabled on their server
- if (count($r) AND ($r["network"] === NETWORK_DIASPORA)) {
+ if ($r AND ($r["network"] === NETWORK_DIASPORA)) {
self::add_fcontact($r, $update);
$person = $r;
}
@@ -415,17 +415,17 @@ class diaspora {
dbesc($handle)
);
- if ($r AND count($r))
+ if ($r)
return $r[0];
$handle_parts = explode("@", $handle);
- $nurl_sql = '%%://' . $handle_parts[1] . '%%/profile/' . $handle_parts[0];
+ $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 AND count($r))
+ if($r)
return $r[0];
return false;
@@ -481,7 +481,7 @@ class diaspora {
dbesc($guid)
);
- if(count($r)) {
+ if($r) {
logger("message ".$guid." already exists for user ".$uid);
return false;
}
@@ -566,7 +566,7 @@ class diaspora {
FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($uid), dbesc($guid));
- if(!count($r)) {
+ if(!$r) {
$result = self::store_by_guid($guid, $contact["url"], $uid);
if (!$result) {
@@ -585,7 +585,7 @@ class diaspora {
}
}
- if (!count($r)) {
+ if (!$r) {
logger("parent item not found: parent: ".$guid." item: ".$guid);
return false;
} else
@@ -722,62 +722,10 @@ class diaspora {
return $message_id;
}
- private function import_conversation($importer, $data) {
- // @todo
- print_r($data);
- die();
-/*
- $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('empty conversation');
- return;
- }
-
- $contact = self::get_allowed_contact_by_handle($importer, $sender, true)
- if (!$contact)
- return false;
-
- $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) {
+ private function import_conversation_message($importer, $contact, $data, $msg, $mesg) {
+ $guid = notags(unxmlify($data->guid));
+ $subject = notags(unxmlify($data->subject));
+ $author = notags(unxmlify($data->author));
$reply = 0;
@@ -786,63 +734,64 @@ class diaspora {
$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)));
+ $msg_author = notags(unxmlify($mesg->diaspora_handle));
$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);
+ } else {
+ $person = self::get_person_by_handle($msg_author);
- if(is_array($person) && x($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"];
- 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')",
+ 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"]),
@@ -854,32 +803,86 @@ class diaspora {
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"])
);
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"
));
}
-*/
+
+ private function import_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));
+
+ $messages = $data->message;
+
+ if (!count($messages)) {
+ logger("empty conversation");
+ return false;
+ }
+
+ $contact = self::get_allowed_contact_by_handle($importer, $msg["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($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::import_conversation_message($importer, $contact, $data, $msg, $mesg);
+
return true;
}
@@ -1007,8 +1010,6 @@ EOT;
$author = notags(unxmlify($data->author));
$conversation_guid = notags(unxmlify($data->conversation_guid));
- $parent_uri = $author.":".$parent_guid;
-
$contact = self::get_allowed_contact_by_handle($importer, $author, true);
if (!$contact)
return false;
@@ -1019,7 +1020,7 @@ EOT;
intval($importer["uid"]),
dbesc($conversation_guid)
);
- if(count($c))
+ if($c)
$conversation = $c[0];
else {
logger("conversation not available.");
@@ -1029,7 +1030,7 @@ EOT;
$reply = 0;
$body = diaspora2bb($text);
- $message_id = $author.":".$guid;
+ $message_uri = $author.":".$guid;
$person = self::get_person_by_handle($author);
if (!$person) {
@@ -1038,10 +1039,10 @@ EOT;
}
$r = q("SELECT `id` FROM `mail` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
- dbesc($message_id),
+ dbesc($message_uri),
intval($importer["uid"])
);
- if(count($r)) {
+ if($r) {
logger("duplicate message already delivered.", LOGGER_DEBUG);
return false;
}
@@ -1059,8 +1060,8 @@ EOT;
dbesc($body),
0,
1,
- dbesc($message_id),
- dbesc($parent_uri),
+ dbesc($message_uri),
+ dbesc($author.":".$parent_guid),
dbesc($created_at)
);
@@ -1174,8 +1175,8 @@ EOT;
// @todo
print_r($data);
/*
- $author = unxmlify($xml->author);
- $recipient = unxmlify($xml->recipient);
+ $author = unxmlify($data->author);
+ $recipient = unxmlify($data->recipient);
if (!$author || !$recipient)
return;
@@ -1200,7 +1201,7 @@ EOT;
intval($importer["uid"])
);
- if((count($r)) && (!$r[0]["hide-friends"]) && (!$contact["hidden"]) && intval(get_pconfig($importer["uid"],'system','post_newfriend'))) {
+ if($r && !$r[0]["hide-friends"] && !$contact["hidden"] && intval(get_pconfig($importer["uid"],'system','post_newfriend'))) {
$self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
intval($importer["uid"])
@@ -1208,7 +1209,7 @@ EOT;
// they are not CONTACT_IS_FOLLOWER anymore but that's what we have in the array
- if(count($self) && $contact["rel"] == CONTACT_IS_FOLLOWER) {
+ if($self && $contact["rel"] == CONTACT_IS_FOLLOWER) {
$arr = array();
$arr["uri"] = $arr["parent-uri"] = item_new_uri(App::get_hostname(), $importer["uid"]);
@@ -1224,17 +1225,16 @@ EOT;
$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]';
+ $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["object"] = ''. "\n";
$arr["last-child"] = 1;
$arr["allow_cid"] = $user[0]["allow_cid"];
@@ -1256,12 +1256,12 @@ EOT;
$ret = self::get_person_by_handle($author);
- if((! count($ret)) || ($ret["network"] != NETWORK_DIASPORA)) {
- logger('diaspora_request: Cannot resolve diaspora handle ' . $author . ' for ' . $recipient);
+ if (!$ret || ($ret["network"] != NETWORK_DIASPORA)) {
+ logger('Cannot resolve diaspora handle '.$author .' for '.$recipient);
return;
}
- $batch = (($ret["batch"]) ? $ret["batch"] : implode('/', array_slice(explode('/',$ret["url"]),0,3)) . '/receive/public');
+ $batch = (($ret["batch"]) ? $ret["batch"] : implode('/', array_slice(explode('/',$ret["url"]),0,3)) .'/receive/public');
@@ -1286,10 +1286,10 @@ EOT;
// find the contact record we just created
- $contact_record = diaspora_get_contact_by_handle($importer["uid"],$author);
+ $contact_record = self::get_contact_by_handle($importer["uid"],$author);
if(! $contact_record) {
- logger('diaspora_request: unable to locate newly created contact record.');
+ logger('unable to locate newly created contact record.');
return;
}
@@ -1360,7 +1360,7 @@ EOT;
FROM `item` WHERE `guid` = '%s' AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1",
dbesc($guid));
- if(count($r)) {
+ if($r) {
logger("reshared message ".$guid." already exists on system.");
// Maybe it is already a reshared item?
@@ -1371,23 +1371,23 @@ EOT;
return $r[0];
}
- if (!count($r)) {
- $server = 'https://'.substr($orig_author,strpos($orig_author,'@')+1);
+ 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 = 'https://'.substr($author,strpos($author,'@')+1);
+ $server = "https://".substr($author, strpos($author, "@") + 1);
logger("2nd try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
$item = self::store_by_guid($guid, $server);
}
if (!$item_id) {
- $server = 'http://'.substr($orig_author,strpos($orig_author,'@')+1);
+ $server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
logger("3rd try: reshared message ".$guid." will be fetched from original server: ".$server);
$item = self::store_by_guid($guid, $server);
}
if (!$item_id) {
- $server = 'http://'.substr($author,strpos($author,'@')+1);
+ $server = "http://".substr($author, strpos($author, "@") + 1);
logger("4th try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
$item = self::store_by_guid($guid, $server);
}
From 5bbc8a14ceccf40defc37011308d2d549127f2f6 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sat, 5 Mar 2016 00:27:44 +0100
Subject: [PATCH 026/485] "import" is now "receive"
---
include/diaspora2.php | 311 +++++++++++++++++++++---------------------
1 file changed, 157 insertions(+), 154 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index b834e3deb9..031058ab75 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -116,53 +116,53 @@ class diaspora {
switch ($type) {
case "account_deletion": // Done
- return true;
- //return self::import_account_deletion($importer, $fields);
+ //return true;
+ return self::receive_account_deletion($importer, $fields);
case "comment": // Done
- return true;
- //return self::import_comment($importer, $sender, $fields);
-
- case "conversation":
//return true;
- return self::import_conversation($importer, $msg, $fields);
+ return self::receive_comment($importer, $sender, $fields);
+
+ case "conversation": // Done
+ //return true;
+ return self::receive_conversation($importer, $msg, $fields);
case "like": // Done
- return true;
- //return self::import_like($importer, $sender, $fields);
+ //return true;
+ return self::receive_like($importer, $sender, $fields);
case "message": // Done
- return true;
- //return self::import_message($importer, $fields);
+ //return true;
+ return self::receive_message($importer, $fields);
case "participation": // Not implemented
- return self::import_participation($importer, $fields);
+ return self::receive_participation($importer, $fields);
case "photo": // Not needed
- return self::import_photo($importer, $fields);
+ return self::receive_photo($importer, $fields);
case "poll_participation": // Not implemented
- return self::import_poll_participation($importer, $fields);
+ return self::receive_poll_participation($importer, $fields);
case "profile": // Done
- return true;
- //return self::import_profile($importer, $fields);
+ //return true;
+ return self::receive_profile($importer, $fields);
case "request":
//return true;
- return self::import_request($importer, $fields);
+ return self::receive_request($importer, $fields);
case "reshare": // Done
- return true;
- //return self::import_reshare($importer, $fields);
+ //return true;
+ return self::receive_reshare($importer, $fields);
case "retraction": // Done
- return true;
- //return self::import_retraction($importer, $sender, $fields);
-
- case "status_message":
//return true;
- return self::import_status_message($importer, $fields);
+ return self::receive_retraction($importer, $sender, $fields);
+
+ case "status_message": // Done
+ //return true;
+ return self::receive_status_message($importer, $fields);
default:
logger("Unknown message type ".$type);
@@ -633,7 +633,7 @@ class diaspora {
return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
}
- private function import_account_deletion($importer, $data) {
+ private function receive_account_deletion($importer, $data) {
$author = notags(unxmlify($data->author));
$contact = self::get_contact_by_handle($importer["uid"], $author);
@@ -647,7 +647,7 @@ class diaspora {
return true;
}
- private function import_comment($importer, $sender, $data) {
+ private function receive_comment($importer, $sender, $data) {
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
$text = unxmlify($data->text);
@@ -722,7 +722,7 @@ class diaspora {
return $message_id;
}
- private function import_conversation_message($importer, $contact, $data, $msg, $mesg) {
+ private function receive_conversation_message($importer, $contact, $data, $msg, $mesg) {
$guid = notags(unxmlify($data->guid));
$subject = notags(unxmlify($data->subject));
$author = notags(unxmlify($data->author));
@@ -735,7 +735,14 @@ class diaspora {
$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_author = notags(unxmlify($mesg->diaspora_handle));
+
+ if ($mesg->diaspora_handle)
+ $msg_author = notags(unxmlify($mesg->diaspora_handle));
+ elseif ($mesg->author)
+ $msg_author = notags(unxmlify($mesg->author));
+ else
+ return false;
+
$msg_conversation_guid = notags(unxmlify($mesg->conversation_guid));
if($msg_conversation_guid != $guid) {
@@ -829,7 +836,7 @@ class diaspora {
));
}
- private function import_conversation($importer, $msg, $data) {
+ 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)));
@@ -881,7 +888,7 @@ class diaspora {
}
foreach($messages as $mesg)
- self::import_conversation_message($importer, $contact, $data, $msg, $mesg);
+ self::receive_conversation_message($importer, $contact, $data, $msg, $mesg);
return true;
}
@@ -916,7 +923,7 @@ EOT;
return $obj;
}
- private function import_like($importer, $sender, $data) {
+ private function receive_like($importer, $sender, $data) {
$positive = notags(unxmlify($data->positive));
$guid = notags(unxmlify($data->guid));
$parent_type = notags(unxmlify($data->parent_type));
@@ -1002,7 +1009,7 @@ EOT;
return $message_id;
}
- private function import_message($importer, $data) {
+ private function receive_message($importer, $data) {
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
$text = unxmlify($data->text);
@@ -1073,22 +1080,22 @@ EOT;
return true;
}
- private function import_participation($importer, $data) {
+ private function receive_participation($importer, $data) {
// I'm not sure if we can fully support this message type
return true;
}
- private function import_photo($importer, $data) {
+ 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;
}
- private function import_poll_participation($importer, $data) {
+ private function receive_poll_participation($importer, $data) {
// We don't support polls by now
return true;
}
- private function import_profile($importer, $data) {
+ private function receive_profile($importer, $data) {
$author = notags(unxmlify($data->author));
$contact = self::get_contact_by_handle($importer["uid"], $author);
@@ -1171,23 +1178,7 @@ EOT;
return true;
}
- private function import_request($importer, $data) {
- // @todo
- print_r($data);
-/*
- $author = unxmlify($data->author);
- $recipient = unxmlify($data->recipient);
-
- if (!$author || !$recipient)
- return;
-
- $contact = self::get_contact_by_handle($importer["uid"],$author);
-
- if($contact) {
-
- // perhaps we were already sharing with this person. Now they're sharing with us.
- // That makes us friends.
-
+ private function receive_request_make_friend($importer, $contact) {
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),
@@ -1201,9 +1192,9 @@ EOT;
intval($importer["uid"])
);
- if($r && !$r[0]["hide-friends"] && !$contact["hidden"] && intval(get_pconfig($importer["uid"],'system','post_newfriend'))) {
+ if($r && !$r[0]["hide-friends"] && !$contact["hidden"] && intval(get_pconfig($importer["uid"], "system", "post_newfriend"))) {
- $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
+ $self = q("SELECT * FROM `contact` WHERE `self` AND `uid` = %d LIMIT 1",
intval($importer["uid"])
);
@@ -1225,16 +1216,16 @@ EOT;
$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;
+ $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["object"] = "\n";
$arr["last-child"] = 1;
$arr["allow_cid"] = $user[0]["allow_cid"];
@@ -1244,111 +1235,123 @@ EOT;
$i = item_store($arr);
if($i)
- proc_run('php',"include/notifier.php","activity","$i");
+ proc_run("php", "include/notifier.php", "activity", $i);
}
}
-
- return;
}
- $ret = self::get_person_by_handle($author);
+ private function receive_request($importer, $data) {
+ $author = unxmlify($data->author);
+ $recipient = unxmlify($data->recipient);
+ if (!$author || !$recipient)
+ return;
- if (!$ret || ($ret["network"] != NETWORK_DIASPORA)) {
- logger('Cannot resolve diaspora handle '.$author .' for '.$recipient);
- return;
- }
+ $contact = self::get_contact_by_handle($importer["uid"],$author);
- $batch = (($ret["batch"]) ? $ret["batch"] : implode('/', array_slice(explode('/',$ret["url"]),0,3)) .'/receive/public');
+ if($contact) {
+ // perhaps we were already sharing with this person. Now they're sharing with us.
+ // That makes us friends.
+ self::receive_request_make_friend($importer, $contact);
+ return true;
+ }
- $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
- );
+ $ret = self::get_person_by_handle($author);
- // find the contact record we just created
+ if (!$ret || ($ret["network"] != NETWORK_DIASPORA)) {
+ logger("Cannot resolve diaspora handle ".$author ." for ".$recipient);
+ return false;
+ }
- $contact_record = self::get_contact_by_handle($importer["uid"],$author);
+ $batch = (($ret["batch"]) ? $ret["batch"] : implode("/", array_slice(explode("/", $ret["url"]), 0, 3))."/receive/public");
- 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' )",
+ $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"]),
- 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)
- $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"])
+ 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
);
- $u = q("select * from user where uid = %d limit 1",intval($importer["uid"]));
- if($u)
- $ret = diaspora_share($u[0],$contact_record);
- }
-*/
+ // find the contact record we just created
+
+ $contact_record = self::get_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)
+ $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 true;
}
@@ -1406,7 +1409,7 @@ EOT;
return false;
}
- private function import_reshare($importer, $data) {
+ private function receive_reshare($importer, $data) {
$root_author = notags(unxmlify($data->root_author));
$root_guid = notags(unxmlify($data->root_guid));
$guid = notags(unxmlify($data->guid));
@@ -1520,7 +1523,7 @@ EOT;
}
}
- private function import_retraction($importer, $sender, $data) {
+ private function receive_retraction($importer, $sender, $data) {
$target_type = notags(unxmlify($data->target_type));
$contact = self::get_contact_by_handle($importer["uid"], $sender);
@@ -1548,7 +1551,7 @@ EOT;
return true;
}
- private function import_status_message($importer, $data) {
+ private function receive_status_message($importer, $data) {
$raw_message = unxmlify($data->raw_message);
$guid = notags(unxmlify($data->guid));
From 2a4ebaa438c0e4c84e20d2567d708e472a7c7192 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sat, 5 Mar 2016 01:30:49 +0100
Subject: [PATCH 027/485] Small cleanup
---
include/diaspora2.php | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 031058ab75..939a816f40 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -553,7 +553,6 @@ class diaspora {
$msg = array("message" => $x, "author" => $author);
- // We don't really need this, but until the work is unfinished we better will keep this
$msg["key"] = self::get_key($msg["author"]);
return $msg;
@@ -736,10 +735,12 @@ class diaspora {
$msg_text = unxmlify($mesg->text);
$msg_created_at = datetime_convert("UTC", "UTC", notags(unxmlify($mesg->created_at)));
- if ($mesg->diaspora_handle)
- $msg_author = notags(unxmlify($mesg->diaspora_handle));
- elseif ($mesg->author)
+ // "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;
From 71227b5d0d5a0110354ec9d5e928cdeb0a832026 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 6 Mar 2016 00:53:30 +0100
Subject: [PATCH 028/485] Receiving should be complete, sending partially works
---
include/diaspora2.php | 539 ++++++++++++++++++++++++++++++++++++++----
include/xml.php | 39 +++
2 files changed, 538 insertions(+), 40 deletions(-)
create mode 100644 include/xml.php
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 939a816f40..197cb1da11 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -11,44 +11,8 @@ require_once("include/Contact.php");
require_once("include/Photo.php");
require_once("include/socgraph.php");
require_once("include/group.php");
-require_once("include/api.php");
-
-/**
- * @brief This class contain functions to work with XML data
- *
- */
-class xml {
- function from_array($array, &$xml) {
-
- if (!is_object($xml)) {
- foreach($array as $key => $value) {
- $root = new SimpleXMLElement("<".$key."/>");
- array_to_xml($value, $root);
-
- $dom = dom_import_simplexml($root)->ownerDocument;
- $dom->formatOutput = true;
- return $dom->saveXML();
- }
- }
-
- foreach($array as $key => $value) {
- if (!is_array($value) AND !is_numeric($key))
- $xml->addChild($key, $value);
- elseif (is_array($value))
- array_to_xml($value, $xml->addChild($key));
- }
- }
-
- function copy(&$source, &$target, $elementname) {
- if (count($source->children()) == 0)
- $target->addChild($elementname, $source);
- else {
- $child = $target->addChild($elementname);
- foreach ($source->children() AS $childfield => $childentry)
- self::copy($childentry, $child, $childfield);
- }
- }
-}
+require_once("include/xml.php");
+require_once("include/datetime.php");
/**
* @brief This class contain functions to create and send Diaspora XML files
@@ -56,6 +20,50 @@ class xml {
*/
class diaspora {
+ public static function 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;
+ }
+
/**
* @brief Dispatches public messages and find the fitting receivers
*
@@ -1180,6 +1188,9 @@ EOT;
}
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),
@@ -1204,7 +1215,7 @@ EOT;
if($self && $contact["rel"] == CONTACT_IS_FOLLOWER) {
$arr = array();
- $arr["uri"] = $arr["parent-uri"] = item_new_uri(App::get_hostname(), $importer["uid"]);
+ $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;
@@ -1369,7 +1380,7 @@ EOT;
// 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
- if (api_share_as_retweet($r[0]))
+ if (self::is_reshare($r[0]["body"]))
$r = array();
else
return $r[0];
@@ -1639,5 +1650,453 @@ EOT;
return $message_id;
}
+
+ /*******************************************************************************************
+ * Here come all the functions that are needed to transmit data with the Diaspora protocol *
+ *******************************************************************************************/
+
+ private function get_my_handle($me) {
+ 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.
+ return $me["nickname"]."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
+ }
+
+ function build_public_message($msg, $user, $contact, $prvkey, $pubkey) {
+
+ logger("Message: ".$msg, LOGGER_DATA);
+
+ $handle = self::get_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);
+
+$magic_env = <<< EOT
+
+
+
+ $handle
+
+
+ base64url
+ RSA-SHA256
+ $data
+ $sig
+
+
+EOT;
+
+ logger("magic_env: ".$magic_env, LOGGER_DATA);
+ return $magic_env;
+ }
+
+ 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::get_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);
+
+$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("magic_env: ".$magic_env, LOGGER_DATA);
+ return $magic_env;
+ }
+
+ 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;
+ }
+
+ private 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;
+ }
+ }
+
+ logger("transmit: ".$logid."-".$guid." returns: ".$return_code);
+
+ if(!$return_code || (($return_code == 503) && (stristr($a->get_curl_headers(), "retry-after")))) {
+ logger("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("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));
+ }
+
+ public static function send_share($me,$contact) {
+ $myaddr = self::get_my_handle($me);
+ $theiraddr = $contact["addr"];
+
+ $data = array("XML" => array("post" => array("request" => array(
+ "sender_handle" => $myaddr,
+ "recipient_handle" => $theiraddr
+ ))));
+
+ $msg = xml::from_array($data, $xml);
+
+ $slap = self::build_message($msg, $me, $contact, $me["prvkey"], $contact["pubkey"]);
+
+ return(self::transmit($owner,$contact,$slap, false));
+
+ }
+
+ public static function send_unshare($me,$contact) {
+ $myaddr = self::get_my_handle($me);
+
+ $data = array("XML" => array("post" => array("retraction" => array(
+ "post_guid" => $me["guid"],
+ "diaspora_handle" => $myaddr,
+ "type" => "Person"
+ ))));
+
+ $msg = xml::from_array($data, $xml);
+
+ $slap = self::build_message($msg, $me, $contact, $me["prvkey"], $contact["pubkey"]);
+
+ return(self::transmit($owner,$contact,$slap, false));
+ }
+
+ function 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 send_status($item, $owner, $contact, $public_batch = false) {
+
+ $myaddr = self::get_my_handle($owner);
+ $theiraddr = $contact["addr"];
+
+ $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";
+ }
+ }
+
+
+ $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"]);
+
+ $data = array("XML" => array("post" => array("reshare" => $message)));
+ } else {
+ $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"]);
+
+ $data = array("XML" => array("post" => array("status_message" => $message)));
+ }
+
+ $msg = xml::from_array($data, $xml);
+
+ logger("status: ".$owner["username"]." -> ".$contact["name"]." base message: ".$msg, LOGGER_DATA);
+ logger("send guid ".$item["guid"], LOGGER_DEBUG);
+
+ $slap = self::build_message($msg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], $public_batch);
+
+ $return_code = self::transmit($owner,$contact,$slap, false);
+
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
+ }
+
+ function send_mail($item,$owner,$contact) {
+
+ $myaddr = self::get_my_handle($owner);
+
+ $r = q("SELECT * FROM `conv` WHERE `id` = %d AND `uid` = %d LIMIT 1",
+ intval($item["convid"]),
+ intval($item["uid"])
+ );
+
+ if (!count($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"])
+ $data = array("XML" => array("post" => array("message" => $msg)));
+ 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"]);
+
+ $data = array("XML" => array("post" => array("conversation" => $message)));
+ }
+
+ $xmsg = xml::from_array($data, $xml);
+
+ logger("conversation: ".print_r($xmsg,true), LOGGER_DATA);
+ logger("send guid ".$item["guid"], LOGGER_DEBUG);
+
+ $slap = self::build_message($xmsg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], false);
+
+ $return_code = self::transmit($owner, $contact, $slap, false, false, $item["guid"]);
+
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
+ }
}
?>
diff --git a/include/xml.php b/include/xml.php
new file mode 100644
index 0000000000..e46f53acc0
--- /dev/null
+++ b/include/xml.php
@@ -0,0 +1,39 @@
+ $value) {
+ $root = new SimpleXMLElement("<".$key."/>");
+ self::from_array($value, $root);
+
+ $dom = dom_import_simplexml($root)->ownerDocument;
+ $dom->formatOutput = true;
+ $xml = $dom;
+ return $dom->saveXML();
+ }
+ }
+
+ foreach($array as $key => $value) {
+ if (!is_array($value) AND !is_numeric($key))
+ $xml->addChild($key, $value);
+ elseif (is_array($value))
+ self::from_array($value, $xml->addChild($key));
+ }
+ }
+
+ function copy(&$source, &$target, $elementname) {
+ if (count($source->children()) == 0)
+ $target->addChild($elementname, $source);
+ else {
+ $child = $target->addChild($elementname);
+ foreach ($source->children() AS $childfield => $childentry)
+ self::copy($childentry, $child, $childfield);
+ }
+ }
+}
+?>
From 6468fbb9051ab6fe09bfcaaf0f46ce03491ace4f Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 6 Mar 2016 01:37:47 +0100
Subject: [PATCH 029/485] Retraction could work now as well.
---
include/diaspora2.php | 34 ++++++++++++++++++++
include/xml.php | 2 +-
view/templates/diaspora_relay_retraction.tpl | 5 ++-
3 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 197cb1da11..c745ab8366 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -2031,6 +2031,40 @@ EOT;
return $return_code;
}
+ function send_retraction($item, $owner, $contact, $public_batch = false) {
+
+ $myaddr = self::get_my_handle($owner);
+
+ // 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";
+ }
+
+ $signed_text = $item["guid"].";".$target_type;
+
+ $message = array("target_guid" => $item['guid'],
+ "target_type" => $target_type,
+ "sender_handle" => $myaddr,
+ "target_author_signature" => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
+
+ $data = array("XML" => array("post" => array($msg_type => $message)));
+ $msg = xml::from_array($data, $xml);
+
+ logger("send guid ".$item["guid"], LOGGER_DEBUG);
+
+ $slap = self::build_message($msg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], $public_batch);
+
+ $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $item["guid"]);
+
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
+ }
+
function send_mail($item,$owner,$contact) {
$myaddr = self::get_my_handle($owner);
diff --git a/include/xml.php b/include/xml.php
index e46f53acc0..9c458dab12 100644
--- a/include/xml.php
+++ b/include/xml.php
@@ -20,7 +20,7 @@ class xml {
foreach($array as $key => $value) {
if (!is_array($value) AND !is_numeric($key))
- $xml->addChild($key, $value);
+ $xml->addChild($key, xmlify($value));
elseif (is_array($value))
self::from_array($value, $xml->addChild($key));
}
diff --git a/view/templates/diaspora_relay_retraction.tpl b/view/templates/diaspora_relay_retraction.tpl
index b3f97a2e13..c4b44cd05f 100644
--- a/view/templates/diaspora_relay_retraction.tpl
+++ b/view/templates/diaspora_relay_retraction.tpl
@@ -1,11 +1,10 @@
-
- {{$type}}
{{$guid}}
- {{$signature}}
+ {{$type}}
{{$handle}}
+ {{$signature}}
From af7b028b13b411bb241dacf488b1085dbaf26780 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 6 Mar 2016 11:41:51 +0100
Subject: [PATCH 030/485] Preparation for followups
---
include/diaspora2.php | 77 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 72 insertions(+), 5 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index c745ab8366..ef1b1c3801 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -1664,7 +1664,7 @@ EOT;
return $me["nickname"]."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
}
- function build_public_message($msg, $user, $contact, $prvkey, $pubkey) {
+ private function build_public_message($msg, $user, $contact, $prvkey, $pubkey) {
logger("Message: ".$msg, LOGGER_DATA);
@@ -1884,7 +1884,7 @@ EOT;
return(self::transmit($owner,$contact,$slap, false));
}
- function is_reshare($body) {
+ private function is_reshare($body) {
$body = trim($body);
// Skip if it isn't a pure repeated messages
@@ -1951,7 +1951,7 @@ EOT;
return($ret);
}
- function send_status($item, $owner, $contact, $public_batch = false) {
+ public static function send_status($item, $owner, $contact, $public_batch = false) {
$myaddr = self::get_my_handle($owner);
$theiraddr = $contact["addr"];
@@ -2030,8 +2030,75 @@ EOT;
return $return_code;
}
+/*
+ public static function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
- function send_retraction($item, $owner, $contact, $public_batch = false) {
+ $myaddr = self::get_my_handle($owner);
+
+ // 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;
+
+ if($item['verb'] === ACTIVITY_LIKE) {
+ $tpl = get_markup_template('diaspora_like.tpl');
+ $like = true;
+ $target_type = ( $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment');
+ $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)));
+
+ return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
+ }
+*/
+ public static function send_retraction($item, $owner, $contact, $public_batch = false) {
$myaddr = self::get_my_handle($owner);
@@ -2065,7 +2132,7 @@ EOT;
return $return_code;
}
- function send_mail($item,$owner,$contact) {
+ public static function send_mail($item,$owner,$contact) {
$myaddr = self::get_my_handle($owner);
From 182bee265e3aa68bb9c85f732e8306ef28ab6b1f Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 6 Mar 2016 22:49:50 +0100
Subject: [PATCH 031/485] Sending like and comment should work now.
---
include/diaspora2.php | 131 ++++++++++++++++++++++++------------------
1 file changed, 75 insertions(+), 56 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index ef1b1c3801..0ab28d7b2c 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -2030,74 +2030,93 @@ EOT;
return $return_code;
}
-/*
- public static function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
+
+ private function construct_like($item,$owner,$contact,$public_batch = false) {
$myaddr = self::get_my_handle($owner);
- // 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;
+ $p = q("SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1",
+ dbesc($item["thr-parent"])
+ );
+ if(!$p)
+ return false;
- if($item['verb'] === ACTIVITY_LIKE) {
- $tpl = get_markup_template('diaspora_like.tpl');
- $like = true;
- $target_type = ( $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment');
- $positive = 'true';
+ $parent = $p[0];
- 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']));
+ $target_type = ($parent["uri"] === $parent["parent-uri"] ? "Post" : "Comment");
+ $positive = "true";
// sign it
+ $signed_text = $positive.";".$item["guid"].";".$target_type.";".$parent["guid"].";".$myaddr;
- 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"));
- $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
+ $message = array("positive" => $positive,
+ "guid" => $item["guid"],
+ "target_type" => $item["guid"],
+ "parent_guid" => $parent["guid"],
+ "author_signature" => $authorsig,
+ "diaspora_handle" => $myaddr);
- $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)
- ));
+ $data = array("XML" => array("post" => array("like" => $message)));
- 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)));
-
- return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
+ return xml::from_array($data, $xml);
}
-*/
+
+ private function construct_comment($item,$owner,$contact,$public_batch = false) {
+
+ $myaddr = self::get_my_handle($owner);
+
+ $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
+ intval($item["parent"]),
+ intval($item["parent"])
+ );
+
+ if (!$p)
+ return false;
+
+ $parent = $p[0];
+
+ $text = html_entity_decode(bb2diaspora($item["body"]));
+
+ // sign it
+ $signed_text = $item["guid"].";".$parent["guid"].";".$text.";".$myaddr;
+
+ $authorsig = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+
+ $message = array("guid" => $item["guid"],
+ "parent_guid" => $parent["guid"],
+ "author_signature" => $authorsig,
+ "text" => $text,
+ "diaspora_handle" => $myaddr);
+
+ $data = array("XML" => array("post" => array("comment" => $message)));
+
+ return xml::from_array($data, $xml);
+ }
+
+ public static function send_followup($item,$owner,$contact,$public_batch = false) {
+
+ if($item['verb'] === ACTIVITY_LIKE)
+ $msg = self::construct_like($item, $owner, $contact, $public_batch);
+ else
+ $msg = self::construct_comment($item, $owner, $contact, $public_batch);
+
+ if (!$msg)
+ return $msg;
+
+ logger("base message: ".$msg, LOGGER_DATA);
+ logger("send guid ".$item["guid"], LOGGER_DEBUG);
+
+ $slap = self::build_message($msg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], $public_batch);
+
+ $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $item["guid"]);
+
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
+ }
+
public static function send_retraction($item, $owner, $contact, $public_batch = false) {
$myaddr = self::get_my_handle($owner);
From db15f76177fedd9620ed62518d4c11c6ac493107 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 7 Mar 2016 01:34:06 +0100
Subject: [PATCH 032/485] Relaying is nearly done
---
include/diaspora2.php | 219 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 203 insertions(+), 16 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 0ab28d7b2c..1cc6e55e3b 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -2063,32 +2063,45 @@ EOT;
return xml::from_array($data, $xml);
}
- private function construct_comment($item,$owner,$contact,$public_batch = false) {
+ private function construct_comment($item,$owner,$contact,$public_batch = false, $data = null) {
- $myaddr = self::get_my_handle($owner);
+ if (is_array($data))
+ $message = $data;
+ else {
+ $myaddr = self::get_my_handle($owner);
- $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
- intval($item["parent"]),
- intval($item["parent"])
- );
+ $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
+ intval($item["parent"]),
+ intval($item["parent"])
+ );
- if (!$p)
- return false;
+ if (!$p)
+ return false;
- $parent = $p[0];
+ $parent = $p[0];
- $text = html_entity_decode(bb2diaspora($item["body"]));
+ $text = html_entity_decode(bb2diaspora($item["body"]));
+
+ $message = array("guid" => $item["guid"],
+ "parent_guid" => $parent["guid"],
+ "author_signature" => "",
+ "text" => $text,
+ "diaspora_handle" => $myaddr);
+ }
// sign it
- $signed_text = $item["guid"].";".$parent["guid"].";".$text.";".$myaddr;
+ $sigmsg = $message;
+ unset($sigmsg["author_signature"]);
+ unset($sigmsg["parent_author_signature"]);
+
+ $signed_text = implode(";", $sigmsg);
$authorsig = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
- $message = array("guid" => $item["guid"],
- "parent_guid" => $parent["guid"],
- "author_signature" => $authorsig,
- "text" => $text,
- "diaspora_handle" => $myaddr);
+ if ($message["author_signature"] == "")
+ $message["author_signature"] = $authorsig;
+ else
+ $message["parent_author_signature"] = $authorsig;
$data = array("XML" => array("post" => array("comment" => $message)));
@@ -2117,6 +2130,180 @@ EOT;
return $return_code;
}
+ function send_relay($item, $owner, $contact, $public_batch = false) {
+
+ if ($item["deleted"])
+ $sql_sign_id = "retract_iid";
+ else
+ $sql_sign_id = "iid";
+
+ // fetch the original signature if the relayable was created by a Diaspora
+ // or DFRN user.
+
+ $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 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);
+
+ $data = array("guid" => $guid,
+ "parent_guid" => $parent_guid,
+ "parent_author_signature" => "",
+ "author_signature" => $orig_sign['signature'],
+ "text" => implode(";", $signed_parts),
+ "diaspora_handle" => $handle);
+ }
+
+
+ $myaddr = self::get_my_handle($owner);
+
+ if ($item['deleted'])
+ ; // Retraction
+ elseif($item['verb'] === ACTIVITY_LIKE)
+ $msg = self::construct_like($item, $owner, $contact, $public_batch);
+ else
+ $msg = self::construct_comment($item, $owner, $contact, $public_batch, $data);
+die($msg);
+/*
+ // 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']));
+*/
+ }
+
+
public static function send_retraction($item, $owner, $contact, $public_batch = false) {
$myaddr = self::get_my_handle($owner);
From 373beb0343738fb357b5fbddd9ec76783b003ad5 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 7 Mar 2016 08:17:21 +0100
Subject: [PATCH 033/485] Relayed Likes and relayed comments should work, code
needs beautification
---
include/diaspora2.php | 122 +++++++++++++++++++++++++-----------------
1 file changed, 74 insertions(+), 48 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 1cc6e55e3b..48093cc5b9 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -1799,6 +1799,16 @@ EOT;
return $slap;
}
+ private function get_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"));
+ }
+
private function transmit($owner, $contact, $slap, $public_batch, $queue_run=false, $guid = "") {
$a = get_app();
@@ -2031,32 +2041,37 @@ EOT;
return $return_code;
}
- private function construct_like($item,$owner,$contact,$public_batch = false) {
+ private function construct_like($item,$owner,$contact,$public_batch = false, $data = null) {
- $myaddr = self::get_my_handle($owner);
+ if (is_array($data))
+ $message = $data;
+ else {
+ $myaddr = self::get_my_handle($owner);
- $p = q("SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1",
- dbesc($item["thr-parent"])
- );
- if(!$p)
- return false;
+ $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];
+ $parent = $p[0];
- $target_type = ($parent["uri"] === $parent["parent-uri"] ? "Post" : "Comment");
- $positive = "true";
+ $target_type = ($parent["uri"] === $parent["parent-uri"] ? "Post" : "Comment");
+ $positive = "true";
- // sign it
- $signed_text = $positive.";".$item["guid"].";".$target_type.";".$parent["guid"].";".$myaddr;
+ $message = array("positive" => $positive,
+ "guid" => $item["guid"],
+ "target_type" => $target_type,
+ "parent_guid" => $parent["guid"],
+ "author_signature" => $authorsig,
+ "diaspora_handle" => $myaddr);
+ }
- $authorsig = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+ $authorsig = self::get_signature($owner, $message);
- $message = array("positive" => $positive,
- "guid" => $item["guid"],
- "target_type" => $item["guid"],
- "parent_guid" => $parent["guid"],
- "author_signature" => $authorsig,
- "diaspora_handle" => $myaddr);
+ if ($message["author_signature"] == "")
+ $message["author_signature"] = $authorsig;
+ else
+ $message["parent_author_signature"] = $authorsig;
$data = array("XML" => array("post" => array("like" => $message)));
@@ -2089,14 +2104,7 @@ EOT;
"diaspora_handle" => $myaddr);
}
- // sign it
- $sigmsg = $message;
- unset($sigmsg["author_signature"]);
- unset($sigmsg["parent_author_signature"]);
-
- $signed_text = implode(";", $sigmsg);
-
- $authorsig = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+ $authorsig = self::get_signature($owner, $message);
if ($message["author_signature"] == "")
$message["author_signature"] = $authorsig;
@@ -2153,36 +2161,56 @@ EOT;
// Split the signed text
$signed_parts = explode(";", $signed_text);
- // Remove the comment guid
- $guid = array_shift($signed_parts);
+ if ($item['verb'] === ACTIVITY_LIKE) {
+ $data = array("positive" => $signed_parts[0],
+ "guid" => $signed_parts[1],
+ "target_type" => $signed_parts[2],
+ "parent_guid" => $signed_parts[3],
+ "parent_author_signature" => "",
+ "author_signature" => $orig_sign['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 parent guid
+ $parent_guid = array_shift($signed_parts);
- // Remove the handle
- $handle = array_pop($signed_parts);
+ // Remove the handle
+ $handle = array_pop($signed_parts);
- // Glue the parts together
- $text = implode(";", $signed_parts);
+ // Glue the parts together
+ $text = implode(";", $signed_parts);
- $data = array("guid" => $guid,
- "parent_guid" => $parent_guid,
- "parent_author_signature" => "",
- "author_signature" => $orig_sign['signature'],
- "text" => implode(";", $signed_parts),
- "diaspora_handle" => $handle);
+ $data = array("guid" => $guid,
+ "parent_guid" => $parent_guid,
+ "parent_author_signature" => "",
+ "author_signature" => $orig_sign['signature'],
+ "text" => implode(";", $signed_parts),
+ "diaspora_handle" => $handle);
+ }
}
-
- $myaddr = self::get_my_handle($owner);
-
if ($item['deleted'])
- ; // Retraction
+ ; // Relayed Retraction
elseif($item['verb'] === ACTIVITY_LIKE)
- $msg = self::construct_like($item, $owner, $contact, $public_batch);
+ $msg = self::construct_like($item, $owner, $contact, $public_batch, $data);
else
$msg = self::construct_comment($item, $owner, $contact, $public_batch, $data);
die($msg);
+
+ logger('base message: '.$msg, LOGGER_DATA);
+ logger('send guid '.$item['guid'], LOGGER_DEBUG);
+
+ $slap = self::build_message($msg,$owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
+
+ $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $item['guid']);
+
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
+ }
+
/*
// Diaspora doesn't support threaded comments, but some
// versions of Diaspora (i.e. Diaspora-pistos) support
@@ -2301,8 +2329,6 @@ die($msg);
return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
*/
- }
-
public static function send_retraction($item, $owner, $contact, $public_batch = false) {
From 16eb8fd9bf705ad5d4d9f739b9264d7c8d15dace Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 7 Mar 2016 15:20:48 +0100
Subject: [PATCH 034/485] Small things ...
---
include/diaspora2.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 48093cc5b9..4c9d79912e 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -1525,7 +1525,7 @@ EOT;
// 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')",
+ q("INSERT INTO `sign` (`retract_iid`,`signed_text`) VALUES (%d,'%s')",
intval($r[0]["id"]),
dbesc(json_encode($data))
);
@@ -1552,7 +1552,7 @@ EOT;
case "StatusMessage":
return self::item_retraction($importer, $contact, $data);;
- case "Person":
+ case "Person": /// @todo an "unshare" shouldn't remove the contact
contact_remove($contact["id"]);
return true;
From 32c66246c4fcddcab30e4850d5c6b62bdfac225a Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 9 Mar 2016 19:30:04 +0100
Subject: [PATCH 035/485] Some fixes for the fetching of postings by using /p/
---
include/diaspora2.php | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 4c9d79912e..7aa0fc6989 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -550,12 +550,15 @@ class diaspora {
return self::fetch_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)
+ 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;
@@ -1391,22 +1394,24 @@ EOT;
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 = "https://".substr($author, strpos($author, "@") + 1);
- logger("2nd try: reshared message ".$guid." will be fetched from sharer's server: ".$server);
- $item = self::store_by_guid($guid, $server);
- }
if (!$item_id) {
$server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
- logger("3rd try: reshared message ".$guid." will be fetched from original server: ".$server);
- $item = self::store_by_guid($guid, $server);
+ 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 = self::store_by_guid($guid, $server);
+ $item_id = self::store_by_guid($guid, $server);
}
-
+*/
if ($item_id) {
$r = q("SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`,
`author-name`, `author-link`, `author-avatar`
From 0f65eee69567483d5b55023e53014655c38a5237 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sat, 12 Mar 2016 19:19:20 +0100
Subject: [PATCH 036/485] Everything could work - needs some beautification and
documentation
---
include/diaspora2.php | 473 +++++++++++++-----------------------------
1 file changed, 142 insertions(+), 331 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 7aa0fc6989..3d12ef5bbf 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -123,53 +123,43 @@ class diaspora {
$type = $fields->getName();
switch ($type) {
- case "account_deletion": // Done
- //return true;
+ case "account_deletion":
return self::receive_account_deletion($importer, $fields);
- case "comment": // Done
- //return true;
+ case "comment":
return self::receive_comment($importer, $sender, $fields);
- case "conversation": // Done
- //return true;
+ case "conversation":
return self::receive_conversation($importer, $msg, $fields);
- case "like": // Done
- //return true;
+ case "like":
return self::receive_like($importer, $sender, $fields);
- case "message": // Done
- //return true;
+ case "message":
return self::receive_message($importer, $fields);
case "participation": // Not implemented
return self::receive_participation($importer, $fields);
- case "photo": // Not needed
+ case "photo": // Not implemented
return self::receive_photo($importer, $fields);
case "poll_participation": // Not implemented
return self::receive_poll_participation($importer, $fields);
- case "profile": // Done
- //return true;
+ case "profile":
return self::receive_profile($importer, $fields);
case "request":
- //return true;
return self::receive_request($importer, $fields);
- case "reshare": // Done
- //return true;
+ case "reshare":
return self::receive_reshare($importer, $fields);
- case "retraction": // Done
- //return true;
+ case "retraction":
return self::receive_retraction($importer, $sender, $fields);
- case "status_message": // Done
- //return true;
+ case "status_message":
return self::receive_status_message($importer, $fields);
default:
@@ -1364,7 +1354,7 @@ EOT;
$u = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer["uid"]));
if($u)
- $ret = diaspora_share($u[0], $contact_record);
+ $ret = self::send_share($u[0], $contact_record);
}
return true;
@@ -1557,8 +1547,10 @@ EOT;
case "StatusMessage":
return self::item_retraction($importer, $contact, $data);;
- case "Person": /// @todo an "unshare" shouldn't remove the contact
- contact_remove($contact["id"]);
+ 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:
@@ -1862,41 +1854,43 @@ EOT;
}
}
-
return(($return_code) ? $return_code : (-1));
}
- public static function send_share($me,$contact) {
- $myaddr = self::get_my_handle($me);
- $theiraddr = $contact["addr"];
- $data = array("XML" => array("post" => array("request" => array(
- "sender_handle" => $myaddr,
- "recipient_handle" => $theiraddr
- ))));
+ private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "") {
+
+ $data = array("XML" => array("post" => array($type => $message)));
$msg = xml::from_array($data, $xml);
- $slap = self::build_message($msg, $me, $contact, $me["prvkey"], $contact["pubkey"]);
+ logger('message: '.$msg, LOGGER_DATA);
+ logger('send guid '.$guid, LOGGER_DEBUG);
- return(self::transmit($owner,$contact,$slap, false));
+ $slap = self::build_message($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
+die($slap);
+ $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $guid);
+ logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
+
+ return $return_code;
}
- public static function send_unshare($me,$contact) {
- $myaddr = self::get_my_handle($me);
+ public static function send_share($owner,$contact) {
- $data = array("XML" => array("post" => array("retraction" => array(
- "post_guid" => $me["guid"],
- "diaspora_handle" => $myaddr,
- "type" => "Person"
- ))));
+ $message = array("sender_handle" => self::get_my_handle($owner),
+ "recipient_handle" => $contact["addr"]);
- $msg = xml::from_array($data, $xml);
+ return self::build_and_transmit($owner, $contact, "request", $message);
+ }
- $slap = self::build_message($msg, $me, $contact, $me["prvkey"], $contact["pubkey"]);
+ public static function send_unshare($owner,$contact) {
- return(self::transmit($owner,$contact,$slap, false));
+ $message = array("post_guid" => $owner["guid"],
+ "diaspora_handle" => self::get_my_handle($owner),
+ "type" => "Person");
+
+ return self::build_and_transmit($owner, $contact, "retraction", $message);
}
private function is_reshare($body) {
@@ -1969,27 +1963,6 @@ EOT;
public static function send_status($item, $owner, $contact, $public_batch = false) {
$myaddr = self::get_my_handle($owner);
- $theiraddr = $contact["addr"];
-
- $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";
- }
- }
-
$public = (($item["private"]) ? "false" : "true");
@@ -2005,8 +1978,27 @@ EOT;
"created_at" => $created,
"provider_display_name" => $item["app"]);
- $data = array("XML" => array("post" => array("reshare" => $message)));
+ $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"] != "")
@@ -2029,126 +2021,87 @@ EOT;
if (count($location) == 0)
unset($message["location"]);
- $data = array("XML" => array("post" => array("status_message" => $message)));
+ $type = "status_message";
}
- $msg = xml::from_array($data, $xml);
-
- logger("status: ".$owner["username"]." -> ".$contact["name"]." base message: ".$msg, LOGGER_DATA);
- logger("send guid ".$item["guid"], LOGGER_DEBUG);
-
- $slap = self::build_message($msg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], $public_batch);
-
- $return_code = self::transmit($owner,$contact,$slap, false);
-
- logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
-
- return $return_code;
+ return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
- private function construct_like($item,$owner,$contact,$public_batch = false, $data = null) {
+ private function construct_like($item, $owner) {
- if (is_array($data))
- $message = $data;
- else {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::get_my_handle($owner);
- $p = q("SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1",
- dbesc($item["thr-parent"]));
- if(!$p)
- return false;
+ $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];
+ $parent = $p[0];
- $target_type = ($parent["uri"] === $parent["parent-uri"] ? "Post" : "Comment");
- $positive = "true";
+ $target_type = ($parent["uri"] === $parent["parent-uri"] ? "Post" : "Comment");
+ $positive = "true";
- $message = array("positive" => $positive,
- "guid" => $item["guid"],
- "target_type" => $target_type,
- "parent_guid" => $parent["guid"],
- "author_signature" => $authorsig,
- "diaspora_handle" => $myaddr);
- }
-
- $authorsig = self::get_signature($owner, $message);
-
- if ($message["author_signature"] == "")
- $message["author_signature"] = $authorsig;
- else
- $message["parent_author_signature"] = $authorsig;
-
- $data = array("XML" => array("post" => array("like" => $message)));
-
- return xml::from_array($data, $xml);
+ return(array("positive" => $positive,
+ "guid" => $item["guid"],
+ "target_type" => $target_type,
+ "parent_guid" => $parent["guid"],
+ "author_signature" => $authorsig,
+ "diaspora_handle" => $myaddr));
}
- private function construct_comment($item,$owner,$contact,$public_batch = false, $data = null) {
+ private function construct_comment($item, $owner) {
- if (is_array($data))
- $message = $data;
- else {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::get_my_handle($owner);
- $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
- intval($item["parent"]),
- intval($item["parent"])
- );
+ $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
+ intval($item["parent"]),
+ intval($item["parent"])
+ );
- if (!$p)
- return false;
+ if (!$p)
+ return false;
- $parent = $p[0];
+ $parent = $p[0];
- $text = html_entity_decode(bb2diaspora($item["body"]));
+ $text = html_entity_decode(bb2diaspora($item["body"]));
- $message = array("guid" => $item["guid"],
- "parent_guid" => $parent["guid"],
- "author_signature" => "",
- "text" => $text,
- "diaspora_handle" => $myaddr);
- }
-
- $authorsig = self::get_signature($owner, $message);
-
- if ($message["author_signature"] == "")
- $message["author_signature"] = $authorsig;
- else
- $message["parent_author_signature"] = $authorsig;
-
- $data = array("XML" => array("post" => array("comment" => $message)));
-
- return xml::from_array($data, $xml);
+ return(array("guid" => $item["guid"],
+ "parent_guid" => $parent["guid"],
+ "author_signature" => "",
+ "text" => $text,
+ "diaspora_handle" => $myaddr));
}
public static function send_followup($item,$owner,$contact,$public_batch = false) {
- if($item['verb'] === ACTIVITY_LIKE)
- $msg = self::construct_like($item, $owner, $contact, $public_batch);
- else
- $msg = self::construct_comment($item, $owner, $contact, $public_batch);
+ if($item['verb'] === ACTIVITY_LIKE) {
+ $message = self::construct_like($item, $owner);
+ $type = "like";
+ } else {
+ $message = self::construct_comment($item, $owner);
+ $type = "comment";
+ }
- if (!$msg)
- return $msg;
+ if (!$message)
+ return false;
- logger("base message: ".$msg, LOGGER_DATA);
- logger("send guid ".$item["guid"], LOGGER_DEBUG);
+ $message["author_signature"] = self::get_signature($owner, $message);
- $slap = self::build_message($msg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], $public_batch);
-
- $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $item["guid"]);
-
- logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
-
- return $return_code;
+ return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
function send_relay($item, $owner, $contact, $public_batch = false) {
- if ($item["deleted"])
+ if ($item["deleted"]) {
$sql_sign_id = "retract_iid";
- else
+ $type = "relayable_retraction";
+ } elseif ($item['verb'] === ACTIVITY_LIKE) {
$sql_sign_id = "iid";
+ $type = "like";
+ } else {
+ $sql_sign_id = "iid";
+ $type = "comment";
+ }
// fetch the original signature if the relayable was created by a Diaspora
// or DFRN user.
@@ -2157,24 +2110,32 @@ EOT;
intval($item["id"])
);
- if(count($r)) {
- $orig_sign = $r[0];
- $signed_text = $orig_sign['signed_text'];
- $authorsig = $orig_sign['signature'];
- $handle = $orig_sign['signer'];
+ if (!$r)
+ return self::send_followup($item, $owner, $contact, $public_batch);
+
+ $orig_sign = $r[0];
+
+ // Old way - can be removed for the master branch
+ if ($orig_sign['signed_text'] AND $orig_sign['signature'] AND $orig_sign['signer']) {
// Split the signed text
- $signed_parts = explode(";", $signed_text);
+ $signed_parts = explode(";", $orig_sign['signed_text']);
- if ($item['verb'] === ACTIVITY_LIKE) {
- $data = array("positive" => $signed_parts[0],
+ if ($item["deleted"])
+ $message = array("parent_author_signature" => "",
+ "target_guid" => $signed_parts[0],
+ "target_type" => $signed_parts[1],
+ "sender_handle" => $orig_sign['signer'],
+ "target_author_signature" => $orig_sign['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" => $orig_sign['signature'],
"diaspora_handle" => $signed_parts[4]);
- } else {
+ else {
// Remove the comment guid
$guid = array_shift($signed_parts);
@@ -2187,154 +2148,26 @@ EOT;
// Glue the parts together
$text = implode(";", $signed_parts);
- $data = array("guid" => $guid,
+ $message = array("guid" => $guid,
"parent_guid" => $parent_guid,
"parent_author_signature" => "",
"author_signature" => $orig_sign['signature'],
"text" => implode(";", $signed_parts),
"diaspora_handle" => $handle);
}
+ } else { // New way
+ $message = json_decode($orig_sign['signed_text']);
}
- if ($item['deleted'])
- ; // Relayed Retraction
- elseif($item['verb'] === ACTIVITY_LIKE)
- $msg = self::construct_like($item, $owner, $contact, $public_batch, $data);
- else
- $msg = self::construct_comment($item, $owner, $contact, $public_batch, $data);
-die($msg);
+ if ($item["deleted"]) {
+ $signed_text = $message["target_guid"].';'.$message["target_type"];
+ $message["parent_author_signature"] = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+ } else
+ $message["parent_author_signature"] = self::get_signature($owner, $message);
- logger('base message: '.$msg, LOGGER_DATA);
- logger('send guid '.$item['guid'], LOGGER_DEBUG);
-
- $slap = self::build_message($msg,$owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
-
- $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $item['guid']);
-
- logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
-
- return $return_code;
+ return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
-/*
- // 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']));
-*/
-
public static function send_retraction($item, $owner, $contact, $public_batch = false) {
$myaddr = self::get_my_handle($owner);
@@ -2355,21 +2188,10 @@ die($msg);
"sender_handle" => $myaddr,
"target_author_signature" => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
- $data = array("XML" => array("post" => array($msg_type => $message)));
- $msg = xml::from_array($data, $xml);
-
- logger("send guid ".$item["guid"], LOGGER_DEBUG);
-
- $slap = self::build_message($msg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], $public_batch);
-
- $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $item["guid"]);
-
- logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
-
- return $return_code;
+ return self::build_and_transmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]);
}
- public static function send_mail($item,$owner,$contact) {
+ public static function send_mail($item, $owner, $contact) {
$myaddr = self::get_my_handle($owner);
@@ -2396,7 +2218,6 @@ die($msg);
$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(
@@ -2410,9 +2231,10 @@ die($msg);
"conversation_guid" => $cnv["guid"]
);
- if ($item["reply"])
- $data = array("XML" => array("post" => array("message" => $msg)));
- else {
+ 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'),
@@ -2420,21 +2242,10 @@ die($msg);
"diaspora_handle" => $cnv["creator"],
"participant_handles" => $cnv["recips"]);
- $data = array("XML" => array("post" => array("conversation" => $message)));
+ $type = "conversation";
}
- $xmsg = xml::from_array($data, $xml);
-
- logger("conversation: ".print_r($xmsg,true), LOGGER_DATA);
- logger("send guid ".$item["guid"], LOGGER_DEBUG);
-
- $slap = self::build_message($xmsg, $owner, $contact, $owner["uprvkey"], $contact["pubkey"], false);
-
- $return_code = self::transmit($owner, $contact, $slap, false, false, $item["guid"]);
-
- logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
-
- return $return_code;
+ return self::build_and_transmit($owner, $contact, $type, $message, false, $item["guid"]);
}
}
?>
From f978bc9cc8011ab31e9abd90519008c6248cdebb Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 13 Mar 2016 07:10:24 +0100
Subject: [PATCH 037/485] Some code cleaning, changes to the xml generation
---
include/diaspora2.php | 183 ++++++++++++++++++++++++------------------
include/xml.php | 10 ++-
2 files changed, 114 insertions(+), 79 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 3d12ef5bbf..97d5ecee9f 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -20,7 +20,7 @@ require_once("include/datetime.php");
*/
class diaspora {
- public static function fetch_relay() {
+ public static function relay_list() {
$serverdata = get_config("system", "relay_server");
if ($serverdata == "")
@@ -277,13 +277,13 @@ class diaspora {
return false;
if (isset($parent_author_signature)) {
- $key = self::get_key($msg["author"]);
+ $key = self::key($msg["author"]);
if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256"))
return false;
}
- $key = self::get_key($fields->author);
+ $key = self::key($fields->author);
return rsa_verify($signed_data, $author_signature, $key, "sha256");
}
@@ -295,10 +295,10 @@ class diaspora {
*
* @return string The public key
*/
- private function get_key($handle) {
+ private function key($handle) {
logger("Fetching diaspora key for: ".$handle);
- $r = self::get_person_by_handle($handle);
+ $r = self::person_by_handle($handle);
if($r)
return $r["pubkey"];
@@ -312,7 +312,7 @@ class diaspora {
*
* @return array the queried data
*/
- private function get_person_by_handle($handle) {
+ private function person_by_handle($handle) {
$r = q("SELECT * FROM `fcontact` WHERE `network` = '%s' AND `addr` = '%s' LIMIT 1",
dbesc(NETWORK_DIASPORA),
@@ -407,7 +407,33 @@ class diaspora {
return $r;
}
- private function get_contact_by_handle($uid, $handle) {
+ public static function handle_from_contact($contact_id) {
+ $handle = False;
+
+ logger("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("contact 'self' = ".$contact['self']." 'url' = ".$contact['url'], LOGGER_DEBUG);
+
+ if($contact['addr'] != "")
+ $handle = $contact['addr'];
+ 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;
+ }
+ }
+
+ return $handle;
+ }
+
+ private function contact_by_handle($uid, $handle) {
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `addr` = '%s' LIMIT 1",
intval($uid),
dbesc($handle)
@@ -459,8 +485,8 @@ class diaspora {
return false;
}
- private function get_allowed_contact_by_handle($importer, $handle, $is_comment = false) {
- $contact = self::get_contact_by_handle($importer["uid"], $handle);
+ 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;
@@ -505,7 +531,7 @@ class diaspora {
logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
- $msg = self::fetch_message($guid, $server);
+ $msg = self::message($guid, $server);
if (!$msg)
return false;
@@ -516,7 +542,7 @@ class diaspora {
return self::dispatch_public($msg);
}
- private function fetch_message($guid, $server, $level = 0) {
+ private function message($guid, $server, $level = 0) {
if ($level > 5)
return false;
@@ -534,10 +560,10 @@ class diaspora {
if ($source_xml->post->reshare) {
// Reshare of a reshare - old Diaspora version
- return self::fetch_message($source_xml->post->reshare->root_guid, $server, ++$level);
+ 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::fetch_message($source_xml->root_guid, $server, ++$level);
+ return self::message($source_xml->root_guid, $server, ++$level);
}
$author = "";
@@ -554,12 +580,12 @@ class diaspora {
$msg = array("message" => $x, "author" => $author);
- $msg["key"] = self::get_key($msg["author"]);
+ $msg["key"] = self::key($msg["author"]);
return $msg;
}
- private function fetch_parent_item($uid, $guid, $author, $contact) {
+ 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`
@@ -570,7 +596,7 @@ class diaspora {
$result = self::store_by_guid($guid, $contact["url"], $uid);
if (!$result) {
- $person = self::get_person_by_handle($author);
+ $person = self::person_by_handle($author);
$result = self::store_by_guid($guid, $person["url"], $uid);
}
@@ -592,7 +618,7 @@ class diaspora {
return $r[0];
}
- private function get_author_contact_by_url($contact, $person, $uid) {
+ private function author_contact_by_url($contact, $person, $uid) {
$r = q("SELECT `id`, `network` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d LIMIT 1",
dbesc(normalise_link($person["url"])), intval($uid));
@@ -636,7 +662,7 @@ class diaspora {
private function receive_account_deletion($importer, $data) {
$author = notags(unxmlify($data->author));
- $contact = self::get_contact_by_handle($importer["uid"], $author);
+ $contact = self::contact_by_handle($importer["uid"], $author);
if (!$contact) {
logger("cannot find contact for author: ".$author);
return false;
@@ -653,25 +679,25 @@ class diaspora {
$text = unxmlify($data->text);
$author = notags(unxmlify($data->author));
- $contact = self::get_allowed_contact_by_handle($importer, $sender, true);
+ $contact = self::allowed_contact_by_handle($importer, $sender, true);
if (!$contact)
return false;
if (self::message_exists($importer["uid"], $guid))
return false;
- $parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
+ $parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item)
return false;
- $person = self::get_person_by_handle($author);
+ $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::get_author_contact_by_url($contact, $person, $importer["uid"]);
+ $author_contact = self::author_contact_by_url($contact, $person, $importer["uid"]);
$datarray = array();
@@ -763,7 +789,7 @@ class diaspora {
$person = $contact;
$key = $msg["key"];
} else {
- $person = self::get_person_by_handle($msg_author);
+ $person = self::person_by_handle($msg_author);
if (is_array($person) && x($person, "pubkey"))
$key = $person["pubkey"];
@@ -852,7 +878,7 @@ class diaspora {
return false;
}
- $contact = self::get_allowed_contact_by_handle($importer, $msg["author"], true);
+ $contact = self::allowed_contact_by_handle($importer, $msg["author"], true);
if (!$contact)
return false;
@@ -907,22 +933,17 @@ class diaspora {
private function construct_like_object($importer, $parent_item) {
$objtype = ACTIVITY_OBJ_NOTE;
- $link = xmlify(''."\n") ;
+ $link = '';
$parent_body = $parent_item["body"];
- $obj = <<< EOT
+ $xmldata = array("object" => array("type" => $objtype,
+ "local" => "1",
+ "id" => $parent_item["uri"],
+ "link" => $link,
+ "title" => "",
+ "content" => $parent_body));
-
-EOT;
-
- return $obj;
+ return xml::from_array($xmldata, $xml, true);
}
private function receive_like($importer, $sender, $data) {
@@ -937,25 +958,25 @@ EOT;
if (!in_array($parent_type, array("Post", "Comment")))
return false;
- $contact = self::get_allowed_contact_by_handle($importer, $sender, true);
+ $contact = self::allowed_contact_by_handle($importer, $sender, true);
if (!$contact)
return false;
if (self::message_exists($importer["uid"], $guid))
return false;
- $parent_item = self::fetch_parent_item($importer["uid"], $parent_guid, $author, $contact);
+ $parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item)
return false;
- $person = self::get_person_by_handle($author);
+ $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::get_author_contact_by_url($contact, $person, $importer["uid"]);
+ $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.
@@ -1019,7 +1040,7 @@ EOT;
$author = notags(unxmlify($data->author));
$conversation_guid = notags(unxmlify($data->conversation_guid));
- $contact = self::get_allowed_contact_by_handle($importer, $author, true);
+ $contact = self::allowed_contact_by_handle($importer, $author, true);
if (!$contact)
return false;
@@ -1041,7 +1062,7 @@ EOT;
$body = diaspora2bb($text);
$message_uri = $author.":".$guid;
- $person = self::get_person_by_handle($author);
+ $person = self::person_by_handle($author);
if (!$person) {
logger("unable to find author details");
return false;
@@ -1100,7 +1121,7 @@ EOT;
private function receive_profile($importer, $data) {
$author = notags(unxmlify($data->author));
- $contact = self::get_contact_by_handle($importer["uid"], $author);
+ $contact = self::contact_by_handle($importer["uid"], $author);
if (!$contact)
return;
@@ -1254,7 +1275,7 @@ EOT;
if (!$author || !$recipient)
return;
- $contact = self::get_contact_by_handle($importer["uid"],$author);
+ $contact = self::contact_by_handle($importer["uid"],$author);
if($contact) {
@@ -1265,7 +1286,7 @@ EOT;
return true;
}
- $ret = self::get_person_by_handle($author);
+ $ret = self::person_by_handle($author);
if (!$ret || ($ret["network"] != NETWORK_DIASPORA)) {
logger("Cannot resolve diaspora handle ".$author ." for ".$recipient);
@@ -1295,7 +1316,7 @@ EOT;
// find the contact record we just created
- $contact_record = self::get_contact_by_handle($importer["uid"],$author);
+ $contact_record = self::contact_by_handle($importer["uid"],$author);
if (!$contact_record) {
logger("unable to locate newly created contact record.");
@@ -1360,7 +1381,7 @@ EOT;
return true;
}
- private function get_original_item($guid, $orig_author, $author) {
+ 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`,
@@ -1424,14 +1445,14 @@ EOT;
$public = notags(unxmlify($data->public));
$created_at = notags(unxmlify($data->created_at));
- $contact = self::get_allowed_contact_by_handle($importer, $author, false);
+ $contact = self::allowed_contact_by_handle($importer, $author, false);
if (!$contact)
return false;
if (self::message_exists($importer["uid"], $guid))
return false;
- $original_item = self::get_original_item($root_guid, $root_author, $author);
+ $original_item = self::original_item($root_guid, $root_author, $author);
if (!$original_item)
return false;
@@ -1482,7 +1503,7 @@ EOT;
$target_guid = notags(unxmlify($data->target_guid));
$author = notags(unxmlify($data->author));
- $person = self::get_person_by_handle($author);
+ $person = self::person_by_handle($author);
if (!is_array($person)) {
logger("unable to find author detail for ".$author);
return false;
@@ -1533,7 +1554,7 @@ EOT;
private function receive_retraction($importer, $sender, $data) {
$target_type = notags(unxmlify($data->target_type));
- $contact = self::get_contact_by_handle($importer["uid"], $sender);
+ $contact = self::contact_by_handle($importer["uid"], $sender);
if (!$contact) {
logger("cannot find contact for sender: ".$sender." and user ".$importer["uid"]);
return false;
@@ -1575,7 +1596,7 @@ EOT;
// print_r($poll);
// die("poll!\n");
//}
- $contact = self::get_allowed_contact_by_handle($importer, $author, false);
+ $contact = self::allowed_contact_by_handle($importer, $author, false);
if (!$contact)
return false;
@@ -1652,7 +1673,7 @@ EOT;
* Here come all the functions that are needed to transmit data with the Diaspora protocol *
*******************************************************************************************/
- private function get_my_handle($me) {
+ private function my_handle($me) {
if ($contact["addr"] != "")
return $contact["addr"];
@@ -1665,7 +1686,7 @@ EOT;
logger("Message: ".$msg, LOGGER_DATA);
- $handle = self::get_my_handle($user);
+ $handle = self::my_handle($user);
$b64url_data = base64url_encode($msg);
@@ -1694,7 +1715,7 @@ $magic_env = <<< EOT
EOT;
-
+die($magic_env."\n");
logger("magic_env: ".$magic_env, LOGGER_DATA);
return $magic_env;
}
@@ -1720,7 +1741,7 @@ EOT;
$outer_iv = random_string(16);
$b_outer_iv = base64_encode($outer_iv);
- $handle = self::get_my_handle($user);
+ $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);
@@ -1740,14 +1761,11 @@ EOT;
$signature = rsa_sign($signable_data,$prvkey);
$sig = base64url_encode($signature);
-$decrypted_header = <<< EOT
-
- $b_inner_iv
- $b_inner_aes_key
- $handle
-
-EOT;
+ $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);
@@ -1765,6 +1783,15 @@ EOT;
"ciphertext" => base64_encode($ciphertext)));
$cipher_json = base64_encode($encrypted_header_json_object);
+ $xml = nul;
+ $xmldata = array("diaspora" => array("encrypted_header" => $cipher_json,
+ "me:env" => array("me:encoding" => "base64url",
+ "me:alg" => "RSA-SHA256",
+ "me:data" => $data,
+ "me:sig" => $sig)));
+ $encrypted_header = xml::from_array($xmldata, $xml, true);
+echo $encrypted_header."\n";
+
$encrypted_header = "".$cipher_json." ";
$magic_env = <<< EOT
@@ -1779,6 +1806,7 @@ $magic_env = <<< EOT
EOT;
+die($magic_env."\n");
logger("magic_env: ".$magic_env, LOGGER_DATA);
return $magic_env;
@@ -1796,7 +1824,7 @@ EOT;
return $slap;
}
- private function get_signature($owner, $message) {
+ private function signature($owner, $message) {
$sigmsg = $message;
unset($sigmsg["author_signature"]);
unset($sigmsg["parent_author_signature"]);
@@ -1806,7 +1834,7 @@ EOT;
return base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
}
- private function transmit($owner, $contact, $slap, $public_batch, $queue_run=false, $guid = "") {
+ public static function transmit($owner, $contact, $slap, $public_batch, $queue_run=false, $guid = "") {
$a = get_app();
@@ -1878,7 +1906,7 @@ die($slap);
public static function send_share($owner,$contact) {
- $message = array("sender_handle" => self::get_my_handle($owner),
+ $message = array("sender_handle" => self::my_handle($owner),
"recipient_handle" => $contact["addr"]);
return self::build_and_transmit($owner, $contact, "request", $message);
@@ -1887,7 +1915,7 @@ die($slap);
public static function send_unshare($owner,$contact) {
$message = array("post_guid" => $owner["guid"],
- "diaspora_handle" => self::get_my_handle($owner),
+ "diaspora_handle" => self::my_handle($owner),
"type" => "Person");
return self::build_and_transmit($owner, $contact, "retraction", $message);
@@ -1924,7 +1952,7 @@ die($slap);
dbesc($guid), NETWORK_DFRN, NETWORK_DIASPORA);
if ($r) {
$ret= array();
- $ret["root_handle"] = diaspora_handle_from_contact($r[0]["contact-id"]);
+ $ret["root_handle"] = self::handle_from_contact($r[0]["contact-id"]);
$ret["root_guid"] = $guid;
return($ret);
}
@@ -1962,7 +1990,7 @@ die($slap);
public static function send_status($item, $owner, $contact, $public_batch = false) {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::my_handle($owner);
$public = (($item["private"]) ? "false" : "true");
@@ -2029,7 +2057,7 @@ die($slap);
private function construct_like($item, $owner) {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::my_handle($owner);
$p = q("SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1",
dbesc($item["thr-parent"]));
@@ -2051,7 +2079,7 @@ die($slap);
private function construct_comment($item, $owner) {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::my_handle($owner);
$p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
intval($item["parent"]),
@@ -2085,7 +2113,7 @@ die($slap);
if (!$message)
return false;
- $message["author_signature"] = self::get_signature($owner, $message);
+ $message["author_signature"] = self::signature($owner, $message);
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
@@ -2115,7 +2143,8 @@ die($slap);
$orig_sign = $r[0];
- // Old way - can be removed for the master branch
+ // Old way - is used by the internal Friendica functions
+ /// @todo Change all signatur storing functions to the new format
if ($orig_sign['signed_text'] AND $orig_sign['signature'] AND $orig_sign['signer']) {
// Split the signed text
@@ -2163,14 +2192,14 @@ die($slap);
$signed_text = $message["target_guid"].';'.$message["target_type"];
$message["parent_author_signature"] = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
} else
- $message["parent_author_signature"] = self::get_signature($owner, $message);
+ $message["parent_author_signature"] = self::signature($owner, $message);
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
public static function send_retraction($item, $owner, $contact, $public_batch = false) {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::my_handle($owner);
// Check whether the retraction is for a top-level post or whether it's a relayable
if ($item["uri"] !== $item["parent-uri"]) {
@@ -2193,7 +2222,7 @@ die($slap);
public static function send_mail($item, $owner, $contact) {
- $myaddr = self::get_my_handle($owner);
+ $myaddr = self::my_handle($owner);
$r = q("SELECT * FROM `conv` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($item["convid"]),
diff --git a/include/xml.php b/include/xml.php
index 9c458dab12..91480dc03b 100644
--- a/include/xml.php
+++ b/include/xml.php
@@ -4,7 +4,7 @@
*
*/
class xml {
- function from_array($array, &$xml) {
+ function from_array($array, &$xml, $remove_header = false) {
if (!is_object($xml)) {
foreach($array as $key => $value) {
@@ -14,7 +14,13 @@ class xml {
$dom = dom_import_simplexml($root)->ownerDocument;
$dom->formatOutput = true;
$xml = $dom;
- return $dom->saveXML();
+
+ $xml_text = $dom->saveXML();
+
+ if ($remove_header)
+ $xml_text = trim(substr($xml_text, 21));
+
+ return $xml_text;
}
}
From f8f19038bf43aef56aae3898324a3658e2f04c14 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 13 Mar 2016 09:57:44 +0100
Subject: [PATCH 038/485] XML generation is now improved
---
include/diaspora2.php | 158 +++++++++++++++++++-----------------------
include/xml.php | 42 +++++++++--
2 files changed, 105 insertions(+), 95 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 97d5ecee9f..da772d68bd 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -729,7 +729,6 @@ class diaspora {
self::fetch_guid($datarray);
$message_id = item_store($datarray);
- // print_r($datarray);
// If we are the origin of the parent we store the original data and notify our followers
if($message_id AND $parent_item["origin"]) {
@@ -1013,7 +1012,6 @@ class diaspora {
$datarray["body"] = self::construct_like_body($contact, $parent_item, $guid);
$message_id = item_store($datarray);
- // print_r($datarray);
// If we are the origin of the parent we store the original data and notify our followers
if($message_id AND $parent_item["origin"]) {
@@ -1493,7 +1491,6 @@ class diaspora {
self::fetch_guid($datarray);
$message_id = item_store($datarray);
- // print_r($datarray);
return $message_id;
}
@@ -1662,16 +1659,15 @@ class diaspora {
self::fetch_guid($datarray);
$message_id = item_store($datarray);
- // print_r($datarray);
logger("Stored item with message id ".$message_id, LOGGER_DEBUG);
return $message_id;
}
- /*******************************************************************************************
- * Here come all the functions that are needed to transmit data with the Diaspora protocol *
- *******************************************************************************************/
+ /******************************************************************************************
+ * Here are all the functions that are needed to transmit data with the Diaspora protocol *
+ ******************************************************************************************/
private function my_handle($me) {
if ($contact["addr"] != "")
@@ -1701,21 +1697,18 @@ class diaspora {
$signature = rsa_sign($signable_data,$prvkey);
$sig = base64url_encode($signature);
-$magic_env = <<< EOT
-
-
-
- $handle
-
-
- base64url
- RSA-SHA256
- $data
- $sig
-
-
-EOT;
-die($magic_env."\n");
+ $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;
}
@@ -1783,30 +1776,17 @@ die($magic_env."\n");
"ciphertext" => base64_encode($ciphertext)));
$cipher_json = base64_encode($encrypted_header_json_object);
- $xml = nul;
$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)));
- $encrypted_header = xml::from_array($xmldata, $xml, true);
-echo $encrypted_header."\n";
- $encrypted_header = "".$cipher_json." ";
+ $namespaces = array("" => "https://joindiaspora.com/protocol",
+ "me" => "http://salmon-protocol.org/ns/magic-env");
-$magic_env = <<< EOT
-
-
- $encrypted_header
-
- base64url
- RSA-SHA256
- $data
- $sig
-
-
-EOT;
-die($magic_env."\n");
+ $magic_env = xml::from_array($xmldata, $xml, false, $namespaces);
logger("magic_env: ".$magic_env, LOGGER_DATA);
return $magic_env;
@@ -1896,7 +1876,7 @@ die($magic_env."\n");
logger('send guid '.$guid, LOGGER_DEBUG);
$slap = self::build_message($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
-die($slap);
+
$return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $guid);
logger("guid: ".$item["guid"]." result ".$return_code, LOGGER_DEBUG);
@@ -2118,7 +2098,49 @@ die($slap);
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
- function send_relay($item, $owner, $contact, $public_batch = false) {
+ private function message_from_signatur($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;
+ }
+
+ public static function send_relay($item, $owner, $contact, $public_batch = false) {
if ($item["deleted"]) {
$sql_sign_id = "retract_iid";
@@ -2131,62 +2153,22 @@ die($slap);
$type = "comment";
}
- // fetch the original signature if the relayable was created by a Diaspora
- // or DFRN user.
+ // fetch the original signature
$r = q("SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE `".$sql_sign_id."` = %d LIMIT 1",
- intval($item["id"])
- );
+ intval($item["id"]));
if (!$r)
return self::send_followup($item, $owner, $contact, $public_batch);
- $orig_sign = $r[0];
+ $signature = $r[0];
// Old way - is used by the internal Friendica functions
/// @todo Change all signatur storing functions to the new format
- if ($orig_sign['signed_text'] AND $orig_sign['signature'] AND $orig_sign['signer']) {
-
- // Split the signed text
- $signed_parts = explode(";", $orig_sign['signed_text']);
-
- if ($item["deleted"])
- $message = array("parent_author_signature" => "",
- "target_guid" => $signed_parts[0],
- "target_type" => $signed_parts[1],
- "sender_handle" => $orig_sign['signer'],
- "target_author_signature" => $orig_sign['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" => $orig_sign['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" => $orig_sign['signature'],
- "text" => implode(";", $signed_parts),
- "diaspora_handle" => $handle);
- }
- } else { // New way
- $message = json_decode($orig_sign['signed_text']);
- }
+ if ($signature['signed_text'] AND $signature['signature'] AND $signature['signer'])
+ $message = self::message_from_signatur($item, $signature);
+ else // New way
+ $message = json_decode($signature['signed_text']);
if ($item["deleted"]) {
$signed_text = $message["target_guid"].';'.$message["target_type"];
diff --git a/include/xml.php b/include/xml.php
index 91480dc03b..c2313648ce 100644
--- a/include/xml.php
+++ b/include/xml.php
@@ -4,12 +4,15 @@
*
*/
class xml {
- function from_array($array, &$xml, $remove_header = false) {
+ function from_array($array, &$xml, $remove_header = false, $namespaces = array(), $root = true) {
- if (!is_object($xml)) {
+ if ($root) {
foreach($array as $key => $value) {
+ foreach ($namespaces AS $nskey => $nsvalue)
+ $key .= " xmlns".($nskey == "" ? "":":").$nskey.'="'.$nsvalue.'"';
+
$root = new SimpleXMLElement("<".$key."/>");
- self::from_array($value, $root);
+ self::from_array($value, $root, $remove_header, $namespaces, false);
$dom = dom_import_simplexml($root)->ownerDocument;
$dom->formatOutput = true;
@@ -25,10 +28,35 @@ class xml {
}
foreach($array as $key => $value) {
- if (!is_array($value) AND !is_numeric($key))
- $xml->addChild($key, xmlify($value));
- elseif (is_array($value))
- self::from_array($value, $xml->addChild($key));
+ 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);
+ }
}
}
From 07818a65536c1cb6373f4494245c583853e0fa95 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 13 Mar 2016 16:14:51 +0100
Subject: [PATCH 039/485] Decode function is now there as well.
---
include/diaspora.php | 15 ++--
include/diaspora2.php | 168 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 174 insertions(+), 9 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 78ba520790..2b85befa8c 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -111,18 +111,18 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
$ret = diaspora_reshare($importer,$xmlbase->reshare,$msg);
}
elseif($xmlbase->retraction) {
- $tempfile = tempnam(get_temppath(), "diaspora-retraction");
- file_put_contents($tempfile, json_encode($data));
+ //$tempfile = tempnam(get_temppath(), "diaspora-retraction");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
}
elseif($xmlbase->signed_retraction) {
- $tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
- file_put_contents($tempfile, json_encode($data));
+ //$tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
}
elseif($xmlbase->relayable_retraction) {
- $tempfile = tempnam(get_temppath(), "diaspora-relayable_retraction");
- file_put_contents($tempfile, json_encode($data));
+ //$tempfile = tempnam(get_temppath(), "diaspora-relayable_retraction");
+ //file_put_contents($tempfile, json_encode($data));
$ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
}
elseif($xmlbase->photo) {
@@ -468,6 +468,9 @@ EOT;
function diaspora_decode($importer,$xml) {
+ $tempfile = tempnam(get_temppath(), "diaspora-decode");
+ file_put_contents($tempfile, json_encode(array("importer" => $importer, "xml" => $xml)));
+
$public = false;
$basedom = parse_xml_string($xml);
diff --git a/include/diaspora2.php b/include/diaspora2.php
index da772d68bd..081eaf153a 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -64,6 +64,168 @@ class diaspora {
return $relay;
}
+ function 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 = self::repair_signature($signature, $handle, ++$level);
+ }
+
+ return($signature);
+ }
+
+ /**
+ * @brief: Decodes incoming Diaspora message
+ *
+ * @param array $importer from user table
+ * @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)
+ */
+ function decode($importer, $xml) {
+
+ $public = false;
+ $basedom = parse_xml_string($xml);
+
+ if (!is_object($basedom))
+ return false;
+
+ $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=
+ * galaxor@diaspora.priateship.org
+ *
+ */
+
+ 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' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
+
+ }
+
+
/**
* @brief Dispatches public messages and find the fitting receivers
*
@@ -1287,7 +1449,7 @@ class diaspora {
$ret = self::person_by_handle($author);
if (!$ret || ($ret["network"] != NETWORK_DIASPORA)) {
- logger("Cannot resolve diaspora handle ".$author ." for ".$recipient);
+ logger("Cannot resolve diaspora handle ".$author." for ".$recipient);
return false;
}
@@ -1854,7 +2016,7 @@ class diaspora {
dbesc($slap),
intval($public_batch)
);
- if(count($r)) {
+ if($r) {
logger("add_to_queue ignored - identical item already in queue");
} else {
// queue message for redelivery
@@ -2211,7 +2373,7 @@ class diaspora {
intval($item["uid"])
);
- if (!count($r)) {
+ if (!$r) {
logger("conversation not found.");
return;
}
From 2841aa0281442e7a5570c122d5f3d9ab3a6504a7 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 13 Mar 2016 19:47:02 +0100
Subject: [PATCH 040/485] New implementation is now live.
---
include/delivery.php | 182 +++++++++++++++++++++---------------------
include/diaspora.php | 1 +
include/diaspora2.php | 49 ++++++++++--
mod/receive.php | 14 ++--
4 files changed, 144 insertions(+), 102 deletions(-)
diff --git a/include/delivery.php b/include/delivery.php
index e5ca0946b3..d184fe12e1 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,7 +53,7 @@ function delivery_run(&$argv, &$argc){
dbesc($item_id),
dbesc($contact_id)
);
- if(! count($r)) {
+ if (!count($r)) {
continue;
}
@@ -68,7 +68,7 @@ function delivery_run(&$argv, &$argc){
dbesc($contact_id)
);
- if((! $item_id) || (! $contact_id))
+ if (!$item_id || !$contact_id)
continue;
$expire = false;
@@ -84,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
@@ -106,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;
@@ -131,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;
}
@@ -145,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;
}
@@ -184,7 +184,7 @@ function delivery_run(&$argv, &$argc){
intval($uid)
);
- if(! count($r))
+ if (!count($r))
continue;
$owner = $r[0];
@@ -193,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];
@@ -217,7 +217,7 @@ function delivery_run(&$argv, &$argc){
$localhost = $a->get_hostname();
- if(strpos($localhost,':'))
+ if (strpos($localhost,':'))
$localhost = substr($localhost,0,strpos($localhost,':'));
/**
@@ -230,17 +230,17 @@ 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']))) {
@@ -253,10 +253,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;
@@ -266,7 +266,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']);
@@ -276,13 +276,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;
}
}
@@ -290,19 +290,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;
@@ -317,15 +317,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']));
@@ -347,10 +347,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;
@@ -370,14 +370,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);
}
@@ -385,9 +385,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.
@@ -397,67 +397,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
@@ -465,23 +465,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);
@@ -489,60 +489,64 @@ 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);
+ //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);
+ logger('delivery: diaspora retract: '.$loc);
- diaspora_send_retraction($target_item,$owner,$contact,$public_message);
+ diaspora::send_retraction($target_item,$owner,$contact,$public_message);
+ //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);
+ diaspora::send_followup($target_item,$owner,$contact,$public_message);
+ //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('delivery: diaspora relay: '.$loc);
+ diaspora::send_relay($target_item,$owner,$contact,$public_message);
+ //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('delivery: diaspora status: '.$loc);
+ diaspora::send_status($target_item,$owner,$contact,$public_message);
+ //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/diaspora.php b/include/diaspora.php
index 2b85befa8c..11fe2c9b57 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -15,6 +15,7 @@ require_once('include/lock.php');
require_once('include/threads.php');
require_once('mod/share.php');
require_once('include/enotify.php');
+require_once('include/diaspora2.php');
function diaspora_dispatch_public($msg) {
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 081eaf153a..b031651675 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -284,6 +284,8 @@ class diaspora {
$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);
@@ -654,7 +656,7 @@ class diaspora {
return false;
}
- if (!self::post_allow($importer, $contact, false)) {
+ if (!self::post_allow($importer, $contact, $is_comment)) {
logger("The handle: ".$handle." is not allowed to post to user ".$importer["uid"]);
return false;
}
@@ -669,10 +671,10 @@ class diaspora {
if($r) {
logger("message ".$guid." already exists for user ".$uid);
- return false;
+ return true;
}
- return true;
+ return false;
}
private function fetch_guid($item) {
@@ -774,10 +776,12 @@ class diaspora {
}
if (!$r) {
- logger("parent item not found: parent: ".$guid." item: ".$guid);
+ logger("parent item not found: parent: ".$guid." - user: ".$uid);
return false;
- } else
+ } else {
+ logger("parent item found: parent: ".$guid." - user: ".$uid);
return $r[0];
+ }
}
private function author_contact_by_url($contact, $person, $uid) {
@@ -892,6 +896,9 @@ class diaspora {
$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"]) {
@@ -1175,6 +1182,9 @@ class diaspora {
$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"]) {
@@ -1358,6 +1368,8 @@ class diaspora {
update_gcontact($gcontact);
+ logger("Profile of contact ".$contact["id"]." stored for user ".$importer["uid"], LOGGER_DEBUG);
+
return true;
}
@@ -1654,6 +1666,9 @@ class diaspora {
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;
}
@@ -1695,6 +1710,8 @@ class diaspora {
);
delete_thread($r[0]["id"], $r[0]["parent-uri"]);
+ logger("Deleted target ".$target_guid." from user ".$importer["uid"], LOGGER_DEBUG);
+
// Now check if the retraction needs to be relayed by us
if($p[0]["origin"]) {
@@ -1822,7 +1839,8 @@ class diaspora {
self::fetch_guid($datarray);
$message_id = item_store($datarray);
- logger("Stored item with message id ".$message_id, LOGGER_DEBUG);
+ if ($message_id)
+ logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
return $message_id;
}
@@ -2329,8 +2347,21 @@ class diaspora {
/// @todo Change all signatur storing functions to the new format
if ($signature['signed_text'] AND $signature['signature'] AND $signature['signer'])
$message = self::message_from_signatur($item, $signature);
- else // New way
- $message = json_decode($signature['signed_text']);
+ else {// New way
+ $msg = json_decode($signature['signed_text'], true);
+
+ $message = array();
+ foreach ($msg AS $field => $data) {
+ if (!$item["deleted"]) {
+ if ($field == "author")
+ $field = "diaspora_handle";
+ if ($field == "parent_type")
+ $field = "target_type";
+ }
+
+ $message[$field] = $data;
+ }
+ }
if ($item["deleted"]) {
$signed_text = $message["target_guid"].';'.$message["target_type"];
@@ -2338,6 +2369,8 @@ class diaspora {
} else
$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"]);
}
diff --git a/mod/receive.php b/mod/receive.php
index 95a5101675..051ea8c25c 100644
--- a/mod/receive.php
+++ b/mod/receive.php
@@ -53,7 +53,8 @@ function receive_post(&$a) {
logger('mod-diaspora: message is okay', LOGGER_DEBUG);
- $msg = diaspora_decode($importer,$xml);
+ $msg = diaspora::decode($importer,$xml);
+ //$msg = diaspora_decode($importer,$xml);
logger('mod-diaspora: decoded', LOGGER_DEBUG);
@@ -65,10 +66,13 @@ function receive_post(&$a) {
logger('mod-diaspora: dispatching', LOGGER_DEBUG);
$ret = 0;
- if($public)
- diaspora_dispatch_public($msg);
- else
- $ret = diaspora_dispatch($importer,$msg);
+ if($public) {
+ diaspora::dispatch_public($msg);
+ //diaspora_dispatch_public($msg);
+ } else {
+ $ret = diaspora::dispatch($importer,$msg);
+ //$ret = diaspora_dispatch($importer,$msg);
+ }
http_status_exit(($ret) ? $ret : 200);
// NOTREACHED
From 75f5cfe63e2d84fbe55384a7b2769c55bbf423b6 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 13 Mar 2016 21:11:48 +0100
Subject: [PATCH 041/485] Retraction and reshares work
---
include/diaspora2.php | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index b031651675..f6b8b9a704 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -1628,6 +1628,8 @@ class diaspora {
if (!$original_item)
return false;
+ $orig_url = App::get_baseurl()."/display/".$original_item["guid"];
+
$datarray = array();
$datarray["uid"] = $importer["uid"];
@@ -1651,7 +1653,7 @@ class diaspora {
$datarray["object"] = json_encode($data);
$prefix = share_header($original_item["author-name"], $original_item["author-link"], $original_item["author-avatar"],
- $original_item["guid"], $original_item["created"], $original_item["uri"]);
+ $original_item["guid"], $original_item["created"], $orig_url);
$datarray["body"] = $prefix.$original_item["body"]."[/share]";
$datarray["tag"] = $original_item["tag"];
@@ -1691,16 +1693,20 @@ class diaspora {
return false;
// Only delete it if the author really fits
- if (!link_compare($r[0]["author-link"],$person["url"]))
+ 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 `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"]))
+ 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",
@@ -1736,6 +1742,8 @@ class diaspora {
return false;
}
+ logger("Got retraction for ".$target_type.", sender ".$sender." and user ".$importer["uid"], LOGGER_DEBUG);
+
switch ($target_type) {
case "Comment":
case "Like":
From 9ae2b2292fd07a53f46689f778cd4630031912a7 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 14 Mar 2016 08:11:14 +0100
Subject: [PATCH 042/485] Some more function calls changed to the new class
---
include/Contact.php | 2 +-
include/contact_selectors.php | 2 +-
include/delivery.php | 8 ++++----
include/diaspora2.php | 10 ++++++++--
include/follow.php | 2 +-
include/notifier.php | 6 +++---
include/queue.php | 2 +-
7 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/include/Contact.php b/include/Contact.php
index 3799e0b189..d76c8f826c 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');
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/delivery.php b/include/delivery.php
index d184fe12e1..1e1dadcd93 100644
--- a/include/delivery.php
+++ b/include/delivery.php
@@ -522,25 +522,25 @@ function delivery_run(&$argv, &$argc){
if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
// top-level retraction
- logger('delivery: diaspora retract: '.$loc);
-
+ logger('diaspora retract: '.$loc);
diaspora::send_retraction($target_item,$owner,$contact,$public_message);
//diaspora_send_retraction($target_item,$owner,$contact,$public_message);
break;
} elseif ($followup) {
// send comments and likes to owner to relay
+ logger('diaspora followup: '.$loc);
diaspora::send_followup($target_item,$owner,$contact,$public_message);
//diaspora_send_followup($target_item,$owner,$contact,$public_message);
break;
} 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);
+ logger('diaspora relay: '.$loc);
diaspora::send_relay($target_item,$owner,$contact,$public_message);
//diaspora_send_relay($target_item,$owner,$contact,$public_message);
break;
} elseif ($top_level && !$walltowall) {
// currently no workable solution for sending walltowall
- logger('delivery: diaspora status: '.$loc);
+ logger('diaspora status: '.$loc);
diaspora::send_status($target_item,$owner,$contact,$public_message);
//diaspora_send_status($target_item,$owner,$contact,$public_message);
break;
diff --git a/include/diaspora2.php b/include/diaspora2.php
index f6b8b9a704..5c17754e80 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -460,6 +460,8 @@ class diaspora {
* @return string The public key
*/
private function key($handle) {
+ $handle = strval($handle);
+
logger("Fetching diaspora key for: ".$handle);
$r = self::person_by_handle($handle);
@@ -1699,7 +1701,7 @@ class diaspora {
}
// Check if the sender is the thread owner
- $p = q("SELECT `author-link`, `origin` FROM `item` WHERE `id` = %d",
+ $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
@@ -1716,7 +1718,7 @@ class diaspora {
);
delete_thread($r[0]["id"], $r[0]["parent-uri"]);
- logger("Deleted target ".$target_guid." from user ".$importer["uid"], LOGGER_DEBUG);
+ 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"]) {
@@ -1727,6 +1729,8 @@ class diaspora {
intval($r[0]["id"]),
dbesc(json_encode($data))
);
+ $s = q("select * from sign where retract_iid = %d", intval($r[0]["id"]));
+ logger("Stored signatur for item ".$r[0]["id"]." - ".print_r($s, true), LOGGER_DEBUG);
// notify others
proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
@@ -2341,6 +2345,8 @@ class diaspora {
$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 `".$sql_sign_id."` = %d LIMIT 1",
diff --git a/include/follow.php b/include/follow.php
index 3af629536d..6eab7e12fa 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -303,7 +303,7 @@ function new_contact($uid,$url,$interactive = false) {
}
if($contact['network'] == NETWORK_DIASPORA) {
require_once('include/diaspora.php');
- $ret = diaspora_share($a->user,$contact);
+ $ret = diaspora::send_share($a->user,$contact);
logger('mod_follow: diaspora_share returns: ' . $ret);
}
}
diff --git a/include/notifier.php b/include/notifier.php
index 6c42f19c6a..e65da3adf2 100644
--- a/include/notifier.php
+++ b/include/notifier.php
@@ -536,7 +536,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();
@@ -629,11 +629,11 @@ function notifier_run(&$argv, &$argc){
}
// If the item was deleted, clean up the `sign` table
- if($target_item['deleted']) {
+ /* if($target_item['deleted']) {
$r = q("DELETE FROM sign where `retract_iid` = %d",
intval($target_item['id'])
);
- }
+ } */
logger('notifier: calling hooks', LOGGER_DEBUG);
diff --git a/include/queue.php b/include/queue.php
index 183ce0f9cd..878c149731 100644
--- a/include/queue.php
+++ b/include/queue.php
@@ -193,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']);
From 3734555715ab780c1d951c7c9d59c91b76b17b39 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 14 Mar 2016 20:04:17 +0100
Subject: [PATCH 043/485] Conversations are working now too
---
include/diaspora2.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 5c17754e80..c0e054c384 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -918,7 +918,7 @@ class diaspora {
return $message_id;
}
- private function receive_conversation_message($importer, $contact, $data, $msg, $mesg) {
+ 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));
@@ -1086,7 +1086,7 @@ class diaspora {
}
foreach($messages as $mesg)
- self::receive_conversation_message($importer, $contact, $data, $msg, $mesg);
+ self::receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation);
return true;
}
From 56cb6cc8972f55d82030c8c2b908b05e656640f6 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 14 Mar 2016 20:53:44 +0100
Subject: [PATCH 044/485] Removed just more old diaspora function calls.
---
database.sql | 11 -------
doc/database.md | 1 -
doc/database/db_dsprphotoq.md | 11 -------
include/cron.php | 4 ---
include/dbstructure.php | 11 -------
include/delivery.php | 5 ----
include/diaspora2.php | 2 +-
include/dsprphotoq.php | 55 -----------------------------------
include/follow.php | 2 +-
mod/dfrn_confirm.php | 4 +--
mod/p.php | 6 ++--
mod/receive.php | 3 --
object/Item.php | 2 +-
13 files changed, 8 insertions(+), 109 deletions(-)
delete mode 100644 doc/database/db_dsprphotoq.md
delete mode 100644 include/dsprphotoq.php
diff --git a/database.sql b/database.sql
index 25faf0f4c0..02e5c9b378 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
--
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/include/cron.php b/include/cron.php
index db7d44be0b..60c62786e6 100644
--- a/include/cron.php
+++ b/include/cron.php
@@ -71,10 +71,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");
diff --git a/include/dbstructure.php b/include/dbstructure.php
index ddf036f2c1..e5e748bb24 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"),
diff --git a/include/delivery.php b/include/delivery.php
index 1e1dadcd93..9ac9f2391b 100644
--- a/include/delivery.php
+++ b/include/delivery.php
@@ -501,7 +501,6 @@ function delivery_run(&$argv, &$argc){
if ($mail) {
diaspora::send_mail($item,$owner,$contact);
- //diaspora_send_mail($item,$owner,$contact);
break;
}
@@ -524,25 +523,21 @@ function delivery_run(&$argv, &$argc){
// top-level retraction
logger('diaspora retract: '.$loc);
diaspora::send_retraction($target_item,$owner,$contact,$public_message);
- //diaspora_send_retraction($target_item,$owner,$contact,$public_message);
break;
} elseif ($followup) {
// send comments and likes to owner to relay
logger('diaspora followup: '.$loc);
diaspora::send_followup($target_item,$owner,$contact,$public_message);
- //diaspora_send_followup($target_item,$owner,$contact,$public_message);
break;
} elseif ($target_item['uri'] !== $target_item['parent-uri']) {
// we are the relay - send comments, likes and relayable_retractions to our conversants
logger('diaspora relay: '.$loc);
diaspora::send_relay($target_item,$owner,$contact,$public_message);
- //diaspora_send_relay($target_item,$owner,$contact,$public_message);
break;
} elseif ($top_level && !$walltowall) {
// currently no workable solution for sending walltowall
logger('diaspora status: '.$loc);
diaspora::send_status($target_item,$owner,$contact,$public_message);
- //diaspora_send_status($target_item,$owner,$contact,$public_message);
break;
}
diff --git a/include/diaspora2.php b/include/diaspora2.php
index c0e054c384..1a354e9cf2 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -2093,7 +2093,7 @@ class diaspora {
return self::build_and_transmit($owner, $contact, "retraction", $message);
}
- private function is_reshare($body) {
+ public static function is_reshare($body) {
$body = trim($body);
// Skip if it isn't a pure repeated messages
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/follow.php b/include/follow.php
index 6eab7e12fa..d0411a466a 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -304,7 +304,7 @@ function new_contact($uid,$url,$interactive = false) {
if($contact['network'] == NETWORK_DIASPORA) {
require_once('include/diaspora.php');
$ret = diaspora::send_share($a->user,$contact);
- logger('mod_follow: diaspora_share returns: ' . $ret);
+ logger('share returns: '.$ret);
}
}
diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php
index 68950ec285..cc09021dca 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...
diff --git a/mod/p.php b/mod/p.php
index 92b72dc1ce..20d6cfdbaf 100644
--- a/mod/p.php
+++ b/mod/p.php
@@ -28,14 +28,14 @@ function p_init($a){
$post = array();
- $reshared = diaspora_is_reshare($item[0]["body"]);
+ $reshared = diaspora::is_reshare($item[0]["body"]);
if ($reshared) {
$nodename = "reshare";
$post["root_diaspora_id"] = $reshared["root_handle"];
$post["root_guid"] = $reshared["root_guid"];
$post["guid"] = $item[0]["guid"];
- $post["diaspora_handle"] = diaspora_handle_from_contact($item[0]["contact-id"]);
+ $post["diaspora_handle"] = diaspora::handle_from_contact($item[0]["contact-id"]);
$post["public"] = (!$item[0]["private"] ? 'true':'false');
$post["created_at"] = datetime_convert('UTC','UTC',$item[0]["created"]);
} else {
@@ -48,7 +48,7 @@ function p_init($a){
$nodename = "status_message";
$post["raw_message"] = str_replace("&", "&", $body);
$post["guid"] = $item[0]["guid"];
- $post["diaspora_handle"] = diaspora_handle_from_contact($item[0]["contact-id"]);
+ $post["diaspora_handle"] = diaspora::handle_from_contact($item[0]["contact-id"]);
$post["public"] = (!$item[0]["private"] ? 'true':'false');
$post["created_at"] = datetime_convert('UTC','UTC',$item[0]["created"]);
$post["provider_display_name"] = $item[0]["app"];
diff --git a/mod/receive.php b/mod/receive.php
index 051ea8c25c..4991ac47e8 100644
--- a/mod/receive.php
+++ b/mod/receive.php
@@ -54,7 +54,6 @@ function receive_post(&$a) {
logger('mod-diaspora: message is okay', LOGGER_DEBUG);
$msg = diaspora::decode($importer,$xml);
- //$msg = diaspora_decode($importer,$xml);
logger('mod-diaspora: decoded', LOGGER_DEBUG);
@@ -68,10 +67,8 @@ function receive_post(&$a) {
$ret = 0;
if($public) {
diaspora::dispatch_public($msg);
- //diaspora_dispatch_public($msg);
} else {
$ret = diaspora::dispatch($importer,$msg);
- //$ret = diaspora_dispatch($importer,$msg);
}
http_status_exit(($ret) ? $ret : 200);
diff --git a/object/Item.php b/object/Item.php
index e9c96cf159..59659cdaff 100644
--- a/object/Item.php
+++ b/object/Item.php
@@ -324,7 +324,7 @@ class Item extends BaseObject {
// Diaspora isn't able to do likes on comments - but red does
if (($item["item_network"] == NETWORK_DIASPORA) AND ($indent == 'comment') AND
- !diaspora_is_redmatrix($item["owner-link"]) AND isset($buttons["like"]))
+ !diaspora::is_redmatrix($item["owner-link"]) AND isset($buttons["like"]))
unset($buttons["like"]);
// Diaspora doesn't has multithreaded comments
From 6f43d3a4c4f87dd282691d3e65c75b0ed99a1b3b Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 14 Mar 2016 22:10:26 +0100
Subject: [PATCH 045/485] Profile update is now working with the new function
as well
---
include/diaspora2.php | 86 ++++++++++++++++++++++++++++++++++-
include/profile_update.php | 92 +-------------------------------------
2 files changed, 85 insertions(+), 93 deletions(-)
diff --git a/include/diaspora2.php b/include/diaspora2.php
index 1a354e9cf2..75cedeccd1 100644
--- a/include/diaspora2.php
+++ b/include/diaspora2.php
@@ -2058,7 +2058,7 @@ class diaspora {
}
- private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "") {
+ private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "", $spool = false) {
$data = array("XML" => array("post" => array($type => $message)));
@@ -2069,7 +2069,11 @@ class diaspora {
$slap = self::build_message($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch);
- $return_code = self::transmit($owner, $contact, $slap, $public_batch, false, $guid);
+ 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);
@@ -2467,5 +2471,83 @@ class diaspora {
return self::build_and_transmit($owner, $contact, $type, $message, false, $item["guid"]);
}
+
+ 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);
+ }
+
+ $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);
+
+ foreach($recips as $recip)
+ self::build_and_transmit($profile, $recip, "profile", $message, false, "", true);
+ }
}
?>
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());
}
From dc2e7a66b3cf9401afbc4cf425fc5a37c66d2d74 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 14 Mar 2016 23:11:43 +0100
Subject: [PATCH 046/485] The Diaspora class is now productive
---
include/diaspora.php | 5338 ++++++++++++++++++-----------------------
include/diaspora2.php | 2553 --------------------
2 files changed, 2359 insertions(+), 5532 deletions(-)
delete mode 100644 include/diaspora2.php
diff --git a/include/diaspora.php b/include/diaspora.php
index 11fe2c9b57..75cedeccd1 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -1,1702 +1,927 @@
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;
}
- $data = $msg;
+ function repair_signature($signature, $handle = "", $level = 1) {
- // php doesn't like dashes in variable names
+ if ($signature == "")
+ return ($signature);
- $msg['message'] = str_replace(
- array('',' '),
- array('',' '),
- $msg['message']);
+ 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) {
- $tempfile = tempnam(get_temppath(), "diaspora-request");
- file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_request($importer,$xmlbase->request);
- }
- elseif($xmlbase->status_message) {
- //$tempfile = tempnam(get_temppath(), "diaspora-status_message");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_post($importer,$xmlbase->status_message,$msg);
- }
- elseif($xmlbase->profile) {
- //$tempfile = tempnam(get_temppath(), "diaspora-profile");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_profile($importer,$xmlbase->profile,$msg);
- }
- elseif($xmlbase->comment) {
- //$tempfile = tempnam(get_temppath(), "diaspora-comment");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_comment($importer,$xmlbase->comment,$msg);
- }
- elseif($xmlbase->like) {
- //$tempfile = tempnam(get_temppath(), "diaspora-like");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_like($importer,$xmlbase->like,$msg);
- }
- elseif($xmlbase->asphoto) {
- $tempfile = tempnam(get_temppath(), "diaspora-asphoto");
- file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg);
- }
- elseif($xmlbase->reshare) {
- //$tempfile = tempnam(get_temppath(), "diaspora-reshare");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg);
- }
- elseif($xmlbase->retraction) {
- //$tempfile = tempnam(get_temppath(), "diaspora-retraction");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
- }
- elseif($xmlbase->signed_retraction) {
- //$tempfile = tempnam(get_temppath(), "diaspora-signed_retraction");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
- }
- elseif($xmlbase->relayable_retraction) {
- //$tempfile = tempnam(get_temppath(), "diaspora-relayable_retraction");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
- }
- elseif($xmlbase->photo) {
- //$tempfile = tempnam(get_temppath(), "diaspora-photo");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_photo($importer,$xmlbase->photo,$msg,$attempt);
- }
- elseif($xmlbase->conversation) {
- $tempfile = tempnam(get_temppath(), "diaspora-conversation");
- file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_conversation($importer,$xmlbase->conversation,$msg);
- }
- elseif($xmlbase->message) {
- $tempfile = tempnam(get_temppath(), "diaspora-message");
- file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_message($importer,$xmlbase->message,$msg);
- }
- elseif($xmlbase->participation) {
- //$tempfile = tempnam(get_temppath(), "diaspora-participation");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_participation($importer,$xmlbase->participation);
- }
- elseif($xmlbase->poll_participation) {
- //$tempfile = tempnam(get_temppath(), "diaspora-poll_participation");
- //file_put_contents($tempfile, json_encode($data));
- $ret = diaspora_participation($importer,$xmlbase->poll_participation);
- }
- else {
- $tempfile = tempnam(get_temppath(), "diaspora-unknown");
- file_put_contents($tempfile, json_encode($data));
- 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 from user table
+ * @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)
+ */
+ 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);
+
+ /**
+ * $decrypted now contains something like
+ *
+ *
+ * 8e+G2+ET8l5BPuW0sVTnQw==
+ * UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU=
+ * galaxor@diaspora.priateship.org
+ *
+ */
+
+ 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' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
+
+ }
+
+
+ /**
+ * @brief Dispatches public messages and find the fitting receivers
+ *
+ * @param array $msg The post that will be dispatched
+ *
+ * @return bool Was the message accepted?
+ */
+ 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);
+ $item_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 $item_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 bool Was the message accepted?
+ */
+ 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);
+
+ 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 "request":
+ return self::receive_request($importer, $fields);
+
+ case "reshare":
+ return self::receive_reshare($importer, $fields);
+
+ case "retraction":
+ return self::receive_retraction($importer, $sender, $fields);
+
+ case "status_message":
+ return self::receive_status_message($importer, $fields);
+
+ 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";
+
+ $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) {
+ /// @todo Remove this function from include/network.php
- $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) {
-
- $tempfile = tempnam(get_temppath(), "diaspora-decode");
- file_put_contents($tempfile, json_encode(array("importer" => $importer, "xml" => $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);
+ public static function handle_from_contact($contact_id) {
+ $handle = False;
- // figure out where in the DOM tree our data is hiding
+ logger("contact id is ".$contact_id, LOGGER_DEBUG);
- if($dom->provenance->data)
- $base = $dom->provenance;
- elseif($dom->env->data)
- $base = $dom->env;
- elseif($dom->data)
- $base = $dom;
+ $r = q("SELECT `network`, `addr`, `self`, `url`, `nick` FROM `contact` WHERE `id` = %d",
+ intval($contact_id)
+ );
+ if($r) {
+ $contact = $r[0];
- if(! $base) {
- logger('mod-diaspora: unable to locate salmon data in xml ');
- http_status_exit(400);
+ logger("contact 'self' = ".$contact['self']." 'url' = ".$contact['url'], LOGGER_DEBUG);
+
+ if($contact['addr'] != "")
+ $handle = $contact['addr'];
+ 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;
+ }
+ }
+
+ return $handle;
}
+ 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) {
+ 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;
- }
-
- $def_gid = get_default_group($importer['uid'], $ret["network"]);
- if (intval($def_gid)) {
- require_once('include/group.php');
- group_add_member($importer['uid'], '', $contact_record['id'], $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);
+ 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;
+ 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 true;
+ }
- /// @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;
+ 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;
+ 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;
+ 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;
+ 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;
+ }
+
+ 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 = "";
+ 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;
+ public static function is_redmatrix($url) {
+ return(strstr($url, "/channel/"));
}
- $datarray["object"] = json_encode($xml);
- $datarray['object-type'] = $objecttype;
+ 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);
+ 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)
+ private function receive_comment($importer, $sender, $data) {
+ $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;
+
+ if (self::message_exists($importer["uid"], $guid))
+ return false;
+
+ $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"] = json_encode($data);
+
+ $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) {
+ 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;
@@ -1705,1469 +930,1624 @@ 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;
-}
+ 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;
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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;
+
+ if (self::message_exists($importer["uid"], $guid))
+ return false;
+
+ $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;
+ }
+
+ 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;
+ }
+
+ private function receive_participation($importer, $data) {
+ // I'm not sure if we can fully support this message type
+ return 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;
+ }
+
+ private function receive_poll_participation($importer, $data) {
+ // We don't support polls by now
+ return true;
+ }
+
+ private function receive_profile($importer, $data) {
+ $author = notags(unxmlify($data->author));
+
+ $contact = self::contact_by_handle($importer["uid"], $author);
+ if (!$contact)
+ return;
+
+ $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;
+ }
+
+ 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"] = "\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);
+
+ }
+
+ }
}
+
+ private function receive_request($importer, $data) {
+ $author = unxmlify($data->author);
+ $recipient = unxmlify($data->recipient);
+
+ if (!$author || !$recipient)
+ return;
+
+ $contact = self::contact_by_handle($importer["uid"],$author);
+
+ if($contact) {
+
+ // perhaps we were already sharing with this person. Now they're sharing with us.
+ // That makes us friends.
+
+ self::receive_request_make_friend($importer, $contact);
+ return true;
+ }
+
+ $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)
+ $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 = self::send_share($u[0], $contact_record);
+ }
+
+ return true;
+ }
+
+ 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, since there can be many side effects with reshared posts from other networks or reshares from reshares
+ if (self::is_reshare($r[0]["body"]))
+ $r = array();
+ 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;
+ }
+
+ private function receive_reshare($importer, $data) {
+ $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;
+
+ if (self::message_exists($importer["uid"], $guid))
+ return false;
+
+ $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"] = json_encode($data);
+
+ $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;
+ }
+
+ 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"]) {
+
+ // 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` (`retract_iid`,`signed_text`) VALUES (%d,'%s')",
+ intval($r[0]["id"]),
+ dbesc(json_encode($data))
+ );
+ $s = q("select * from sign where retract_iid = %d", intval($r[0]["id"]));
+ logger("Stored signatur for item ".$r[0]["id"]." - ".print_r($s, true), LOGGER_DEBUG);
+
+ // notify others
+ proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
+ }
+ }
+
+ 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;
+ }
+
+ private function receive_status_message($importer, $data) {
+
+ $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;
+
+ if (self::message_exists($importer["uid"], $guid))
+ return false;
+
+ $address = array();
+ if ($data->location)
+ foreach ($data->location->children() AS $fieldname => $data)
+ $address[$fieldname] = notags(unxmlify($data));
+
+ $body = diaspora2bb($raw_message);
+
+ $datarray = array();
+
+ if ($data->photo) {
+ foreach ($data->photo AS $photo)
+ $body = "[img]".$photo->remote_photo_path.$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"] = json_encode($data);
+
+ $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 *
+ ******************************************************************************************/
+
+ private function my_handle($me) {
+ 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.
+ return $me["nickname"]."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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"));
+ }
+
+ 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'])
+
+ 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;
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ public static function 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"] = 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 ($ret["root_guid"] == ""))
+ return(false);
+ return($ret);
+ }
+
+ 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"]);
+ }
+
+ private function construct_like($item, $owner) {
+
+ $myaddr = self::my_handle($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" => $authorsig,
+ "diaspora_handle" => $myaddr));
+ }
+
+ private function construct_comment($item, $owner) {
+
+ $myaddr = self::my_handle($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" => $myaddr));
+ }
+
+ 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"]);
+ }
+
+ private function message_from_signatur($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;
+ }
+
+ public static function send_relay($item, $owner, $contact, $public_batch = false) {
+
+ if ($item["deleted"]) {
+ $sql_sign_id = "retract_iid";
+ $type = "relayable_retraction";
+ } elseif ($item['verb'] === ACTIVITY_LIKE) {
+ $sql_sign_id = "iid";
+ $type = "like";
+ } else {
+ $sql_sign_id = "iid";
+ $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 `".$sql_sign_id."` = %d LIMIT 1",
+ intval($item["id"]));
+
+ if (!$r)
+ return self::send_followup($item, $owner, $contact, $public_batch);
+
+ $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_signatur($item, $signature);
+ else {// New way
+ $msg = json_decode($signature['signed_text'], true);
+
+ $message = array();
+ foreach ($msg AS $field => $data) {
+ if (!$item["deleted"]) {
+ if ($field == "author")
+ $field = "diaspora_handle";
+ if ($field == "parent_type")
+ $field = "target_type";
+ }
+
+ $message[$field] = $data;
+ }
+ }
+
+ if ($item["deleted"]) {
+ $signed_text = $message["target_guid"].';'.$message["target_type"];
+ $message["parent_author_signature"] = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
+ } else
+ $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"]);
+ }
+
+ public static function send_retraction($item, $owner, $contact, $public_batch = false) {
+
+ $myaddr = self::my_handle($owner);
+
+ // 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";
+ }
+
+ $signed_text = $item["guid"].";".$target_type;
+
+ $message = array("target_guid" => $item['guid'],
+ "target_type" => $target_type,
+ "sender_handle" => $myaddr,
+ "target_author_signature" => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
+
+ return self::build_and_transmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]);
+ }
+
+ 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"]);
+ }
+
+ 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
-}
-
-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;
- }
-
- $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
- if(! $contact)
- return;
-
- //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'])
- );
- }
- }
- } */
-
- 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);
- }
- }
-*/
-
- //if(strlen($title))
- // $body = "[b]".html_entity_decode($title)."[/b]\n\n".$body;
-
- // convert to markdown
- $body = xmlify(html_entity_decode(bb2diaspora($body)));
- //$body = 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";
- }
- }
- }
-
-
- $public = (($item['private']) ? 'false' : 'true');
-
- require_once('include/datetime.php');
- $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C');
-
- // 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'])
- );
- 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'))
- ));
-
-
- 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']);
- }
-
-}
-
-function diaspora_send_followup($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;
-
- 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;
+ $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);
+
+ foreach($recips as $recip)
+ self::build_and_transmit($profile, $recip, "profile", $message, false, "", true);
+ }
}
+?>
diff --git a/include/diaspora2.php b/include/diaspora2.php
deleted file mode 100644
index 75cedeccd1..0000000000
--- a/include/diaspora2.php
+++ /dev/null
@@ -1,2553 +0,0 @@
- decoded Diaspora XML message
- * 'author' -> author diaspora handle
- * 'key' -> author public key (converted to pkcs#8)
- */
- function decode($importer, $xml) {
-
- $public = false;
- $basedom = parse_xml_string($xml);
-
- if (!is_object($basedom))
- return false;
-
- $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=
- * galaxor@diaspora.priateship.org
- *
- */
-
- 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' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
-
- }
-
-
- /**
- * @brief Dispatches public messages and find the fitting receivers
- *
- * @param array $msg The post that will be dispatched
- *
- * @return bool Was the message accepted?
- */
- 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);
- $item_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 $item_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 bool Was the message accepted?
- */
- 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);
-
- 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 "request":
- return self::receive_request($importer, $fields);
-
- case "reshare":
- return self::receive_reshare($importer, $fields);
-
- case "retraction":
- return self::receive_retraction($importer, $sender, $fields);
-
- case "status_message":
- return self::receive_status_message($importer, $fields);
-
- 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";
-
- $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 ($r) {
- $person = $r[0];
- 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"))
- $update = true;
- }
-
- if (!$person OR $update) {
- logger("create or refresh", LOGGER_DEBUG);
- $r = probe_url($handle, PROBE_DIASPORA);
-
- // 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;
- }
- }
- return $person;
- }
-
- /**
- * @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) {
- /// @todo Remove this function from include/network.php
-
- 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;
- }
-
- public static function handle_from_contact($contact_id) {
- $handle = False;
-
- logger("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("contact 'self' = ".$contact['self']." 'url' = ".$contact['url'], LOGGER_DEBUG);
-
- if($contact['addr'] != "")
- $handle = $contact['addr'];
- 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;
- }
- }
-
- return $handle;
- }
-
- private function contact_by_handle($uid, $handle) {
- $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `addr` = '%s' LIMIT 1",
- intval($uid),
- dbesc($handle)
- );
-
- if ($r)
- return $r[0];
-
- $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];
-
- return false;
- }
-
- 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.
- // 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("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)
- return true;
-
- // Messages for the global users are always accepted
- if ($importer["uid"] == 0)
- return true;
-
- return false;
- }
-
- 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;
- }
-
- 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;
- }
-
- private function message_exists($uid, $guid) {
- $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
- intval($uid),
- dbesc($guid)
- );
-
- if($r) {
- logger("message ".$guid." already exists for user ".$uid);
- return true;
- }
-
- return false;
- }
-
- 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"]);
- }
-
- 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"]);
- }
-
- 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);
- }
-
- private function message($guid, $server, $level = 0) {
-
- if ($level > 5)
- return false;
-
- // This will work for Diaspora and newer Friendica servers
- $source_url = $server."/p/".$guid.".xml";
- $x = fetch_url($source_url);
- if(!$x)
- return false;
-
- $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;
- }
-
- 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];
- }
- }
-
- private function author_contact_by_url($contact, $person, $uid) {
-
- $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;
- }
-
- return (array("cid" => $cid, "network" => $network));
- }
-
- public static function is_redmatrix($url) {
- return(strstr($url, "/channel/"));
- }
-
- private function 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 (self::is_redmatrix($r[0]["url"]))
- return $r[0]["url"]."/?f=&mid=".$guid;
-
- return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
- }
-
- private function receive_account_deletion($importer, $data) {
- $author = notags(unxmlify($data->author));
-
- $contact = self::contact_by_handle($importer["uid"], $author);
- if (!$contact) {
- logger("cannot find contact for author: ".$author);
- return false;
- }
-
- // We now remove the contact
- contact_remove($contact["id"]);
- return true;
- }
-
- private function receive_comment($importer, $sender, $data) {
- $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;
-
- if (self::message_exists($importer["uid"], $guid))
- return false;
-
- $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"] = json_encode($data);
-
- $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;
- }
-
- 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;
-
- $msg_guid = notags(unxmlify($mesg->guid));
- $msg_parent_guid = notags(unxmlify($mesg->parent_guid));
- $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)));
-
- // "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("message conversation guid does not belong to the current conversation.");
- return false;
- }
-
- $body = diaspora2bb($msg_text);
- $message_uri = $msg_author.":".$msg_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_author,$msg["author"]) == 0) {
- $person = $contact;
- $key = $msg["key"];
- } else {
- $person = self::person_by_handle($msg_author);
-
- if (is_array($person) && x($person, "pubkey"))
- $key = $person["pubkey"];
- else {
- logger("unable to find author details");
- return false;
- }
- }
-
- 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_author.";".$msg_conversation_guid;
-
- $parent_author_signature = base64_decode($msg_parent_author_signature);
-
- $key = $msg["key"];
-
- 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_uri)
- );
- 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($msg_guid),
- intval($conversation["id"]),
- dbesc($person["name"]),
- dbesc($person["photo"]),
- dbesc($person["url"]),
- intval($contact["id"]),
- dbesc($subject),
- dbesc($body),
- 0,
- 0,
- dbesc($message_uri),
- dbesc($author.":".$guid),
- dbesc($msg_created_at)
- );
-
- q("UPDATE `conv` SET `updated` = '%s' WHERE `id` = %d",
- dbesc(datetime_convert()),
- 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"
- ));
- }
-
- 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));
-
- $messages = $data->message;
-
- if (!count($messages)) {
- logger("empty conversation");
- return false;
- }
-
- $contact = self::allowed_contact_by_handle($importer, $msg["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($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;
- }
-
- 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);
- }
-
- 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);
- }
-
- 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;
-
- if (self::message_exists($importer["uid"], $guid))
- return false;
-
- $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;
- }
-
- 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;
- }
-
- private function receive_participation($importer, $data) {
- // I'm not sure if we can fully support this message type
- return 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;
- }
-
- private function receive_poll_participation($importer, $data) {
- // We don't support polls by now
- return true;
- }
-
- private function receive_profile($importer, $data) {
- $author = notags(unxmlify($data->author));
-
- $contact = self::contact_by_handle($importer["uid"], $author);
- if (!$contact)
- return;
-
- $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;
- }
-
- 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"] = "\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);
-
- }
-
- }
- }
-
- private function receive_request($importer, $data) {
- $author = unxmlify($data->author);
- $recipient = unxmlify($data->recipient);
-
- if (!$author || !$recipient)
- return;
-
- $contact = self::contact_by_handle($importer["uid"],$author);
-
- if($contact) {
-
- // perhaps we were already sharing with this person. Now they're sharing with us.
- // That makes us friends.
-
- self::receive_request_make_friend($importer, $contact);
- return true;
- }
-
- $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)
- $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 = self::send_share($u[0], $contact_record);
- }
-
- return true;
- }
-
- 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, since there can be many side effects with reshared posts from other networks or reshares from reshares
- if (self::is_reshare($r[0]["body"]))
- $r = array();
- 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 ($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));
-
- if ($r)
- return $r[0];
-
- }
- }
- return false;
- }
-
- private function receive_reshare($importer, $data) {
- $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;
-
- if (self::message_exists($importer["uid"], $guid))
- return false;
-
- $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"] = json_encode($data);
-
- $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;
- }
-
- 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 (!$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"]) {
-
- // 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` (`retract_iid`,`signed_text`) VALUES (%d,'%s')",
- intval($r[0]["id"]),
- dbesc(json_encode($data))
- );
- $s = q("select * from sign where retract_iid = %d", intval($r[0]["id"]));
- logger("Stored signatur for item ".$r[0]["id"]." - ".print_r($s, true), LOGGER_DEBUG);
-
- // notify others
- proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
- }
- }
-
- 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;
- }
-
- private function receive_status_message($importer, $data) {
-
- $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;
-
- if (self::message_exists($importer["uid"], $guid))
- return false;
-
- $address = array();
- if ($data->location)
- foreach ($data->location->children() AS $fieldname => $data)
- $address[$fieldname] = notags(unxmlify($data));
-
- $body = diaspora2bb($raw_message);
-
- $datarray = array();
-
- if ($data->photo) {
- foreach ($data->photo AS $photo)
- $body = "[img]".$photo->remote_photo_path.$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"] = json_encode($data);
-
- $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 *
- ******************************************************************************************/
-
- private function my_handle($me) {
- 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.
- return $me["nickname"]."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
- }
-
- 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;
- }
-
- 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;
- }
-
- 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;
- }
-
- 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"));
- }
-
- 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;
- }
- }
-
- logger("transmit: ".$logid."-".$guid." returns: ".$return_code);
-
- if(!$return_code || (($return_code == 503) && (stristr($a->get_curl_headers(), "retry-after")))) {
- logger("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($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);
- }
- }
-
- return(($return_code) ? $return_code : (-1));
- }
-
-
- 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;
- }
-
- 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);
- }
-
- 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);
- }
-
- public static function 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"] = 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 ($ret["root_guid"] == ""))
- return(false);
- return($ret);
- }
-
- 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"]);
- }
-
- private function construct_like($item, $owner) {
-
- $myaddr = self::my_handle($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" => $authorsig,
- "diaspora_handle" => $myaddr));
- }
-
- private function construct_comment($item, $owner) {
-
- $myaddr = self::my_handle($owner);
-
- $p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
- intval($item["parent"]),
- intval($item["parent"])
- );
-
- if (!$p)
- return false;
-
- $parent = $p[0];
-
- $text = html_entity_decode(bb2diaspora($item["body"]));
-
- return(array("guid" => $item["guid"],
- "parent_guid" => $parent["guid"],
- "author_signature" => "",
- "text" => $text,
- "diaspora_handle" => $myaddr));
- }
-
- 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"]);
- }
-
- private function message_from_signatur($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;
- }
-
- public static function send_relay($item, $owner, $contact, $public_batch = false) {
-
- if ($item["deleted"]) {
- $sql_sign_id = "retract_iid";
- $type = "relayable_retraction";
- } elseif ($item['verb'] === ACTIVITY_LIKE) {
- $sql_sign_id = "iid";
- $type = "like";
- } else {
- $sql_sign_id = "iid";
- $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 `".$sql_sign_id."` = %d LIMIT 1",
- intval($item["id"]));
-
- if (!$r)
- return self::send_followup($item, $owner, $contact, $public_batch);
-
- $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_signatur($item, $signature);
- else {// New way
- $msg = json_decode($signature['signed_text'], true);
-
- $message = array();
- foreach ($msg AS $field => $data) {
- if (!$item["deleted"]) {
- if ($field == "author")
- $field = "diaspora_handle";
- if ($field == "parent_type")
- $field = "target_type";
- }
-
- $message[$field] = $data;
- }
- }
-
- if ($item["deleted"]) {
- $signed_text = $message["target_guid"].';'.$message["target_type"];
- $message["parent_author_signature"] = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
- } else
- $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"]);
- }
-
- public static function send_retraction($item, $owner, $contact, $public_batch = false) {
-
- $myaddr = self::my_handle($owner);
-
- // 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";
- }
-
- $signed_text = $item["guid"].";".$target_type;
-
- $message = array("target_guid" => $item['guid'],
- "target_type" => $target_type,
- "sender_handle" => $myaddr,
- "target_author_signature" => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
-
- return self::build_and_transmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]);
- }
-
- 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"]);
- }
-
- 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);
- }
-
- $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);
-
- foreach($recips as $recip)
- self::build_and_transmit($profile, $recip, "profile", $message, false, "", true);
- }
-}
-?>
From 4b5e7007a7148d85858f6851bdb8900dfb05e7cd Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Mon, 14 Mar 2016 23:54:01 +0100
Subject: [PATCH 047/485] Bugfix: XML copy had problems with "&"
---
include/diaspora.php | 12 ++++++------
include/xml.php | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 75cedeccd1..4c3cb41726 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -291,7 +291,7 @@ class diaspora {
return self::receive_account_deletion($importer, $fields);
case "comment":
- return self::receive_comment($importer, $sender, $fields);
+ return self::receive_comment($importer, $sender, $fields, $msg["message"]);
case "conversation":
return self::receive_conversation($importer, $msg, $fields);
@@ -324,7 +324,7 @@ class diaspora {
return self::receive_retraction($importer, $sender, $fields);
case "status_message":
- return self::receive_status_message($importer, $fields);
+ return self::receive_status_message($importer, $fields, $msg["message"]);
default:
logger("Unknown message type ".$type);
@@ -841,7 +841,7 @@ class diaspora {
return true;
}
- private function receive_comment($importer, $sender, $data) {
+ private function receive_comment($importer, $sender, $data, $xml) {
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
$text = unxmlify($data->text);
@@ -890,7 +890,7 @@ class diaspora {
$datarray["parent-uri"] = $parent_item["uri"];
$datarray["object-type"] = ACTIVITY_OBJ_COMMENT;
- $datarray["object"] = json_encode($data);
+ $datarray["object"] = $xml;
$datarray["body"] = diaspora2bb($text);
@@ -1769,7 +1769,7 @@ class diaspora {
return true;
}
- private function receive_status_message($importer, $data) {
+ private function receive_status_message($importer, $data, $xml) {
$raw_message = unxmlify($data->raw_message);
$guid = notags(unxmlify($data->guid));
@@ -1831,7 +1831,7 @@ class diaspora {
$datarray["verb"] = ACTIVITY_POST;
$datarray["gravity"] = GRAVITY_PARENT;
- $datarray["object"] = json_encode($data);
+ $datarray["object"] = $xml;
$datarray["body"] = $body;
diff --git a/include/xml.php b/include/xml.php
index c2313648ce..c74c23c473 100644
--- a/include/xml.php
+++ b/include/xml.php
@@ -62,7 +62,7 @@ class xml {
function copy(&$source, &$target, $elementname) {
if (count($source->children()) == 0)
- $target->addChild($elementname, $source);
+ $target->addChild($elementname, xmlify($source));
else {
$child = $target->addChild($elementname);
foreach ($source->children() AS $childfield => $childentry)
From eed55664fc61a0e285dcf5c814b39496537c7039 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 15 Mar 2016 00:26:28 +0100
Subject: [PATCH 048/485] Reshares now store the original XML as well.
---
include/diaspora.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 4c3cb41726..3c3f5cb25a 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -318,7 +318,7 @@ class diaspora {
return self::receive_request($importer, $fields);
case "reshare":
- return self::receive_reshare($importer, $fields);
+ return self::receive_reshare($importer, $fields, $msg["message"]);
case "retraction":
return self::receive_retraction($importer, $sender, $fields);
@@ -1611,7 +1611,7 @@ class diaspora {
return false;
}
- private function receive_reshare($importer, $data) {
+ 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));
@@ -1652,7 +1652,7 @@ class diaspora {
$datarray["verb"] = ACTIVITY_POST;
$datarray["gravity"] = GRAVITY_PARENT;
- $datarray["object"] = json_encode($data);
+ $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);
From 3f2a23d48c0b588f0a31bb7cdb8b6490f307029f Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 15 Mar 2016 07:05:10 +0100
Subject: [PATCH 049/485] Unused files are removed
---
view/templates/diasp_dec_hdr.tpl | 9 ------
view/templates/diaspora_comment.tpl | 12 --------
view/templates/diaspora_comment_relay.tpl | 13 --------
view/templates/diaspora_conversation.tpl | 30 -------------------
view/templates/diaspora_like.tpl | 13 --------
view/templates/diaspora_like_relay.tpl | 14 ---------
view/templates/diaspora_message.tpl | 17 -----------
view/templates/diaspora_photo.tpl | 14 ---------
view/templates/diaspora_post.tpl | 13 --------
view/templates/diaspora_profile.tpl | 17 -----------
view/templates/diaspora_relay_retraction.tpl | 10 -------
.../diaspora_relayable_retraction.tpl | 12 --------
view/templates/diaspora_reshare.tpl | 14 ---------
view/templates/diaspora_retract.tpl | 10 -------
view/templates/diaspora_share.tpl | 9 ------
view/templates/diaspora_signed_retract.tpl | 11 -------
16 files changed, 218 deletions(-)
delete mode 100644 view/templates/diasp_dec_hdr.tpl
delete mode 100644 view/templates/diaspora_comment.tpl
delete mode 100644 view/templates/diaspora_comment_relay.tpl
delete mode 100644 view/templates/diaspora_conversation.tpl
delete mode 100644 view/templates/diaspora_like.tpl
delete mode 100644 view/templates/diaspora_like_relay.tpl
delete mode 100644 view/templates/diaspora_message.tpl
delete mode 100644 view/templates/diaspora_photo.tpl
delete mode 100644 view/templates/diaspora_post.tpl
delete mode 100644 view/templates/diaspora_profile.tpl
delete mode 100644 view/templates/diaspora_relay_retraction.tpl
delete mode 100644 view/templates/diaspora_relayable_retraction.tpl
delete mode 100644 view/templates/diaspora_reshare.tpl
delete mode 100644 view/templates/diaspora_retract.tpl
delete mode 100644 view/templates/diaspora_share.tpl
delete mode 100644 view/templates/diaspora_signed_retract.tpl
diff --git a/view/templates/diasp_dec_hdr.tpl b/view/templates/diasp_dec_hdr.tpl
deleted file mode 100644
index 136d1ca302..0000000000
--- a/view/templates/diasp_dec_hdr.tpl
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- {{$inner_iv}}
- {{$inner_key}}
-
- {{$author_name}}
- {{$author_uri}}
-
-
diff --git a/view/templates/diaspora_comment.tpl b/view/templates/diaspora_comment.tpl
deleted file mode 100644
index 107cc73022..0000000000
--- a/view/templates/diaspora_comment.tpl
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- {{$guid}}
- {{$parent_guid}}
- {{$authorsig}}
- {{$body}}
- {{$handle}}
-
-
-
\ No newline at end of file
diff --git a/view/templates/diaspora_comment_relay.tpl b/view/templates/diaspora_comment_relay.tpl
deleted file mode 100644
index b4f84dc84e..0000000000
--- a/view/templates/diaspora_comment_relay.tpl
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- {{$guid}}
- {{$parent_guid}}
- {{$parentsig}}
- {{$authorsig}}
- {{$body}}
- {{$handle}}
-
-
-
\ No newline at end of file
diff --git a/view/templates/diaspora_conversation.tpl b/view/templates/diaspora_conversation.tpl
deleted file mode 100644
index 28e4cdb98f..0000000000
--- a/view/templates/diaspora_conversation.tpl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- {{$conv.guid}}
- {{$conv.subject}}
- {{$conv.created_at}}
-
- {{foreach $conv.messages as $msg}}
-
-
- {{$msg.guid}}
- {{$msg.parent_guid}}
- {{if $msg.parent_author_signature}}
- {{$msg.parent_author_signature}}
- {{/if}}
- {{$msg.author_signature}}
- {{$msg.text}}
- {{$msg.created_at}}
- {{$msg.diaspora_handle}}
- {{$msg.conversation_guid}}
-
-
- {{/foreach}}
-
- {{$conv.diaspora_handle}}
- {{$conv.participant_handles}}
-
-
-
diff --git a/view/templates/diaspora_like.tpl b/view/templates/diaspora_like.tpl
deleted file mode 100644
index 165b0f5f7b..0000000000
--- a/view/templates/diaspora_like.tpl
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- {{$positive}}
- {{$guid}}
- {{$target_type}}
- {{$parent_guid}}
- {{$authorsig}}
- {{$handle}}
-
-
-
diff --git a/view/templates/diaspora_like_relay.tpl b/view/templates/diaspora_like_relay.tpl
deleted file mode 100644
index e1696e722a..0000000000
--- a/view/templates/diaspora_like_relay.tpl
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- {{$positive}}
- {{$guid}}
- {{$target_type}}
- {{$parent_guid}}
- {{$parentsig}}
- {{$authorsig}}
- {{$handle}}
-
-
-
diff --git a/view/templates/diaspora_message.tpl b/view/templates/diaspora_message.tpl
deleted file mode 100644
index f9adb833b6..0000000000
--- a/view/templates/diaspora_message.tpl
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- {{$msg.guid}}
- {{$msg.parent_guid}}
- {{if $msg.parent_author_signature}}
- {{$msg.parent_author_signature}}
- {{/if}}
- {{$msg.author_signature}}
- {{$msg.text}}
- {{$msg.created_at}}
- {{$msg.diaspora_handle}}
- {{$msg.conversation_guid}}
-
-
-
diff --git a/view/templates/diaspora_photo.tpl b/view/templates/diaspora_photo.tpl
deleted file mode 100644
index 0330499577..0000000000
--- a/view/templates/diaspora_photo.tpl
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- {{$guid}}
- {{$handle}}
- {{$public}}
- {{$created_at}}
- {{$path}}
- {{$filename}}
- {{$msg_guid}}
-
-
-
diff --git a/view/templates/diaspora_post.tpl b/view/templates/diaspora_post.tpl
deleted file mode 100644
index d6ba97327c..0000000000
--- a/view/templates/diaspora_post.tpl
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- {{$body}}
- {{$guid}}
- {{$handle}}
- {{$public}}
- {{$created}}
- {{$provider}}
-
-
-
diff --git a/view/templates/diaspora_profile.tpl b/view/templates/diaspora_profile.tpl
deleted file mode 100644
index afbbb1e1a2..0000000000
--- a/view/templates/diaspora_profile.tpl
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- {{$handle}}
- {{$first}}
- {{$last}}
- {{$large}}
- {{$medium}}
- {{$small}}
- {{$dob}}
- {{$gender}}
- {{$about}}
- {{$location}}
- {{$searchable}}
- {{$tags}}
-
-
diff --git a/view/templates/diaspora_relay_retraction.tpl b/view/templates/diaspora_relay_retraction.tpl
deleted file mode 100644
index c4b44cd05f..0000000000
--- a/view/templates/diaspora_relay_retraction.tpl
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- {{$guid}}
- {{$type}}
- {{$handle}}
- {{$signature}}
-
-
-
diff --git a/view/templates/diaspora_relayable_retraction.tpl b/view/templates/diaspora_relayable_retraction.tpl
deleted file mode 100644
index 2ae776d1d0..0000000000
--- a/view/templates/diaspora_relayable_retraction.tpl
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- {{$parentsig}}
- {{$guid}}
- {{$target_type}}
- {{$handle}}
- {{$authorsig}}
-
-
-
diff --git a/view/templates/diaspora_reshare.tpl b/view/templates/diaspora_reshare.tpl
deleted file mode 100644
index 6a4776b1bc..0000000000
--- a/view/templates/diaspora_reshare.tpl
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- {{$root_handle}}
- {{$root_guid}}
- {{$guid}}
- {{$handle}}
- {{$public}}
- {{$created}}
- {{$provider}}
-
-
-
diff --git a/view/templates/diaspora_retract.tpl b/view/templates/diaspora_retract.tpl
deleted file mode 100644
index 3ddfcabfa7..0000000000
--- a/view/templates/diaspora_retract.tpl
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- {{$guid}}
- {{$handle}}
- {{$type}}
-
-
-
diff --git a/view/templates/diaspora_share.tpl b/view/templates/diaspora_share.tpl
deleted file mode 100644
index 0142ab36c5..0000000000
--- a/view/templates/diaspora_share.tpl
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- {{$sender}}
- {{$recipient}}
-
-
-
\ No newline at end of file
diff --git a/view/templates/diaspora_signed_retract.tpl b/view/templates/diaspora_signed_retract.tpl
deleted file mode 100644
index 83d0def4d2..0000000000
--- a/view/templates/diaspora_signed_retract.tpl
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- {{$guid}}
- {{$type}}
- {{$handle}}
- {{$signature}}
-
-
-
From 8027854886a7d8a51fb3b97864e01f877403fc4a Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 15 Mar 2016 07:18:11 +0100
Subject: [PATCH 050/485] Removed moved function
---
include/diaspora.php | 1 -
include/network.php | 58 --------------------------------------------
2 files changed, 59 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 3c3f5cb25a..d5f2a21d9e 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -517,7 +517,6 @@ class diaspora {
* @return string The id of the fcontact entry
*/
private function add_fcontact($arr, $update = false) {
- /// @todo Remove this function from include/network.php
if($update) {
$r = q("UPDATE `fcontact` SET
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"
From be001d171b385af3650cb8152542f3a60c645f63 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Tue, 15 Mar 2016 20:14:08 +0100
Subject: [PATCH 051/485] Values are sanitized, messages are not relayed when
there is no signature
---
include/diaspora.php | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index d5f2a21d9e..f4e3132959 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -221,7 +221,9 @@ class diaspora {
logger('Message verified.');
- return array('message' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
+ return array('message' => (string)$inner_decrypted,
+ 'author' => unxmlify($author_link),
+ 'key' => (string)$key);
}
@@ -1801,7 +1803,8 @@ class diaspora {
if ($data->photo) {
foreach ($data->photo AS $photo)
- $body = "[img]".$photo->remote_photo_path.$photo->remote_photo_name."[/img]\n".$body;
+ $body = "[img]".unxmlify($photo->remote_photo_path).
+ unxmlify($photo->remote_photo_name)."[/img]\n".$body;
$datarray["object-type"] = ACTIVITY_OBJ_PHOTO;
} else {
@@ -2355,8 +2358,10 @@ class diaspora {
$r = q("SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE `".$sql_sign_id."` = %d LIMIT 1",
intval($item["id"]));
- if (!$r)
- return self::send_followup($item, $owner, $contact, $public_batch);
+ if (!$r) {
+ logger("Couldn't fetch signatur for contact ".$contact["addr"]." at item ".$item["guid"]." (".$item["id"].")", LOGGER_DEBUG);
+ return false;
+ }
$signature = $r[0];
From 071ffd43bf66ff6478c09a4afc6ef010e34d8384 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 16 Mar 2016 11:44:45 +0100
Subject: [PATCH 052/485] DFRN: Mentions were imported as hash tags
---
include/dfrn.php | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/include/dfrn.php b/include/dfrn.php
index ad04a91295..1c5ac2b012 100644
--- a/include/dfrn.php
+++ b/include/dfrn.php
@@ -2022,14 +2022,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]";
}
+ }
}
}
From 84a475e5897d5753c45b6cbb0a982893ee2cda1e Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 16 Mar 2016 16:49:54 +0100
Subject: [PATCH 053/485] Missing include
---
include/diaspora.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/diaspora.php b/include/diaspora.php
index f4e3132959..da69cdc799 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -13,6 +13,7 @@ require_once("include/socgraph.php");
require_once("include/group.php");
require_once("include/xml.php");
require_once("include/datetime.php");
+require_once("include/queue_fn.php");
/**
* @brief This class contain functions to create and send Diaspora XML files
From 468734a26ee6f7aeadcaaa5a2ba10c3b613c8dcc Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 16 Mar 2016 19:30:46 +0100
Subject: [PATCH 054/485] Added checklist
---
include/diaspora.php | 51 ++++++++++++++++++++++++++++++++++++--------
1 file changed, 42 insertions(+), 9 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index da69cdc799..f7c38c2271 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -2,6 +2,36 @@
/**
* @file include/diaspora.php
* @brief The implementation of the diaspora protocol
+ *
+ * Checklist:
+ *
+ * Checked:
+ * - send status
+ * - send comment
+ * - send like
+ * - send mail
+ * - receive status
+ * - receive reshare
+ * - receive comment
+ * - receive like
+ * - receive connect request
+ * - receive profile data
+ * - receive mail
+ * - relay comment
+ * - relay like
+ * -
+ * -
+ *
+ * Unchecked:
+ * - receive account deletion
+ * - send share
+ * - send unshare
+ * - send status retraction
+ * - send comment retraction
+ * - send like retraction
+ * - relay comment retraction
+ * - relay like retraction
+ * -
*/
require_once("include/items.php");
@@ -2374,16 +2404,19 @@ class diaspora {
$msg = json_decode($signature['signed_text'], true);
$message = array();
- foreach ($msg AS $field => $data) {
- if (!$item["deleted"]) {
- if ($field == "author")
- $field = "diaspora_handle";
- if ($field == "parent_type")
- $field = "target_type";
- }
+ 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;
- }
+ $message[$field] = $data;
+ }
+ } else
+ logger("Signature text for item ".$item["guid"]." (".$item["id"].") couldn't be extracted: ".$signature['signed_text'], LOGGER_DEBUG);
}
if ($item["deleted"]) {
From e058feed289269e9edccd3047318d8b06dce7739 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Wed, 16 Mar 2016 21:27:07 +0100
Subject: [PATCH 055/485] Better reshare detection
---
include/diaspora.php | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index f7c38c2271..4a6cbad131 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -1600,7 +1600,7 @@ class diaspora {
// 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
- if (self::is_reshare($r[0]["body"]))
+ if (self::is_reshare($r[0]["body"], false))
$r = array();
else
return $r[0];
@@ -2130,7 +2130,7 @@ class diaspora {
return self::build_and_transmit($owner, $contact, "retraction", $message);
}
- public static function is_reshare($body) {
+ public static function is_reshare($body, $complete = true) {
$body = trim($body);
// Skip if it isn't a pure repeated messages
@@ -2147,6 +2147,10 @@ class diaspora {
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] != "")
From 88fea17cab1fa3e1e8fb7bb0e2c3ea3480dbb8ee Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Thu, 17 Mar 2016 00:37:44 +0100
Subject: [PATCH 056/485] Everything tested, one open to-do
---
include/delivery.php | 3 ++-
include/diaspora.php | 40 +++++++++++++++++++++++++++++-----------
2 files changed, 31 insertions(+), 12 deletions(-)
diff --git a/include/delivery.php b/include/delivery.php
index 9ac9f2391b..fe33774382 100644
--- a/include/delivery.php
+++ b/include/delivery.php
@@ -243,7 +243,8 @@ function delivery_run(&$argv, &$argc){
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
}
diff --git a/include/diaspora.php b/include/diaspora.php
index 4a6cbad131..870466497d 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -10,6 +10,11 @@
* - send comment
* - send like
* - send mail
+ * - send status retraction
+ * - send comment retraction on own post
+ * - send comment retraction on diaspora post
+ * - send like retraction on own post
+ * - send like retraction on diaspora post
* - receive status
* - receive reshare
* - receive comment
@@ -17,21 +22,21 @@
* - receive connect request
* - receive profile data
* - receive mail
+ * - receive comment retraction
+ * - receive like retraction
* - relay comment
* - relay like
- * -
- * -
+ * - relay comment retraction from diaspora
+ * - relay comment retraction from friendica
+ * - relay like retraction from diaspora
+ * - relay like retraction from friendica
*
- * Unchecked:
+ * Should work:
* - receive account deletion
* - send share
* - send unshare
- * - send status retraction
- * - send comment retraction
- * - send like retraction
- * - relay comment retraction
- * - relay like retraction
- * -
+ *
+ * Unchecked:
*/
require_once("include/items.php");
@@ -2394,7 +2399,10 @@ class diaspora {
intval($item["id"]));
if (!$r) {
- logger("Couldn't fetch signatur for contact ".$contact["addr"]." at item ".$item["guid"]." (".$item["id"].")", LOGGER_DEBUG);
+ if ($item["deleted"])
+ return self::send_retraction($item, $owner, $contact, $public_batch);
+
+ logger("Couldn't fetch signatur for item ".$item["guid"]." (".$item["id"].")", LOGGER_DEBUG);
return false;
}
@@ -2436,6 +2444,9 @@ class diaspora {
public static function send_retraction($item, $owner, $contact, $public_batch = false) {
+ /// @todo Fetch handle from every contact (via gcontact)
+ $itemaddr = self::handle_from_contact($item["contact-id"]);
+
$myaddr = self::my_handle($owner);
// Check whether the retraction is for a top-level post or whether it's a relayable
@@ -2451,9 +2462,16 @@ class diaspora {
$message = array("target_guid" => $item['guid'],
"target_type" => $target_type,
- "sender_handle" => $myaddr,
+ "sender_handle" => $itemaddr,
"target_author_signature" => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
+ if ($itemaddr != $myaddr) {
+ $message["parent_author_signature"] = $message["target_author_signature"];
+ unset($message["target_author_signature"]);
+ }
+
+ logger("Got message ".print_r($message, true), LOGGER_DEBUG);
+
return self::build_and_transmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]);
}
From 16b92af71f0d838f7859869461f1acea25329d95 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Thu, 17 Mar 2016 12:24:23 +0100
Subject: [PATCH 057/485] Retraction do work as well
---
database.sql | 4 +--
doc/database/db_sign.md | 1 -
include/dbstructure.php | 2 --
include/diaspora.php | 73 ++++++++++++++++-------------------------
include/items.php | 51 ----------------------------
include/like.php | 69 --------------------------------------
include/notifier.php | 7 ----
7 files changed, 29 insertions(+), 178 deletions(-)
diff --git a/database.sql b/database.sql
index 02e5c9b378..89b821e23a 100644
--- a/database.sql
+++ b/database.sql
@@ -901,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/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/include/dbstructure.php b/include/dbstructure.php
index e5e748bb24..e34e409023 100644
--- a/include/dbstructure.php
+++ b/include/dbstructure.php
@@ -1235,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" => ""),
@@ -1243,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/diaspora.php b/include/diaspora.php
index 870466497d..c888959d71 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -12,8 +12,8 @@
* - send mail
* - send status retraction
* - send comment retraction on own post
- * - send comment retraction on diaspora post
* - send like retraction on own post
+ * - send comment retraction on diaspora post
* - send like retraction on diaspora post
* - receive status
* - receive reshare
@@ -30,10 +30,10 @@
* - relay comment retraction from friendica
* - relay like retraction from diaspora
* - relay like retraction from friendica
+ * - send share
*
* Should work:
* - receive account deletion
- * - send share
* - send unshare
*
* Unchecked:
@@ -610,15 +610,21 @@ class diaspora {
return $r;
}
- public static function handle_from_contact($contact_id) {
+ public static function handle_from_contact($contact_id, $gcontact_id = 0) {
$handle = False;
- logger("contact id is ".$contact_id, LOGGER_DEBUG);
+ logger("contact id is ".$contact_id." - gcontact id is ".$gcontact_id, LOGGER_DEBUG);
+
+ if ($gcontact_id != 0) {
+ $r = q("SELECT `addr` FROM `gcontact` WHERE `id` = %d AND `addr` != ''",
+ intval($gcontact_id));
+ if ($r)
+ return $r[0]["addr"];
+ }
$r = q("SELECT `network`, `addr`, `self`, `url`, `nick` FROM `contact` WHERE `id` = %d",
- intval($contact_id)
- );
- if($r) {
+ intval($contact_id));
+ if ($r) {
$contact = $r[0];
logger("contact 'self' = ".$contact['self']." 'url' = ".$contact['url'], LOGGER_DEBUG);
@@ -1759,16 +1765,6 @@ class diaspora {
// Now check if the retraction needs to be relayed by us
if($p[0]["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` (`retract_iid`,`signed_text`) VALUES (%d,'%s')",
- intval($r[0]["id"]),
- dbesc(json_encode($data))
- );
- $s = q("select * from sign where retract_iid = %d", intval($r[0]["id"]));
- logger("Stored signatur for item ".$r[0]["id"]." - ".print_r($s, true), LOGGER_DEBUG);
-
// notify others
proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
}
@@ -2380,28 +2376,21 @@ class diaspora {
public static function send_relay($item, $owner, $contact, $public_batch = false) {
- if ($item["deleted"]) {
- $sql_sign_id = "retract_iid";
- $type = "relayable_retraction";
- } elseif ($item['verb'] === ACTIVITY_LIKE) {
- $sql_sign_id = "iid";
+ if ($item["deleted"])
+ return self::send_retraction($item, $owner, $contact, $public_batch, true);
+ elseif ($item['verb'] === ACTIVITY_LIKE)
$type = "like";
- } else {
- $sql_sign_id = "iid";
+ 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 `".$sql_sign_id."` = %d LIMIT 1",
+ $r = q("SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE `iid` = %d LIMIT 1",
intval($item["id"]));
if (!$r) {
- if ($item["deleted"])
- return self::send_retraction($item, $owner, $contact, $public_batch);
-
logger("Couldn't fetch signatur for item ".$item["guid"]." (".$item["id"].")", LOGGER_DEBUG);
return false;
}
@@ -2431,23 +2420,17 @@ class diaspora {
logger("Signature text for item ".$item["guid"]." (".$item["id"].") couldn't be extracted: ".$signature['signed_text'], LOGGER_DEBUG);
}
- if ($item["deleted"]) {
- $signed_text = $message["target_guid"].';'.$message["target_type"];
- $message["parent_author_signature"] = base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
- } else
- $message["parent_author_signature"] = self::signature($owner, $message);
+ $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"]);
}
- public static function send_retraction($item, $owner, $contact, $public_batch = false) {
+ public static function send_retraction($item, $owner, $contact, $public_batch = false, $relay = false) {
- /// @todo Fetch handle from every contact (via gcontact)
- $itemaddr = self::handle_from_contact($item["contact-id"]);
-
- $myaddr = self::my_handle($owner);
+ $itemaddr = self::handle_from_contact($item["contact-id"], $item["gcontact-id"]);
+ //$myaddr = self::my_handle($owner);
// Check whether the retraction is for a top-level post or whether it's a relayable
if ($item["uri"] !== $item["parent-uri"]) {
@@ -2458,17 +2441,17 @@ class diaspora {
$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,
- "target_author_signature" => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
-
- if ($itemaddr != $myaddr) {
- $message["parent_author_signature"] = $message["target_author_signature"];
- unset($message["target_author_signature"]);
- }
+ $signature => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')));
logger("Got message ".print_r($message, true), LOGGER_DEBUG);
diff --git a/include/items.php b/include/items.php
index 8d6b5b471c..f8c3149d58 100644
--- a/include/items.php
+++ b/include/items.php
@@ -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..2e5367e51e 100644
--- a/include/like.php
+++ b/include/like.php
@@ -151,9 +151,6 @@ function do_like($item_id, $verb) {
intval($like_item['id'])
);
- // Save the author information for the unlike in case we need to relay to Diaspora
- store_diaspora_like_retract_sig($activity, $item, $like_item, $contact);
-
$like_item_id = $like_item['id'];
proc_run('php',"include/notifier.php","like","$like_item_id");
@@ -251,72 +248,6 @@ EOT;
return true;
}
-
-
-function store_diaspora_like_retract_sig($activity, $item, $like_item, $contact) {
- // 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
- //
- // If $item['resource-id'] exists, it means the item is a photo. Diaspora doesn't support
- // likes on photos, so don't bother.
-
- $enabled = intval(get_config('system','diaspora_enabled'));
- if(! $enabled) {
- logger('mod_like: diaspora support disabled, not storing like retraction signature', LOGGER_DEBUG);
- return;
- }
-
- logger('mod_like: storing diaspora like retraction signature');
-
- if(($activity === ACTIVITY_LIKE) && (! $item['resource-id'])) {
- $signed_text = $like_item['guid'] . ';' . 'Like';
-
- // 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)
- );
-*/
- // 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)
- $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
diff --git a/include/notifier.php b/include/notifier.php
index e65da3adf2..a46744f070 100644
--- a/include/notifier.php
+++ b/include/notifier.php
@@ -628,13 +628,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)
From bc579ff799595d7c4271e3562b554d5cecaf5b5b Mon Sep 17 00:00:00 2001
From: Tobias Diekershoff
Date: Thu, 17 Mar 2016 17:41:06 +0100
Subject: [PATCH 058/485] added title element to emoji images in main
repository
---
include/text.php | 70 ++++++++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/include/text.php b/include/text.php
index 07524e851d..c868499cc6 100644
--- a/include/text.php
+++ b/include/text.php
@@ -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);
From fab48926d07907568aea5fb9766dad8a132a97c7 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Thu, 17 Mar 2016 23:44:18 +0100
Subject: [PATCH 059/485] Added some documentation, script to generate a basic
doxygen header
---
include/diaspora.php | 479 ++++++++++++++++++++++++++++++++++++++++-
util/createdoxygen.php | 82 +++++++
2 files changed, 552 insertions(+), 9 deletions(-)
create mode 100755 util/createdoxygen.php
diff --git a/include/diaspora.php b/include/diaspora.php
index c888959d71..dd0efa1d73 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -56,6 +56,13 @@ require_once("include/queue_fn.php");
*/
class diaspora {
+ /**
+ * @brief Return a list of relay servers
+ *
+ * This is an experimental Diaspora feature.
+ *
+ * @return array of relay servers
+ */
public static function relay_list() {
$serverdata = get_config("system", "relay_server");
@@ -100,6 +107,15 @@ class diaspora {
return $relay;
}
+ /**
+ * @brief repairs a signature that was double encoded
+ *
+ * @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 the repaired signature
+ */
function repair_signature($signature, $handle = "", $level = 1) {
if ($signature == "")
@@ -120,7 +136,7 @@ class diaspora {
/**
* @brief: Decodes incoming Diaspora message
*
- * @param array $importer from user table
+ * @param array $importer Array of the importer user
* @param string $xml urldecoded Diaspora salmon
*
* @return array
@@ -610,6 +626,14 @@ class diaspora {
return $r;
}
+ /**
+ * @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;
@@ -642,6 +666,14 @@ class diaspora {
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),
@@ -664,6 +696,15 @@ class diaspora {
return false;
}
+ /**
+ * @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.
@@ -694,6 +735,15 @@ class diaspora {
return false;
}
+ /**
+ * @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 bool is posting allowed?
+ */
private function allowed_contact_by_handle($importer, $handle, $is_comment = false) {
$contact = self::contact_by_handle($importer["uid"], $handle);
if (!$contact) {
@@ -708,6 +758,14 @@ class diaspora {
return $contact;
}
+ /**
+ * @brief Does the message already exists on the system?
+ *
+ * @param int $uid The user id
+ * @param string $guid The guid of the message
+ *
+ * @return bool "true" if the message already was stored into the system
+ */
private function message_exists($uid, $guid) {
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($uid),
@@ -722,6 +780,11 @@ class diaspora {
return false;
}
+ /**
+ * @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){
@@ -729,11 +792,26 @@ class diaspora {
},$item["body"]);
}
+ /**
+ * @brief sub function of "fetch_guid"
+ *
+ * @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"]);
}
+ /**
+ * @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"];
@@ -751,6 +829,15 @@ class diaspora {
return self::dispatch_public($msg);
}
+ /**
+ * @brief
+ *
+ * @param string $guid message guid
+ * @param $server
+ * @param $level
+ *
+ * @return
+ */
private function message($guid, $server, $level = 0) {
if ($level > 5)
@@ -794,6 +881,16 @@ class diaspora {
return $msg;
}
+ /**
+ * @brief
+ *
+ * @param int $uid The user id
+ * @param string $guid message guid
+ * @param $author
+ * @param array $contact The contact that is checked
+ *
+ * @return
+ */
private function parent_item($uid, $guid, $author, $contact) {
$r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
`author-name`, `author-link`, `author-avatar`,
@@ -829,6 +926,15 @@ class diaspora {
}
}
+ /**
+ * @brief
+ *
+ * @param array $contact The contact that is checked
+ * @param $person
+ * @param int $uid The user id
+ *
+ * @return
+ */
private function author_contact_by_url($contact, $person, $uid) {
$r = q("SELECT `id`, `network` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d LIMIT 1",
@@ -844,10 +950,25 @@ class diaspora {
return (array("cid" => $cid, "network" => $network));
}
+ /**
+ * @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/"));
}
+ /**
+ * @brief Generate a post link with a given handle and message guid
+ *
+ * @param $addr
+ * @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));
@@ -870,6 +991,14 @@ class diaspora {
return "https://".substr($addr,strpos($addr,"@")+1)."/posts/".$guid;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_account_deletion($importer, $data) {
$author = notags(unxmlify($data->author));
@@ -884,6 +1013,16 @@ class diaspora {
return true;
}
+ /**
+ * @brief
+ *
+ * @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));
@@ -961,6 +1100,18 @@ class diaspora {
return $message_id;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact that is checked
+ * @param object $data The message object
+ * @param $msg
+ * @param $mesg
+ * @param $conversation
+ *
+ * @return
+ */
private function receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation) {
$guid = notags(unxmlify($data->guid));
$subject = notags(unxmlify($data->subject));
@@ -1077,6 +1228,15 @@ class diaspora {
));
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param $msg
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_conversation($importer, $msg, $data) {
$guid = notags(unxmlify($data->guid));
$subject = notags(unxmlify($data->subject));
@@ -1134,6 +1294,15 @@ class diaspora {
return true;
}
+ /**
+ * @brief
+ *
+ * @param array $contact The contact that is checked
+ * @param $parent_item
+ * @param string $guid message guid
+ *
+ * @return
+ */
private function construct_like_body($contact, $parent_item, $guid) {
$bodyverb = t('%1$s likes %2$s\'s %3$s');
@@ -1144,6 +1313,14 @@ class diaspora {
return sprintf($bodyverb, $ulink, $alink, $plink);
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param $parent_item
+ *
+ * @return
+ */
private function construct_like_object($importer, $parent_item) {
$objtype = ACTIVITY_OBJ_NOTE;
$link = '';
@@ -1159,6 +1336,15 @@ class diaspora {
return xml::from_array($xmldata, $xml, true);
}
+ /**
+ * @brief
+ *
+ * @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));
@@ -1247,6 +1433,14 @@ class diaspora {
return $message_id;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_message($importer, $data) {
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
@@ -1318,27 +1512,59 @@ class diaspora {
return true;
}
+ /**
+ * @brief
+ *
+ * @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
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return
+ */
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
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_poll_participation($importer, $data) {
// We don't support polls by now
return true;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_profile($importer, $data) {
$author = notags(unxmlify($data->author));
$contact = self::contact_by_handle($importer["uid"], $author);
if (!$contact)
- return;
+ return false;
$name = unxmlify($data->first_name).((strlen($data->last_name)) ? " ".unxmlify($data->last_name) : "");
$image_url = unxmlify($data->image_url);
@@ -1418,6 +1644,14 @@ class diaspora {
return true;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact that is checked
+ *
+ * @return
+ */
private function receive_request_make_friend($importer, $contact) {
$a = get_app();
@@ -1485,6 +1719,14 @@ class diaspora {
}
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_request($importer, $data) {
$author = unxmlify($data->author);
$recipient = unxmlify($data->recipient);
@@ -1598,6 +1840,15 @@ class diaspora {
return true;
}
+ /**
+ * @brief
+ *
+ * @param string $guid message guid
+ * @param $orig_author
+ * @param $author
+ *
+ * @return
+ */
private function original_item($guid, $orig_author, $author) {
// Do we already have this item?
@@ -1654,6 +1905,15 @@ class diaspora {
return false;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ * @param string $xml The original XML of the message
+ *
+ * @return
+ */
private function receive_reshare($importer, $data, $xml) {
$root_author = notags(unxmlify($data->root_author));
$root_guid = notags(unxmlify($data->root_guid));
@@ -1719,6 +1979,15 @@ class diaspora {
return $message_id;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param array $contact The contact that is checked
+ * @param object $data The message object
+ *
+ * @return
+ */
private function item_retraction($importer, $contact, $data) {
$target_type = notags(unxmlify($data->target_type));
$target_guid = notags(unxmlify($data->target_guid));
@@ -1770,6 +2039,15 @@ class diaspora {
}
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param string $sender The sender of the message
+ * @param object $data The message object
+ *
+ * @return
+ */
private function receive_retraction($importer, $sender, $data) {
$target_type = notags(unxmlify($data->target_type));
@@ -1802,6 +2080,15 @@ class diaspora {
return true;
}
+ /**
+ * @brief
+ *
+ * @param array $importer Array of the importer user
+ * @param object $data The message object
+ * @param string $xml The original XML of the message
+ *
+ * @return
+ */
private function receive_status_message($importer, $data, $xml) {
$raw_message = unxmlify($data->raw_message);
@@ -1895,6 +2182,13 @@ class diaspora {
* Here are all the functions that are needed to transmit data with the Diaspora protocol *
******************************************************************************************/
+ /**
+ * @brief
+ *
+ * @param $me
+ *
+ * @return
+ */
private function my_handle($me) {
if ($contact["addr"] != "")
return $contact["addr"];
@@ -1904,6 +2198,17 @@ class diaspora {
return $me["nickname"]."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
}
+ /**
+ * @brief
+ *
+ * @param $msg
+ * @param $user
+ * @param array $contact The contact that is checked
+ * @param $prvkey
+ * @param $pubkey
+ *
+ * @return
+ */
private function build_public_message($msg, $user, $contact, $prvkey, $pubkey) {
logger("Message: ".$msg, LOGGER_DATA);
@@ -1939,6 +2244,17 @@ class diaspora {
return $magic_env;
}
+ /**
+ * @brief
+ *
+ * @param $msg
+ * @param $user
+ * @param array $contact The contact that is checked
+ * @param $prvkey
+ * @param $pubkey
+ *
+ * @return
+ */
private function build_private_message($msg, $user, $contact, $prvkey, $pubkey) {
logger("Message: ".$msg, LOGGER_DATA);
@@ -2018,6 +2334,18 @@ class diaspora {
return $magic_env;
}
+ /**
+ * @brief
+ *
+ * @param $msg
+ * @param $user
+ * @param array $contact The contact that is checked
+ * @param $prvkey
+ * @param $pubkey
+ * @param $public
+ *
+ * @return
+ */
private function build_message($msg, $user, $contact, $prvkey, $pubkey, $public = false) {
if ($public)
@@ -2030,6 +2358,14 @@ class diaspora {
return $slap;
}
+ /**
+ * @brief
+ *
+ * @param array $owner the array of the item owner
+ * @param $message
+ *
+ * @return
+ */
private function signature($owner, $message) {
$sigmsg = $message;
unset($sigmsg["author_signature"]);
@@ -2040,6 +2376,18 @@ class diaspora {
return base64_encode(rsa_sign($signed_text, $owner["uprvkey"], "sha256"));
}
+ /**
+ * @brief
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ * @param $slap
+ * @param bool $public_batch Is it a public post?
+ * @param $queue_run
+ * @param string $guid message guid
+ *
+ * @return
+ */
public static function transmit($owner, $contact, $slap, $public_batch, $queue_run=false, $guid = "") {
$a = get_app();
@@ -2092,6 +2440,19 @@ class diaspora {
}
+ /**
+ * @brief
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ * @param $type
+ * @param $message
+ * @param bool $public_batch Is it a public post?
+ * @param string $guid message guid
+ * @param $spool
+ *
+ * @return
+ */
private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "", $spool = false) {
$data = array("XML" => array("post" => array($type => $message)));
@@ -2114,6 +2475,14 @@ class diaspora {
return $return_code;
}
+ /**
+ * @brief
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ *
+ * @return int The result of the transmission
+ */
public static function send_share($owner,$contact) {
$message = array("sender_handle" => self::my_handle($owner),
@@ -2122,6 +2491,14 @@ class diaspora {
return self::build_and_transmit($owner, $contact, "request", $message);
}
+ /**
+ * @brief
+ *
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ *
+ * @return int The result of the transmission
+ */
public static function send_unshare($owner,$contact) {
$message = array("post_guid" => $owner["guid"],
@@ -2131,6 +2508,14 @@ class diaspora {
return self::build_and_transmit($owner, $contact, "retraction", $message);
}
+ /**
+ * @brief
+ *
+ * @param $body
+ * @param $complete
+ *
+ * @return
+ */
public static function is_reshare($body, $complete = true) {
$body = trim($body);
@@ -2202,6 +2587,16 @@ class diaspora {
return($ret);
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ * @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);
@@ -2269,10 +2664,16 @@ class diaspora {
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ *
+ * @return
+ */
private function construct_like($item, $owner) {
- $myaddr = self::my_handle($owner);
-
$p = q("SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1",
dbesc($item["thr-parent"]));
if(!$p)
@@ -2288,13 +2689,19 @@ class diaspora {
"target_type" => $target_type,
"parent_guid" => $parent["guid"],
"author_signature" => $authorsig,
- "diaspora_handle" => $myaddr));
+ "diaspora_handle" => self::my_handle($owner)));
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ *
+ * @return
+ */
private function construct_comment($item, $owner) {
- $myaddr = self::my_handle($owner);
-
$p = q("SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1",
intval($item["parent"]),
intval($item["parent"])
@@ -2311,9 +2718,19 @@ class diaspora {
"parent_guid" => $parent["guid"],
"author_signature" => "",
"text" => $text,
- "diaspora_handle" => $myaddr));
+ "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 The contact that is checked
+ * @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) {
@@ -2332,6 +2749,14 @@ class diaspora {
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param $signature
+ *
+ * @return int The result of the transmission
+ */
private function message_from_signatur($item, $signature) {
// Split the signed text
@@ -2374,6 +2799,16 @@ class diaspora {
return $message;
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ * @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"])
@@ -2427,10 +2862,20 @@ class diaspora {
return self::build_and_transmit($owner, $contact, $type, $message, $public_batch, $item["guid"]);
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner the array of the item owner
+ * @param array $contact The contact that is checked
+ * @param bool $public_batch Is it a public post?
+ * @param $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"]);
- //$myaddr = self::my_handle($owner);
// Check whether the retraction is for a top-level post or whether it's a relayable
if ($item["uri"] !== $item["parent-uri"]) {
@@ -2458,6 +2903,15 @@ class diaspora {
return self::build_and_transmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]);
}
+ /**
+ * @brief
+ *
+ * @param array $item The item that will be exported
+ * @param array $owner The owner
+ * @param array $contact The contact that is checked
+ *
+ * @return int The result of the transmission
+ */
public static function send_mail($item, $owner, $contact) {
$myaddr = self::my_handle($owner);
@@ -2515,6 +2969,13 @@ class diaspora {
return self::build_and_transmit($owner, $contact, $type, $message, false, $item["guid"]);
}
+ /**
+ * @brief
+ *
+ * @param int $uid The user id
+ *
+ * @return int The result of the transmission
+ */
public static function send_profile($uid) {
if (!$uid)
diff --git a/util/createdoxygen.php b/util/createdoxygen.php
new file mode 100755
index 0000000000..d48114b671
--- /dev/null
+++ b/util/createdoxygen.php
@@ -0,0 +1,82 @@
+#!/usr/bin/php
+ 0)
+ $block .= $space." *\n";
+ }
+
+ $block .= $space." * @return \n".
+ $space." */\n";
+
+ return $block;
+}
+?>
From e74587b37576df113e05a56bc7a4d29f736a4fb5 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Fri, 18 Mar 2016 08:07:23 +0100
Subject: [PATCH 060/485] Just some more documentation
---
include/diaspora.php | 149 ++++++++++++++++++++++---------------------
1 file changed, 75 insertions(+), 74 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index dd0efa1d73..14ff6e42f8 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -830,13 +830,13 @@ class diaspora {
}
/**
- * @brief
+ * @brief Fetches a message from a server
*
* @param string $guid message guid
- * @param $server
- * @param $level
+ * @param string $server The url of the server
+ * @param int $level Endless loop prevention
*
- * @return
+ * @return array of message, author and public key
*/
private function message($guid, $server, $level = 0) {
@@ -882,14 +882,14 @@ class diaspora {
}
/**
- * @brief
+ * @brief Fetches the item record of a given guid
*
* @param int $uid The user id
* @param string $guid message guid
- * @param $author
+ * @param string $author The handle of the item
* @param array $contact The contact that is checked
*
- * @return
+ * @return array the item record
*/
private function parent_item($uid, $guid, $author, $contact) {
$r = q("SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
@@ -927,13 +927,13 @@ class diaspora {
}
/**
- * @brief
+ * @brief returns contact details
*
- * @param array $contact The contact that is checked
- * @param $person
+ * @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
+ * @return array of contact id and network type
*/
private function author_contact_by_url($contact, $person, $uid) {
@@ -964,7 +964,7 @@ class diaspora {
/**
* @brief Generate a post link with a given handle and message guid
*
- * @param $addr
+ * @param string $addr The user handle
* @param string $guid message guid
*
* @return string the post link
@@ -1101,16 +1101,16 @@ class diaspora {
}
/**
- * @brief
+ * @brief processes and stores private messages
*
* @param array $importer Array of the importer user
* @param array $contact The contact that is checked
* @param object $data The message object
- * @param $msg
- * @param $mesg
- * @param $conversation
+ * @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
+ * @return bool "true" if it was successful
*/
private function receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation) {
$guid = notags(unxmlify($data->guid));
@@ -1226,13 +1226,14 @@ class diaspora {
"verb" => ACTIVITY_POST,
"otype" => "mail"
));
+ return true;
}
/**
* @brief
*
* @param array $importer Array of the importer user
- * @param $msg
+ * @param array $msg Array of the processed message, author handle and key
* @param object $data The message object
*
* @return
@@ -2183,11 +2184,11 @@ class diaspora {
******************************************************************************************/
/**
- * @brief
+ * @brief returnes the handle of a contact
*
- * @param $me
+ * @param array $me contact array
*
- * @return
+ * @return string the handle in the format user@domain.tld
*/
private function my_handle($me) {
if ($contact["addr"] != "")
@@ -2199,15 +2200,15 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates the envelope for a public message
*
- * @param $msg
- * @param $user
- * @param array $contact The contact that is checked
- * @param $prvkey
- * @param $pubkey
+ * @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
+ * @return string The envelope
*/
private function build_public_message($msg, $user, $contact, $prvkey, $pubkey) {
@@ -2245,15 +2246,15 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates the envelope for a private message
*
- * @param $msg
- * @param $user
- * @param array $contact The contact that is checked
- * @param $prvkey
- * @param $pubkey
+ * @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
+ * @return string The envelope
*/
private function build_private_message($msg, $user, $contact, $prvkey, $pubkey) {
@@ -2335,14 +2336,14 @@ class diaspora {
}
/**
- * @brief
+ * @brief Create the envelope for a message
*
- * @param $msg
- * @param $user
- * @param array $contact The contact that is checked
- * @param $prvkey
- * @param $pubkey
- * @param $public
+ * @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
*/
@@ -2359,12 +2360,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates a signature for a message
*
- * @param array $owner the array of the item owner
- * @param $message
+ * @param array $owner the array of the owner of the message
+ * @param array $message The message that is to be signed
*
- * @return
+ * @return string The signature
*/
private function signature($owner, $message) {
$sigmsg = $message;
@@ -2377,16 +2378,16 @@ class diaspora {
}
/**
- * @brief
+ * @brief Transmit a message to a target server
*
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
- * @param $slap
+ * @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 $queue_run
+ * @param bool $queue_run Is the transmission called from the queue?
* @param string $guid message guid
*
- * @return
+ * @return int Result of the transmission
*/
public static function transmit($owner, $contact, $slap, $public_batch, $queue_run=false, $guid = "") {
@@ -2444,14 +2445,14 @@ class diaspora {
* @brief
*
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
- * @param $type
- * @param $message
+ * @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 $spool
+ * @param bool $spool Should the transmission be spooled or transmitted?
*
- * @return
+ * @return int Result of the transmission
*/
private function build_and_transmit($owner, $contact, $type, $message, $public_batch = false, $guid = "", $spool = false) {
@@ -2479,7 +2480,7 @@ class diaspora {
* @brief
*
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
+ * @param array $contact Target of the communication
*
* @return int The result of the transmission
*/
@@ -2495,7 +2496,7 @@ class diaspora {
* @brief
*
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
+ * @param array $contact Target of the communication
*
* @return int The result of the transmission
*/
@@ -2509,12 +2510,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Checks a message body if it is a reshare
*
- * @param $body
- * @param $complete
+ * @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
+ * @return array|bool Reshare details or "false" if no reshare
*/
public static function is_reshare($body, $complete = true) {
$body = trim($body);
@@ -2592,7 +2593,7 @@ class diaspora {
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
+ * @param array $contact Target of the communication
* @param bool $public_batch Is it a public post?
*
* @return int The result of the transmission
@@ -2726,7 +2727,7 @@ class diaspora {
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
+ * @param array $contact Target of the communication
* @param bool $public_batch Is it a public post?
*
* @return int The result of the transmission
@@ -2750,14 +2751,14 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates a message from a signature record entry
*
* @param array $item The item that will be exported
- * @param $signature
+ * @param array $signature The entry of the "sign" record
*
- * @return int The result of the transmission
+ * @return string The message
*/
- private function message_from_signatur($item, $signature) {
+ private function message_from_signature($item, $signature) {
// Split the signed text
$signed_parts = explode(";", $signature['signed_text']);
@@ -2804,7 +2805,7 @@ class diaspora {
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
- * @param array $contact The contact that is checked
+ * @param array $contact Target of the communication
* @param bool $public_batch Is it a public post?
*
* @return int The result of the transmission
@@ -2835,7 +2836,7 @@ class diaspora {
// 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_signatur($item, $signature);
+ $message = self::message_from_signature($item, $signature);
else {// New way
$msg = json_decode($signature['signed_text'], true);
@@ -2863,13 +2864,13 @@ class diaspora {
}
/**
- * @brief
+ * @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 The contact that is checked
+ * @param array $contact Target of the communication
* @param bool $public_batch Is it a public post?
- * @param $relay
+ * @param bool $relay Is the retraction transmitted from a relay?
*
* @return int The result of the transmission
*/
@@ -2908,7 +2909,7 @@ class diaspora {
*
* @param array $item The item that will be exported
* @param array $owner The owner
- * @param array $contact The contact that is checked
+ * @param array $contact Target of the communication
*
* @return int The result of the transmission
*/
From a2507804f2eab92df5ff721b3c836da5d1ca7461 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Fri, 18 Mar 2016 16:42:10 +0100
Subject: [PATCH 061/485] There is no table "sess_data" - this database call is
useless
---
include/session.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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;
}}
From 5c44a787bf0f6c514ee33cb75faee544618eb775 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Fri, 18 Mar 2016 22:28:20 +0100
Subject: [PATCH 062/485] The documentation should now be complete
---
include/diaspora.php | 118 +++++++++++++++++++++----------------------
1 file changed, 58 insertions(+), 60 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 14ff6e42f8..4e1b300507 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -110,6 +110,8 @@ class diaspora {
/**
* @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
@@ -887,7 +889,7 @@ class diaspora {
* @param int $uid The user id
* @param string $guid message guid
* @param string $author The handle of the item
- * @param array $contact The contact that is checked
+ * @param array $contact The contact of the item owner
*
* @return array the item record
*/
@@ -992,12 +994,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes an account deletion
*
* @param array $importer Array of the importer user
* @param object $data The message object
*
- * @return
+ * @return bool Success
*/
private function receive_account_deletion($importer, $data) {
$author = notags(unxmlify($data->author));
@@ -1014,7 +1016,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes an incoming comment
*
* @param array $importer Array of the importer user
* @param string $sender The sender of the message
@@ -1104,7 +1106,7 @@ class diaspora {
* @brief processes and stores private messages
*
* @param array $importer Array of the importer user
- * @param array $contact The contact that is checked
+ * @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
@@ -1230,13 +1232,13 @@ class diaspora {
}
/**
- * @brief
+ * @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
+ * @return bool Success
*/
private function receive_conversation($importer, $msg, $data) {
$guid = notags(unxmlify($data->guid));
@@ -1296,13 +1298,13 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates the body for a "like" message
*
- * @param array $contact The contact that is checked
- * @param $parent_item
+ * @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
+ * @return string the body
*/
private function construct_like_body($contact, $parent_item, $guid) {
$bodyverb = t('%1$s likes %2$s\'s %3$s');
@@ -1315,12 +1317,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates a XML object for a "like"
*
* @param array $importer Array of the importer user
- * @param $parent_item
+ * @param array $parent_item The item array of the parent item
*
- * @return
+ * @return string The XML
*/
private function construct_like_object($importer, $parent_item) {
$objtype = ACTIVITY_OBJ_NOTE;
@@ -1338,7 +1340,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes "like" messages
*
* @param array $importer Array of the importer user
* @param string $sender The sender of the message
@@ -1435,12 +1437,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes private messages
*
* @param array $importer Array of the importer user
* @param object $data The message object
*
- * @return
+ * @return bool Success?
*/
private function receive_message($importer, $data) {
$guid = notags(unxmlify($data->guid));
@@ -1514,7 +1516,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes participations - unsupported by now
*
* @param array $importer Array of the importer user
* @param object $data The message object
@@ -1527,12 +1529,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes photos - unneeded
*
* @param array $importer Array of the importer user
* @param object $data The message object
*
- * @return
+ * @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
@@ -1540,12 +1542,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes poll participations - unssupported
*
* @param array $importer Array of the importer user
* @param object $data The message object
*
- * @return
+ * @return bool always true
*/
private function receive_poll_participation($importer, $data) {
// We don't support polls by now
@@ -1553,12 +1555,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes incoming profile updates
*
* @param array $importer Array of the importer user
* @param object $data The message object
*
- * @return
+ * @return bool Success
*/
private function receive_profile($importer, $data) {
$author = notags(unxmlify($data->author));
@@ -1646,12 +1648,10 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes incoming friend requests
*
* @param array $importer Array of the importer user
- * @param array $contact The contact that is checked
- *
- * @return
+ * @param array $contact The contact that send the request
*/
private function receive_request_make_friend($importer, $contact) {
@@ -1714,26 +1714,24 @@ class diaspora {
$i = item_store($arr);
if($i)
proc_run("php", "include/notifier.php", "activity", $i);
-
}
-
}
}
/**
- * @brief
+ * @brief Processes incoming sharing notification
*
* @param array $importer Array of the importer user
* @param object $data The message object
*
- * @return
+ * @return bool Success
*/
private function receive_request($importer, $data) {
$author = unxmlify($data->author);
$recipient = unxmlify($data->recipient);
if (!$author || !$recipient)
- return;
+ return false;
$contact = self::contact_by_handle($importer["uid"],$author);
@@ -1842,13 +1840,13 @@ class diaspora {
}
/**
- * @brief
+ * @brief Fetches a message with a given guid
*
* @param string $guid message guid
- * @param $orig_author
- * @param $author
+ * @param string $orig_author handle of the original post
+ * @param string $author handle of the sharer
*
- * @return
+ * @return array The fetched item
*/
private function original_item($guid, $orig_author, $author) {
@@ -1907,13 +1905,13 @@ class diaspora {
}
/**
- * @brief
+ * @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
+ * @return int the message id
*/
private function receive_reshare($importer, $data, $xml) {
$root_author = notags(unxmlify($data->root_author));
@@ -1981,13 +1979,13 @@ class diaspora {
}
/**
- * @brief
+ * @brief Processes retractions
*
* @param array $importer Array of the importer user
- * @param array $contact The contact that is checked
+ * @param array $contact The contact of the item owner
* @param object $data The message object
*
- * @return
+ * @return bool success
*/
private function item_retraction($importer, $contact, $data) {
$target_type = notags(unxmlify($data->target_type));
@@ -2038,16 +2036,18 @@ class diaspora {
// notify others
proc_run("php", "include/notifier.php", "drop", $r[0]["id"]);
}
+
+ return true;
}
/**
- * @brief
+ * @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
+ * @return bool Success
*/
private function receive_retraction($importer, $sender, $data) {
$target_type = notags(unxmlify($data->target_type));
@@ -2082,13 +2082,13 @@ class diaspora {
}
/**
- * @brief
+ * @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
+ * @return int The message id of the newly created item
*/
private function receive_status_message($importer, $data, $xml) {
@@ -2345,7 +2345,7 @@ class diaspora {
* @param string $pubkey The public key of the receiver
* @param bool $public Is the message public?
*
- * @return
+ * @return string The message that will be transmitted to other servers
*/
private function build_message($msg, $user, $contact, $prvkey, $pubkey, $public = false) {
@@ -2442,7 +2442,7 @@ class diaspora {
/**
- * @brief
+ * @brief Builds and transmit messages
*
* @param array $owner the array of the item owner
* @param array $contact Target of the communication
@@ -2477,7 +2477,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief Sends a "share" message
*
* @param array $owner the array of the item owner
* @param array $contact Target of the communication
@@ -2493,7 +2493,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief sends an "unshare"
*
* @param array $owner the array of the item owner
* @param array $contact Target of the communication
@@ -2589,7 +2589,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief Sends a post
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
@@ -2666,12 +2666,12 @@ class diaspora {
}
/**
- * @brief
+ * @brief Creates a "like" object
*
* @param array $item The item that will be exported
* @param array $owner the array of the item owner
*
- * @return
+ * @return array The data for a "like"
*/
private function construct_like($item, $owner) {
@@ -2694,12 +2694,12 @@ class diaspora {
}
/**
- * @brief
+ * @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
+ * @return array The data for a comment
*/
private function construct_comment($item, $owner) {
@@ -2801,7 +2801,7 @@ class diaspora {
}
/**
- * @brief
+ * @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
@@ -2905,7 +2905,7 @@ class diaspora {
}
/**
- * @brief
+ * @brief Sends a mail
*
* @param array $item The item that will be exported
* @param array $owner The owner
@@ -2971,11 +2971,9 @@ class diaspora {
}
/**
- * @brief
+ * @brief Sends profile data
*
* @param int $uid The user id
- *
- * @return int The result of the transmission
*/
public static function send_profile($uid) {
From d676ae0f32a33e0f75c28d31f32f3d9476b4efd6 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sat, 19 Mar 2016 15:49:47 +0100
Subject: [PATCH 063/485] The signature creation now moved into the Diaspora
class. That's much cleaner.
---
include/diaspora.php | 124 +++++++++++++++++++++++++++++++++++++++++--
include/like.php | 83 +----------------------------
mod/item.php | 42 +--------------
3 files changed, 125 insertions(+), 124 deletions(-)
diff --git a/include/diaspora.php b/include/diaspora.php
index 4e1b300507..59bad946e2 100644
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -2190,13 +2190,18 @@ class diaspora {
*
* @return string the handle in the format user@domain.tld
*/
- private function my_handle($me) {
+ 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.
- return $me["nickname"]."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
+ if ($contact["nickname"] != "")
+ $nick = $contact["nickname"];
+ else
+ $nick = $contact["nick"];
+
+ return $nick."@".substr(App::get_baseurl(), strpos(App::get_baseurl(),"://") + 3);
}
/**
@@ -2689,7 +2694,7 @@ class diaspora {
"guid" => $item["guid"],
"target_type" => $target_type,
"parent_guid" => $parent["guid"],
- "author_signature" => $authorsig,
+ "author_signature" => "",
"diaspora_handle" => self::my_handle($owner)));
}
@@ -3052,5 +3057,118 @@ class diaspora {
foreach($recips as $recip)
self::build_and_transmit($profile, $recip, "profile", $message, false, "", true);
}
+
+ /**
+ * @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
+ */
+ function store_like_signature($contact, $post_id) {
+
+ $enabled = intval(get_config('system','diaspora_enabled'));
+ if (!$enabled) {
+ logger('Diaspora support disabled, not storing like signature', LOGGER_DEBUG);
+ return false;
+ }
+
+ // 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;
+ }
+
+ $r = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1", intval($contact['uid']));
+ if(!$r)
+ return false;
+
+ $contact["uprvkey"] = $r[0]['prvkey'];
+
+ $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($post_id));
+ if (!$r)
+ return false;
+
+ 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);
+
+ // 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["positive"].";".$message["guid"].";".$message["target_type"].";".
+ $message["parent_guid"].";".$message["diaspora_handle"];
+
+ 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"])
+ );
+
+ // 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 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
+ */
+ function store_comment_signature($item, $contact, $uprvkey, $message_id) {
+
+ if ($uprvkey == "") {
+ logger('No private key, so not storing comment signature', LOGGER_DEBUG);
+ return false;
+ }
+
+ $enabled = intval(get_config('system','diaspora_enabled'));
+ if (!$enabled) {
+ logger('Diaspora support disabled, not storing comment signature', LOGGER_DEBUG);
+ return false;
+ }
+
+ $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;
+ }
}
?>
diff --git a/include/like.php b/include/like.php
index 2e5367e51e..49534ea613 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)
- $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/mod/item.php b/mod/item.php
index 2ade524a05..14c8203c98 100644
--- a/mod/item.php
+++ b/mod/item.php
@@ -24,6 +24,7 @@ require_once('include/threads.php');
require_once('include/text.php');
require_once('include/items.php');
require_once('include/Scrape.php');
+require_once('include/diaspora.php');
function item_post(&$a) {
@@ -900,7 +901,7 @@ function item_post(&$a) {
// Store the comment signature information in case we need to relay to Diaspora
- store_diaspora_comment_sig($datarray, $author, ($self ? $user['prvkey'] : false), $parent_item, $post_id);
+ diaspora::store_comment_signature($datarray, $author, ($self ? $user['prvkey'] : false), $post_id);
} else {
$parent = $post_id;
@@ -1245,42 +1246,3 @@ function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $netwo
return array('replaced' => $replaced, 'contact' => $r[0]);
}
-
-
-function store_diaspora_comment_sig($datarray, $author, $uprvkey, $parent_item, $post_id) {
- // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key
-
- $enabled = intval(get_config('system','diaspora_enabled'));
- if(! $enabled) {
- logger('mod_item: diaspora support disabled, not storing comment signature', LOGGER_DEBUG);
- return;
- }
-
-
- logger('mod_item: storing diaspora comment signature');
-
- require_once('include/bb2diaspora.php');
- $signed_body = html_entity_decode(bb2diaspora($datarray['body']));
-
- // Only works for NETWORK_DFRN
- $contact_baseurl_start = strpos($author['url'],'://') + 3;
- $contact_baseurl_length = strpos($author['url'],'/profile') - $contact_baseurl_start;
- $contact_baseurl = substr($author['url'], $contact_baseurl_start, $contact_baseurl_length);
- $diaspora_handle = $author['nick'] . '@' . $contact_baseurl;
-
- $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $diaspora_handle;
-
- if( $uprvkey !== false )
- $authorsig = rsa_sign($signed_text,$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(base64_encode($authorsig)),
- dbesc($diaspora_handle)
- );
-
- return;
-}
From 186eaf1264320de3e5604d09b7ae7818ba5c4465 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 20 Mar 2016 10:30:06 +0100
Subject: [PATCH 064/485] Take the second largest picture as preview - not the
smallest one
---
mod/fbrowser.php | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/mod/fbrowser.php b/mod/fbrowser.php
index 0a2a7dead5..5836efbe52 100644
--- a/mod/fbrowser.php
+++ b/mod/fbrowser.php
@@ -74,10 +74,18 @@ function fbrowser_content($a){
$filename_e = $rr['filename'];
}
+ // Take the second largest picture as preview
+ $p = q("SELECT `scale` FROM `photo` WHERE `resource-id` = '%s' AND `scale` > %d ORDER BY `resource-id`, `scale` LIMIT 1",
+ dbesc($rr['resource-id']), intval($rr['hiq']));
+ if ($p)
+ $scale = $p[0]["scale"];
+ else
+ $scale = $rr['loq'];
+
return array(
$a->get_baseurl() . '/photos/' . $a->user['nickname'] . '/image/' . $rr['resource-id'],
$filename_e,
- $a->get_baseurl() . '/photo/' . $rr['resource-id'] . '-' . $rr['loq'] . '.'. $ext
+ $a->get_baseurl() . '/photo/' . $rr['resource-id'] . '-' . $scale . '.'. $ext
);
}
$files = array_map("_map_files1", $r);
From 8f00836ffb47758fa16101cafeb1a03d13d88de4 Mon Sep 17 00:00:00 2001
From: Michael Vogel
Date: Sun, 20 Mar 2016 15:01:50 +0100
Subject: [PATCH 065/485] Add the guid to items that we create locally
---
include/like.php | 1 +
mod/dfrn_confirm.php | 3 ++-
mod/mood.php | 2 +-
mod/photos.php | 5 +++--
mod/poke.php | 1 +
mod/profiles.php | 2 ++
mod/subthread.php | 5 +++--
mod/tagger.php | 5 +++--
8 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/include/like.php b/include/like.php
index 646e0727be..d852cc3b31 100644
--- a/include/like.php
+++ b/include/like.php
@@ -196,6 +196,7 @@ EOT;
$arr = array();
+ $arr['guid'] = get_guid(32);
$arr['uri'] = $uri;
$arr['uid'] = $owner_uid;
$arr['contact-id'] = $contact['id'];
diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php
index 68950ec285..aed9809ca2 100644
--- a/mod/dfrn_confirm.php
+++ b/mod/dfrn_confirm.php
@@ -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'] = '