]> git.mxchange.org Git - friendica.git/blobdiff - include/diaspora.php
DFRN Deletions should now work too
[friendica.git] / include / diaspora.php
old mode 100755 (executable)
new mode 100644 (file)
index b70cffd..93fe2a4
@@ -1,5 +1,11 @@
 <?php
 
+/**
+ * @file include/diaspora.php
+ * 
+ * @todo GET /people/9aed8882b9f64896/stream
+ */
+
 require_once('include/crypto.php');
 require_once('include/items.php');
 require_once('include/bb2diaspora.php');
@@ -8,6 +14,7 @@ require_once('include/queue_fn.php');
 require_once('include/lock.php');
 require_once('include/threads.php');
 require_once('mod/share.php');
+require_once('include/enotify.php');
 
 function diaspora_dispatch_public($msg) {
 
@@ -17,9 +24,15 @@ function diaspora_dispatch_public($msg) {
                return;
        }
 
+       // Use a dummy importer to import the data for the public copy
+       $importer = array("uid" => 0, "page-flags" => PAGE_FREELOVE);
+       $result = diaspora_dispatch($importer,$msg);
+       logger("Dispatcher reported ".$result, LOGGER_DEBUG);
+
+       // 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 ",
+               ( 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'])
        );
@@ -30,7 +43,7 @@ function diaspora_dispatch_public($msg) {
                }
        }
        else
-               logger('diaspora_public: no subscribers');
+               logger('diaspora_public: no subscribers for '.$msg["author"].' '.print_r($msg, true));
 }
 
 
