]> git.mxchange.org Git - friendica.git/blobdiff - include/diaspora.php
BBCode: Add a linefeed between a picture and the following text. This is important...
[friendica.git] / include / diaspora.php
index a398007e197d206629caa3b17cd92fd5845eb27b..8b85e7b9552c2158b71a81b2d56c8cca5955e427 100755 (executable)
@@ -5,7 +5,7 @@ require_once('include/items.php');
 require_once('include/bb2diaspora.php');
 require_once('include/contact_selectors.php');
 require_once('include/queue_fn.php');
-
+require_once('include/lock.php');
 
 function diaspora_dispatch_public($msg) {
 
@@ -15,7 +15,9 @@ function diaspora_dispatch_public($msg) {
                return;
        }
 
-       $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 ",
+       $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'])
        );
@@ -31,7 +33,7 @@ function diaspora_dispatch_public($msg) {
 
 
 
-function diaspora_dispatch($importer,$msg) {
+function diaspora_dispatch($importer,$msg,$attempt=1) {
 
        $ret = 0;
 
@@ -60,10 +62,10 @@ function diaspora_dispatch($importer,$msg) {
                $ret = diaspora_request($importer,$xmlbase->request);
        }
        elseif($xmlbase->status_message) {
-               $ret = diaspora_post($importer,$xmlbase->status_message);
+               $ret = diaspora_post($importer,$xmlbase->status_message,$msg);
        }
        elseif($xmlbase->profile) {
-               $ret = diaspora_profile($importer,$xmlbase->profile);
+               $ret = diaspora_profile($importer,$xmlbase->profile,$msg);
        }
        elseif($xmlbase->comment) {
                $ret = diaspora_comment($importer,$xmlbase->comment,$msg);
@@ -72,10 +74,10 @@ function diaspora_dispatch($importer,$msg) {
                $ret = diaspora_like($importer,$xmlbase->like,$msg);
        }
        elseif($xmlbase->asphoto) {
-               $ret = diaspora_asphoto($importer,$xmlbase->asphoto);
+               $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg);
        }
        elseif($xmlbase->reshare) {
-               $ret = diaspora_reshare($importer,$xmlbase->reshare);
+               $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg);
        }
        elseif($xmlbase->retraction) {
                $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
@@ -87,7 +89,7 @@ function diaspora_dispatch($importer,$msg) {
                $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
        }
        elseif($xmlbase->photo) {
-               $ret = diaspora_photo($importer,$xmlbase->photo,$msg);
+               $ret = diaspora_photo($importer,$xmlbase->photo,$msg,$attempt);
        }
        elseif($xmlbase->conversation) {
                $ret = diaspora_conversation($importer,$xmlbase->conversation,$msg);
@@ -101,6 +103,37 @@ function diaspora_dispatch($importer,$msg) {
        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);
+               }
+               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 $handle;
+}
+
 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),
@@ -109,31 +142,108 @@ function diaspora_get_contact_by_handle($uid,$handle) {
        );
        if($r && 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 && count($r))
+               return $r[0];
+
        return false;
 }
 
 function find_diaspora_person_by_handle($handle) {
+
+       $person = false;
        $update = false;
-       $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1",
-               dbesc(NETWORK_DIASPORA),
-               dbesc($handle)
-       );
-       if(count($r)) {
-               logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DEBUG);
-               // update record occasionally so it doesn't get stale
-               $d = strtotime($r[0]['updated'] . ' +00:00');
-               if($d > strtotime('now - 14 days'))
-                       return $r[0];
-               $update = true;
-       }
-       logger('find_diaspora_person_by_handle: refresh',LOGGER_DEBUG);
-       require_once('include/Scrape.php');
-       $r = probe_url($handle, PROBE_DIASPORA);
-       if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) {
-               add_fcontact($r,$update);
-               return ($r);
-       }
-       return false;
+       $got_lock = false;
+
+       $endlessloop = 0;
+       $maxloops = 10;
+
+       do {
+               $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('find_diaspora_person_by handle: 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;
+               }
+
+
+               // 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');
+                       }
+               }
+       } 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;
 }
 
 