@@ -99,6 +112,9 @@ function diaspora_dispatch($importer,$msg,$attempt=1) {
        elseif($xmlbase->message) {
                $ret = diaspora_message($importer,$xmlbase->message,$msg);
        }
+       elseif($xmlbase->participation) {
+               $ret = diaspora_participation($importer,$xmlbase->participation);
+       }
        else {
                logger('diaspora_dispatch: unknown message type: ' . print_r($xmlbase,true));
        }
@@ -540,7 +556,7 @@ function diaspora_decode($importer,$xml) {
        // 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);
+       $key = get_diaspora_key($author_link);
 
        if(! $key) {
                logger('mod-diaspora: Could not retrieve author key.');
@@ -578,7 +594,7 @@ function diaspora_request($importer,$xml) {
                // perhaps we were already sharing with this person. Now they're sharing with us.
                // That makes us friends.
 
-               if($contact['rel'] == CONTACT_IS_FOLLOWER && $importer['page-flags'] != PAGE_COMMUNITY) {
+               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']),
@@ -635,7 +651,7 @@ function diaspora_request($importer,$xml) {
 
                                $i = item_store($arr);
                                if($i)
-                               proc_run('php',"include/notifier.php","activity","$i");
+                               proc_run('php',"include/notifier.php","activity","$i");
 
                        }
 
@@ -713,7 +729,7 @@ function diaspora_request($importer,$xml) {
 
                require_once('include/Photo.php');
 
-               $photos = import_profile_photo($contact_record['photo'],$importer['uid'],$contact_record['id']);
+               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
@@ -724,26 +740,17 @@ function diaspora_request($importer,$xml) {
                else
                        $new_relation = CONTACT_IS_FOLLOWER;
 
-               $r = q("UPDATE `contact` SET
-                       `photo` = '%s',
-                       `thumb` = '%s',
-                       `micro` = '%s',
-                       `rel` = %d,
+               $r = q("UPDATE `contact` SET `rel` = %d,
                        `name-date` = '%s',
                        `uri-date` = '%s',
-                       `avatar-date` = '%s',
                        `blocked` = 0,
                        `pending` = 0,
                        `writable` = 1
                        WHERE `id` = %d
                        ",
-                       dbesc($photos[0]),
-                       dbesc($photos[1]),
-                       dbesc($photos[2]),
                        intval($new_relation),
                        dbesc(datetime_convert()),
                        dbesc(datetime_convert()),
-                       dbesc(datetime_convert()),
                        intval($contact_record['id'])
                );
 
@@ -755,12 +762,12 @@ function diaspora_request($importer,$xml) {
        return;
 }
 
-function diaspora_post_allow($importer,$contact) {
+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 && $importer['page-flags'] != PAGE_COMMUNITY) {
+       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']),
@@ -775,8 +782,13 @@ function diaspora_post_allow($importer,$contact) {
        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)
+               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;
 }
 
@@ -785,7 +797,7 @@ function diaspora_is_redmatrix($url) {
 }
 
 function diaspora_plink($addr, $guid) {
-       $r = q("SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", $addr);
+       $r = q("SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", dbesc($addr));
 
        // Fallback
        if (!$r)
@@ -806,6 +818,23 @@ function diaspora_plink($addr, $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();
@@ -818,23 +847,24 @@ function diaspora_post($importer,$xml,$msg) {
        }
 
        $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
-       if(! $contact)
-               return;
+       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)) {
+       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 `uri` = '%s' AND `guid` = '%s' LIMIT 1",
+       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
                intval($importer['uid']),
-               dbesc($message_id),
                dbesc($guid)
        );
        if(count($r)) {
                logger('diaspora_post: message exists: ' . $guid);
-               return;
+               return 208;
        }
 
        $created = unxmlify($xml->created_at);
@@ -889,7 +919,7 @@ function diaspora_post($importer,$xml,$msg) {
        $datarray['body'] = $body;
        $datarray['tag'] = $str_tags;
        if ($xml->provider_display_name)
-                $datarray["app"] = unxmlify($xml->provider_display_name);
+               $datarray["app"] = unxmlify($xml->provider_display_name);
        else
                $datarray['app']  = 'Diaspora';
 
@@ -900,7 +930,9 @@ function diaspora_post($importer,$xml,$msg) {
        DiasporaFetchGuid($datarray);
        $message_id = item_store($datarray);
 
-       return;
+       logger("Stored item with message id ".$message_id, LOGGER_DEBUG);
+
+       return 201;
 
 }
 
@@ -921,8 +953,8 @@ function DiasporaFetchGuidSub($match, $item) {
 function diaspora_store_by_guid($guid, $server, $uid = 0) {
        require_once("include/Contact.php");
 
-        $serverparts = parse_url($server);
-        $server = $serverparts["scheme"]."://".$serverparts["host"];
+       $serverparts = parse_url($server);
+       $server = $serverparts["scheme"]."://".$serverparts["host"];
 
        logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
 
@@ -944,9 +976,8 @@ function diaspora_store_by_guid($guid, $server, $uid = 0) {
        $objecttype = $item["object-type"];
 
        $message_id = $author.':'.$guid;
-       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1",
+       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
                intval($uid),
-               dbesc($message_id),
                dbesc($guid)
        );
        if(count($r))
@@ -954,9 +985,21 @@ function diaspora_store_by_guid($guid, $server, $uid = 0) {
 
        $person = find_diaspora_person_by_handle($author);
 
-        $datarray = array();
+       $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'] = get_contact($person['url'], $uid);
+       $datarray['contact-id'] = $contact_id;
        $datarray['wall'] = 0;
        $datarray['network']  = NETWORK_DIASPORA;
        $datarray['guid'] = $guid;
@@ -984,8 +1027,8 @@ function diaspora_store_by_guid($guid, $server, $uid = 0) {
        DiasporaFetchGuid($datarray);
        $message_id = item_store($datarray);
 
-       // To-Do:
-       // Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
+       /// @TODO
+       /// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
 
        return $message_id;
 }
@@ -1055,8 +1098,8 @@ function diaspora_fetch_message($guid, $server, $level = 0) {
                $body = scale_external_images($body);
 
                // Add OEmbed and other information to the body
-               // To-Do: It could be a repeated redmatrix item
-               // Then we shouldn't add further data to it
+               /// @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);
 
@@ -1096,15 +1139,14 @@ function diaspora_reshare($importer,$xml,$msg) {
        if(! $contact)
                return;
 
-       if(! diaspora_post_allow($importer,$contact)) {
+       if(! diaspora_post_allow($importer,$contact, false)) {
                logger('diaspora_reshare: Ignoring this author: ' . $diaspora_handle . ' ' . print_r($xml,true));
                return 202;
        }
 
        $message_id = $diaspora_handle . ':' . $guid;
-       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1",
+       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
                intval($importer['uid']),
-               dbesc($message_id),
                dbesc($guid)
        );
        if(count($r)) {
@@ -1282,15 +1324,14 @@ function diaspora_asphoto($importer,$xml,$msg) {
        if(! $contact)
                return;
 
-       if(! diaspora_post_allow($importer,$contact)) {
+       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 `uri` = '%s' AND `guid` = '%s' LIMIT 1",
+       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
                intval($importer['uid']),
-               dbesc($message_id),
                dbesc($guid)
        );
        if(count($r)) {
@@ -1355,11 +1396,6 @@ function diaspora_asphoto($importer,$xml,$msg) {
 
 }
 
-
-
-
-
-
 function diaspora_comment($importer,$xml,$msg) {
 
        $a = get_app();
@@ -1378,7 +1414,7 @@ function diaspora_comment($importer,$xml,$msg) {
                return;
        }
 
-       if(! diaspora_post_allow($importer,$contact)) {
+       if(! diaspora_post_allow($importer,$contact, true)) {
                logger('diaspora_comment: Ignoring this author.');
                return 202;
        }
@@ -1479,16 +1515,27 @@ function diaspora_comment($importer,$xml,$msg) {
                }
        }
 
+       // 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'] = $contact['id'];
+       $datarray['contact-id'] = $cid;
        $datarray['type'] = 'remote-comment';
        $datarray['wall'] = $parent_item['wall'];
-       $datarray['network']  = NETWORK_DIASPORA;
+       $datarray['network']  = $network;
        $datarray['verb'] = ACTIVITY_POST;
        $datarray['gravity'] = GRAVITY_COMMENT;
        $datarray['guid'] = $guid;
@@ -1527,62 +1574,22 @@ function diaspora_comment($importer,$xml,$msg) {
                //);
        //}
 
-       if(($parent_item['origin']) && (! $parent_author_signature)) {
+       // 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(base64_encode($author_signature)),
+                       dbesc($author_signature_base64),
                        dbesc($diaspora_handle)
                );
 
-               // if the message isn't already being relayed, notify others
-               // the existence of parent_author_signature means the parent_author or owner
-               // is already relaying.
-
+               // notify others
                proc_run('php','include/notifier.php','comment-import',$message_id);
        }
 
-       $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0 ",
-               dbesc($parent_item['uri']),
-               intval($importer['uid'])
-       );
-
-       if(count($myconv)) {
-               $importer_url = $a->get_baseurl() . '/profile/' . $importer['nickname'];
-
-               foreach($myconv as $conv) {
-
-                       // now if we find a match, it means we're in this conversation
-
-                       if(! link_compare($conv['author-link'],$importer_url))
-                               continue;
-
-                       require_once('include/enotify.php');
-
-                       $conv_parent = $conv['parent'];
-
-                       notification(array(
-                               'type'         => NOTIFY_COMMENT,
-                               'notify_flags' => $importer['notify-flags'],
-                               'language'     => $importer['language'],
-                               'to_name'      => $importer['username'],
-                               'to_email'     => $importer['email'],
-                               'uid'          => $importer['uid'],
-                               'item'         => $datarray,
-                               'link'             => $a->get_baseurl().'/display/'.urlencode($datarray['guid']),
-                               'source_name'  => $datarray['author-name'],
-                               'source_link'  => $datarray['author-link'],
-                               'source_photo' => $datarray['author-avatar'],
-                               'verb'         => ACTIVITY_POST,
-                               'otype'        => 'item',
-                               'parent'       => $conv_parent,
-                               'parent_uri'   => $parent_uri
-                       ));
-
-                       // only send one notification
-                       break;
-               }
-       }
        return;
 }
 
@@ -1600,7 +1607,7 @@ function diaspora_conversation($importer,$xml,$msg) {
        $created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at)));
 
        $parent_uri = $diaspora_handle . ':' . $guid;
+
        $messages = $xml->message;
 
        if(! count($messages)) {
@@ -1614,7 +1621,7 @@ function diaspora_conversation($importer,$xml,$msg) {
                return;
        }
 
-       if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) { 
+       if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
                logger('diaspora_conversation: Ignoring this author.');
                return 202;
        }
@@ -1639,11 +1646,11 @@ function diaspora_conversation($importer,$xml,$msg) {
                );
                if($r)
                        $c = q("select * from conv where uid = %d and guid = '%s' limit 1",
-               intval($importer['uid']),
-           dbesc($guid)
-       );
+               intval($importer['uid']),
+           dbesc($guid)
+       );
            if(count($c))
-           $conversation = $c[0];
+           $conversation = $c[0];
        }
        if(! $conversation) {
                logger('diaspora_conversation: unable to create conversation.');
@@ -1737,7 +1744,6 @@ function diaspora_conversation($importer,$xml,$msg) {
                        intval($conversation['id'])
                );
 
-               require_once('include/enotify.php');
                notification(array(
                        'type' => NOTIFY_MAIL,
                        'notify_flags' => $importer['notify-flags'],
@@ -1770,15 +1776,15 @@ function diaspora_message($importer,$xml,$msg) {
        $msg_diaspora_handle = notags(unxmlify($xml->diaspora_handle));
        $msg_conversation_guid = notags(unxmlify($xml->conversation_guid));
 
-       $parent_uri = $diaspora_handle . ':' . $msg_parent_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'])) { 
+       if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
                logger('diaspora_message: Ignoring this author.');
                return 202;
        }
@@ -1806,7 +1812,7 @@ function diaspora_message($importer,$xml,$msg) {
 
        $author_signature = base64_decode($msg_author_signature);
 
-       $person = find_diaspora_person_by_handle($msg_diaspora_handle); 
+       $person = find_diaspora_person_by_handle($msg_diaspora_handle);
        if(is_array($person) && x($person,'pubkey'))
                $key = $person['pubkey'];
        else {
@@ -1853,6 +1859,9 @@ function diaspora_message($importer,$xml,$msg) {
        return;
 }
 
+function diaspora_participation($importer,$xml) {
+       logger("Unsupported message type 'participation' ".print_r($xml, true));
+}
 
 function diaspora_photo($importer,$xml,$msg,$attempt=1) {
 
@@ -1882,7 +1891,7 @@ function diaspora_photo($importer,$xml,$msg,$attempt=1) {
                return;
        }
 
-       if(! diaspora_post_allow($importer,$contact)) {
+       if(! diaspora_post_allow($importer,$contact, false)) {
                logger('diaspora_photo: Ignoring this author.');
                return 202;
        }
@@ -1929,14 +1938,18 @@ function diaspora_photo($importer,$xml,$msg,$attempt=1) {
        $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));
+                                          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($link_text . $parent_item['body']),
+                       dbesc($parent_item['body']),
                        intval($parent_item['id']),
                        intval($parent_item['uid'])
                );
+               put_item_in_cache($parent_item, true);
                update_thread($parent_item['id']);
        }
 
@@ -1969,7 +1982,7 @@ function diaspora_like($importer,$xml,$msg) {
                return;
        }
 
-       if(! diaspora_post_allow($importer,$contact)) {
+       if(! diaspora_post_allow($importer,$contact, false)) {
                logger('diaspora_like: Ignoring this author.');
                return 202;
        }
@@ -2121,13 +2134,24 @@ function diaspora_like($importer,$xml,$msg) {
 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_DIASPORA;
-       $arr['contact-id'] = $contact['id'];
+       $arr['network']  = $network;
+       $arr['contact-id'] = $cid;
        $arr['type'] = 'activity';
        $arr['wall'] = $parent_item['wall'];
        $arr['gravity'] = GRAVITY_LIKE;
@@ -2170,21 +2194,21 @@ EOT;
        //      );
        //}
 
-       if(! $parent_author_signature) {
+       // 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(base64_encode($author_signature)),
+                       dbesc($author_signature_base64),
                        dbesc($diaspora_handle)
                );
-       }
-
-       // if the message isn't already being relayed, notify others
-       // the existence of parent_author_signature means the parent_author or owner
-       // is already relaying. The parent_item['origin'] indicates the message was created on our system
 
-       if(($parent_item['origin']) && (! $parent_author_signature))
+               // notify others
                proc_run('php','include/notifier.php','comment-import',$message_id);
+       }
 
        return;
 }
@@ -2203,8 +2227,23 @@ function diaspora_retraction($importer,$xml) {
        if($type === 'Person') {
                require_once('include/Contact.php');
                contact_remove($contact['id']);
-       }
-       elseif($type === 'Post') {
+       } 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'])
@@ -2265,8 +2304,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
                        return;
                }
 
-       }
-       else {
+       } else {
 
                $sig_decode = base64_decode($sig);
 
@@ -2295,12 +2333,12 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
                                // 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",
-                                       $r[0]['parent'],
-                                       $r[0]['parent']
+                               $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']) && (! $parent_author_signature)) {
+                                       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),
@@ -2340,10 +2378,10 @@ function diaspora_profile($importer,$xml,$msg) {
        if(! $contact)
                return;
 
-       if($contact['blocked']) {
-               logger('diaspora_post: Ignoring this author.');
-               return 202;
-       }
+       //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);
@@ -2351,6 +2389,8 @@ function diaspora_profile($importer,$xml,$msg) {
        $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);
@@ -2365,6 +2405,8 @@ function diaspora_profile($importer,$xml,$msg) {
        $keywords = implode(", ", $keywords);
 
        $handle_parts = explode("@", $diaspora_handle);
+       $nick = $handle_parts[0];
+
        if($name === '') {
                $name = $handle_parts[0];
        }
@@ -2381,13 +2423,14 @@ function diaspora_profile($importer,$xml,$msg) {
 
        require_once('include/Photo.php');
 
-       $images = import_profile_photo($image_url,$importer['uid'],$contact['id']);
+       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);
 
-       $birthday = datetime_convert('UTC','UTC',$birthday,'Y-m-d');
+       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
@@ -2395,15 +2438,14 @@ function diaspora_profile($importer,$xml,$msg) {
        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.
+       /// @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', `name-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' , `bd` = '%s', `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `id` = %d AND `uid` = %d",
+       $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(datetime_convert()),
-               dbesc($images[0]),
-               dbesc($images[1]),
-               dbesc($images[2]),
+               dbesc($nick),
+               dbesc($diaspora_handle),
                dbesc(datetime_convert()),
                dbesc($birthday),
                dbesc($location),
@@ -2414,26 +2456,17 @@ function diaspora_profile($importer,$xml,$msg) {
                intval($importer['uid'])
        );
 
-       if (unxmlify($xml->searchable) == "true") {
+       if ($searchable) {
                require_once('include/socgraph.php');
-               poco_check($contact['url'], $name, NETWORK_DIASPORA, $images[0], $about, $location, $gender, $keywords, "",
+               poco_check($contact['url'], $name, NETWORK_DIASPORA, $image_url, $about, $location, $gender, $keywords, "",
                        datetime_convert(), 2, $contact['id'], $importer['uid']);
        }
 
-       $profileurl = "";
-       $author = q("SELECT * FROM `unique_contacts` WHERE `url`='%s' LIMIT 1",
-                       dbesc(normalise_link($contact['url'])));
-
-       if (count($author) == 0) {
-               q("INSERT INTO `unique_contacts` (`url`, `name`, `avatar`, `location`, `about`) VALUES ('%s', '%s', '%s', '%s', '%s')",
-                       dbesc(normalise_link($contact['url'])), dbesc($name), dbesc($location), dbesc($about), dbesc($images[0]));
-
-               $author = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
-                       dbesc(normalise_link($contact['url'])));
-       } else if (normalise_link($contact['url']).$name.$location.$about != normalise_link($author[0]["url"]).$author[0]["name"].$author[0]["location"].$author[0]["about"]) {
-               q("UPDATE unique_contacts SET name = '%s', avatar = '%s', `location` = '%s', `about` = '%s' WHERE url = '%s'",
-               dbesc($name), dbesc($images[0]), dbesc($location), dbesc($about), dbesc(normalise_link($contact['url'])));
-       }
+       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) {
@@ -2575,11 +2608,12 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
        }
 
        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);
+       $return_code = diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']);
 
        logger('diaspora_send_status: guid: '.$item['guid'].' result '.$return_code, LOGGER_DEBUG);
 
@@ -2593,28 +2627,28 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
 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);
+       // 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);
+       // 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);
+       $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];
+       $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];
+       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",
@@ -2627,35 +2661,35 @@ function diaspora_is_reshare($body) {
                }
        }
 
-        $profile = "";
-        preg_match("/profile='(.*?)'/ism", $attributes, $matches);
-        if ($matches[1] != "")
-                $profile = $matches[1];
+       $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];
+       preg_match('/profile="(.*?)"/ism', $attributes, $matches);
+       if ($matches[1] != "")
+               $profile = $matches[1];
 
-        $ret= array();
+       $ret= array();
 
-        $ret["root_handle"] = preg_replace("=https?://(.*)/u/(.*)=ism", "$2@$1", $profile);
-        if (($ret["root_handle"] == $profile) OR ($ret["root_handle"] == ""))
-                return(false);
+       $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];
+       $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];
+       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);
+       $ret["root_guid"] = preg_replace("=https?://(.*)/posts/(.*)=ism", "$2", $link);
+       if (($ret["root_guid"] == $link) OR ($ret["root_guid"] == ""))
+               return(false);
 
-        return($ret);
+       return($ret);
 }
 
 function diaspora_send_images($item,$owner,$contact,$images,$public_batch = false) {
@@ -2690,10 +2724,12 @@ function diaspora_send_images($item,$owner,$contact,$images,$public_batch = fals
 
 
                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);
+               diaspora_transmit($owner,$contact,$slap,$public_batch,false,$r[0]['guid']);
        }
 
 }
@@ -2709,7 +2745,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
        // 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'])
+                       dbesc($item['thr-parent'])
                      );
        }
        else {
@@ -2747,7 +2783,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
        // sign it
 
        if($like)
-               $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $myaddr;
+               $signed_text =  $positive . ';' . $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $myaddr;
        else
                $signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $myaddr;
 
@@ -2764,11 +2800,12 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
        ));
 
        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));
+       return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
 }
 
 
@@ -2779,15 +2816,12 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
        $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
 //     $theiraddr = $contact['addr'];
 
-       $body = $item['body'];
-       $text = html_entity_decode(bb2diaspora($body));
-
        // 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'])
+                       dbesc($item['thr-parent'])
                      );
        }
        else {
@@ -2832,61 +2866,53 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
        // 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 * from sign where " . $sql_sign_id . " = %d limit 1",
+       $r = q("SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE " . $sql_sign_id . " = %d LIMIT 1",
                intval($item['id'])
        );
-       if(count($r)) { 
+       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
 
-               // Author signature information (for likes, comments, and retractions of likes or comments,
-               // whether from Diaspora or Friendica) must be placed in the `sign` table before this 
-               // function is called
-               logger('diaspora_send_relay: original author signature not found, cannot send relayable');
-               return;
-       }*/
-
-       /* Since the author signature is only checked by the parent, not by the relay recipients,
-        * I think it may not be necessary for us to do so much work to preserve all the original
-        * signatures. The important thing that Diaspora DOES need is the original creator's handle.
-        * Let's just generate that and forget about all the original author signature stuff.
-        *
-        * Note: this might be more of an problem if we want to support likes on comments for older
-        * versions of Diaspora (diaspora-pistos), but since there are a number of problems with
-        * doing that, let's ignore it for now.
-        *
-        * Currently, only DFRN contacts are supported. StatusNet shouldn't be hard, but it hasn't
-        * been done yet
-        */
-
-       $handle = diaspora_handle_from_contact($item['contact-id']);
-       if(! $handle)
-               return;
+               $body = $item['body'];
+               $text = html_entity_decode(bb2diaspora($body));
 
+               $handle = diaspora_handle_from_contact($item['contact-id']);
+               if(! $handle)
+                       return;
 
-       if($relay_retract)
-               $sender_signed_text = $item['guid'] . ';' . $target_type;
-       elseif($like)
-               $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $handle;
-       else
-               $sender_signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $handle;
+               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;
 
-       // Sign the relayable with the top-level owner's signature
-       //
-       // We'll use the $sender_signed_text that we just created, instead of the $signed_text
-       // stored in the database, because that provides the best chance that Diaspora will
-       // be able to reconstruct the signed text the same way we did. This is particularly a
-       // concern for the comment, whose signed text includes the text of the comment. The
-       // smallest change in the text of the comment, including removing whitespace, will
-       // make the signature verification fail. Since we translate from BB code to Diaspora's
-       // markup at the top of this function, which is AFTER we placed the original $signed_text
-       // in the database, it's hazardous to trust the original $signed_text.
+               $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
+       }
 