@@ -152,7 +262,7 @@ function diaspora_pubmsg_build($msg,$user,$contact,$prvkey,$pubkey) {
 
        logger('diaspora_pubmsg_build: ' . $msg, LOGGER_DATA);
 
-       
+
        $handle = $user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
 
 //     $b64_data = base64_encode($msg);
@@ -166,7 +276,7 @@ function diaspora_pubmsg_build($msg,$user,$contact,$prvkey,$pubkey) {
        $encoding = 'base64url';
        $alg = 'RSA-SHA256';
 
-       $signable_data = $data  . '.' . base64url_encode($type) . '.' 
+       $signable_data = $data  . '.' . base64url_encode($type) . '.'
                . base64url_encode($encoding) . '.' . base64url_encode($alg) ;
 
        $signature = rsa_sign($signable_data,$prvkey);
@@ -219,7 +329,7 @@ function diaspora_msg_build($msg,$user,$contact,$prvkey,$pubkey,$public = false)
        $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);
@@ -235,7 +345,7 @@ function diaspora_msg_build($msg,$user,$contact,$prvkey,$pubkey,$public = false)
        $encoding = 'base64url';
        $alg = 'RSA-SHA256';
 
-       $signable_data = $data  . '.' . base64url_encode($type) . '.' 
+       $signable_data = $data  . '.' . base64url_encode($type) . '.'
                . base64url_encode($encoding) . '.' . base64url_encode($alg) ;
 
        $signature = rsa_sign($signable_data,$prvkey);
@@ -315,7 +425,7 @@ function diaspora_decode($importer,$xml) {
        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);
 
@@ -375,7 +485,7 @@ function diaspora_decode($importer,$xml) {
                $base = $dom->env;
        elseif($dom->data)
                $base = $dom;
-       
+
        if(! $base) {
                logger('mod-diaspora: unable to locate salmon data in xml ');
                http_status_exit(400);
@@ -448,7 +558,7 @@ function diaspora_decode($importer,$xml) {
 
 }
 
-       
+
 function diaspora_request($importer,$xml) {
 
        $a = get_app();
@@ -458,7 +568,7 @@ function diaspora_request($importer,$xml) {
 
        if(! $sender_handle || ! $recipient_handle)
                return;
-        
+
        $contact = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
 
        if($contact) {
@@ -467,7 +577,7 @@ function diaspora_request($importer,$xml) {
                // That makes us friends.
 
                if($contact['rel'] == CONTACT_IS_FOLLOWER && $importer['page-flags'] != PAGE_COMMUNITY) {
-                       q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1",
+                       q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d",
                                intval(CONTACT_IS_FRIEND),
                                intval($contact['id']),
                                intval($importer['uid'])
@@ -503,7 +613,7 @@ function diaspora_request($importer,$xml) {
                                $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]';
@@ -531,7 +641,7 @@ function diaspora_request($importer,$xml) {
 
                return;
        }
-       
+
        $ret = find_diaspora_person_by_handle($sender_handle);
 
 
@@ -562,7 +672,7 @@ function diaspora_request($importer,$xml) {
                1,
                2
        );
-                
+
        // find the contact record we just created
 
        $contact_record = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
@@ -583,7 +693,7 @@ function diaspora_request($importer,$xml) {
        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']),
@@ -602,8 +712,8 @@ function diaspora_request($importer,$xml) {
                require_once('include/Photo.php');
 
                $photos = import_profile_photo($contact_record['photo'],$importer['uid'],$contact_record['id']);
-               
-               // technically they are sharing with us (CONTACT_IS_SHARING), 
+
+               // 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.
 
@@ -622,7 +732,7 @@ function diaspora_request($importer,$xml) {
                        `avatar-date` = '%s', 
                        `blocked` = 0, 
                        `pending` = 0
-                       WHERE `id` = %d LIMIT 1
+                       WHERE `id` = %d
                        ",
                        dbesc($photos[0]),
                        dbesc($photos[1]),
@@ -643,7 +753,21 @@ function diaspora_request($importer,$xml) {
 }
 
 function diaspora_post_allow($importer,$contact) {
-       if(($contact['blocked']) || ($contact['readonly']))
+
+       // 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) {
+               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;
@@ -654,12 +778,17 @@ function diaspora_post_allow($importer,$contact) {
 }
 
 
-function diaspora_post($importer,$xml) {
+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)
                return;
@@ -697,6 +826,9 @@ function diaspora_post($importer,$xml) {
 
        $body = diaspora2bb($xml->raw_message);
 
+       // Add OEmbed and other information to the body
+       $body = add_page_info_to_body($body, false, true);
+
        $datarray = array();
 
        $str_tags = '';
@@ -731,21 +863,27 @@ function diaspora_post($importer,$xml) {
                foreach($matches as $mtch) {
                        if(strlen($str_tags))
                                $str_tags .= ',';
-                       $str_tags .= '@[url=' . $mtch[1] . '[/url]';    
+                       $str_tags .= '@[url=' . $mtch[1] . '[/url]';
                }
        }
 
+       $plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$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['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
+       $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'] = $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'];
@@ -759,18 +897,18 @@ function diaspora_post($importer,$xml) {
 
        $message_id = item_store($datarray);
 
-       if($message_id) {
-               q("update item set plink = '%s' where id = %d limit 1",
-                       dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
-                       intval($message_id)
-               );
-       }
+       //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_reshare($importer,$xml) {
+function diaspora_reshare($importer,$xml,$msg) {
 
        logger('diaspora_reshare: init: ' . print_r($xml,true));
 
@@ -779,6 +917,11 @@ function diaspora_reshare($importer,$xml) {
        $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;
@@ -803,6 +946,7 @@ function diaspora_reshare($importer,$xml) {
        $orig_guid = notags(unxmlify($xml->root_guid));
 
        $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml';
+       $orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid;
        $x = fetch_url($source_url);
        if(! $x)
                $x = fetch_url(str_replace('https://','http://',$source_url));
@@ -825,26 +969,44 @@ function diaspora_reshare($importer,$xml) {
        }
        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) {
+
+                       $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('diaspora_reshare: embedded picture link found: '.$body, LOGGER_DEBUG);
+               }
+
                $body = scale_external_images($body);
 
+               // Add OEmbed and other information to the body
+               $body = add_page_info_to_body($body, false, true);
        }
        else {
+               // Maybe it is a reshare of a photo that will be delivered at a later time (testing)
                logger('diaspora_reshare: no reshare content found: ' . print_r($source_xml,true));
-               return;
-       }
-       if(! $body) {
-               logger('diaspora_reshare: empty body: source= ' . $x);
-               return;
+               $body = "";
+               //return;
        }
 
+       //if(! $body) {
+       //      logger('diaspora_reshare: empty body: source= ' . $x);
+       //      return;
+       //}
+
        $person = find_diaspora_person_by_handle($orig_author);
 
-       if(is_array($person) && x($person,'name') && x($person,'url'))
+       /*if(is_array($person) && x($person,'name') && x($person,'url'))
                $details = '[url=' . $person['url'] . ']' . $person['name'] . '[/url]';
        else
                $details = $orig_author;
-       
-       $prefix = '&#x2672; ' . $details . "\n"; 
+
+       $prefix = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . $details . "\n";*/
 
 
        // allocate a guid on our system - we aren't fixing any collisions.
@@ -891,46 +1053,71 @@ function diaspora_reshare($importer,$xml) {
                        }
                }
        }
-       
+
+       $plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$guid;
+
        $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['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
+       $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['author-name'] = $contact['name'];
-       $datarray['author-link'] = $contact['url'];
-       $datarray['author-avatar'] = $contact['thumb'];
-       $datarray['body'] = $prefix . $body;
+       $datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']);
+       if (!intval(get_config('system','wall-to-wall_share'))) {
+               $prefix = "[share author='".str_replace(array("'", "[", "]"), array("&#x27;", "&#x5B;", "&#x5D;"),$person['name']).
+                               "' profile='".$person['url'].
+                               "' avatar='".((x($person,'thumb')) ? $person['thumb'] : $person['photo']).
+                               "' link='".str_replace(array("'", "[", "]"), array("&#x27;", "&#x5B;", "&#x5D;"),$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;
+       }
+
        $datarray['tag'] = $str_tags;
        $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. (testing)
+       $datarray['visible'] = ((strlen($body)) ? 1 : 0);
+
        $message_id = item_store($datarray);
 
-       if($message_id) {
-               q("update item set plink = '%s' where id = %d limit 1",
-                       dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
-                       intval($message_id)
-               );
-       }
+       //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_asphoto($importer,$xml) {
+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;
@@ -979,35 +1166,39 @@ function diaspora_asphoto($importer,$xml) {
                return;
        }
 
+       $plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$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['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
+       $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'] = $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['app']  = 'Diaspora/Cubbi.es';
 
        $message_id = item_store($datarray);
 
-       if($message_id) {
-               q("update item set plink = '%s' where id = %d limit 1",
-                       dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
-                       intval($message_id)
-               );
-       }
+       //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;
 
@@ -1110,7 +1301,7 @@ function diaspora_comment($importer,$xml,$msg) {
        if(strcasecmp($diaspora_handle,$msg['author']) == 0)
                $person = $contact;
        else {
-               $person = find_diaspora_person_by_handle($diaspora_handle);     
+               $person = find_diaspora_person_by_handle($diaspora_handle);
 
                if(! is_array($person)) {
                        logger('diaspora_comment: unable to find author details');
@@ -1119,7 +1310,6 @@ function diaspora_comment($importer,$xml,$msg) {
        }
 
        $body = diaspora2bb($text);
-
        $message_id = $diaspora_handle . ':' . $guid;
 
        $datarray = array();
@@ -1154,14 +1344,17 @@ function diaspora_comment($importer,$xml,$msg) {
 
        $datarray['uid'] = $importer['uid'];
        $datarray['contact-id'] = $contact['id'];
+       $datarray['type'] = 'remote-comment';
        $datarray['wall'] = $parent_item['wall'];
+       $datarray['network']  = NETWORK_DIASPORA;
+       $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['created'] = $datarray['edited'] = datetime_convert();
+       $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert();
        $datarray['private'] = $parent_item['private'];
 
        $datarray['owner-name'] = $parent_item['owner-name'];
@@ -1175,22 +1368,23 @@ function diaspora_comment($importer,$xml,$msg) {
        $datarray['tag'] = $str_tags;
 
        // We can't be certain what the original app is if the message is relayed.
-       if(($parent_item['origin']) && (! $parent_author_signature)) 
+       if(($parent_item['origin']) && (! $parent_author_signature))
                $datarray['app']  = 'Diaspora';
 
        $message_id = item_store($datarray);
 
-       if($message_id) {
-               q("update item set plink = '%s' where id = %d limit 1",
-                       dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
-                       intval($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(($parent_item['origin']) && (! $parent_author_signature)) {
                q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
                        intval($message_id),
-                       dbesc($author_signed_data),
+                       dbesc($signed_data),
                        dbesc(base64_encode($author_signature)),
                        dbesc($diaspora_handle)
                );
@@ -1199,7 +1393,7 @@ function diaspora_comment($importer,$xml,$msg) {
                // the existence of parent_author_signature means the parent_author or owner
                // is already relaying.
 
-               proc_run('php','include/notifier.php','comment',$message_id);
+               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 ",
@@ -1213,12 +1407,12 @@ function diaspora_comment($importer,$xml,$msg) {
                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(
@@ -1229,14 +1423,14 @@ function diaspora_comment($importer,$xml,$msg) {
                                'to_email'     => $importer['email'],
                                'uid'          => $importer['uid'],
                                'item'         => $datarray,
-                               'link'             => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id,
+                               '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
@@ -1390,15 +1584,15 @@ function diaspora_conversation($importer,$xml,$msg) {
                        dbesc($message_id),
                        dbesc($parent_uri),
                        dbesc($msg_created_at)
-               );                      
+               );
 
-               q("update conv set updated = '%s' where id = %d limit 1",
+               q("update conv set updated = '%s' where id = %d",
                        dbesc(datetime_convert()),
                        intval($conversation['id'])
-               );              
+               );
 
                require_once('include/enotify.php');
-               notification(array(                     
+               notification(array(
                        'type' => NOTIFY_MAIL,
                        'notify_flags' => $importer['notify-flags'],
                        'language' => $importer['language'],
@@ -1412,7 +1606,7 @@ function diaspora_conversation($importer,$xml,$msg) {
                        'verb' => ACTIVITY_POST,
                        'otype' => 'mail'
                ));
-       }       
+       }
 
        return;
 }
@@ -1457,7 +1651,7 @@ function diaspora_message($importer,$xml,$msg) {
        }
 
        $reply = 0;
-                       
+
        $body = diaspora2bb($msg_text);
        $message_id = $msg_diaspora_handle . ':' . $msg_guid;
 
@@ -1503,18 +1697,18 @@ function diaspora_message($importer,$xml,$msg) {
                dbesc($message_id),
                dbesc($parent_uri),
                dbesc($msg_created_at)
-       );                      
+       );
 
-       q("update conv set updated = '%s' where id = %d limit 1",
+       q("update conv set updated = '%s' where id = %d",
                dbesc(datetime_convert()),
                intval($conversation['id'])
-       );              
-       
+       );
+
        return;
 }
 
 
-function diaspora_photo($importer,$xml,$msg) {
+function diaspora_photo($importer,$xml,$msg,$attempt=1) {
 
        $a = get_app();
 
@@ -1552,7 +1746,14 @@ function diaspora_photo($importer,$xml,$msg) {
                dbesc($status_message_guid)
        );
        if(! count($r)) {
-               logger('diaspora_photo: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid);
+               if($attempt <= 3) {
+                       q("INSERT INTO dsprphotoq (uid, msg, attempt) VALUES (%d, '%s', %d)",
+                          intval($importer['uid']),
+                          dbesc(serialize($msg)),
+                          intval($attempt + 1)
+                       );
+               }
+               logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid);
                return;
        }
 
@@ -1564,7 +1765,7 @@ function diaspora_photo($importer,$xml,$msg) {
                                           array($remote_photo_name, 'scaled_full_' . $remote_photo_name));
 
        if(strpos($parent_item['body'],$link_text) === false) {
-               $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d limit 1",
+               $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d",
                        dbesc($link_text . $parent_item['body']),
                        intval($parent_item['id']),
                        intval($parent_item['uid'])
@@ -1591,8 +1792,8 @@ function diaspora_like($importer,$xml,$msg) {
 
        // likes on comments not supported here and likes on photos not supported by Diaspora
 
-       if($target_type !== 'Post')
-               return;
+//     if($target_type !== 'Post')
+//             return;
 
        $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
        if(! $contact) {
@@ -1624,12 +1825,12 @@ function diaspora_like($importer,$xml,$msg) {
                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 LIMIT 1",
+/*                     q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d",
                                intval($r[0]['id']),
                                intval($importer['uid'])
                        );*/
@@ -1670,8 +1871,12 @@ function diaspora_like($importer,$xml,$msg) {
                $parent_author_signature = base64_decode($parent_author_signature);
 
                if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
-                       logger('diaspora_like: top-level owner verification failed.');
-                       return;
+                       if (intval(get_config('system','ignore_diaspora_like_signature')))
+                               logger('diaspora_like: top-level owner verification failed. Proceeding anyway.');
+                       else {
+                               logger('diaspora_like: top-level owner verification failed.');
+                               return;
+                       }
                }
        }
        else {
@@ -1683,8 +1888,12 @@ function diaspora_like($importer,$xml,$msg) {
                $author_signature = base64_decode($author_signature);
 
                if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) {
-                       logger('diaspora_like: like creator verification failed.');
-                       return;
+                       if (intval(get_config('system','ignore_diaspora_like_signature')))
+                               logger('diaspora_like: like creator verification failed. Proceeding anyway');
+                       else {
+                               logger('diaspora_like: like creator verification failed.');
+                               return;
+                       }
                }
        }
 
@@ -1730,6 +1939,7 @@ EOT;
        $arr['uri'] = $uri;
        $arr['uid'] = $importer['uid'];
        $arr['guid'] = $guid;
+       $arr['network']  = NETWORK_DIASPORA;
        $arr['contact-id'] = $contact['id'];
        $arr['type'] = 'activity';
        $arr['wall'] = $parent_item['wall'];
@@ -1739,15 +1949,17 @@ EOT;
 
        $arr['owner-name'] = $parent_item['name'];
        $arr['owner-link'] = $parent_item['url'];
-       $arr['owner-avatar'] = $parent_item['thumb'];
+       //$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/' . $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';
@@ -1763,17 +1975,18 @@ EOT;
        $message_id = item_store($arr);
 
 
-       if($message_id) {
-               q("update item set plink = '%s' where id = %d limit 1",
-                       dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
-                       intval($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/'.$guid),
+       //              intval($message_id)
+       //      );
+       //}
 
        if(! $parent_author_signature) {
                q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
                        intval($message_id),
-                       dbesc($author_signed_data),
+                       dbesc($signed_data),
                        dbesc(base64_encode($author_signature)),
                        dbesc($diaspora_handle)
                );
@@ -1784,7 +1997,7 @@ EOT;
        // is already relaying. The parent_item['origin'] indicates the message was created on our system
 
        if(($parent_item['origin']) && (! $parent_author_signature))
-               proc_run('php','include/notifier.php','comment',$message_id);
+               proc_run('php','include/notifier.php','comment-import',$message_id);
 
        return;
 }
@@ -1811,8 +2024,8 @@ function diaspora_retraction($importer,$xml) {
                );
                if(count($r)) {
                        if(link_compare($r[0]['author-link'],$contact['url'])) {
-                               q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d limit 1",
-                                       dbesc(datetime_convert()),                      
+                               q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d",
+                                       dbesc(datetime_convert()),
                                        intval($r[0]['id'])
                                );
                        }
@@ -1835,7 +2048,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
 
        $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle);
        if(! $contact) {
-               logger('diaspora_signed_retraction: no contact');
+               logger('diaspora_signed_retraction: no contact ' . $diaspora_handle . ' for ' . $importer['uid']);
                return;
        }
 
@@ -1882,12 +2095,12 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
                );
                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 limit 1",
-                                       dbesc(datetime_convert()),                      
-                                       dbesc(datetime_convert()),                      
+                               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'])
                                );
-       
+
                                // 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
@@ -1910,7 +2123,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
                                                // is already relaying.
                                                logger('diaspora_signed_retraction: relaying relayable_retraction');
 
-                                               proc_run('php','include/notifier.php','relayable_retraction',$r[0]['id']);
+                                               proc_run('php','include/notifier.php','drop',$r[0]['id']);
                                        }
                                }
                        }
@@ -1923,11 +2136,17 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
        // NOTREACHED
 }
 
-function diaspora_profile($importer,$xml) {
+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;
@@ -1941,11 +2160,22 @@ function diaspora_profile($importer,$xml) {
        $image_url = unxmlify($xml->image_url);
        $birthday = unxmlify($xml->birthday);
 
-       $r = q("SELECT DISTINCT ( `resource-id` ) FROM `photo` WHERE  `uid` = %d AND `contact-id` = %d AND `album` = 'Contact Photos' ",
+
+       $handle_parts = explode("@", $diaspora_handle);
+       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);
+       $oldphotos = ((count($r)) ? $r : null);*/
 
        require_once('include/Photo.php');
 
@@ -1966,7 +2196,7 @@ function diaspora_profile($importer,$xml) {
        // 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' WHERE `id` = %d AND `uid` = %d LIMIT 1",
+       $r = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' , `bd` = '%s' WHERE `id` = %d AND `uid` = %d",
                dbesc($name),
                dbesc(datetime_convert()),
                dbesc($images[0]),
@@ -1978,7 +2208,7 @@ function diaspora_profile($importer,$xml) {
                intval($importer['uid'])
        ); 
 
-       if($r) {
+/*     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' ",
@@ -1988,7 +2218,7 @@ function diaspora_profile($importer,$xml) {
                                );
                        }
                }
-       }       
+       }       */
 
        return;
 
@@ -2031,7 +2261,6 @@ function diaspora_unshare($me,$contact) {
 }
 
 
-
 function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
 
        $a = get_app();
@@ -2065,8 +2294,6 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
                }
        }
 */
-       // Removal of tags
-       $body = preg_replace('/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $body);
 
        //if(strlen($title))
        //      $body = "[b]".html_entity_decode($title)."[/b]\n\n".$body;
@@ -2087,7 +2314,7 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
                                $body .= '[' . $mtch[3] . '](' . $mtch[1] . ')' . "\n";
                        }
                }
-       }       
+       }
 
 
        $public = (($item['private']) ? 'false' : 'true');
@@ -2095,22 +2322,40 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
        require_once('include/datetime.php');
        $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C');
 
-       $tpl = get_markup_template('diaspora_post.tpl');
-       $msg = replace_macros($tpl, array(
-               '$body' => $body,
-               '$guid' => $item['guid'],
-               '$handle' => xmlify($myaddr),
-               '$public' => $public,
-               '$created' => $created
-       ));
+       // 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('diaspora_send_status: '.$owner['username'].' -> '.$contact['name'].' base message: '.$msg, LOGGER_DATA);
 
        $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);
 
+       logger('diaspora_send_status: guid: '.$item['guid'].' result '.$return_code, LOGGER_DEBUG);
+
        if(count($images)) {
                diaspora_send_images($item,$owner,$contact,$images,$public_batch);
        }
@@ -2118,6 +2363,53 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
        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);
+
+        $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();
@@ -2139,7 +2431,7 @@ function diaspora_send_images($item,$owner,$contact,$images,$public_batch = fals
                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(               
+               $msg = replace_macros($tpl,array(
                        '$path' => xmlify($image['path']),
                        '$filename' => xmlify($image['file']),
                        '$msg_guid' => xmlify($image['guid']),
@@ -2165,22 +2457,33 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
        $myaddr = $owner['nickname'] . '@' .  substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
 //     $theiraddr = $contact['addr'];
 
-       // 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 from item where parent = %d and id = %d limit 1",
-               intval($item['parent']),
-               intval($item['parent'])
-       );
+       // 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_guid = $p[0]['guid'];
+               $parent = $p[0];
        else
                return;
 
        if($item['verb'] === ACTIVITY_LIKE) {
                $tpl = get_markup_template('diaspora_like.tpl');
                $like = true;
-               $target_type = 'Post';
+               $target_type = ( $parent['uri'] === $parent['parent-uri']  ? 'Post' : 'Comment');
+//             $target_type = (strpos($parent['type'], 'comment') ? 'Comment' : 'Post');
 //             $positive = (($item['deleted']) ? 'false' : 'true');
                $positive = 'true';
 
@@ -2197,15 +2500,15 @@ 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 = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $myaddr;
        else
-               $signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $myaddr;
+               $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),
+               '$parent_guid' => xmlify($parent['guid']),
                '$target_type' =>xmlify($target_type),
                '$authorsig' => xmlify($authorsig),
                '$body' => xmlify($text),
@@ -2232,16 +2535,25 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
        $body = $item['body'];
        $text = html_entity_decode(bb2diaspora($body));
 
-
-       // 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 from item where parent = %d and id = %d limit 1",
-               intval($item['parent']),
-               intval($item['parent'])
-       );
+       // 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_guid = $p[0]['guid'];
+               $parent = $p[0];
        else
                return;
 
@@ -2259,7 +2571,7 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
        elseif($item['verb'] === ACTIVITY_LIKE) {
                $like = true;
 
-               $target_type = 'Post';
+               $target_type = ( $parent['uri'] === $parent['parent-uri']  ? 'Post' : 'Comment');
 //             $positive = (($item['deleted']) ? 'false' : 'true');
                $positive = 'true';
 
@@ -2273,7 +2585,7 @@ 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 * from sign where " . $sql_sign_id . " = %d limit 1",
                intval($item['id'])
        );
        if(count($r)) { 
@@ -2289,14 +2601,32 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
                // 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;
+
 
        if($relay_retract)
                $sender_signed_text = $item['guid'] . ';' . $target_type;
        elseif($like)
-               $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $handle;
+               $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $handle;
        else
-               $sender_signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $handle;
+               $sender_signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $handle;
 
        // Sign the relayable with the top-level owner's signature
        //
@@ -2313,7 +2643,7 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
 
        $msg = replace_macros($tpl,array(
                '$guid' => xmlify($item['guid']),
-               '$parent_guid' => xmlify($parent_guid),
+               '$parent_guid' => xmlify($parent['guid']),
                '$target_type' =>xmlify($target_type),
                '$authorsig' => xmlify($authorsig),
                '$parentsig' => xmlify($parentauthorsig),
@@ -2429,7 +2759,7 @@ function diaspora_send_mail($item,$owner,$contact) {
 
 }
 
-function diaspora_transmit($owner,$contact,$slap,$public_batch) {
+function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false) {
 
        $enabled = intval(get_config('system','diaspora_enabled'));
        if(! $enabled) {
@@ -2446,20 +2776,19 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch) {
 
        logger('diaspora_transmit: ' . $logid . ' ' . $dest_url);
 
-       if(was_recently_delayed($contact['id'])) {
+       if( (! $queue_run) && (was_recently_delayed($contact['id'])) ) {
                $return_code = 0;
        }
        else {
-               if(! intval(get_config('system','diaspora_test'))) {
+               if (!intval(get_config('system','diaspora_test'))) {
                        post_url($dest_url . '/', $slap);
                        $return_code = $a->get_curl_code();
-               }
-               else {
+               } else {
                        logger('diaspora_transmit: test_mode');
                        return 200;
                }
        }
-       
+
        logger('diaspora_transmit: ' . $logid . ' returns: ' . $return_code);
 
        if((! $return_code) || (($return_code == 503) && (stristr($a->get_curl_headers(),'retry-after')))) {