-       $parentauthorsig = base64_encode(rsa_sign($sender_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']),
@@ -2900,12 +2926,12 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
        ));
 
        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));
+       return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
 
 }
 
@@ -2937,10 +2963,12 @@ function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) {
                '$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));
+       return(diaspora_transmit($owner,$contact,$slap,$public_batch,false,$item['guid']));
 }
 
 function diaspora_send_mail($item,$owner,$contact) {
@@ -2970,7 +2998,7 @@ function diaspora_send_mail($item,$owner,$contact) {
        $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 .  ';' 
+       $signed_text =  $item['guid'] . ';' . $cnv['guid'] . ';' . $body .  ';'
                . $created . ';' . $myaddr . ';' . $cnv['guid'];
 
        $sig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
@@ -2978,7 +3006,7 @@ function diaspora_send_mail($item,$owner,$contact) {
        $msg = array(
                'guid' => xmlify($item['guid']),
                'parent_guid' => xmlify($cnv['guid']),
-               'parent_author_signature' => (($item['reply']) ? null : xmlify($sig)),
+               'parent_author_signature' => xmlify($sig),
                'author_signature' => xmlify($sig),
                'text' => xmlify($body),
                'created_at' => xmlify($created),
@@ -2997,16 +3025,17 @@ function diaspora_send_mail($item,$owner,$contact) {
        }
 
        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));
+       return(diaspora_transmit($owner,$contact,$slap,false,false,$item['guid']));
 
 
 }
 
-function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false) {
+function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false,$guid = "") {
 
        $enabled = intval(get_config('system','diaspora_enabled'));
        if(! $enabled) {
@@ -3019,9 +3048,9 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false)
        if(! $dest_url) {
                logger('diaspora_transmit: no url for contact: ' . $contact['id'] . ' batch mode =' . $public_batch);
                return 0;
-       } 
+       }
 
-       logger('diaspora_transmit: ' . $logid . ' ' . $dest_url);
+       logger('diaspora_transmit: '.$logid.'-'.$guid.' '.$dest_url);
 
        if( (! $queue_run) && (was_recently_delayed($contact['id'])) ) {
                $return_code = 0;
@@ -3036,7 +3065,7 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false)
                }
        }
 
-       logger('diaspora_transmit: ' . $logid . ' returns: ' . $return_code);
+       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');
@@ -3059,3 +3088,47 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false)
 
        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;
+}