2011-08-09 06:44:29 +02:00
< ? php
2015-12-25 23:17:34 +01:00
/**
* @ file include / diaspora . php
2016-03-14 23:11:43 +01:00
* @ brief The implementation of the diaspora protocol
2016-07-14 07:20:20 +02:00
*
* The new protocol is described here : http :// diaspora . github . io / diaspora_federation / index . html
* Currently this implementation here interprets the old and the new protocol and sends the old one .
* This will change in the future .
2015-12-25 23:17:34 +01:00
*/
2015-07-11 14:37:02 +02:00
2016-03-14 23:11:43 +01:00
require_once ( " include/items.php " );
require_once ( " include/bb2diaspora.php " );
require_once ( " include/Scrape.php " );
require_once ( " include/Contact.php " );
require_once ( " include/Photo.php " );
require_once ( " include/socgraph.php " );
require_once ( " include/group.php " );
require_once ( " include/xml.php " );
require_once ( " include/datetime.php " );
2016-03-16 16:49:54 +01:00
require_once ( " include/queue_fn.php " );
2011-09-15 04:33:42 +02:00
2016-03-14 23:11:43 +01:00
/**
* @ brief This class contain functions to create and send Diaspora XML files
*
*/
class diaspora {
2011-09-15 04:33:42 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Return a list of relay servers
*
* This is an experimental Diaspora feature .
*
* @ return array of relay servers
*/
2016-03-14 23:11:43 +01:00
public static function relay_list () {
2016-02-27 23:54:17 +01:00
2016-03-14 23:11:43 +01:00
$serverdata = get_config ( " system " , " relay_server " );
if ( $serverdata == " " )
return array ();
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$relay = array ();
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$servers = explode ( " , " , $serverdata );
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
foreach ( $servers AS $server ) {
$server = trim ( $server );
$batch = $server . " /receive/public " ;
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
$relais = q ( " SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1 " , dbesc ( $batch ));
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
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 ())
);
2011-12-01 02:08:16 +01:00
2016-03-14 23:11:43 +01:00
$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 ];
}
2011-12-01 02:08:16 +01:00
2016-03-14 23:11:43 +01:00
return $relay ;
2011-08-24 10:21:24 +02:00
}
2012-08-10 06:06:18 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief repairs a signature that was double encoded
*
2016-03-18 22:28:20 +01:00
* The function is unused at the moment . It was copied from the old implementation .
*
2016-03-17 23:44:18 +01:00
* @ param string $signature The signature
* @ param string $handle The handle of the signature owner
* @ param integer $level This value is only set inside this function to avoid endless loops
*
2016-03-21 19:58:45 +01:00
* @ return string the repaired signature
2016-03-17 23:44:18 +01:00
*/
2016-03-27 23:25:32 +02:00
private function repair_signature ( $signature , $handle = " " , $level = 1 ) {
2012-08-10 06:06:18 +02:00
2016-03-14 23:11:43 +01:00
if ( $signature == " " )
return ( $signature );
2012-08-10 06:06:18 +02:00
2016-03-14 23:11:43 +01:00
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 );
2012-08-10 06:06:18 +02:00
2016-03-14 23:11:43 +01:00
// Do a recursive call to be able to fix even multiple levels
if ( $level < 10 )
$signature = self :: repair_signature ( $signature , $handle , ++ $level );
2012-08-10 06:06:18 +02:00
}
2016-03-14 23:11:43 +01:00
return ( $signature );
2012-08-10 06:06:18 +02:00
}
2016-06-30 22:18:48 +02:00
/**
* @ brief verify the envelope and return the verified data
*
* @ param string $envelope The magic envelope
*
* @ return string verified data
*/
private function verify_magic_envelope ( $envelope ) {
$basedom = parse_xml_string ( $envelope , false );
if ( ! is_object ( $basedom )) {
logger ( " Envelope is no XML file " );
return false ;
}
$children = $basedom -> children ( 'http://salmon-protocol.org/ns/magic-env' );
if ( sizeof ( $children ) == 0 ) {
logger ( " XML has no children " );
return false ;
}
$handle = " " ;
$data = base64url_decode ( $children -> data );
$type = $children -> data -> attributes () -> type [ 0 ];
$encoding = $children -> encoding ;
$alg = $children -> alg ;
$sig = base64url_decode ( $children -> sig );
$key_id = $children -> sig -> attributes () -> key_id [ 0 ];
if ( $key_id != " " )
$handle = base64url_decode ( $key_id );
$b64url_data = base64url_encode ( $data );
$msg = str_replace ( array ( " \n " , " \r " , " " , " \t " ), array ( " " , " " , " " , " " ), $b64url_data );
$signable_data = $msg . " . " . base64url_encode ( $type ) . " . " . base64url_encode ( $encoding ) . " . " . base64url_encode ( $alg );
$key = self :: key ( $handle );
$verify = rsa_verify ( $signable_data , $sig , $key );
if ( ! $verify ) {
logger ( 'Message did not verify. Discarding.' );
return false ;
}
return $data ;
}
2016-03-14 23:11:43 +01:00
/**
* @ brief : Decodes incoming Diaspora message
*
2016-03-17 23:44:18 +01:00
* @ param array $importer Array of the importer user
2016-03-14 23:11:43 +01:00
* @ param string $xml urldecoded Diaspora salmon
*
* @ return array
* 'message' -> decoded Diaspora XML message
* 'author' -> author diaspora handle
* 'key' -> author public key ( converted to pkcs #8)
*/
2016-03-27 23:25:32 +02:00
public static function decode ( $importer , $xml ) {
2012-08-10 06:06:18 +02:00
2016-03-14 23:11:43 +01:00
$public = false ;
$basedom = parse_xml_string ( $xml );
2011-08-23 04:27:40 +02:00
2016-03-14 23:11:43 +01:00
if ( ! is_object ( $basedom ))
return false ;
2012-06-15 04:58:25 +02:00
2016-03-14 23:11:43 +01:00
$children = $basedom -> children ( 'https://joindiaspora.com/protocol' );
2012-06-15 04:58:25 +02:00
2016-03-14 23:11:43 +01:00
if ( $children -> header ) {
$public = true ;
$author_link = str_replace ( 'acct:' , '' , $children -> header -> author_id );
} else {
2012-07-06 03:01:13 +02:00
2016-03-14 23:11:43 +01:00
$encrypted_header = json_decode ( base64_decode ( $children -> encrypted_header ));
2012-06-15 04:58:25 +02:00
2016-03-14 23:11:43 +01:00
$encrypted_aes_key_bundle = base64_decode ( $encrypted_header -> aes_key );
$ciphertext = base64_decode ( $encrypted_header -> ciphertext );
2012-06-15 04:58:25 +02:00
2016-03-14 23:11:43 +01:00
$outer_key_bundle = '' ;
openssl_private_decrypt ( $encrypted_aes_key_bundle , $outer_key_bundle , $importer [ 'prvkey' ]);
2012-06-15 04:58:25 +02:00
2016-03-14 23:11:43 +01:00
$j_outer_key_bundle = json_decode ( $outer_key_bundle );
2012-06-15 04:58:25 +02:00
2016-03-14 23:11:43 +01:00
$outer_iv = base64_decode ( $j_outer_key_bundle -> iv );
$outer_key = base64_decode ( $j_outer_key_bundle -> key );
2011-08-23 04:27:40 +02:00
2016-03-14 23:11:43 +01:00
$decrypted = mcrypt_decrypt ( MCRYPT_RIJNDAEL_128 , $outer_key , $ciphertext , MCRYPT_MODE_CBC , $outer_iv );
2011-08-23 04:27:40 +02:00
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$decrypted = pkcs5_unpad ( $decrypted );
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
logger ( 'decrypted: ' . $decrypted , LOGGER_DEBUG );
$idom = parse_xml_string ( $decrypted , false );
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
$inner_iv = base64_decode ( $idom -> iv );
$inner_aes_key = base64_decode ( $idom -> aes_key );
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
$author_link = str_replace ( 'acct:' , '' , $idom -> author_id );
}
2014-04-22 00:58:17 +02:00
2016-03-14 23:11:43 +01:00
$dom = $basedom -> children ( NAMESPACE_SALMON_ME );
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
// figure out where in the DOM tree our data is hiding
2011-09-22 13:11:39 +02:00
2016-03-14 23:11:43 +01:00
if ( $dom -> provenance -> data )
$base = $dom -> provenance ;
elseif ( $dom -> env -> data )
$base = $dom -> env ;
elseif ( $dom -> data )
$base = $dom ;
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $base ) {
logger ( 'unable to locate salmon data in xml' );
http_status_exit ( 400 );
}
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
// Stash the signature away for now. We have to find their key or it won't be good for anything.
$signature = base64url_decode ( $base -> sig );
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
// unpack the data
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
// strip whitespace so our data element will return to one big base64 blob
$data = str_replace ( array ( " " , " \t " , " \r " , " \n " ), array ( " " , " " , " " , " " ), $base -> data );
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
// stash away some other stuff for later
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
$type = $base -> data [ 0 ] -> attributes () -> type [ 0 ];
$keyhash = $base -> sig [ 0 ] -> attributes () -> keyhash [ 0 ];
$encoding = $base -> encoding ;
$alg = $base -> alg ;
2011-09-19 05:17:44 +02:00
2016-03-14 23:11:43 +01:00
$signed_data = $data . '.' . base64url_encode ( $type ) . '.' . base64url_encode ( $encoding ) . '.' . base64url_encode ( $alg );
2011-09-19 05:17:44 +02:00
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
// decode the data
$data = base64url_decode ( $data );
2011-09-22 13:11:39 +02:00
2011-08-19 13:48:54 +02:00
2016-03-14 23:11:43 +01:00
if ( $public )
$inner_decrypted = $data ;
else {
2011-12-20 01:51:57 +01:00
2016-03-14 23:11:43 +01:00
// Decode the encrypted blob
2011-12-20 01:51:57 +01:00
2016-03-14 23:11:43 +01:00
$inner_encrypted = base64_decode ( $data );
$inner_decrypted = mcrypt_decrypt ( MCRYPT_RIJNDAEL_128 , $inner_aes_key , $inner_encrypted , MCRYPT_MODE_CBC , $inner_iv );
$inner_decrypted = pkcs5_unpad ( $inner_decrypted );
}
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $author_link ) {
logger ( 'Could not retrieve author URI.' );
http_status_exit ( 400 );
}
// Once we have the author URI, go to the web and try to find their public key
// (first this will look it up locally if it is in the fcontact cache)
// This will also convert diaspora public key from pkcs#1 to pkcs#8
2014-05-03 23:40:34 +02:00
2016-03-14 23:11:43 +01:00
logger ( 'Fetching key for ' . $author_link );
$key = self :: key ( $author_link );
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $key ) {
logger ( 'Could not retrieve author key.' );
http_status_exit ( 400 );
}
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
$verify = rsa_verify ( $signed_data , $signature , $key );
2011-08-09 15:40:28 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $verify ) {
logger ( 'Message did not verify. Discarding.' );
http_status_exit ( 400 );
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
logger ( 'Message verified.' );
2011-09-15 04:33:42 +02:00
2016-03-15 20:14:08 +01:00
return array ( 'message' => ( string ) $inner_decrypted ,
'author' => unxmlify ( $author_link ),
'key' => ( string ) $key );
2016-03-14 23:11:43 +01:00
}
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
/**
* @ brief Dispatches public messages and find the fitting receivers
*
* @ param array $msg The post that will be dispatched
*
2016-03-28 22:35:11 +02:00
* @ return int The message id of the generated message , " true " or " false " if there was an error
2016-03-14 23:11:43 +01:00
*/
public static function dispatch_public ( $msg ) {
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
$enabled = intval ( get_config ( " system " , " diaspora_enabled " ));
if ( ! $enabled ) {
logger ( " diaspora is disabled " );
return false ;
}
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
// Use a dummy importer to import the data for the public copy
$importer = array ( " uid " => 0 , " page-flags " => PAGE_FREELOVE );
2016-03-28 22:35:11 +02:00
$message_id = self :: dispatch ( $importer , $msg );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
// Now distribute it to the followers
$r = q ( " SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
( SELECT `contact` . `uid` FROM `contact` WHERE `contact` . `network` = '%s' AND `contact` . `addr` = '%s' )
AND NOT `account_expired` AND NOT `account_removed` " ,
dbesc ( NETWORK_DIASPORA ),
dbesc ( $msg [ " author " ])
);
2016-12-20 21:13:50 +01:00
if ( $r ) {
foreach ( $r as $rr ) {
2016-03-14 23:11:43 +01:00
logger ( " delivering to: " . $rr [ " username " ]);
self :: dispatch ( $rr , $msg );
}
} else
logger ( " No subscribers for " . $msg [ " author " ] . " " . print_r ( $msg , true ));
2011-08-22 13:55:09 +02:00
2016-03-28 22:35:11 +02:00
return $message_id ;
2016-03-14 23:11:43 +01:00
}
2011-08-22 13:55:09 +02:00
2016-03-14 23:11:43 +01:00
/**
* @ brief Dispatches the different message types to the different functions
*
* @ param array $importer Array of the importer user
* @ param array $msg The post that will be dispatched
*
2016-03-28 22:35:11 +02:00
* @ return int The message id of the generated message , " true " or " false " if there was an error
2016-03-14 23:11:43 +01:00
*/
public static function dispatch ( $importer , $msg ) {
2011-08-22 13:55:09 +02:00
2016-03-14 23:11:43 +01:00
// The sender is the handle of the contact that sent the message.
// This will often be different with relayed messages (for example "like" and "comment")
$sender = $msg [ " author " ];
2011-08-22 13:55:09 +02:00
2016-03-14 23:11:43 +01:00
if ( ! diaspora :: valid_posting ( $msg , $fields )) {
logger ( " Invalid posting " );
return false ;
}
2011-08-22 02:24:50 +02:00
2016-03-14 23:11:43 +01:00
$type = $fields -> getName ();
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
logger ( " Received message type " . $type . " from " . $sender . " for user " . $importer [ " uid " ], LOGGER_DEBUG );
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
switch ( $type ) {
case " account_deletion " :
return self :: receive_account_deletion ( $importer , $fields );
2011-08-09 06:44:29 +02:00
2016-03-14 23:11:43 +01:00
case " comment " :
2016-03-14 23:54:01 +01:00
return self :: receive_comment ( $importer , $sender , $fields , $msg [ " message " ]);
2011-08-09 11:53:51 +02:00
2016-03-25 00:49:18 +01:00
case " contact " :
return self :: receive_contact_request ( $importer , $fields );
2016-03-14 23:11:43 +01:00
case " conversation " :
return self :: receive_conversation ( $importer , $msg , $fields );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
case " like " :
return self :: receive_like ( $importer , $sender , $fields );
2011-08-15 14:27:24 +02:00
2016-03-14 23:11:43 +01:00
case " message " :
return self :: receive_message ( $importer , $fields );
2011-08-15 14:27:24 +02:00
2016-03-14 23:11:43 +01:00
case " participation " : // Not implemented
return self :: receive_participation ( $importer , $fields );
2016-03-13 16:14:51 +01:00
2016-03-14 23:11:43 +01:00
case " photo " : // Not implemented
return self :: receive_photo ( $importer , $fields );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
case " poll_participation " : // Not implemented
return self :: receive_poll_participation ( $importer , $fields );
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
case " profile " :
return self :: receive_profile ( $importer , $fields );
2014-05-03 23:40:34 +02:00
2016-03-14 23:11:43 +01:00
case " reshare " :
2016-03-15 00:26:28 +01:00
return self :: receive_reshare ( $importer , $fields , $msg [ " message " ]);
2011-09-15 04:33:42 +02:00
2016-03-14 23:11:43 +01:00
case " retraction " :
return self :: receive_retraction ( $importer , $sender , $fields );
2011-09-15 04:33:42 +02:00
2016-03-14 23:11:43 +01:00
case " status_message " :
2016-03-14 23:54:01 +01:00
return self :: receive_status_message ( $importer , $fields , $msg [ " message " ]);
2011-09-15 04:33:42 +02:00
2016-03-14 23:11:43 +01:00
default :
logger ( " Unknown message type " . $type );
return false ;
}
2011-09-15 04:33:42 +02:00
2016-03-14 23:11:43 +01:00
return true ;
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
/**
* @ brief Checks if a posting is valid and fetches the data fields .
*
* This function does not only check the signature .
* It also does the conversion between the old and the new diaspora format .
*
* @ param array $msg Array with the XML , the sender handle and the sender signature
* @ param object $fields SimpleXML object that contains the posting when it is valid
*
* @ return bool Is the posting valid ?
*/
private function valid_posting ( $msg , & $fields ) {
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$data = parse_xml_string ( $msg [ " message " ], false );
2011-08-15 15:27:17 +02:00
2016-06-29 10:33:43 +02:00
if ( ! is_object ( $data )) {
logger ( " No valid XML " . $msg [ " message " ], LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return false ;
2016-06-29 10:33:43 +02:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$first_child = $data -> getName ();
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
// Is this the new or the old version?
if ( $data -> getName () == " XML " ) {
$oldXML = true ;
foreach ( $data -> post -> children () as $child )
$element = $child ;
} else {
$oldXML = false ;
$element = $data ;
}
2011-08-20 13:53:11 +02:00
2016-03-14 23:11:43 +01:00
$type = $element -> getName ();
$orig_type = $type ;
2011-08-09 11:53:51 +02:00
2016-07-10 12:09:58 +02:00
logger ( " Got message type " . $type . " : " . $msg [ " message " ], LOGGER_DATA );
2016-03-14 23:11:43 +01:00
// All retractions are handled identically from now on.
// In the new version there will only be "retraction".
if ( in_array ( $type , array ( " signed_retraction " , " relayable_retraction " )))
$type = " retraction " ;
2011-08-09 11:53:51 +02:00
2016-03-25 00:49:18 +01:00
if ( $type == " request " )
$type = " contact " ;
2016-03-14 23:11:43 +01:00
$fields = new SimpleXMLElement ( " < " . $type . " /> " );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$signed_data = " " ;
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
foreach ( $element -> children () AS $fieldname => $entry ) {
if ( $oldXML ) {
// Translation for the old XML structure
if ( $fieldname == " diaspora_handle " )
$fieldname = " author " ;
2011-09-15 04:33:42 +02:00
2016-03-14 23:11:43 +01:00
if ( $fieldname == " participant_handles " )
$fieldname = " participants " ;
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( in_array ( $type , array ( " like " , " participation " ))) {
if ( $fieldname == " target_type " )
$fieldname = " parent_type " ;
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( $fieldname == " sender_handle " )
$fieldname = " author " ;
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( $fieldname == " recipient_handle " )
$fieldname = " recipient " ;
2014-04-04 10:52:53 +02:00
2016-03-14 23:11:43 +01:00
if ( $fieldname == " root_diaspora_id " )
$fieldname = " root_author " ;
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( $type == " retraction " ) {
if ( $fieldname == " post_guid " )
$fieldname = " target_guid " ;
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( $fieldname == " type " )
$fieldname = " target_type " ;
}
}
2011-08-09 11:53:51 +02:00
2016-06-29 10:33:43 +02:00
if (( $fieldname == " author_signature " ) AND ( $entry != " " ))
2016-03-14 23:11:43 +01:00
$author_signature = base64_decode ( $entry );
2016-06-29 10:33:43 +02:00
elseif (( $fieldname == " parent_author_signature " ) AND ( $entry != " " ))
2016-03-14 23:11:43 +01:00
$parent_author_signature = base64_decode ( $entry );
2016-06-29 20:37:04 +02:00
elseif ( ! in_array ( $fieldname , array ( " author_signature " , " parent_author_signature " , " target_author_signature " ))) {
2016-03-14 23:11:43 +01:00
if ( $signed_data != " " ) {
$signed_data .= " ; " ;
$signed_data_parent .= " ; " ;
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$signed_data .= $entry ;
}
if ( ! in_array ( $fieldname , array ( " parent_author_signature " , " target_author_signature " )) OR
( $orig_type == " relayable_retraction " ))
xml :: copy ( $entry , $fields , $fieldname );
}
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
// This is something that shouldn't happen at all.
if ( in_array ( $type , array ( " status_message " , " reshare " , " profile " )))
if ( $msg [ " author " ] != $fields -> author ) {
logger ( " Message handle is not the same as envelope sender. Quitting this message. " );
return false ;
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
// Only some message types have signatures. So we quit here for the other types.
if ( ! in_array ( $type , array ( " comment " , " message " , " like " )))
return true ;
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
// No author_signature? This is a must, so we quit.
2016-06-29 10:33:43 +02:00
if ( ! isset ( $author_signature )) {
2016-06-29 20:37:04 +02:00
logger ( " No author signature for type " . $type . " - Message: " . $msg [ " message " ], LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return false ;
2016-06-29 10:33:43 +02:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( isset ( $parent_author_signature )) {
$key = self :: key ( $msg [ " author " ]);
2011-08-17 13:24:26 +02:00
2016-06-29 10:33:43 +02:00
if ( ! rsa_verify ( $signed_data , $parent_author_signature , $key , " sha256 " )) {
logger ( " No valid parent author signature for author " . $msg [ " author " ] . " in type " . $type . " - signed data: " . $signed_data . " - Message: " . $msg [ " message " ] . " - Signature " . $parent_author_signature , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return false ;
2016-06-29 10:33:43 +02:00
}
2016-03-14 23:11:43 +01:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$key = self :: key ( $fields -> author );
2011-08-09 11:53:51 +02:00
2016-06-29 10:33:43 +02:00
if ( ! rsa_verify ( $signed_data , $author_signature , $key , " sha256 " )) {
logger ( " No valid author signature for author " . $msg [ " author " ] . " in type " . $type . " - signed data: " . $signed_data . " - Message: " . $msg [ " message " ] . " - Signature " . $author_signature , LOGGER_DEBUG );
return false ;
} else
return true ;
2016-03-14 23:11:43 +01:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
/**
* @ brief Fetches the public key for a given handle
*
* @ param string $handle The handle
*
* @ return string The public key
*/
private function key ( $handle ) {
$handle = strval ( $handle );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
logger ( " Fetching diaspora key for: " . $handle );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$r = self :: person_by_handle ( $handle );
if ( $r )
return $r [ " pubkey " ];
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
return " " ;
2011-09-15 04:33:42 +02:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
/**
* @ brief Fetches data for a given handle
*
* @ param string $handle The handle
*
* @ return array the queried data
*/
private function person_by_handle ( $handle ) {
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT * FROM `fcontact` WHERE `network` = '%s' AND `addr` = '%s' LIMIT 1 " ,
dbesc ( NETWORK_DIASPORA ),
dbesc ( $handle )
);
if ( $r ) {
$person = $r [ 0 ];
logger ( " In cache " . print_r ( $r , true ), LOGGER_DEBUG );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
// update record occasionally so it doesn't get stale
$d = strtotime ( $person [ " updated " ] . " +00:00 " );
if ( $d < strtotime ( " now - 14 days " ))
$update = true ;
2016-07-10 12:09:58 +02:00
if ( $person [ " guid " ] == " " )
$update = true ;
2016-03-14 23:11:43 +01:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $person OR $update ) {
logger ( " create or refresh " , LOGGER_DEBUG );
$r = probe_url ( $handle , PROBE_DIASPORA );
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
// Note that Friendica contacts will return a "Diaspora person"
// if Diaspora connectivity is enabled on their server
if ( $r AND ( $r [ " network " ] === NETWORK_DIASPORA )) {
self :: add_fcontact ( $r , $update );
$person = $r ;
}
}
return $person ;
}
/**
* @ brief Updates the fcontact table
*
* @ param array $arr The fcontact data
* @ param bool $update Update or insert ?
*
* @ return string The id of the fcontact entry
*/
private function add_fcontact ( $arr , $update = false ) {
if ( $update ) {
$r = q ( " UPDATE `fcontact` SET
`name` = '%s' ,
`photo` = '%s' ,
`request` = '%s' ,
`nick` = '%s' ,
`addr` = '%s' ,
2016-07-10 12:09:58 +02:00
`guid` = '%s' ,
2016-03-14 23:11:43 +01:00
`batch` = '%s' ,
`notify` = '%s' ,
`poll` = '%s' ,
`confirm` = '%s' ,
`alias` = '%s' ,
`pubkey` = '%s' ,
`updated` = '%s'
WHERE `url` = '%s' AND `network` = '%s' " ,
dbesc ( $arr [ " name " ]),
dbesc ( $arr [ " photo " ]),
dbesc ( $arr [ " request " ]),
dbesc ( $arr [ " nick " ]),
2016-08-23 07:48:48 +02:00
dbesc ( strtolower ( $arr [ " addr " ])),
2016-07-10 12:09:58 +02:00
dbesc ( $arr [ " guid " ]),
2016-03-14 23:11:43 +01:00
dbesc ( $arr [ " batch " ]),
dbesc ( $arr [ " notify " ]),
dbesc ( $arr [ " poll " ]),
dbesc ( $arr [ " confirm " ]),
dbesc ( $arr [ " alias " ]),
dbesc ( $arr [ " pubkey " ]),
dbesc ( datetime_convert ()),
dbesc ( $arr [ " url " ]),
dbesc ( $arr [ " network " ])
);
} else {
2016-07-10 12:09:58 +02:00
$r = q ( " INSERT INTO `fcontact` (`url`,`name`,`photo`,`request`,`nick`,`addr`, `guid`,
2016-03-14 23:11:43 +01:00
`batch` , `notify` , `poll` , `confirm` , `network` , `alias` , `pubkey` , `updated` )
2016-07-15 17:25:30 +02:00
VALUES ( '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' ) " ,
2016-03-14 23:11:43 +01:00
dbesc ( $arr [ " url " ]),
dbesc ( $arr [ " name " ]),
dbesc ( $arr [ " photo " ]),
dbesc ( $arr [ " request " ]),
dbesc ( $arr [ " nick " ]),
dbesc ( $arr [ " addr " ]),
2016-07-10 12:09:58 +02:00
dbesc ( $arr [ " guid " ]),
2016-03-14 23:11:43 +01:00
dbesc ( $arr [ " batch " ]),
dbesc ( $arr [ " notify " ]),
dbesc ( $arr [ " poll " ]),
dbesc ( $arr [ " confirm " ]),
dbesc ( $arr [ " network " ]),
dbesc ( $arr [ " alias " ]),
dbesc ( $arr [ " pubkey " ]),
dbesc ( datetime_convert ())
);
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
return $r ;
2011-08-09 11:53:51 +02:00
}
2016-03-17 23:44:18 +01:00
/**
* @ brief get a handle ( user @ domain . tld ) from a given contact id or gcontact id
*
* @ param int $contact_id The id in the contact table
* @ param int $gcontact_id The id in the gcontact table
*
* @ return string the handle
*/
2016-03-17 12:24:23 +01:00
public static function handle_from_contact ( $contact_id , $gcontact_id = 0 ) {
2016-03-14 23:11:43 +01:00
$handle = False ;
2011-08-09 11:53:51 +02:00
2016-03-17 12:24:23 +01:00
logger ( " contact id is " . $contact_id . " - gcontact id is " . $gcontact_id , LOGGER_DEBUG );
if ( $gcontact_id != 0 ) {
$r = q ( " SELECT `addr` FROM `gcontact` WHERE `id` = %d AND `addr` != '' " ,
intval ( $gcontact_id ));
if ( $r )
2016-08-23 07:48:48 +02:00
return strtolower ( $r [ 0 ][ " addr " ]);
2016-03-17 12:24:23 +01:00
}
2011-08-09 11:53:51 +02:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `network`, `addr`, `self`, `url`, `nick` FROM `contact` WHERE `id` = %d " ,
2016-03-17 12:24:23 +01:00
intval ( $contact_id ));
if ( $r ) {
2016-03-14 23:11:43 +01:00
$contact = $r [ 0 ];
logger ( " contact 'self' = " . $contact [ 'self' ] . " 'url' = " . $contact [ 'url' ], LOGGER_DEBUG );
if ( $contact [ 'addr' ] != " " )
$handle = $contact [ 'addr' ];
2016-03-22 07:13:56 +01:00
else {
2016-03-14 23:11:43 +01:00
$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 ;
}
}
2013-01-20 14:08:28 +01:00
2016-08-23 07:48:48 +02:00
return strtolower ( $handle );
2016-03-14 23:11:43 +01:00
}
2011-08-10 14:10:48 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Get a contact id for a given handle
*
* @ param int $uid The user id
* @ param string $handle The handle in the format user @ domain . tld
*
* @ return The contact id
*/
2016-03-14 23:11:43 +01:00
private function contact_by_handle ( $uid , $handle ) {
$r = q ( " SELECT * FROM `contact` WHERE `uid` = %d AND `addr` = '%s' LIMIT 1 " ,
intval ( $uid ),
dbesc ( $handle )
);
2011-11-12 13:06:33 +01:00
2016-03-14 23:11:43 +01:00
if ( $r )
return $r [ 0 ];
2011-08-12 12:01:11 +02:00
2016-03-14 23:11:43 +01:00
$handle_parts = explode ( " @ " , $handle );
$nurl_sql = " %%:// " . $handle_parts [ 1 ] . " %%/profile/ " . $handle_parts [ 0 ];
$r = q ( " SELECT * FROM `contact` WHERE `network` = '%s' AND `uid` = %d AND `nurl` LIKE '%s' LIMIT 1 " ,
dbesc ( NETWORK_DFRN ),
intval ( $uid ),
dbesc ( $nurl_sql )
);
if ( $r )
return $r [ 0 ];
2013-01-20 14:08:28 +01:00
2016-03-14 23:11:43 +01:00
return false ;
}
2011-08-16 08:19:17 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Check if posting is allowed for this contact
*
* @ param array $importer Array of the importer user
* @ param array $contact The contact that is checked
* @ param bool $is_comment Is the check for a comment ?
*
* @ return bool is the contact allowed to post ?
*/
2016-03-14 23:11:43 +01:00
private function post_allow ( $importer , $contact , $is_comment = false ) {
2011-08-17 13:24:26 +02:00
// perhaps we were already sharing with this person. Now they're sharing with us.
// That makes us friends.
2016-03-14 23:11:43 +01:00
// Normally this should have handled by getting a request - but this could get lost
if ( $contact [ " rel " ] == CONTACT_IS_FOLLOWER && in_array ( $importer [ " page-flags " ], array ( PAGE_FREELOVE ))) {
2014-03-09 09:19:14 +01:00
q ( " UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d " ,
2011-08-16 08:19:17 +02:00
intval ( CONTACT_IS_FRIEND ),
2016-03-14 23:11:43 +01:00
intval ( $contact [ " id " ]),
intval ( $importer [ " uid " ])
2011-08-16 08:19:17 +02:00
);
2016-03-14 23:11:43 +01:00
$contact [ " rel " ] = CONTACT_IS_FRIEND ;
logger ( " defining user " . $contact [ " nick " ] . " as friend " );
2011-08-16 08:19:17 +02:00
}
2011-11-12 13:06:33 +01:00
2016-03-14 23:11:43 +01:00
if (( $contact [ " blocked " ]) || ( $contact [ " readonly " ]) || ( $contact [ " archive " ]))
return false ;
if ( $contact [ " rel " ] == CONTACT_IS_SHARING || $contact [ " rel " ] == CONTACT_IS_FRIEND )
return true ;
if ( $contact [ " rel " ] == CONTACT_IS_FOLLOWER )
if (( $importer [ " page-flags " ] == PAGE_COMMUNITY ) OR $is_comment )
return true ;
2011-11-12 13:06:33 +01:00
2016-03-14 23:11:43 +01:00
// Messages for the global users are always accepted
if ( $importer [ " uid " ] == 0 )
return true ;
2011-11-12 13:06:33 +01:00
2016-03-14 23:11:43 +01:00
return false ;
2011-08-12 12:01:11 +02:00
}
2013-12-27 01:58:21 +01:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Fetches the contact id for a handle and checks if posting is allowed
*
* @ param array $importer Array of the importer user
* @ param string $handle The checked handle in the format user @ domain . tld
* @ param bool $is_comment Is the check for a comment ?
*
2016-03-27 23:38:35 +02:00
* @ return array The contact data
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function allowed_contact_by_handle ( $importer , $handle , $is_comment = false ) {
$contact = self :: contact_by_handle ( $importer [ " uid " ], $handle );
if ( ! $contact ) {
logger ( " A Contact for handle " . $handle . " and user " . $importer [ " uid " ] . " was not found " );
return false ;
}
2011-08-13 15:52:33 +02:00
2016-03-14 23:11:43 +01:00
if ( ! self :: post_allow ( $importer , $contact , $is_comment )) {
logger ( " The handle: " . $handle . " is not allowed to post to user " . $importer [ " uid " ]);
return false ;
}
return $contact ;
2011-08-13 15:52:33 +02:00
}
2011-08-19 07:03:58 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Does the message already exists on the system ?
*
* @ param int $uid The user id
* @ param string $guid The guid of the message
2016-03-24 15:59:53 +01:00
*
2016-03-23 09:22:59 +01:00
* @ return int | bool message id if the message already was stored into the system - or false .
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function message_exists ( $uid , $guid ) {
$r = q ( " SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1 " ,
intval ( $uid ),
dbesc ( $guid )
);
2011-08-16 09:52:34 +02:00
2016-12-20 21:13:50 +01:00
if ( $r ) {
2016-03-14 23:11:43 +01:00
logger ( " message " . $guid . " already exists for user " . $uid );
2016-03-23 09:22:59 +01:00
return $r [ 0 ][ " id " ];
2016-03-14 23:11:43 +01:00
}
2011-08-12 12:01:11 +02:00
2016-03-14 23:11:43 +01:00
return false ;
2012-01-04 23:30:25 +01:00
}
2016-03-17 23:44:18 +01:00
/**
* @ brief Checks for links to posts in a message
*
* @ param array $item The item array
*/
2016-03-14 23:11:43 +01:00
private function fetch_guid ( $item ) {
preg_replace_callback ( " & \ [url=/posts/([^ \ [ \ ]]*) \ ](.*) \ [ \ /url \ ]&Usi " ,
function ( $match ) use ( $item ){
return ( self :: fetch_guid_sub ( $match , $item ));
}, $item [ " body " ]);
2012-05-18 07:44:52 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-21 19:58:45 +01:00
* @ brief sub function of " fetch_guid " which checks for links in messages
2016-03-17 23:44:18 +01:00
*
* @ param array $match array containing a link that has to be checked for a message link
* @ param array $item The item array
*/
2016-03-14 23:11:43 +01:00
private function fetch_guid_sub ( $match , $item ) {
if ( ! self :: store_by_guid ( $match [ 1 ], $item [ " author-link " ]))
self :: store_by_guid ( $match [ 1 ], $item [ " owner-link " ]);
2011-08-13 15:52:33 +02:00
}
2012-01-04 23:30:25 +01:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Fetches an item with a given guid from a given server
*
* @ param string $guid the message guid
* @ param string $server The server address
* @ param int $uid The user id of the user
*
* @ return int the message id of the stored message or false
*/
2016-03-14 23:11:43 +01:00
private function store_by_guid ( $guid , $server , $uid = 0 ) {
$serverparts = parse_url ( $server );
$server = $serverparts [ " scheme " ] . " :// " . $serverparts [ " host " ];
2012-01-04 23:30:25 +01:00
2016-03-14 23:11:43 +01:00
logger ( " Trying to fetch item " . $guid . " from " . $server , LOGGER_DEBUG );
2012-01-04 23:30:25 +01:00
2016-03-14 23:11:43 +01:00
$msg = self :: message ( $guid , $server );
2014-04-04 10:52:53 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $msg )
return false ;
2012-01-04 23:30:25 +01:00
2016-03-14 23:11:43 +01:00
logger ( " Successfully fetched item " . $guid . " from " . $server , LOGGER_DEBUG );
2012-01-05 22:25:43 +01:00
2016-03-14 23:11:43 +01:00
// Now call the dispatcher
return self :: dispatch_public ( $msg );
2012-01-04 23:30:25 +01:00
}
2011-08-19 07:03:58 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Fetches a message from a server
2016-03-17 23:44:18 +01:00
*
* @ param string $guid message guid
2016-03-18 08:07:23 +01:00
* @ param string $server The url of the server
* @ param int $level Endless loop prevention
2016-03-17 23:44:18 +01:00
*
2016-03-21 19:58:45 +01:00
* @ return array
* 'message' => The message XML
* 'author' => The author handle
* 'key' => The public key of the author
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function message ( $guid , $server , $level = 0 ) {
2011-08-10 14:10:48 +02:00
2016-03-14 23:11:43 +01:00
if ( $level > 5 )
return false ;
2013-01-20 14:08:28 +01:00
2016-06-30 22:18:48 +02:00
// This will work for new Diaspora servers and Friendica servers from 3.5
$source_url = $server . " /fetch/post/ " . $guid ;
logger ( " Fetch post from " . $source_url , LOGGER_DEBUG );
$envelope = fetch_url ( $source_url );
if ( $envelope ) {
logger ( " Envelope was fetched. " , LOGGER_DEBUG );
$x = self :: verify_magic_envelope ( $envelope );
2016-06-30 22:58:56 +02:00
if ( ! $x )
2016-06-30 22:18:48 +02:00
logger ( " Envelope could not be verified. " , LOGGER_DEBUG );
2016-06-30 22:58:56 +02:00
else
logger ( " Envelope was verified. " , LOGGER_DEBUG );
} else
$x = false ;
// This will work for older Diaspora and Friendica servers
if ( ! $x ) {
2016-06-30 22:18:48 +02:00
$source_url = $server . " /p/ " . $guid . " .xml " ;
logger ( " Fetch post from " . $source_url , LOGGER_DEBUG );
$x = fetch_url ( $source_url );
if ( ! $x )
return false ;
}
2015-08-09 14:28:59 +02:00
2016-03-14 23:11:43 +01:00
$source_xml = parse_xml_string ( $x , false );
2015-08-09 14:28:59 +02:00
2016-03-14 23:11:43 +01:00
if ( ! is_object ( $source_xml ))
return false ;
2012-02-23 04:56:28 +01:00
2016-03-14 23:11:43 +01:00
if ( $source_xml -> post -> reshare ) {
// Reshare of a reshare - old Diaspora version
2016-06-30 22:42:46 +02:00
logger ( " Message is a reshare " , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return self :: message ( $source_xml -> post -> reshare -> root_guid , $server , ++ $level );
} elseif ( $source_xml -> getName () == " reshare " ) {
// Reshare of a reshare - new Diaspora version
2016-06-30 22:42:46 +02:00
logger ( " Message is a new reshare " , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return self :: message ( $source_xml -> root_guid , $server , ++ $level );
}
2015-04-25 00:50:48 +02:00
2016-03-14 23:11:43 +01:00
$author = " " ;
2015-04-06 12:26:31 +02:00
2016-03-14 23:11:43 +01:00
// Fetch the author - for the old and the new Diaspora version
if ( $source_xml -> post -> status_message -> diaspora_handle )
$author = ( string ) $source_xml -> post -> status_message -> diaspora_handle ;
elseif ( $source_xml -> author AND ( $source_xml -> getName () == " status_message " ))
$author = ( string ) $source_xml -> author ;
2015-04-06 12:26:31 +02:00
2016-03-14 23:11:43 +01:00
// If this isn't a "status_message" then quit
2016-06-30 22:42:46 +02:00
if ( ! $author ) {
logger ( " Message doesn't seem to be a status message " , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return false ;
2016-06-30 22:42:46 +02:00
}
2015-05-25 19:07:59 +02:00
2016-03-14 23:11:43 +01:00
$msg = array ( " message " => $x , " author " => $author );
2015-05-25 19:07:59 +02:00
2016-03-14 23:11:43 +01:00
$msg [ " key " ] = self :: key ( $msg [ " author " ]);
2015-04-06 12:26:31 +02:00
2016-03-14 23:11:43 +01:00
return $msg ;
}
2012-02-23 04:56:28 +01:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Fetches the item record of a given guid
2016-03-17 23:44:18 +01:00
*
* @ param int $uid The user id
* @ param string $guid message guid
2016-03-18 08:07:23 +01:00
* @ param string $author The handle of the item
2016-03-18 22:28:20 +01:00
* @ param array $contact The contact of the item owner
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return array the item record
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function parent_item ( $uid , $guid , $author , $contact ) {
$r = q ( " SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
`author-name` , `author-link` , `author-avatar` ,
`owner-name` , `owner-link` , `owner-avatar`
FROM `item` WHERE `uid` = % d AND `guid` = '%s' LIMIT 1 " ,
intval ( $uid ), dbesc ( $guid ));
2016-01-21 13:57:21 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $r ) {
$result = self :: store_by_guid ( $guid , $contact [ " url " ], $uid );
2016-01-21 13:57:21 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $result ) {
$person = self :: person_by_handle ( $author );
$result = self :: store_by_guid ( $guid , $person [ " url " ], $uid );
}
2016-01-21 13:21:47 +01:00
2016-03-14 23:11:43 +01:00
if ( $result ) {
logger ( " Fetched missing item " . $guid . " - result: " . $result , LOGGER_DEBUG );
2016-01-21 13:21:47 +01:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `id`, `body`, `wall`, `uri`, `private`, `origin`,
`author-name` , `author-link` , `author-avatar` ,
`owner-name` , `owner-link` , `owner-avatar`
FROM `item` WHERE `uid` = % d AND `guid` = '%s' LIMIT 1 " ,
intval ( $uid ), dbesc ( $guid ));
}
}
2016-01-21 13:21:47 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $r ) {
logger ( " parent item not found: parent: " . $guid . " - user: " . $uid );
return false ;
} else {
logger ( " parent item found: parent: " . $guid . " - user: " . $uid );
return $r [ 0 ];
}
}
2011-08-10 14:10:48 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief returns contact details
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param array $contact The default contact if the person isn ' t found
* @ param array $person The record of the person
2016-03-17 23:44:18 +01:00
* @ param int $uid The user id
*
2016-03-27 23:38:35 +02:00
* @ return array
* 'cid' => contact id
* 'network' => network type
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function author_contact_by_url ( $contact , $person , $uid ) {
2011-08-16 08:19:17 +02:00
2016-11-19 21:10:29 +01:00
$r = q ( " SELECT `id`, `network`, `url` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d LIMIT 1 " ,
2016-03-14 23:11:43 +01:00
dbesc ( normalise_link ( $person [ " url " ])), intval ( $uid ));
if ( $r ) {
$cid = $r [ 0 ][ " id " ];
$network = $r [ 0 ][ " network " ];
2016-11-19 21:10:29 +01:00
// We are receiving content from a user that is about to be terminated
// This means the user is vital, so we remove a possible termination date.
unmark_for_death ( $contact );
2016-03-14 23:11:43 +01:00
} else {
$cid = $contact [ " id " ];
$network = NETWORK_DIASPORA ;
}
2012-07-09 07:32:04 +02:00
2016-11-19 21:10:29 +01:00
return array ( " cid " => $cid , " network " => $network );
2015-08-09 20:39:11 +02:00
}
2011-08-16 08:19:17 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Is the profile a hubzilla profile ?
*
* @ param string $url The profile link
*
* @ return bool is it a hubzilla server ?
*/
2016-03-14 23:11:43 +01:00
public static function is_redmatrix ( $url ) {
return ( strstr ( $url , " /channel/ " ));
2011-08-16 08:19:17 +02:00
}
2016-03-17 23:44:18 +01:00
/**
* @ brief Generate a post link with a given handle and message guid
*
2016-03-18 08:07:23 +01:00
* @ param string $addr The user handle
2016-03-17 23:44:18 +01:00
* @ param string $guid message guid
*
* @ return string the post link
*/
2016-03-14 23:11:43 +01:00
private function plink ( $addr , $guid ) {
$r = q ( " SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1 " , dbesc ( $addr ));
2011-08-14 01:39:59 +02:00
2016-03-14 23:11:43 +01:00
// Fallback
if ( ! $r )
return " https:// " . substr ( $addr , strpos ( $addr , " @ " ) + 1 ) . " /posts/ " . $guid ;
2011-08-14 01:39:59 +02:00
2016-03-14 23:11:43 +01:00
// Friendica contacts are often detected as Diaspora contacts in the "fcontact" table
// So we try another way as well.
$s = q ( " SELECT `network` FROM `gcontact` WHERE `nurl`='%s' LIMIT 1 " , dbesc ( normalise_link ( $r [ 0 ][ " url " ])));
if ( $s )
$r [ 0 ][ " network " ] = $s [ 0 ][ " network " ];
2011-08-14 01:39:59 +02:00
2016-03-14 23:11:43 +01:00
if ( $r [ 0 ][ " network " ] == NETWORK_DFRN )
return ( str_replace ( " /profile/ " . $r [ 0 ][ " nick " ] . " / " , " /display/ " . $guid , $r [ 0 ][ " url " ] . " / " ));
2011-10-06 05:48:00 +02:00
2016-03-14 23:11:43 +01:00
if ( self :: is_redmatrix ( $r [ 0 ][ " url " ]))
return $r [ 0 ][ " url " ] . " /?f=&mid= " . $guid ;
2015-05-25 13:27:45 +02:00
2016-03-14 23:11:43 +01:00
return " https:// " . substr ( $addr , strpos ( $addr , " @ " ) + 1 ) . " /posts/ " . $guid ;
2015-05-25 13:27:45 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes an account deletion
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool Success
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_account_deletion ( $importer , $data ) {
2016-04-19 07:39:17 +02:00
/// @todo Account deletion should remove the contact from the global contacts as well
2016-03-14 23:11:43 +01:00
$author = notags ( unxmlify ( $data -> author ));
2011-10-06 05:48:00 +02:00
2016-03-14 23:11:43 +01:00
$contact = self :: contact_by_handle ( $importer [ " uid " ], $author );
if ( ! $contact ) {
logger ( " cannot find contact for author: " . $author );
return false ;
2011-12-07 00:24:01 +01:00
}
2015-02-03 00:29:21 +01:00
2016-03-14 23:11:43 +01:00
// We now remove the contact
contact_remove ( $contact [ " id " ]);
return true ;
}
2015-02-03 00:29:21 +01:00
2016-06-20 22:48:55 +02:00
/**
* @ brief Fetch the uri from our database if we already have this item ( maybe from ourselves )
*
* @ param string $author Author handle
* @ param string $guid Message guid
*
* @ return string The constructed uri or the one from our database
*/
private function get_uri_from_guid ( $author , $guid ) {
$r = q ( " SELECT `uri` FROM `item` WHERE `guid` = '%s' LIMIT 1 " , dbesc ( $guid ));
if ( $r )
return $r [ 0 ][ " uri " ];
else
return $author . " : " . $guid ;
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes an incoming comment
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param string $sender The sender of the message
* @ param object $data The message object
* @ param string $xml The original XML of the message
*
* @ return int The message id of the generated comment or " false " if there was an error
*/
2016-03-14 23:54:01 +01:00
private function receive_comment ( $importer , $sender , $data , $xml ) {
2016-03-14 23:11:43 +01:00
$guid = notags ( unxmlify ( $data -> guid ));
$parent_guid = notags ( unxmlify ( $data -> parent_guid ));
$text = unxmlify ( $data -> text );
$author = notags ( unxmlify ( $data -> author ));
2015-02-01 21:54:44 +01:00
2016-07-14 07:20:20 +02:00
if ( isset ( $data -> created_at ))
$created_at = datetime_convert ( " UTC " , " UTC " , notags ( unxmlify ( $data -> created_at )));
else
$created_at = datetime_convert ();
2016-03-14 23:11:43 +01:00
$contact = self :: allowed_contact_by_handle ( $importer , $sender , true );
if ( ! $contact )
return false ;
2015-05-09 19:39:47 +02:00
2016-03-23 09:22:59 +01:00
$message_id = self :: message_exists ( $importer [ " uid " ], $guid );
if ( $message_id )
return $message_id ;
2015-02-03 00:29:21 +01:00
2016-03-14 23:11:43 +01:00
$parent_item = self :: parent_item ( $importer [ " uid " ], $parent_guid , $author , $contact );
if ( ! $parent_item )
return false ;
2015-02-01 21:54:44 +01:00
2016-03-14 23:11:43 +01:00
$person = self :: person_by_handle ( $author );
if ( ! is_array ( $person )) {
logger ( " unable to find author details " );
return false ;
}
2015-02-01 21:54:44 +01:00
2016-03-14 23:11:43 +01:00
// Fetch the contact id - if we know this contact
$author_contact = self :: author_contact_by_url ( $contact , $person , $importer [ " uid " ]);
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$datarray = array ();
2015-02-01 21:54:44 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " uid " ] = $importer [ " uid " ];
$datarray [ " contact-id " ] = $author_contact [ " cid " ];
$datarray [ " network " ] = $author_contact [ " network " ];
2015-02-01 21:54:44 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " author-name " ] = $person [ " name " ];
$datarray [ " author-link " ] = $person [ " url " ];
$datarray [ " author-avatar " ] = (( x ( $person , " thumb " )) ? $person [ " thumb " ] : $person [ " photo " ]);
2015-02-01 21:54:44 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " owner-name " ] = $contact [ " name " ];
$datarray [ " owner-link " ] = $contact [ " url " ];
$datarray [ " owner-avatar " ] = (( x ( $contact , " thumb " )) ? $contact [ " thumb " ] : $contact [ " photo " ]);
2015-09-05 12:11:14 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " guid " ] = $guid ;
2016-06-20 22:48:55 +02:00
$datarray [ " uri " ] = self :: get_uri_from_guid ( $author , $guid );
2015-09-05 12:11:14 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " type " ] = " remote-comment " ;
$datarray [ " verb " ] = ACTIVITY_POST ;
$datarray [ " gravity " ] = GRAVITY_COMMENT ;
$datarray [ " parent-uri " ] = $parent_item [ " uri " ];
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " object-type " ] = ACTIVITY_OBJ_COMMENT ;
2016-03-14 23:54:01 +01:00
$datarray [ " object " ] = $xml ;
2015-02-01 21:54:44 +01:00
2016-07-14 07:20:20 +02:00
$datarray [ " changed " ] = $datarray [ " created " ] = $datarray [ " edited " ] = $created_at ;
2016-03-14 23:11:43 +01:00
$datarray [ " body " ] = diaspora2bb ( $text );
2015-02-02 20:24:19 +01:00
2016-03-14 23:11:43 +01:00
self :: fetch_guid ( $datarray );
2015-02-01 21:54:44 +01:00
2016-03-14 23:11:43 +01:00
$message_id = item_store ( $datarray );
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
if ( $message_id )
logger ( " Stored comment " . $datarray [ " guid " ] . " with message id " . $message_id , LOGGER_DEBUG );
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
// If we are the origin of the parent we store the original data and notify our followers
if ( $message_id AND $parent_item [ " origin " ]) {
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
// Formerly we stored the signed text, the signature and the author in different fields.
// We now store the raw data so that we are more flexible.
q ( " INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s') " ,
intval ( $message_id ),
dbesc ( json_encode ( $data ))
);
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
// notify others
2016-08-03 18:24:22 +02:00
proc_run ( PRIORITY_HIGH , " include/notifier.php " , " comment-import " , $message_id );
2016-03-14 23:11:43 +01:00
}
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
return $message_id ;
}
2015-01-25 00:01:58 +01:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief processes and stores private messages
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
2016-03-18 22:28:20 +01:00
* @ param array $contact The contact of the message
2016-03-17 23:44:18 +01:00
* @ param object $data The message object
2016-03-18 08:07:23 +01:00
* @ param array $msg Array of the processed message , author handle and key
* @ param object $mesg The private message
* @ param array $conversation The conversation record to which this message belongs
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return bool " true " if it was successful
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_conversation_message ( $importer , $contact , $data , $msg , $mesg , $conversation ) {
$guid = notags ( unxmlify ( $data -> guid ));
$subject = notags ( unxmlify ( $data -> subject ));
$author = notags ( unxmlify ( $data -> author ));
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$reply = 0 ;
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$msg_guid = notags ( unxmlify ( $mesg -> guid ));
$msg_parent_guid = notags ( unxmlify ( $mesg -> parent_guid ));
$msg_parent_author_signature = notags ( unxmlify ( $mesg -> parent_author_signature ));
$msg_author_signature = notags ( unxmlify ( $mesg -> author_signature ));
$msg_text = unxmlify ( $mesg -> text );
$msg_created_at = datetime_convert ( " UTC " , " UTC " , notags ( unxmlify ( $mesg -> created_at )));
// "diaspora_handle" is the element name from the old version
// "author" is the element name from the new version
if ( $mesg -> author )
$msg_author = notags ( unxmlify ( $mesg -> author ));
elseif ( $mesg -> diaspora_handle )
$msg_author = notags ( unxmlify ( $mesg -> diaspora_handle ));
else
return false ;
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$msg_conversation_guid = notags ( unxmlify ( $mesg -> conversation_guid ));
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
if ( $msg_conversation_guid != $guid ) {
logger ( " message conversation guid does not belong to the current conversation. " );
return false ;
}
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$body = diaspora2bb ( $msg_text );
$message_uri = $msg_author . " : " . $msg_guid ;
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$author_signed_data = $msg_guid . " ; " . $msg_parent_guid . " ; " . $msg_text . " ; " . unxmlify ( $mesg -> created_at ) . " ; " . $msg_author . " ; " . $msg_conversation_guid ;
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$author_signature = base64_decode ( $msg_author_signature );
2015-05-25 13:27:45 +02:00
2016-03-14 23:11:43 +01:00
if ( strcasecmp ( $msg_author , $msg [ " author " ]) == 0 ) {
$person = $contact ;
$key = $msg [ " key " ];
} else {
$person = self :: person_by_handle ( $msg_author );
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
if ( is_array ( $person ) && x ( $person , " pubkey " ))
$key = $person [ " pubkey " ];
else {
logger ( " unable to find author details " );
return false ;
}
}
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
if ( ! rsa_verify ( $author_signed_data , $author_signature , $key , " sha256 " )) {
logger ( " verification failed. " );
return false ;
}
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
if ( $msg_parent_author_signature ) {
$owner_signed_data = $msg_guid . " ; " . $msg_parent_guid . " ; " . $msg_text . " ; " . unxmlify ( $mesg -> created_at ) . " ; " . $msg_author . " ; " . $msg_conversation_guid ;
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$parent_author_signature = base64_decode ( $msg_parent_author_signature );
2015-03-01 20:40:38 +01:00
2016-03-14 23:11:43 +01:00
$key = $msg [ " key " ];
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
if ( ! rsa_verify ( $owner_signed_data , $parent_author_signature , $key , " sha256 " )) {
logger ( " owner verification failed. " );
return false ;
}
}
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `id` FROM `mail` WHERE `uri` = '%s' LIMIT 1 " ,
dbesc ( $message_uri )
);
2016-12-14 09:42:36 +01:00
if ( dbm :: is_result ( $r )) {
2016-03-14 23:11:43 +01:00
logger ( " duplicate message already delivered. " , LOGGER_DEBUG );
return false ;
}
2011-10-20 11:07:38 +02:00
2016-03-14 23:11:43 +01:00
q ( " INSERT INTO `mail` (`uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`)
VALUES ( % d , '%s' , % d , '%s' , '%s' , '%s' , % d , '%s' , '%s' , % d , % d , '%s' , '%s' , '%s' ) " ,
intval ( $importer [ " uid " ]),
dbesc ( $msg_guid ),
intval ( $conversation [ " id " ]),
dbesc ( $person [ " name " ]),
dbesc ( $person [ " photo " ]),
dbesc ( $person [ " url " ]),
intval ( $contact [ " id " ]),
dbesc ( $subject ),
dbesc ( $body ),
0 ,
0 ,
dbesc ( $message_uri ),
dbesc ( $author . " : " . $guid ),
dbesc ( $msg_created_at )
);
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
q ( " UPDATE `conv` SET `updated` = '%s' WHERE `id` = %d " ,
dbesc ( datetime_convert ()),
intval ( $conversation [ " id " ])
);
2011-10-20 11:07:38 +02:00
2016-03-14 23:11:43 +01:00
notification ( array (
" type " => NOTIFY_MAIL ,
" notify_flags " => $importer [ " notify-flags " ],
" language " => $importer [ " language " ],
" to_name " => $importer [ " username " ],
" to_email " => $importer [ " email " ],
" uid " => $importer [ " uid " ],
" item " => array ( " subject " => $subject , " body " => $body ),
" source_name " => $person [ " name " ],
" source_link " => $person [ " url " ],
" source_photo " => $person [ " thumb " ],
" verb " => ACTIVITY_POST ,
" otype " => " mail "
));
2016-03-18 08:07:23 +01:00
return true ;
2012-07-09 07:32:04 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes new private messages ( answers to private messages are processed elsewhere )
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
2016-03-18 08:07:23 +01:00
* @ param array $msg Array of the processed message , author handle and key
2016-03-17 23:44:18 +01:00
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool Success
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_conversation ( $importer , $msg , $data ) {
$guid = notags ( unxmlify ( $data -> guid ));
$subject = notags ( unxmlify ( $data -> subject ));
$created_at = datetime_convert ( " UTC " , " UTC " , notags ( unxmlify ( $data -> created_at )));
$author = notags ( unxmlify ( $data -> author ));
$participants = notags ( unxmlify ( $data -> participants ));
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
$messages = $data -> message ;
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
if ( ! count ( $messages )) {
logger ( " empty conversation " );
return false ;
2015-05-03 22:15:26 +02:00
}
2014-03-23 18:50:28 +01:00
2016-03-14 23:11:43 +01:00
$contact = self :: allowed_contact_by_handle ( $importer , $msg [ " author " ], true );
if ( ! $contact )
return false ;
2014-03-23 18:50:28 +01:00
2016-03-14 23:11:43 +01:00
$conversation = null ;
2014-03-23 18:50:28 +01:00
2016-03-14 23:11:43 +01:00
$c = q ( " SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1 " ,
intval ( $importer [ " uid " ]),
dbesc ( $guid )
);
if ( $c )
$conversation = $c [ 0 ];
else {
$r = q ( " INSERT INTO `conv` (`uid`, `guid`, `creator`, `created`, `updated`, `subject`, `recips`)
VALUES ( % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' ) " ,
intval ( $importer [ " uid " ]),
dbesc ( $guid ),
dbesc ( $author ),
2016-07-14 07:20:20 +02:00
dbesc ( $created_at ),
2016-03-14 23:11:43 +01:00
dbesc ( datetime_convert ()),
dbesc ( $subject ),
dbesc ( $participants )
);
if ( $r )
$c = q ( " SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1 " ,
intval ( $importer [ " uid " ]),
dbesc ( $guid )
);
if ( $c )
$conversation = $c [ 0 ];
2015-01-25 00:01:58 +01:00
}
2016-03-14 23:11:43 +01:00
if ( ! $conversation ) {
logger ( " unable to create conversation. " );
return ;
2014-03-23 18:50:28 +01:00
}
2016-03-14 23:11:43 +01:00
foreach ( $messages as $mesg )
self :: receive_conversation_message ( $importer , $contact , $data , $msg , $mesg , $conversation );
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
return true ;
2012-11-17 16:27:49 +01:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Creates the body for a " like " message
2016-03-17 23:44:18 +01:00
*
2016-03-18 22:28:20 +01:00
* @ param array $contact The contact that send us the " like "
* @ param array $parent_item The item array of the parent item
2016-03-17 23:44:18 +01:00
* @ param string $guid message guid
*
2016-03-18 22:28:20 +01:00
* @ return string the body
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function construct_like_body ( $contact , $parent_item , $guid ) {
$bodyverb = t ( '%1$s likes %2$s\'s %3$s' );
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
$ulink = " [url= " . $contact [ " url " ] . " ] " . $contact [ " name " ] . " [/url] " ;
$alink = " [url= " . $parent_item [ " author-link " ] . " ] " . $parent_item [ " author-name " ] . " [/url] " ;
$plink = " [url= " . App :: get_baseurl () . " /display/ " . urlencode ( $guid ) . " ] " . t ( " status " ) . " [/url] " ;
2015-01-25 00:01:58 +01:00
2016-03-14 23:11:43 +01:00
return sprintf ( $bodyverb , $ulink , $alink , $plink );
2015-01-25 00:01:58 +01:00
}
2011-10-19 00:56:35 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Creates a XML object for a " like "
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
2016-03-18 22:28:20 +01:00
* @ param array $parent_item The item array of the parent item
2016-03-17 23:44:18 +01:00
*
2016-03-18 22:28:20 +01:00
* @ return string The XML
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function construct_like_object ( $importer , $parent_item ) {
$objtype = ACTIVITY_OBJ_NOTE ;
$link = '<link rel="alternate" type="text/html" href="' . App :: get_baseurl () . " /display/ " . $importer [ " nickname " ] . " / " . $parent_item [ " id " ] . '" />' ;
$parent_body = $parent_item [ " body " ];
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
$xmldata = array ( " object " => array ( " type " => $objtype ,
" local " => " 1 " ,
" id " => $parent_item [ " uri " ],
" link " => $link ,
" title " => " " ,
" content " => $parent_body ));
2011-10-19 00:56:35 +02:00
2016-03-14 23:11:43 +01:00
return xml :: from_array ( $xmldata , $xml , true );
}
2011-10-19 00:56:35 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes " like " messages
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param string $sender The sender of the message
* @ param object $data The message object
*
* @ return int The message id of the generated like or " false " if there was an error
*/
2016-03-14 23:11:43 +01:00
private function receive_like ( $importer , $sender , $data ) {
$positive = notags ( unxmlify ( $data -> positive ));
$guid = notags ( unxmlify ( $data -> guid ));
$parent_type = notags ( unxmlify ( $data -> parent_type ));
$parent_guid = notags ( unxmlify ( $data -> parent_guid ));
$author = notags ( unxmlify ( $data -> author ));
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
// likes on comments aren't supported by Diaspora - only on posts
// But maybe this will be supported in the future, so we will accept it.
if ( ! in_array ( $parent_type , array ( " Post " , " Comment " )))
return false ;
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$contact = self :: allowed_contact_by_handle ( $importer , $sender , true );
if ( ! $contact )
return false ;
2012-07-09 07:32:04 +02:00
2016-03-23 09:22:59 +01:00
$message_id = self :: message_exists ( $importer [ " uid " ], $guid );
if ( $message_id )
return $message_id ;
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$parent_item = self :: parent_item ( $importer [ " uid " ], $parent_guid , $author , $contact );
if ( ! $parent_item )
return false ;
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$person = self :: person_by_handle ( $author );
if ( ! is_array ( $person )) {
logger ( " unable to find author details " );
return false ;
}
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
// Fetch the contact id - if we know this contact
$author_contact = self :: author_contact_by_url ( $contact , $person , $importer [ " uid " ]);
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
// "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora
// We would accept this anyhow.
2016-03-25 00:49:18 +01:00
if ( $positive == " true " )
2016-03-14 23:11:43 +01:00
$verb = ACTIVITY_LIKE ;
else
$verb = ACTIVITY_DISLIKE ;
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$datarray = array ();
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " uid " ] = $importer [ " uid " ];
$datarray [ " contact-id " ] = $author_contact [ " cid " ];
$datarray [ " network " ] = $author_contact [ " network " ];
2011-10-18 02:39:25 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " author-name " ] = $person [ " name " ];
$datarray [ " author-link " ] = $person [ " url " ];
$datarray [ " author-avatar " ] = (( x ( $person , " thumb " )) ? $person [ " thumb " ] : $person [ " photo " ]);
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " owner-name " ] = $contact [ " name " ];
$datarray [ " owner-link " ] = $contact [ " url " ];
$datarray [ " owner-avatar " ] = (( x ( $contact , " thumb " )) ? $contact [ " thumb " ] : $contact [ " photo " ]);
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " guid " ] = $guid ;
2016-06-20 22:48:55 +02:00
$datarray [ " uri " ] = self :: get_uri_from_guid ( $author , $guid );
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " type " ] = " activity " ;
$datarray [ " verb " ] = $verb ;
$datarray [ " gravity " ] = GRAVITY_LIKE ;
$datarray [ " parent-uri " ] = $parent_item [ " uri " ];
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " object-type " ] = ACTIVITY_OBJ_NOTE ;
$datarray [ " object " ] = self :: construct_like_object ( $importer , $parent_item );
2011-08-27 02:52:24 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " body " ] = self :: construct_like_body ( $contact , $parent_item , $guid );
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$message_id = item_store ( $datarray );
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
if ( $message_id )
logger ( " Stored like " . $datarray [ " guid " ] . " with message id " . $message_id , LOGGER_DEBUG );
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
// If we are the origin of the parent we store the original data and notify our followers
if ( $message_id AND $parent_item [ " origin " ]) {
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
// Formerly we stored the signed text, the signature and the author in different fields.
// We now store the raw data so that we are more flexible.
q ( " INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s') " ,
intval ( $message_id ),
dbesc ( json_encode ( $data ))
2015-05-09 19:39:47 +02:00
);
2016-03-14 23:11:43 +01:00
// notify others
2016-08-03 18:24:22 +02:00
proc_run ( PRIORITY_HIGH , " include/notifier.php " , " comment-import " , $message_id );
2015-05-09 19:39:47 +02:00
}
2016-03-14 23:11:43 +01:00
return $message_id ;
2011-08-17 13:24:26 +02:00
}
2011-08-14 04:03:59 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes private messages
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool Success ?
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_message ( $importer , $data ) {
$guid = notags ( unxmlify ( $data -> guid ));
$parent_guid = notags ( unxmlify ( $data -> parent_guid ));
$text = unxmlify ( $data -> text );
$created_at = datetime_convert ( " UTC " , " UTC " , notags ( unxmlify ( $data -> created_at )));
$author = notags ( unxmlify ( $data -> author ));
$conversation_guid = notags ( unxmlify ( $data -> conversation_guid ));
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
$contact = self :: allowed_contact_by_handle ( $importer , $author , true );
if ( ! $contact )
return false ;
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
$conversation = null ;
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
$c = q ( " SELECT * FROM `conv` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1 " ,
intval ( $importer [ " uid " ]),
dbesc ( $conversation_guid )
);
if ( $c )
$conversation = $c [ 0 ];
else {
logger ( " conversation not available. " );
return false ;
}
2012-06-09 21:54:21 +02:00
2016-03-14 23:11:43 +01:00
$reply = 0 ;
2012-06-09 21:54:21 +02:00
2016-03-14 23:11:43 +01:00
$body = diaspora2bb ( $text );
$message_uri = $author . " : " . $guid ;
2012-06-09 21:54:21 +02:00
2016-03-14 23:11:43 +01:00
$person = self :: person_by_handle ( $author );
if ( ! $person ) {
logger ( " unable to find author details " );
return false ;
2011-08-17 13:24:26 +02:00
}
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `id` FROM `mail` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1 " ,
dbesc ( $message_uri ),
intval ( $importer [ " uid " ])
);
2016-12-20 21:13:50 +01:00
if ( $r ) {
2016-03-14 23:11:43 +01:00
logger ( " duplicate message already delivered. " , LOGGER_DEBUG );
return false ;
2011-08-17 13:24:26 +02:00
}
2016-03-14 23:11:43 +01:00
q ( " INSERT INTO `mail` (`uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`)
VALUES ( % d , '%s' , % d , '%s' , '%s' , '%s' , % d , '%s' , '%s' , % d , % d , '%s' , '%s' , '%s' ) " ,
intval ( $importer [ " uid " ]),
dbesc ( $guid ),
intval ( $conversation [ " id " ]),
dbesc ( $person [ " name " ]),
dbesc ( $person [ " photo " ]),
dbesc ( $person [ " url " ]),
intval ( $contact [ " id " ]),
dbesc ( $conversation [ " subject " ]),
dbesc ( $body ),
0 ,
1 ,
dbesc ( $message_uri ),
dbesc ( $author . " : " . $parent_guid ),
dbesc ( $created_at )
);
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
q ( " UPDATE `conv` SET `updated` = '%s' WHERE `id` = %d " ,
dbesc ( datetime_convert ()),
intval ( $conversation [ " id " ])
);
2012-06-10 16:41:23 +02:00
2016-03-14 23:11:43 +01:00
return true ;
2012-06-10 16:41:23 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes participations - unsupported by now
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
* @ return bool always true
*/
2016-03-14 23:11:43 +01:00
private function receive_participation ( $importer , $data ) {
// I'm not sure if we can fully support this message type
return true ;
2015-12-01 15:36:32 +01:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes photos - unneeded
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool always true
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_photo ( $importer , $data ) {
// There doesn't seem to be a reason for this function, since the photo data is transmitted in the status message as well
return true ;
}
2011-08-17 13:24:26 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes poll participations - unssupported
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool always true
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_poll_participation ( $importer , $data ) {
// We don't support polls by now
return true ;
2011-08-24 13:42:28 +02:00
}
2012-03-16 13:19:29 +01:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes incoming profile updates
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool Success
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_profile ( $importer , $data ) {
2016-08-23 07:48:48 +02:00
$author = strtolower ( notags ( unxmlify ( $data -> author )));
2011-08-10 14:10:48 +02:00
2016-03-14 23:11:43 +01:00
$contact = self :: contact_by_handle ( $importer [ " uid " ], $author );
if ( ! $contact )
2016-03-17 23:44:18 +01:00
return false ;
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$name = unxmlify ( $data -> first_name ) . (( strlen ( $data -> last_name )) ? " " . unxmlify ( $data -> last_name ) : " " );
$image_url = unxmlify ( $data -> image_url );
$birthday = unxmlify ( $data -> birthday );
$location = diaspora2bb ( unxmlify ( $data -> location ));
$about = diaspora2bb ( unxmlify ( $data -> bio ));
$gender = unxmlify ( $data -> gender );
$searchable = ( unxmlify ( $data -> searchable ) == " true " );
$nsfw = ( unxmlify ( $data -> nsfw ) == " true " );
$tags = unxmlify ( $data -> tag_string );
$tags = explode ( " # " , $tags );
$keywords = array ();
foreach ( $tags as $tag ) {
$tag = trim ( strtolower ( $tag ));
if ( $tag != " " )
$keywords [] = $tag ;
}
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$keywords = implode ( " , " , $keywords );
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$handle_parts = explode ( " @ " , $author );
$nick = $handle_parts [ 0 ];
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
if ( $name === " " )
$name = $handle_parts [ 0 ];
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
if ( preg_match ( " |^https?://| " , $image_url ) === 0 )
$image_url = " http:// " . $handle_parts [ 1 ] . $image_url ;
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
update_contact_avatar ( $image_url , $importer [ " uid " ], $contact [ " id " ]);
2015-08-09 14:28:59 +02:00
2016-03-14 23:11:43 +01:00
// Generic birthday. We don't know the timezone. The year is irrelevant.
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$birthday = str_replace ( " 1000 " , " 1901 " , $birthday );
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
if ( $birthday != " " )
$birthday = datetime_convert ( " UTC " , " UTC " , $birthday , " Y-m-d " );
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
// 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
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
if ( substr ( $birthday , 5 ) === substr ( $contact [ " bd " ], 5 ))
$birthday = $contact [ " bd " ];
$r = q ( " UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `name-date` = '%s', `bd` = '%s',
`location` = '%s' , `about` = '%s' , `keywords` = '%s' , `gender` = '%s' WHERE `id` = % d AND `uid` = % d " ,
dbesc ( $name ),
dbesc ( $nick ),
dbesc ( $author ),
2011-12-06 09:16:13 +01:00
dbesc ( datetime_convert ()),
2016-03-14 23:11:43 +01:00
dbesc ( $birthday ),
dbesc ( $location ),
dbesc ( $about ),
dbesc ( $keywords ),
dbesc ( $gender ),
intval ( $contact [ " id " ]),
intval ( $importer [ " uid " ])
2011-11-29 10:19:09 +01:00
);
2016-03-14 23:11:43 +01:00
if ( $searchable ) {
poco_check ( $contact [ " url " ], $name , NETWORK_DIASPORA , $image_url , $about , $location , $gender , $keywords , " " ,
datetime_convert (), 2 , $contact [ " id " ], $importer [ " uid " ]);
2011-11-28 02:41:23 +01:00
}
2016-03-14 23:11:43 +01:00
$gcontact = array ( " url " => $contact [ " url " ], " network " => NETWORK_DIASPORA , " generation " => 2 ,
" photo " => $image_url , " name " => $name , " location " => $location ,
" about " => $about , " birthday " => $birthday , " gender " => $gender ,
" addr " => $author , " nick " => $nick , " keywords " => $keywords ,
" hide " => ! $searchable , " nsfw " => $nsfw );
2011-12-05 02:26:55 +01:00
2016-03-14 23:11:43 +01:00
update_gcontact ( $gcontact );
2011-12-05 02:26:55 +01:00
2016-03-14 23:11:43 +01:00
logger ( " Profile of contact " . $contact [ " id " ] . " stored for user " . $importer [ " uid " ], LOGGER_DEBUG );
2011-12-05 02:26:55 +01:00
2016-03-14 23:11:43 +01:00
return true ;
}
2011-12-05 02:26:55 +01:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes incoming friend requests
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
2016-03-18 22:28:20 +01:00
* @ param array $contact The contact that send the request
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_request_make_friend ( $importer , $contact ) {
2011-12-05 02:26:55 +01:00
2016-03-14 23:11:43 +01:00
$a = get_app ();
2011-12-05 02:26:55 +01:00
2016-03-14 23:11:43 +01:00
if ( $contact [ " rel " ] == CONTACT_IS_FOLLOWER && in_array ( $importer [ " page-flags " ], array ( PAGE_FREELOVE ))) {
q ( " UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d " ,
intval ( CONTACT_IS_FRIEND ),
intval ( $contact [ " id " ]),
intval ( $importer [ " uid " ])
);
2011-11-28 02:41:23 +01:00
}
2016-03-14 23:11:43 +01:00
// send notification
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1 " ,
intval ( $importer [ " uid " ])
2014-03-09 09:19:14 +01:00
);
2011-12-28 00:49:47 +01:00
2016-03-14 23:11:43 +01:00
if ( $r && ! $r [ 0 ][ " hide-friends " ] && ! $contact [ " hidden " ] && intval ( get_pconfig ( $importer [ " uid " ], " system " , " post_newfriend " ))) {
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$self = q ( " SELECT * FROM `contact` WHERE `self` AND `uid` = %d LIMIT 1 " ,
intval ( $importer [ " uid " ])
);
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
// they are not CONTACT_IS_FOLLOWER anymore but that's what we have in the array
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
if ( $self && $contact [ " rel " ] == CONTACT_IS_FOLLOWER ) {
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
$arr = array ();
$arr [ " uri " ] = $arr [ " parent-uri " ] = item_new_uri ( $a -> get_hostname (), $importer [ " uid " ]);
$arr [ " uid " ] = $importer [ " uid " ];
$arr [ " contact-id " ] = $self [ 0 ][ " id " ];
$arr [ " wall " ] = 1 ;
$arr [ " type " ] = 'wall' ;
$arr [ " gravity " ] = 0 ;
$arr [ " origin " ] = 1 ;
$arr [ " author-name " ] = $arr [ " owner-name " ] = $self [ 0 ][ " name " ];
$arr [ " author-link " ] = $arr [ " owner-link " ] = $self [ 0 ][ " url " ];
$arr [ " author-avatar " ] = $arr [ " owner-avatar " ] = $self [ 0 ][ " thumb " ];
$arr [ " verb " ] = ACTIVITY_FRIEND ;
$arr [ " object-type " ] = ACTIVITY_OBJ_PERSON ;
$A = " [url= " . $self [ 0 ][ " url " ] . " ] " . $self [ 0 ][ " name " ] . " [/url] " ;
$B = " [url= " . $contact [ " url " ] . " ] " . $contact [ " name " ] . " [/url] " ;
$BPhoto = " [url= " . $contact [ " url " ] . " ][img] " . $contact [ " thumb " ] . " [/img][/url] " ;
$arr [ " body " ] = sprintf ( t ( " %1 $s is now friends with %2 $s " ), $A , $B ) . " \n \n \n " . $Bphoto ;
2016-03-23 22:12:08 +01:00
$arr [ " object " ] = self :: construct_new_friend_object ( $contact );
2016-03-14 23:11:43 +01:00
$arr [ " last-child " ] = 1 ;
$arr [ " allow_cid " ] = $user [ 0 ][ " allow_cid " ];
$arr [ " allow_gid " ] = $user [ 0 ][ " allow_gid " ];
$arr [ " deny_cid " ] = $user [ 0 ][ " deny_cid " ];
$arr [ " deny_gid " ] = $user [ 0 ][ " deny_gid " ];
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
$i = item_store ( $arr );
if ( $i )
2016-08-03 18:24:22 +02:00
proc_run ( PRIORITY_HIGH , " include/notifier.php " , " activity " , $i );
2016-03-14 23:11:43 +01:00
}
}
2011-12-07 04:15:42 +01:00
}
2016-03-23 22:12:08 +01:00
/**
* @ brief Creates a XML object for a " new friend " message
*
* @ param array $contact Array of the contact
*
* @ return string The XML
*/
private function construct_new_friend_object ( $contact ) {
$objtype = ACTIVITY_OBJ_PERSON ;
$link = '<link rel="alternate" type="text/html" href="' . $contact [ " url " ] . '" />' . " \n " .
'<link rel="photo" type="image/jpeg" href="' . $contact [ " thumb " ] . '" />' . " \n " ;
$xmldata = array ( " object " => array ( " type " => $objtype ,
" title " => $contact [ " name " ],
" id " => $contact [ " url " ] . " / " . $contact [ " name " ],
" link " => $link ));
return xml :: from_array ( $xmldata , $xml , true );
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes incoming sharing notification
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool Success
2016-03-17 23:44:18 +01:00
*/
2016-03-25 00:49:18 +01:00
private function receive_contact_request ( $importer , $data ) {
2016-03-14 23:11:43 +01:00
$author = unxmlify ( $data -> author );
$recipient = unxmlify ( $data -> recipient );
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $author || ! $recipient )
2016-03-18 22:28:20 +01:00
return false ;
2014-03-16 17:46:05 +01:00
2016-03-25 00:49:18 +01:00
// the current protocol version doesn't know these fields
// That means that we will assume their existance
if ( isset ( $data -> following ))
$following = ( unxmlify ( $data -> following ) == " true " );
else
$following = true ;
2011-12-07 04:15:42 +01:00
2016-03-25 00:49:18 +01:00
if ( isset ( $data -> sharing ))
$sharing = ( unxmlify ( $data -> sharing ) == " true " );
else
$sharing = true ;
2011-11-28 02:41:23 +01:00
2016-03-25 00:49:18 +01:00
$contact = self :: contact_by_handle ( $importer [ " uid " ], $author );
2011-11-28 02:41:23 +01:00
2016-03-25 00:49:18 +01:00
// perhaps we were already sharing with this person. Now they're sharing with us.
// That makes us friends.
if ( $contact ) {
if ( $following AND $sharing ) {
2016-07-10 12:09:58 +02:00
logger ( " Author " . $author . " (Contact " . $contact [ " id " ] . " ) wants to have a bidirectional conection. " , LOGGER_DEBUG );
2016-03-25 00:49:18 +01:00
self :: receive_request_make_friend ( $importer , $contact );
2016-07-10 12:09:58 +02:00
// refetch the contact array
$contact = self :: contact_by_handle ( $importer [ " uid " ], $author );
// If we are now friends, we are sending a share message.
// Normally we needn't to do so, but the first message could have been vanished.
if ( in_array ( $contact [ " rel " ], array ( CONTACT_IS_FRIEND , CONTACT_IS_FOLLOWER ))) {
2016-07-10 12:18:10 +02:00
$u = q ( " SELECT * FROM `user` WHERE `uid` = %d LIMIT 1 " , intval ( $importer [ " uid " ]));
2016-07-10 12:09:58 +02:00
if ( $u ) {
logger ( " Sending share message to author " . $author . " - Contact: " . $contact [ " id " ] . " - User: " . $importer [ " uid " ], LOGGER_DEBUG );
$ret = self :: send_share ( $u [ 0 ], $contact );
}
}
2016-03-25 00:49:18 +01:00
return true ;
2016-07-10 12:09:58 +02:00
} else { /// @todo Handle all possible variations of adding and retracting of permissions
logger ( " Author " . $author . " (Contact " . $contact [ " id " ] . " ) wants to change the relationship: Following: " . $following . " - sharing: " . $sharing . " (By now unsupported) " , LOGGER_DEBUG );
2016-03-25 00:49:18 +01:00
return false ;
2016-07-10 12:09:58 +02:00
}
2016-03-25 00:49:18 +01:00
}
if ( ! $following AND $sharing AND in_array ( $importer [ " page-flags " ], array ( PAGE_SOAPBOX , PAGE_NORMAL ))) {
logger ( " Author " . $author . " wants to share with us - but doesn't want to listen. Request is ignored. " , LOGGER_DEBUG );
return false ;
} elseif ( ! $following AND ! $sharing ) {
logger ( " Author " . $author . " doesn't want anything - and we don't know the author. Request is ignored. " , LOGGER_DEBUG );
return false ;
2016-07-10 12:09:58 +02:00
} elseif ( ! $following AND $sharing ) {
logger ( " Author " . $author . " wants to share with us. " , LOGGER_DEBUG );
} elseif ( $following AND $sharing ) {
logger ( " Author " . $author . " wants to have a bidirectional conection. " , LOGGER_DEBUG );
} elseif ( $following AND ! $sharing ) {
logger ( " Author " . $author . " wants to listen to us. " , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
}
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$ret = self :: person_by_handle ( $author );
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $ret || ( $ret [ " network " ] != NETWORK_DIASPORA )) {
logger ( " Cannot resolve diaspora handle " . $author . " for " . $recipient );
return false ;
}
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
$batch = (( $ret [ " batch " ]) ? $ret [ " batch " ] : implode ( " / " , array_slice ( explode ( " / " , $ret [ " url " ]), 0 , 3 )) . " /receive/public " );
$r = q ( " INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`)
VALUES ( % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , % d , % d ) " ,
intval ( $importer [ " uid " ]),
dbesc ( $ret [ " network " ]),
dbesc ( $ret [ " addr " ]),
datetime_convert (),
dbesc ( $ret [ " url " ]),
dbesc ( normalise_link ( $ret [ " url " ])),
dbesc ( $batch ),
dbesc ( $ret [ " name " ]),
dbesc ( $ret [ " nick " ]),
dbesc ( $ret [ " photo " ]),
dbesc ( $ret [ " pubkey " ]),
dbesc ( $ret [ " notify " ]),
dbesc ( $ret [ " poll " ]),
1 ,
2
);
2011-12-07 04:15:42 +01:00
2016-03-14 23:11:43 +01:00
// find the contact record we just created
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
$contact_record = self :: contact_by_handle ( $importer [ " uid " ], $author );
2011-11-28 02:41:23 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $contact_record ) {
logger ( " unable to locate newly created contact record. " );
return ;
}
2011-08-24 03:17:35 +02:00
2016-07-10 12:09:58 +02:00
logger ( " Author " . $author . " was added as contact number " . $contact_record [ " id " ] . " . " , LOGGER_DEBUG );
2016-04-13 22:21:23 +02:00
$def_gid = get_default_group ( $importer [ 'uid' ], $ret [ " network " ]);
2012-01-23 00:25:29 +01:00
2016-04-13 22:21:23 +02:00
if ( intval ( $def_gid ))
group_add_member ( $importer [ " uid " ], " " , $contact_record [ " id " ], $def_gid );
2012-01-23 00:25:29 +01:00
2016-06-25 13:56:55 +02:00
update_contact_avatar ( $ret [ " photo " ], $importer [ 'uid' ], $contact_record [ " id " ], true );
2016-03-14 23:11:43 +01:00
if ( $importer [ " page-flags " ] == PAGE_NORMAL ) {
2011-08-24 03:17:35 +02:00
2016-07-10 12:09:58 +02:00
logger ( " Sending intra message for author " . $author . " . " , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
$hash = random_string () . ( string ) time (); // Generate a confirm_key
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$ret = q ( " INSERT INTO `intro` (`uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`)
VALUES ( % d , % d , % d , % d , '%s' , '%s' , '%s' ) " ,
intval ( $importer [ " uid " ]),
intval ( $contact_record [ " id " ]),
0 ,
0 ,
dbesc ( t ( " Sharing notification from Diaspora network " )),
dbesc ( $hash ),
dbesc ( datetime_convert ())
);
} else {
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
// automatic friend approval
2011-08-24 03:17:35 +02:00
2016-07-10 12:09:58 +02:00
logger ( " Does an automatic friend approval for author " . $author . " . " , LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
update_contact_avatar ( $contact_record [ " photo " ], $importer [ " uid " ], $contact_record [ " id " ]);
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
// 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.
2011-08-24 03:17:35 +02:00
2016-03-25 00:49:18 +01:00
if (( $importer [ " page-flags " ] == PAGE_FREELOVE ) AND $sharing AND $following )
2016-03-14 23:11:43 +01:00
$new_relation = CONTACT_IS_FRIEND ;
2016-03-25 00:49:18 +01:00
elseif (( $importer [ " page-flags " ] == PAGE_FREELOVE ) AND $sharing )
$new_relation = CONTACT_IS_SHARING ;
2016-03-14 23:11:43 +01:00
else
$new_relation = CONTACT_IS_FOLLOWER ;
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$r = q ( " UPDATE `contact` SET `rel` = %d,
`name-date` = '%s' ,
`uri-date` = '%s' ,
`blocked` = 0 ,
`pending` = 0 ,
`writable` = 1
WHERE `id` = % d
" ,
intval ( $new_relation ),
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
intval ( $contact_record [ " id " ])
);
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$u = q ( " SELECT * FROM `user` WHERE `uid` = %d LIMIT 1 " , intval ( $importer [ " uid " ]));
2016-07-10 12:09:58 +02:00
if ( $u ) {
logger ( " Sending share message (Relation: " . $new_relation . " ) to author " . $author . " - Contact: " . $contact_record [ " id " ] . " - User: " . $importer [ " uid " ], LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
$ret = self :: send_share ( $u [ 0 ], $contact_record );
2016-07-10 13:11:09 +02:00
// Send the profile data, maybe it weren't transmitted before
self :: send_profile ( $importer [ " uid " ], array ( $contact_record ));
2016-07-10 12:09:58 +02:00
}
2016-03-14 23:11:43 +01:00
}
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
return true ;
2011-08-24 03:17:35 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Fetches a message with a given guid
2016-03-17 23:44:18 +01:00
*
* @ param string $guid message guid
2016-03-18 22:28:20 +01:00
* @ param string $orig_author handle of the original post
* @ param string $author handle of the sharer
2016-03-17 23:44:18 +01:00
*
2016-03-18 22:28:20 +01:00
* @ return array The fetched item
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function original_item ( $guid , $orig_author , $author ) {
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
// Do we already have this item?
$r = q ( " SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`,
`author-name` , `author-link` , `author-avatar`
FROM `item` WHERE `guid` = '%s' AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1 " ,
dbesc ( $guid ));
2015-05-09 19:39:47 +02:00
2016-12-20 21:13:50 +01:00
if ( $r ) {
2016-03-14 23:11:43 +01:00
logger ( " reshared message " . $guid . " already exists on system. " );
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
// Maybe it is already a reshared item?
2016-03-22 23:00:42 +01:00
// Then refetch the content, if it is a reshare from a reshare.
// If it is a reshared post from another network then reformat to avoid display problems with two share elements
if ( self :: is_reshare ( $r [ 0 ][ " body " ], true ))
2016-03-14 23:11:43 +01:00
$r = array ();
2016-03-22 23:00:42 +01:00
elseif ( self :: is_reshare ( $r [ 0 ][ " body " ], false )) {
$r [ 0 ][ " body " ] = diaspora2bb ( bb2diaspora ( $r [ 0 ][ " body " ]));
2016-03-23 07:36:17 +01:00
// Add OEmbed and other information to the body
$r [ 0 ][ " body " ] = add_page_info_to_body ( $r [ 0 ][ " body " ], false , true );
2016-03-22 23:00:42 +01:00
return $r [ 0 ];
} else
2016-03-14 23:11:43 +01:00
return $r [ 0 ];
2013-01-12 14:52:15 +01:00
}
2015-05-03 21:25:03 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $r ) {
$server = " https:// " . substr ( $orig_author , strpos ( $orig_author , " @ " ) + 1 );
2016-06-30 22:58:56 +02:00
logger ( " 1st try: reshared message " . $guid . " will be fetched via SSL from the server " . $server );
2016-03-14 23:11:43 +01:00
$item_id = self :: store_by_guid ( $guid , $server );
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $item_id ) {
$server = " http:// " . substr ( $orig_author , strpos ( $orig_author , " @ " ) + 1 );
2016-06-30 22:58:56 +02:00
logger ( " 2nd try: reshared message " . $guid . " will be fetched without SLL from the server " . $server );
2016-03-14 23:11:43 +01:00
$item_id = self :: store_by_guid ( $guid , $server );
}
2011-10-29 01:13:54 +02:00
2016-03-14 23:11:43 +01:00
if ( $item_id ) {
$r = q ( " SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`,
`author-name` , `author-link` , `author-avatar`
FROM `item` WHERE `id` = % d AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1 " ,
intval ( $item_id ));
2016-01-14 21:56:37 +01:00
2016-05-06 08:22:27 +02:00
if ( $r ) {
// If it is a reshared post from another network then reformat to avoid display problems with two share elements
if ( self :: is_reshare ( $r [ 0 ][ " body " ], false ))
$r [ 0 ][ " body " ] = diaspora2bb ( bb2diaspora ( $r [ 0 ][ " body " ]));
2016-03-14 23:11:43 +01:00
return $r [ 0 ];
2016-05-06 08:22:27 +02:00
}
2016-01-14 21:56:37 +01:00
2016-03-14 23:11:43 +01:00
}
}
return false ;
2011-10-06 06:02:00 +02:00
}
2011-08-24 03:17:35 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes a reshare message
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
* @ param string $xml The original XML of the message
*
2016-03-18 22:28:20 +01:00
* @ return int the message id
2016-03-17 23:44:18 +01:00
*/
2016-03-15 00:26:28 +01:00
private function receive_reshare ( $importer , $data , $xml ) {
2016-03-14 23:11:43 +01:00
$root_author = notags ( unxmlify ( $data -> root_author ));
$root_guid = notags ( unxmlify ( $data -> root_guid ));
$guid = notags ( unxmlify ( $data -> guid ));
$author = notags ( unxmlify ( $data -> author ));
$public = notags ( unxmlify ( $data -> public ));
2016-07-14 07:20:20 +02:00
$created_at = datetime_convert ( " UTC " , " UTC " , notags ( unxmlify ( $data -> created_at )));
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$contact = self :: allowed_contact_by_handle ( $importer , $author , false );
if ( ! $contact )
return false ;
2011-08-24 03:17:35 +02:00
2016-03-23 09:22:59 +01:00
$message_id = self :: message_exists ( $importer [ " uid " ], $guid );
if ( $message_id )
return $message_id ;
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$original_item = self :: original_item ( $root_guid , $root_author , $author );
if ( ! $original_item )
return false ;
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$orig_url = App :: get_baseurl () . " /display/ " . $original_item [ " guid " ];
2011-08-10 14:10:48 +02:00
2016-03-14 23:11:43 +01:00
$datarray = array ();
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " uid " ] = $importer [ " uid " ];
$datarray [ " contact-id " ] = $contact [ " id " ];
$datarray [ " network " ] = NETWORK_DIASPORA ;
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " author-name " ] = $contact [ " name " ];
$datarray [ " author-link " ] = $contact [ " url " ];
$datarray [ " author-avatar " ] = (( x ( $contact , " thumb " )) ? $contact [ " thumb " ] : $contact [ " photo " ]);
2011-08-17 13:24:26 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " owner-name " ] = $datarray [ " author-name " ];
$datarray [ " owner-link " ] = $datarray [ " author-link " ];
$datarray [ " owner-avatar " ] = $datarray [ " author-avatar " ];
2011-08-17 07:31:14 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " guid " ] = $guid ;
2016-06-20 22:48:55 +02:00
$datarray [ " uri " ] = $datarray [ " parent-uri " ] = self :: get_uri_from_guid ( $author , $guid );
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " verb " ] = ACTIVITY_POST ;
$datarray [ " gravity " ] = GRAVITY_PARENT ;
2011-08-16 08:19:17 +02:00
2016-03-15 00:26:28 +01:00
$datarray [ " object " ] = $xml ;
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$prefix = share_header ( $original_item [ " author-name " ], $original_item [ " author-link " ], $original_item [ " author-avatar " ],
$original_item [ " guid " ], $original_item [ " created " ], $orig_url );
$datarray [ " body " ] = $prefix . $original_item [ " body " ] . " [/share] " ;
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " tag " ] = $original_item [ " tag " ];
$datarray [ " app " ] = $original_item [ " app " ];
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " plink " ] = self :: plink ( $author , $guid );
$datarray [ " private " ] = (( $public == " false " ) ? 1 : 0 );
2016-07-14 07:20:20 +02:00
$datarray [ " changed " ] = $datarray [ " created " ] = $datarray [ " edited " ] = $created_at ;
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " object-type " ] = $original_item [ " object-type " ];
2015-05-09 19:39:47 +02:00
2016-03-14 23:11:43 +01:00
self :: fetch_guid ( $datarray );
$message_id = item_store ( $datarray );
2011-08-14 04:03:59 +02:00
2016-03-14 23:11:43 +01:00
if ( $message_id )
logger ( " Stored reshare " . $datarray [ " guid " ] . " with message id " . $message_id , LOGGER_DEBUG );
2011-08-17 07:31:14 +02:00
2016-03-14 23:11:43 +01:00
return $message_id ;
2011-08-17 07:31:14 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Processes retractions
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
2016-03-18 22:28:20 +01:00
* @ param array $contact The contact of the item owner
2016-03-17 23:44:18 +01:00
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool success
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function item_retraction ( $importer , $contact , $data ) {
$target_type = notags ( unxmlify ( $data -> target_type ));
$target_guid = notags ( unxmlify ( $data -> target_guid ));
$author = notags ( unxmlify ( $data -> author ));
2011-08-17 07:31:14 +02:00
2016-03-14 23:11:43 +01:00
$person = self :: person_by_handle ( $author );
if ( ! is_array ( $person )) {
logger ( " unable to find author detail for " . $author );
return false ;
}
2015-03-22 21:53:13 +01:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `id`, `parent`, `parent-uri`, `author-link` FROM `item` WHERE `guid` = '%s' AND `uid` = %d AND NOT `file` LIKE '%%[%%' LIMIT 1 " ,
dbesc ( $target_guid ),
intval ( $importer [ " uid " ])
);
if ( ! $r )
return false ;
2015-03-22 21:53:13 +01:00
2016-03-14 23:11:43 +01:00
// Check if the sender is the thread owner
$p = q ( " SELECT `id`, `author-link`, `origin` FROM `item` WHERE `id` = %d " ,
intval ( $r [ 0 ][ " parent " ]));
2011-08-14 04:03:59 +02:00
2016-03-14 23:11:43 +01:00
// Only delete it if the parent author really fits
if ( ! link_compare ( $p [ 0 ][ " author-link " ], $contact [ " url " ]) AND ! link_compare ( $r [ 0 ][ " author-link " ], $contact [ " url " ])) {
logger ( " Thread author " . $p [ 0 ][ " author-link " ] . " and item author " . $r [ 0 ][ " author-link " ] . " don't fit to expected contact " . $contact [ " url " ], LOGGER_DEBUG );
return false ;
}
2011-08-14 04:03:59 +02:00
2016-03-14 23:11:43 +01:00
// Currently we don't have a central deletion function that we could use in this case. The function "item_drop" doesn't work for that case
q ( " UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '' , `title` = '' WHERE `id` = %d " ,
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ " id " ])
);
delete_thread ( $r [ 0 ][ " id " ], $r [ 0 ][ " parent-uri " ]);
2015-03-22 21:53:13 +01:00
2016-03-14 23:11:43 +01:00
logger ( " Deleted target " . $target_guid . " ( " . $r [ 0 ][ " id " ] . " ) from user " . $importer [ " uid " ] . " parent: " . $p [ 0 ][ " id " ], LOGGER_DEBUG );
2012-06-09 21:54:21 +02:00
2016-03-14 23:11:43 +01:00
// Now check if the retraction needs to be relayed by us
if ( $p [ 0 ][ " origin " ]) {
// notify others
2016-08-03 18:24:22 +02:00
proc_run ( PRIORITY_HIGH , " include/notifier.php " , " drop " , $r [ 0 ][ " id " ]);
2011-08-17 07:31:14 +02:00
}
2016-03-18 22:28:20 +01:00
return true ;
2011-08-17 07:31:14 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Receives retraction messages
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param string $sender The sender of the message
* @ param object $data The message object
*
2016-03-18 22:28:20 +01:00
* @ return bool Success
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function receive_retraction ( $importer , $sender , $data ) {
$target_type = notags ( unxmlify ( $data -> target_type ));
2011-08-17 07:31:14 +02:00
2016-03-14 23:11:43 +01:00
$contact = self :: contact_by_handle ( $importer [ " uid " ], $sender );
if ( ! $contact ) {
logger ( " cannot find contact for sender: " . $sender . " and user " . $importer [ " uid " ]);
return false ;
}
2012-06-10 16:41:23 +02:00
2016-03-14 23:11:43 +01:00
logger ( " Got retraction for " . $target_type . " , sender " . $sender . " and user " . $importer [ " uid " ], LOGGER_DEBUG );
switch ( $target_type ) {
case " Comment " :
case " Like " :
case " Post " : // "Post" will be supported in a future version
case " Reshare " :
case " StatusMessage " :
return self :: item_retraction ( $importer , $contact , $data );;
2016-04-19 07:39:17 +02:00
case " Contact " :
2016-03-14 23:11:43 +01:00
case " Person " :
/// @todo What should we do with an "unshare"?
// Removing the contact isn't correct since we still can read the public items
2016-04-19 07:39:17 +02:00
contact_remove ( $contact [ " id " ]);
2016-03-14 23:11:43 +01:00
return true ;
default :
logger ( " Unknown target type " . $target_type );
return false ;
2012-06-10 16:41:23 +02:00
}
2016-03-14 23:11:43 +01:00
return true ;
2012-06-10 16:41:23 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Receives status messages
2016-03-17 23:44:18 +01:00
*
* @ param array $importer Array of the importer user
* @ param object $data The message object
* @ param string $xml The original XML of the message
*
2016-03-18 22:28:20 +01:00
* @ return int The message id of the newly created item
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:54:01 +01:00
private function receive_status_message ( $importer , $data , $xml ) {
2016-03-14 23:11:43 +01:00
$raw_message = unxmlify ( $data -> raw_message );
$guid = notags ( unxmlify ( $data -> guid ));
$author = notags ( unxmlify ( $data -> author ));
$public = notags ( unxmlify ( $data -> public ));
2016-07-14 07:20:20 +02:00
$created_at = datetime_convert ( " UTC " , " UTC " , notags ( unxmlify ( $data -> created_at )));
2016-03-14 23:11:43 +01:00
$provider_display_name = notags ( unxmlify ( $data -> provider_display_name ));
2011-08-14 04:03:59 +02:00
2016-03-14 23:11:43 +01:00
/// @todo enable support for polls
//if ($data->poll) {
// foreach ($data->poll AS $poll)
// print_r($poll);
// die("poll!\n");
//}
$contact = self :: allowed_contact_by_handle ( $importer , $author , false );
if ( ! $contact )
return false ;
2011-08-14 04:03:59 +02:00
2016-03-23 09:22:59 +01:00
$message_id = self :: message_exists ( $importer [ " uid " ], $guid );
if ( $message_id )
return $message_id ;
2011-08-10 14:10:48 +02:00
2016-03-14 23:11:43 +01:00
$address = array ();
if ( $data -> location )
foreach ( $data -> location -> children () AS $fieldname => $data )
$address [ $fieldname ] = notags ( unxmlify ( $data ));
2011-08-16 08:19:17 +02:00
2016-03-14 23:11:43 +01:00
$body = diaspora2bb ( $raw_message );
2011-12-21 23:42:12 +01:00
2016-03-14 23:11:43 +01:00
$datarray = array ();
2011-08-16 08:19:17 +02:00
2016-03-24 15:59:53 +01:00
// Attach embedded pictures to the body
2016-03-14 23:11:43 +01:00
if ( $data -> photo ) {
foreach ( $data -> photo AS $photo )
2016-03-15 20:14:08 +01:00
$body = " [img] " . unxmlify ( $photo -> remote_photo_path ) .
unxmlify ( $photo -> remote_photo_name ) . " [/img] \n " . $body ;
2011-08-16 08:19:17 +02:00
2016-12-20 08:10:47 +01:00
$datarray [ " object-type " ] = ACTIVITY_OBJ_IMAGE ;
2016-03-14 23:11:43 +01:00
} else {
$datarray [ " object-type " ] = ACTIVITY_OBJ_NOTE ;
2015-12-03 08:35:47 +01:00
2016-03-14 23:11:43 +01:00
// Add OEmbed and other information to the body
if ( ! self :: is_redmatrix ( $contact [ " url " ]))
$body = add_page_info_to_body ( $body , false , true );
2011-08-23 05:35:34 +02:00
}
2011-08-10 14:10:48 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " uid " ] = $importer [ " uid " ];
$datarray [ " contact-id " ] = $contact [ " id " ];
$datarray [ " network " ] = NETWORK_DIASPORA ;
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$datarray [ " author-name " ] = $contact [ " name " ];
$datarray [ " author-link " ] = $contact [ " url " ];
$datarray [ " author-avatar " ] = (( x ( $contact , " thumb " )) ? $contact [ " thumb " ] : $contact [ " photo " ]);
2011-12-21 23:42:12 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " owner-name " ] = $datarray [ " author-name " ];
$datarray [ " owner-link " ] = $datarray [ " author-link " ];
$datarray [ " owner-avatar " ] = $datarray [ " author-avatar " ];
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " guid " ] = $guid ;
2016-06-20 22:48:55 +02:00
$datarray [ " uri " ] = $datarray [ " parent-uri " ] = self :: get_uri_from_guid ( $author , $guid );
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " verb " ] = ACTIVITY_POST ;
$datarray [ " gravity " ] = GRAVITY_PARENT ;
2012-05-26 02:26:09 +02:00
2016-03-14 23:54:01 +01:00
$datarray [ " object " ] = $xml ;
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " body " ] = $body ;
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
if ( $provider_display_name != " " )
$datarray [ " app " ] = $provider_display_name ;
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
$datarray [ " plink " ] = self :: plink ( $author , $guid );
$datarray [ " private " ] = (( $public == " false " ) ? 1 : 0 );
2016-07-14 07:20:20 +02:00
$datarray [ " changed " ] = $datarray [ " created " ] = $datarray [ " edited " ] = $created_at ;
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
if ( isset ( $address [ " address " ]))
$datarray [ " location " ] = $address [ " address " ];
2012-05-26 02:26:09 +02:00
2016-03-14 23:11:43 +01:00
if ( isset ( $address [ " lat " ]) AND isset ( $address [ " lng " ]))
$datarray [ " coord " ] = $address [ " lat " ] . " " . $address [ " lng " ];
2012-06-09 21:54:21 +02:00
2016-03-14 23:11:43 +01:00
self :: fetch_guid ( $datarray );
$message_id = item_store ( $datarray );
2012-06-09 21:54:21 +02:00
2016-03-14 23:11:43 +01:00
if ( $message_id )
logger ( " Stored item " . $datarray [ " guid " ] . " with message id " . $message_id , LOGGER_DEBUG );
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
return $message_id ;
}
2011-11-05 22:45:29 +01:00
2016-03-23 22:12:08 +01:00
/* ************************************************************************************** *
2016-03-14 23:11:43 +01:00
* Here are all the functions that are needed to transmit data with the Diaspora protocol *
2016-03-23 22:12:08 +01:00
* ************************************************************************************** */
2012-06-09 21:54:21 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief returnes the handle of a contact
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param array $me contact array
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return string the handle in the format user @ domain . tld
2016-03-17 23:44:18 +01:00
*/
2016-06-30 07:32:07 +02:00
private function my_handle ( $contact ) {
2016-03-14 23:11:43 +01:00
if ( $contact [ " addr " ] != " " )
return $contact [ " addr " ];
2012-05-26 02:26:09 +02:00
2016-03-14 23:11:43 +01:00
// Normally we should have a filled "addr" field - but in the past this wasn't the case
// So - just in case - we build the the address here.
2016-03-19 15:49:47 +01:00
if ( $contact [ " nickname " ] != " " )
$nick = $contact [ " nickname " ];
else
$nick = $contact [ " nick " ];
return $nick . " @ " . substr ( App :: get_baseurl (), strpos ( App :: get_baseurl (), " :// " ) + 3 );
2011-11-05 22:45:29 +01:00
}
2016-06-30 07:32:07 +02:00
/**
* @ brief Creates the envelope for the " fetch " endpoint
*
* @ param string $msg The message that is to be transmitted
* @ param array $user The record of the sender
*
* @ return string The envelope
*/
2016-06-30 22:18:48 +02:00
public static function build_magic_envelope ( $msg , $user ) {
2016-06-30 07:32:07 +02:00
$b64url_data = base64url_encode ( $msg );
$data = str_replace ( array ( " \n " , " \r " , " " , " \t " ), array ( " " , " " , " " , " " ), $b64url_data );
$key_id = base64url_encode ( diaspora :: my_handle ( $user ));
$type = " application/xml " ;
$encoding = " base64url " ;
$alg = " RSA-SHA256 " ;
$signable_data = $data . " . " . base64url_encode ( $type ) . " . " . base64url_encode ( $encoding ) . " . " . base64url_encode ( $alg );
$signature = rsa_sign ( $signable_data , $user [ " prvkey " ]);
$sig = base64url_encode ( $signature );
$xmldata = array ( " me:env " => array ( " me:data " => $data ,
" @attributes " => array ( " type " => $type ),
" me:encoding " => $encoding ,
" me:alg " => $alg ,
" me:sig " => $sig ,
" @attributes2 " => array ( " key_id " => $key_id )));
$namespaces = array ( " me " => " http://salmon-protocol.org/ns/magic-env " );
return xml :: from_array ( $xmldata , $xml , false , $namespaces );
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Creates the envelope for a public message
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param string $msg The message that is to be transmitted
* @ param array $user The record of the sender
* @ param array $contact Target of the communication
* @ param string $prvkey The private key of the sender
* @ param string $pubkey The public key of the receiver
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return string The envelope
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function build_public_message ( $msg , $user , $contact , $prvkey , $pubkey ) {
2011-11-05 22:45:29 +01:00
2016-03-14 23:11:43 +01:00
logger ( " Message: " . $msg , LOGGER_DATA );
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$handle = self :: my_handle ( $user );
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$b64url_data = base64url_encode ( $msg );
2012-07-09 07:32:04 +02:00
2016-03-14 23:11:43 +01:00
$data = str_replace ( array ( " \n " , " \r " , " " , " \t " ), array ( " " , " " , " " , " " ), $b64url_data );
2012-07-09 07:32:04 +02:00
2016-03-14 23:11:43 +01:00
$type = " application/xml " ;
$encoding = " base64url " ;
$alg = " RSA-SHA256 " ;
2015-01-25 13:19:37 +01:00
2016-03-14 23:11:43 +01:00
$signable_data = $data . " . " . base64url_encode ( $type ) . " . " . base64url_encode ( $encoding ) . " . " . base64url_encode ( $alg );
2012-09-20 04:35:39 +02:00
2016-03-14 23:11:43 +01:00
$signature = rsa_sign ( $signable_data , $prvkey );
$sig = base64url_encode ( $signature );
2016-01-06 14:13:59 +01:00
2016-03-14 23:11:43 +01:00
$xmldata = array ( " diaspora " => array ( " header " => array ( " author_id " => $handle ),
2016-06-30 07:32:07 +02:00
" me:env " => array ( " me:encoding " => $encoding ,
" me:alg " => $alg ,
" me:data " => $data ,
" @attributes " => array ( " type " => $type ),
" me:sig " => $sig )));
2015-01-07 01:46:13 +01:00
2016-03-14 23:11:43 +01:00
$namespaces = array ( " " => " https://joindiaspora.com/protocol " ,
" me " => " http://salmon-protocol.org/ns/magic-env " );
$magic_env = xml :: from_array ( $xmldata , $xml , false , $namespaces );
logger ( " magic_env: " . $magic_env , LOGGER_DATA );
return $magic_env ;
2012-09-20 04:35:39 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Creates the envelope for a private message
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param string $msg The message that is to be transmitted
* @ param array $user The record of the sender
* @ param array $contact Target of the communication
* @ param string $prvkey The private key of the sender
* @ param string $pubkey The public key of the receiver
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return string The envelope
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function build_private_message ( $msg , $user , $contact , $prvkey , $pubkey ) {
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
logger ( " Message: " . $msg , LOGGER_DATA );
2011-10-18 10:12:51 +02:00
2016-03-14 23:11:43 +01:00
// without a public key nothing will work
2015-01-07 01:46:13 +01:00
2016-03-14 23:11:43 +01:00
if ( ! $pubkey ) {
logger ( " pubkey missing: contact id: " . $contact [ " id " ]);
return false ;
}
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$inner_aes_key = random_string ( 32 );
$b_inner_aes_key = base64_encode ( $inner_aes_key );
$inner_iv = random_string ( 16 );
$b_inner_iv = base64_encode ( $inner_iv );
2011-10-18 10:12:51 +02:00
2016-03-14 23:11:43 +01:00
$outer_aes_key = random_string ( 32 );
$b_outer_aes_key = base64_encode ( $outer_aes_key );
$outer_iv = random_string ( 16 );
$b_outer_iv = base64_encode ( $outer_iv );
2011-10-14 09:20:37 +02:00
2016-03-14 23:11:43 +01:00
$handle = self :: my_handle ( $user );
2011-12-20 04:06:25 +01:00
2016-03-14 23:11:43 +01:00
$padded_data = pkcs5_pad ( $msg , 16 );
$inner_encrypted = mcrypt_encrypt ( MCRYPT_RIJNDAEL_128 , $inner_aes_key , $padded_data , MCRYPT_MODE_CBC , $inner_iv );
2011-12-20 04:06:25 +01:00
2016-03-14 23:11:43 +01:00
$b64_data = base64_encode ( $inner_encrypted );
2012-02-25 07:47:43 +01:00
2011-10-18 10:12:51 +02:00
2016-03-14 23:11:43 +01:00
$b64url_data = base64url_encode ( $b64_data );
$data = str_replace ( array ( " \n " , " \r " , " " , " \t " ), array ( " " , " " , " " , " " ), $b64url_data );
2015-01-25 13:19:37 +01:00
2016-03-14 23:11:43 +01:00
$type = " application/xml " ;
$encoding = " base64url " ;
$alg = " RSA-SHA256 " ;
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$signable_data = $data . " . " . base64url_encode ( $type ) . " . " . base64url_encode ( $encoding ) . " . " . base64url_encode ( $alg );
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$signature = rsa_sign ( $signable_data , $prvkey );
$sig = base64url_encode ( $signature );
2011-10-14 03:32:02 +02:00
2016-03-14 23:11:43 +01:00
$xmldata = array ( " decrypted_header " => array ( " iv " => $b_inner_iv ,
" aes_key " => $b_inner_aes_key ,
" author_id " => $handle ));
2011-08-15 05:38:31 +02:00
2016-03-14 23:11:43 +01:00
$decrypted_header = xml :: from_array ( $xmldata , $xml , true );
$decrypted_header = pkcs5_pad ( $decrypted_header , 16 );
2011-08-15 05:38:31 +02:00
2016-03-14 23:11:43 +01:00
$ciphertext = mcrypt_encrypt ( MCRYPT_RIJNDAEL_128 , $outer_aes_key , $decrypted_header , MCRYPT_MODE_CBC , $outer_iv );
2011-08-15 05:38:31 +02:00
2016-03-14 23:11:43 +01:00
$outer_json = json_encode ( array ( " iv " => $b_outer_iv , " key " => $b_outer_aes_key ));
2011-08-15 05:38:31 +02:00
2016-03-14 23:11:43 +01:00
$encrypted_outer_key_bundle = " " ;
openssl_public_encrypt ( $outer_json , $encrypted_outer_key_bundle , $pubkey );
2011-08-23 05:35:34 +02:00
2016-03-14 23:11:43 +01:00
$b64_encrypted_outer_key_bundle = base64_encode ( $encrypted_outer_key_bundle );
2011-08-23 05:35:34 +02:00
2016-03-14 23:11:43 +01:00
logger ( " outer_bundle: " . $b64_encrypted_outer_key_bundle . " key: " . $pubkey , LOGGER_DATA );
2011-08-23 05:35:34 +02:00
2016-03-14 23:11:43 +01:00
$encrypted_header_json_object = json_encode ( array ( " aes_key " => base64_encode ( $encrypted_outer_key_bundle ),
" ciphertext " => base64_encode ( $ciphertext )));
$cipher_json = base64_encode ( $encrypted_header_json_object );
2011-08-23 05:35:34 +02:00
2016-03-14 23:11:43 +01:00
$xmldata = array ( " diaspora " => array ( " encrypted_header " => $cipher_json ,
2016-06-29 22:50:30 +02:00
" me:env " => array ( " me:encoding " => $encoding ,
" me:alg " => $alg ,
2016-03-14 23:11:43 +01:00
" me:data " => $data ,
2016-06-29 22:50:30 +02:00
" @attributes " => array ( " type " => $type ),
2016-03-14 23:11:43 +01:00
" me:sig " => $sig )));
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
$namespaces = array ( " " => " https://joindiaspora.com/protocol " ,
" me " => " http://salmon-protocol.org/ns/magic-env " );
$magic_env = xml :: from_array ( $xmldata , $xml , false , $namespaces );
2011-08-23 05:35:34 +02:00
2016-03-14 23:11:43 +01:00
logger ( " magic_env: " . $magic_env , LOGGER_DATA );
return $magic_env ;
}
2011-08-23 05:35:34 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Create the envelope for a message
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param string $msg The message that is to be transmitted
* @ param array $user The record of the sender
* @ param array $contact Target of the communication
* @ param string $prvkey The private key of the sender
* @ param string $pubkey The public key of the receiver
* @ param bool $public Is the message public ?
2016-03-17 23:44:18 +01:00
*
2016-03-18 22:28:20 +01:00
* @ return string The message that will be transmitted to other servers
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function build_message ( $msg , $user , $contact , $prvkey , $pubkey , $public = false ) {
2011-08-15 06:23:02 +02:00
2016-03-14 23:11:43 +01:00
if ( $public )
$magic_env = self :: build_public_message ( $msg , $user , $contact , $prvkey , $pubkey );
else
$magic_env = self :: build_private_message ( $msg , $user , $contact , $prvkey , $pubkey );
2011-08-15 06:23:02 +02:00
2016-03-14 23:11:43 +01:00
// The data that will be transmitted is double encoded via "urlencode", strange ...
$slap = " xml= " . urlencode ( urlencode ( $magic_env ));
return $slap ;
}
2011-08-24 03:17:35 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Creates a signature for a message
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param array $owner the array of the owner of the message
* @ param array $message The message that is to be signed
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return string The signature
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function signature ( $owner , $message ) {
$sigmsg = $message ;
unset ( $sigmsg [ " author_signature " ]);
unset ( $sigmsg [ " parent_author_signature " ]);
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$signed_text = implode ( " ; " , $sigmsg );
2011-10-24 04:05:32 +02:00
2016-03-14 23:11:43 +01:00
return base64_encode ( rsa_sign ( $signed_text , $owner [ " uprvkey " ], " sha256 " ));
2012-06-17 19:49:05 +02:00
}
2012-06-23 12:42:01 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Transmit a message to a target server
2016-03-17 23:44:18 +01:00
*
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
* @ param string $slap The message that is to be transmitted
2016-03-17 23:44:18 +01:00
* @ param bool $public_batch Is it a public post ?
2016-03-18 08:07:23 +01:00
* @ param bool $queue_run Is the transmission called from the queue ?
2016-03-17 23:44:18 +01:00
* @ param string $guid message guid
*
2016-03-18 08:07:23 +01:00
* @ return int Result of the transmission
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
public static function transmit ( $owner , $contact , $slap , $public_batch , $queue_run = false , $guid = " " ) {
$a = get_app ();
$enabled = intval ( get_config ( " system " , " diaspora_enabled " ));
if ( ! $enabled )
return 200 ;
2012-06-17 19:49:05 +02:00
2016-03-14 23:11:43 +01:00
$logid = random_string ( 4 );
$dest_url = (( $public_batch ) ? $contact [ " batch " ] : $contact [ " notify " ]);
if ( ! $dest_url ) {
logger ( " no url for contact: " . $contact [ " id " ] . " batch mode = " . $public_batch );
return 0 ;
}
2012-04-02 04:16:13 +02:00
2016-03-14 23:11:43 +01:00
logger ( " transmit: " . $logid . " - " . $guid . " " . $dest_url );
2012-04-02 04:16:13 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $queue_run && was_recently_delayed ( $contact [ " id " ])) {
$return_code = 0 ;
} else {
if ( ! intval ( get_config ( " system " , " diaspora_test " ))) {
post_url ( $dest_url . " / " , $slap );
$return_code = $a -> get_curl_code ();
} else {
logger ( " test_mode " );
return 200 ;
2011-11-02 01:30:52 +01:00
}
}
2016-03-14 23:11:43 +01:00
logger ( " transmit: " . $logid . " - " . $guid . " returns: " . $return_code );
2011-11-02 01:30:52 +01:00
2016-12-20 21:13:50 +01:00
if ( ! $return_code || (( $return_code == 503 ) && ( stristr ( $a -> get_curl_headers (), " retry-after " )))) {
2016-03-14 23:11:43 +01:00
logger ( " queue message " );
2011-08-15 06:23:02 +02:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `id` FROM `queue` WHERE `cid` = %d AND `network` = '%s' AND `content` = '%s' AND `batch` = %d LIMIT 1 " ,
intval ( $contact [ " id " ]),
dbesc ( NETWORK_DIASPORA ),
dbesc ( $slap ),
intval ( $public_batch )
);
2016-12-20 21:13:50 +01:00
if ( $r ) {
2016-03-14 23:11:43 +01:00
logger ( " add_to_queue ignored - identical item already in queue " );
} else {
// queue message for redelivery
add_to_queue ( $contact [ " id " ], NETWORK_DIASPORA , $slap , $public_batch );
2016-11-19 21:10:29 +01:00
// The message could not be delivered. We mark the contact as "dead"
mark_for_death ( $contact );
2016-03-14 23:11:43 +01:00
}
2016-11-19 21:10:29 +01:00
} elseif (( $return_code >= 200 ) AND ( $return_code <= 299 )) {
// We successfully delivered a message, the contact is alive
unmark_for_death ( $contact );
2016-03-14 23:11:43 +01:00
}
2011-08-15 06:23:02 +02:00
2016-03-14 23:11:43 +01:00
return (( $return_code ) ? $return_code : ( - 1 ));
2014-04-26 01:35:02 +02:00
}
2011-08-15 06:23:02 +02:00
2016-06-30 07:46:00 +02:00
/**
* @ brief Build the post xml
*
* @ param string $type The message type
* @ param array $message The message data
*
* @ return string The post XML
*/
public static function build_post_xml ( $type , $message ) {
$data = array ( " XML " => array ( " post " => array ( $type => $message )));
return xml :: from_array ( $data , $xml );
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Builds and transmit messages
2016-03-17 23:44:18 +01:00
*
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
* @ param string $type The message type
* @ param array $message The message data
2016-03-17 23:44:18 +01:00
* @ param bool $public_batch Is it a public post ?
* @ param string $guid message guid
2016-03-18 08:07:23 +01:00
* @ param bool $spool Should the transmission be spooled or transmitted ?
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return int Result of the transmission
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function build_and_transmit ( $owner , $contact , $type , $message , $public_batch = false , $guid = " " , $spool = false ) {
2011-08-24 03:17:35 +02:00
2016-06-30 07:56:06 +02:00
$msg = self :: build_post_xml ( $type , $message );
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
logger ( 'message: ' . $msg , LOGGER_DATA );
logger ( 'send guid ' . $guid , LOGGER_DEBUG );
2011-08-15 06:23:02 +02:00
2016-07-10 12:18:10 +02:00
// Fallback if the private key wasn't transmitted in the expected field
if ( $owner [ 'uprvkey' ] == " " )
$owner [ 'uprvkey' ] = $owner [ 'prvkey' ];
2016-03-14 23:11:43 +01:00
$slap = self :: build_message ( $msg , $owner , $contact , $owner [ 'uprvkey' ], $contact [ 'pubkey' ], $public_batch );
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
if ( $spool ) {
add_to_queue ( $contact [ 'id' ], NETWORK_DIASPORA , $slap , $public_batch );
return true ;
} else
$return_code = self :: transmit ( $owner , $contact , $slap , $public_batch , false , $guid );
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
logger ( " guid: " . $item [ " guid " ] . " result " . $return_code , LOGGER_DEBUG );
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
return $return_code ;
}
2014-04-26 01:35:02 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Sends a " share " message
2016-03-17 23:44:18 +01:00
*
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
2016-03-17 23:44:18 +01:00
*
* @ return int The result of the transmission
*/
2016-03-14 23:11:43 +01:00
public static function send_share ( $owner , $contact ) {
2015-04-03 13:06:19 +02:00
2016-03-14 23:11:43 +01:00
$message = array ( " sender_handle " => self :: my_handle ( $owner ),
" recipient_handle " => $contact [ " addr " ]);
2015-04-03 13:06:19 +02:00
2016-07-10 12:09:58 +02:00
logger ( " Send share " . print_r ( $message , true ), LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return self :: build_and_transmit ( $owner , $contact , " request " , $message );
2015-04-03 13:06:19 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief sends an " unshare "
2016-03-17 23:44:18 +01:00
*
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
2016-03-17 23:44:18 +01:00
*
* @ return int The result of the transmission
*/
2016-03-14 23:11:43 +01:00
public static function send_unshare ( $owner , $contact ) {
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
$message = array ( " post_guid " => $owner [ " guid " ],
" diaspora_handle " => self :: my_handle ( $owner ),
" type " => " Person " );
2014-04-26 01:35:02 +02:00
2016-07-10 12:09:58 +02:00
logger ( " Send unshare " . print_r ( $message , true ), LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return self :: build_and_transmit ( $owner , $contact , " retraction " , $message );
}
2014-04-26 01:35:02 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Checks a message body if it is a reshare
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ param string $body The message body that is to be check
* @ param bool $complete Should it be a complete check or a simple check ?
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return array | bool Reshare details or " false " if no reshare
2016-03-17 23:44:18 +01:00
*/
2016-03-16 21:27:07 +01:00
public static function is_reshare ( $body , $complete = true ) {
2016-03-14 23:11:43 +01:00
$body = trim ( $body );
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
// Skip if it isn't a pure repeated messages
// Does it start with a share?
2016-05-06 08:22:27 +02:00
if (( strpos ( $body , " [share " ) > 0 ) AND $complete )
2016-03-14 23:11:43 +01:00
return ( false );
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
// Does it end with a share?
if ( strlen ( $body ) > ( strrpos ( $body , " [/share] " ) + 8 ))
return ( false );
2014-04-26 01:35:02 +02:00
2016-03-14 23:11:43 +01:00
$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 );
2014-04-26 01:35:02 +02:00
2016-03-16 21:27:07 +01:00
// If we don't do the complete check we quit here
if ( ! $complete )
return true ;
2016-03-14 23:11:43 +01:00
$guid = " " ;
preg_match ( " /guid='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " )
$guid = $matches [ 1 ];
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
preg_match ( '/guid="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " )
$guid = $matches [ 1 ];
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
if ( $guid != " " ) {
$r = q ( " SELECT `contact-id` FROM `item` WHERE `guid` = '%s' AND `network` IN ('%s', '%s') LIMIT 1 " ,
dbesc ( $guid ), NETWORK_DFRN , NETWORK_DIASPORA );
if ( $r ) {
$ret = array ();
$ret [ " root_handle " ] = self :: handle_from_contact ( $r [ 0 ][ " contact-id " ]);
$ret [ " root_guid " ] = $guid ;
return ( $ret );
}
}
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
$profile = " " ;
preg_match ( " /profile='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " )
$profile = $matches [ 1 ];
2016-01-11 14:24:54 +01:00
2016-03-14 23:11:43 +01:00
preg_match ( '/profile="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " )
$profile = $matches [ 1 ];
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$ret = array ();
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$ret [ " root_handle " ] = preg_replace ( " =https?://(.*)/u/(.*)=ism " , " $ 2@ $ 1 " , $profile );
if (( $ret [ " root_handle " ] == $profile ) OR ( $ret [ " root_handle " ] == " " ))
return ( false );
2011-08-24 03:17:35 +02:00
2016-03-14 23:11:43 +01:00
$link = " " ;
preg_match ( " /link='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " )
$link = $matches [ 1 ];
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
preg_match ( '/link="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " )
$link = $matches [ 1 ];
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$ret [ " root_guid " ] = preg_replace ( " =https?://(.*)/posts/(.*)=ism " , " $ 2 " , $link );
2016-03-24 21:32:55 +01:00
if (( $ret [ " root_guid " ] == $link ) OR ( trim ( $ret [ " root_guid " ]) == " " ))
2016-03-14 23:11:43 +01:00
return ( false );
2016-03-24 21:32:55 +01:00
2016-03-14 23:11:43 +01:00
return ( $ret );
2011-08-19 06:09:44 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-06-30 07:32:07 +02:00
* @ brief Create a post ( status message or reshare )
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
*
2016-06-30 07:32:07 +02:00
* @ return array
* 'type' -> Message type ( " status_message " or " reshare " )
* 'message' -> Array of XML elements of the status
2016-03-17 23:44:18 +01:00
*/
2016-06-30 07:32:07 +02:00
public static function build_status ( $item , $owner ) {
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$myaddr = self :: my_handle ( $owner );
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$public = (( $item [ " private " ]) ? " false " : " true " );
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$created = datetime_convert ( " UTC " , " UTC " , $item [ " created " ], 'Y-m-d H:i:s \U\T\C' );
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
// Detect a share element and do a reshare
if ( ! $item [ 'private' ] AND ( $ret = self :: is_reshare ( $item [ " body " ]))) {
$message = array ( " root_diaspora_id " => $ret [ " root_handle " ],
" root_guid " => $ret [ " root_guid " ],
" guid " => $item [ " guid " ],
" diaspora_handle " => $myaddr ,
" public " => $public ,
" created_at " => $created ,
" provider_display_name " => $item [ " app " ]);
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$type = " reshare " ;
} else {
$title = $item [ " title " ];
$body = $item [ " body " ];
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
// convert to markdown
$body = html_entity_decode ( bb2diaspora ( $body ));
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
// Adding the title
if ( strlen ( $title ))
$body = " ## " . html_entity_decode ( $title ) . " \n \n " . $body ;
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
if ( $item [ " attach " ]) {
$cnt = preg_match_all ( '/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism' , $item [ " attach " ], $matches , PREG_SET_ORDER );
if ( cnt ) {
$body .= " \n " . t ( " Attachments: " ) . " \n " ;
foreach ( $matches as $mtch )
$body .= " [ " . $mtch [ 3 ] . " ]( " . $mtch [ 1 ] . " ) \n " ;
}
}
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$location = array ();
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
if ( $item [ " location " ] != " " )
$location [ " address " ] = $item [ " location " ];
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
if ( $item [ " coord " ] != " " ) {
$coord = explode ( " " , $item [ " coord " ]);
$location [ " lat " ] = $coord [ 0 ];
$location [ " lng " ] = $coord [ 1 ];
}
2012-06-17 07:58:22 +02:00
2016-03-14 23:11:43 +01:00
$message = array ( " raw_message " => $body ,
" location " => $location ,
" guid " => $item [ " guid " ],
" diaspora_handle " => $myaddr ,
" public " => $public ,
" created_at " => $created ,
" provider_display_name " => $item [ " app " ]);
2011-08-19 06:09:44 +02:00
2016-11-13 19:28:55 +01:00
// Diaspora rejects messages when they contain a location without "lat" or "lng"
2016-11-13 18:42:26 +01:00
if ( ! isset ( $location [ " lat " ]) OR ! isset ( $location [ " lng " ])) {
2016-03-14 23:11:43 +01:00
unset ( $message [ " location " ]);
2016-11-13 18:42:26 +01:00
}
2012-06-17 07:58:22 +02:00
2016-03-14 23:11:43 +01:00
$type = " status_message " ;
}
2016-06-30 07:32:07 +02:00
return array ( " type " => $type , " message " => $message );
}
/**
* @ brief Sends a post
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
* @ param array $contact Target of the communication
* @ param bool $public_batch Is it a public post ?
*
* @ return int The result of the transmission
*/
public static function send_status ( $item , $owner , $contact , $public_batch = false ) {
$status = diaspora :: build_status ( $item , $owner );
2012-06-17 07:58:22 +02:00
2016-06-30 07:32:07 +02:00
return self :: build_and_transmit ( $owner , $contact , $status [ " type " ], $status [ " message " ], $public_batch , $item [ " guid " ]);
2012-06-03 00:11:31 +02:00
}
2012-06-17 07:58:22 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Creates a " like " object
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
*
2016-03-18 22:28:20 +01:00
* @ return array The data for a " like "
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function construct_like ( $item , $owner ) {
2012-06-17 07:58:22 +02:00
2016-03-14 23:11:43 +01:00
$p = q ( " SELECT `guid`, `uri`, `parent-uri` FROM `item` WHERE `uri` = '%s' LIMIT 1 " ,
dbesc ( $item [ " thr-parent " ]));
2016-12-14 09:42:36 +01:00
if ( ! dbm :: is_result ( $p ))
2016-03-14 23:11:43 +01:00
return false ;
2012-06-01 03:40:12 +02:00
2016-03-14 23:11:43 +01:00
$parent = $p [ 0 ];
2016-01-20 04:22:07 +01:00
2016-03-14 23:11:43 +01:00
$target_type = ( $parent [ " uri " ] === $parent [ " parent-uri " ] ? " Post " : " Comment " );
$positive = " true " ;
2016-01-20 04:22:07 +01:00
2016-03-14 23:11:43 +01:00
return ( array ( " positive " => $positive ,
" guid " => $item [ " guid " ],
" target_type " => $target_type ,
" parent_guid " => $parent [ " guid " ],
2016-03-19 15:49:47 +01:00
" author_signature " => " " ,
2016-03-17 23:44:18 +01:00
" diaspora_handle " => self :: my_handle ( $owner )));
2016-03-14 23:11:43 +01:00
}
2016-01-20 04:22:07 +01:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Creates the object for a comment
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
*
2016-03-18 22:28:20 +01:00
* @ return array The data for a comment
2016-03-17 23:44:18 +01:00
*/
2016-03-14 23:11:43 +01:00
private function construct_comment ( $item , $owner ) {
2016-01-20 04:22:07 +01:00
2016-03-14 23:11:43 +01:00
$p = q ( " SELECT `guid` FROM `item` WHERE `parent` = %d AND `id` = %d LIMIT 1 " ,
intval ( $item [ " parent " ]),
intval ( $item [ " parent " ])
);
2011-08-28 14:00:30 +02:00
2016-09-18 23:21:18 +02:00
if ( ! dbm :: is_result ( $p ))
2016-03-14 23:11:43 +01:00
return false ;
2012-08-10 06:06:18 +02:00
2016-03-14 23:11:43 +01:00
$parent = $p [ 0 ];
2011-08-26 16:29:22 +02:00
2016-03-14 23:11:43 +01:00
$text = html_entity_decode ( bb2diaspora ( $item [ " body " ]));
2016-01-20 04:22:07 +01:00
2016-03-14 23:11:43 +01:00
return ( array ( " guid " => $item [ " guid " ],
" parent_guid " => $parent [ " guid " ],
" author_signature " => " " ,
" text " => $text ,
2016-03-17 23:44:18 +01:00
" diaspora_handle " => self :: my_handle ( $owner )));
2016-01-20 04:22:07 +01:00
}
2012-06-24 06:04:20 +02:00
2016-03-17 23:44:18 +01:00
/**
* @ brief Send a like or a comment
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
2016-03-17 23:44:18 +01:00
* @ param bool $public_batch Is it a public post ?
*
* @ return int The result of the transmission
*/
2016-03-14 23:11:43 +01:00
public static function send_followup ( $item , $owner , $contact , $public_batch = false ) {
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
if ( $item [ 'verb' ] === ACTIVITY_LIKE ) {
$message = self :: construct_like ( $item , $owner );
$type = " like " ;
} else {
$message = self :: construct_comment ( $item , $owner );
$type = " comment " ;
}
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $message )
return false ;
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
$message [ " author_signature " ] = self :: signature ( $owner , $message );
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
return self :: build_and_transmit ( $owner , $contact , $type , $message , $public_batch , $item [ " guid " ]);
}
2011-08-19 06:09:44 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Creates a message from a signature record entry
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
2016-03-18 08:07:23 +01:00
* @ param array $signature The entry of the " sign " record
2016-03-17 23:44:18 +01:00
*
2016-03-18 08:07:23 +01:00
* @ return string The message
2016-03-17 23:44:18 +01:00
*/
2016-03-18 08:07:23 +01:00
private function message_from_signature ( $item , $signature ) {
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
// Split the signed text
$signed_parts = explode ( " ; " , $signature [ 'signed_text' ]);
if ( $item [ " deleted " ])
$message = array ( " parent_author_signature " => " " ,
" target_guid " => $signed_parts [ 0 ],
" target_type " => $signed_parts [ 1 ],
" sender_handle " => $signature [ 'signer' ],
" target_author_signature " => $signature [ 'signature' ]);
elseif ( $item [ 'verb' ] === ACTIVITY_LIKE )
$message = array ( " positive " => $signed_parts [ 0 ],
" guid " => $signed_parts [ 1 ],
" target_type " => $signed_parts [ 2 ],
" parent_guid " => $signed_parts [ 3 ],
" parent_author_signature " => " " ,
" author_signature " => $signature [ 'signature' ],
" diaspora_handle " => $signed_parts [ 4 ]);
else {
// Remove the comment guid
$guid = array_shift ( $signed_parts );
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
// Remove the parent guid
$parent_guid = array_shift ( $signed_parts );
2011-08-19 06:09:44 +02:00
2016-03-14 23:11:43 +01:00
// Remove the handle
$handle = array_pop ( $signed_parts );
2012-06-01 03:40:12 +02:00
2016-03-14 23:11:43 +01:00
// Glue the parts together
$text = implode ( " ; " , $signed_parts );
2015-05-25 13:27:45 +02:00
2016-03-14 23:11:43 +01:00
$message = array ( " guid " => $guid ,
" parent_guid " => $parent_guid ,
" parent_author_signature " => " " ,
" author_signature " => $signature [ 'signature' ],
" text " => implode ( " ; " , $signed_parts ),
" diaspora_handle " => $handle );
}
return $message ;
2012-06-01 03:40:12 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Relays messages ( like , comment , retraction ) to other servers if we are the thread owner
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
2016-03-17 23:44:18 +01:00
* @ param bool $public_batch Is it a public post ?
*
* @ return int The result of the transmission
*/
2016-03-14 23:11:43 +01:00
public static function send_relay ( $item , $owner , $contact , $public_batch = false ) {
2011-11-05 22:45:29 +01:00
2016-03-17 12:24:23 +01:00
if ( $item [ " deleted " ])
return self :: send_retraction ( $item , $owner , $contact , $public_batch , true );
elseif ( $item [ 'verb' ] === ACTIVITY_LIKE )
2016-03-14 23:11:43 +01:00
$type = " like " ;
2016-03-17 12:24:23 +01:00
else
2016-03-14 23:11:43 +01:00
$type = " comment " ;
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
logger ( " Got relayable data " . $type . " for item " . $item [ " guid " ] . " ( " . $item [ " id " ] . " ) " , LOGGER_DEBUG );
2011-12-06 09:16:13 +01:00
2016-03-14 23:11:43 +01:00
// fetch the original signature
2011-12-06 09:16:13 +01:00
2016-03-17 12:24:23 +01:00
$r = q ( " SELECT `signed_text`, `signature`, `signer` FROM `sign` WHERE `iid` = %d LIMIT 1 " ,
2016-03-14 23:11:43 +01:00
intval ( $item [ " id " ]));
2011-12-06 09:16:13 +01:00
2016-03-15 20:14:08 +01:00
if ( ! $r ) {
2016-03-17 00:37:44 +01:00
logger ( " Couldn't fetch signatur for item " . $item [ " guid " ] . " ( " . $item [ " id " ] . " ) " , LOGGER_DEBUG );
2016-03-15 20:14:08 +01:00
return false ;
}
2011-12-06 09:16:13 +01:00
2016-03-14 23:11:43 +01:00
$signature = $r [ 0 ];
2011-12-06 09:16:13 +01:00
2016-03-14 23:11:43 +01:00
// Old way - is used by the internal Friendica functions
/// @todo Change all signatur storing functions to the new format
if ( $signature [ 'signed_text' ] AND $signature [ 'signature' ] AND $signature [ 'signer' ])
2016-03-18 08:07:23 +01:00
$message = self :: message_from_signature ( $item , $signature );
2016-03-14 23:11:43 +01:00
else { // New way
$msg = json_decode ( $signature [ 'signed_text' ], true );
2011-12-06 09:16:13 +01:00
2016-03-14 23:11:43 +01:00
$message = array ();
2016-03-16 19:30:46 +01:00
if ( is_array ( $msg )) {
foreach ( $msg AS $field => $data ) {
if ( ! $item [ " deleted " ]) {
if ( $field == " author " )
$field = " diaspora_handle " ;
if ( $field == " parent_type " )
$field = " target_type " ;
}
$message [ $field ] = $data ;
2016-03-14 23:11:43 +01:00
}
2016-03-16 19:30:46 +01:00
} else
logger ( " Signature text for item " . $item [ " guid " ] . " ( " . $item [ " id " ] . " ) couldn't be extracted: " . $signature [ 'signed_text' ], LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
}
2011-12-06 09:16:13 +01:00
2016-03-17 12:24:23 +01:00
$message [ " parent_author_signature " ] = self :: signature ( $owner , $message );
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
logger ( " Relayed data " . print_r ( $message , true ), LOGGER_DEBUG );
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
return self :: build_and_transmit ( $owner , $contact , $type , $message , $public_batch , $item [ " guid " ]);
2012-04-05 05:48:35 +02:00
}
2016-03-17 23:44:18 +01:00
/**
2016-03-18 08:07:23 +01:00
* @ brief Sends a retraction ( deletion ) of a message , like or comment
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
* @ param array $owner the array of the item owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
2016-03-17 23:44:18 +01:00
* @ param bool $public_batch Is it a public post ?
2016-03-18 08:07:23 +01:00
* @ param bool $relay Is the retraction transmitted from a relay ?
2016-03-17 23:44:18 +01:00
*
* @ return int The result of the transmission
*/
2016-03-17 12:24:23 +01:00
public static function send_retraction ( $item , $owner , $contact , $public_batch = false , $relay = false ) {
2016-03-17 00:37:44 +01:00
2016-03-17 12:24:23 +01:00
$itemaddr = self :: handle_from_contact ( $item [ " contact-id " ], $item [ " gcontact-id " ]);
2011-11-07 01:48:13 +01:00
2016-03-14 23:11:43 +01:00
// Check whether the retraction is for a top-level post or whether it's a relayable
if ( $item [ " uri " ] !== $item [ " parent-uri " ]) {
$msg_type = " relayable_retraction " ;
$target_type = (( $item [ " verb " ] === ACTIVITY_LIKE ) ? " Like " : " Comment " );
2013-10-02 22:17:56 +02:00
} else {
2016-03-14 23:11:43 +01:00
$msg_type = " signed_retraction " ;
$target_type = " StatusMessage " ;
2012-05-08 00:54:49 +02:00
}
2016-03-14 23:11:43 +01:00
2016-03-17 12:24:23 +01:00
if ( $relay AND ( $item [ " uri " ] !== $item [ " parent-uri " ]))
$signature = " parent_author_signature " ;
else
$signature = " target_author_signature " ;
2016-03-14 23:11:43 +01:00
$signed_text = $item [ " guid " ] . " ; " . $target_type ;
$message = array ( " target_guid " => $item [ 'guid' ],
" target_type " => $target_type ,
2016-03-17 00:37:44 +01:00
" sender_handle " => $itemaddr ,
2016-03-17 12:24:23 +01:00
$signature => base64_encode ( rsa_sign ( $signed_text , $owner [ 'uprvkey' ], 'sha256' )));
2016-03-17 00:37:44 +01:00
logger ( " Got message " . print_r ( $message , true ), LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
return self :: build_and_transmit ( $owner , $contact , $msg_type , $message , $public_batch , $item [ " guid " ]);
2012-01-27 05:46:42 +01:00
}
2013-10-02 22:17:56 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Sends a mail
2016-03-17 23:44:18 +01:00
*
* @ param array $item The item that will be exported
* @ param array $owner The owner
2016-03-18 08:07:23 +01:00
* @ param array $contact Target of the communication
2016-03-17 23:44:18 +01:00
*
* @ return int The result of the transmission
*/
2016-03-14 23:11:43 +01:00
public static function send_mail ( $item , $owner , $contact ) {
2011-08-24 10:21:24 +02:00
2016-03-14 23:11:43 +01:00
$myaddr = self :: my_handle ( $owner );
2011-11-07 01:48:13 +01:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT * FROM `conv` WHERE `id` = %d AND `uid` = %d LIMIT 1 " ,
intval ( $item [ " convid " ]),
intval ( $item [ " uid " ])
2011-11-07 01:48:13 +01:00
);
2011-08-19 06:09:44 +02:00
2016-09-18 23:21:18 +02:00
if ( ! dbm :: is_result ( $r )) {
2016-03-14 23:11:43 +01:00
logger ( " conversation not found. " );
return ;
}
$cnv = $r [ 0 ];
$conv = array (
" guid " => $cnv [ " guid " ],
" subject " => $cnv [ " subject " ],
" created_at " => datetime_convert ( " UTC " , " UTC " , $cnv [ 'created' ], 'Y-m-d H:i:s \U\T\C' ),
" diaspora_handle " => $cnv [ " creator " ],
" participant_handles " => $cnv [ " recips " ]
);
2011-09-28 04:27:47 +02:00
2016-03-14 23:11:43 +01:00
$body = bb2diaspora ( $item [ " body " ]);
$created = datetime_convert ( " UTC " , " UTC " , $item [ " created " ], 'Y-m-d H:i:s \U\T\C' );
$signed_text = $item [ " guid " ] . " ; " . $cnv [ " guid " ] . " ; " . $body . " ; " . $created . " ; " . $myaddr . " ; " . $cnv [ 'guid' ];
$sig = base64_encode ( rsa_sign ( $signed_text , $owner [ " uprvkey " ], " sha256 " ));
$msg = array (
" guid " => $item [ " guid " ],
" parent_guid " => $cnv [ " guid " ],
" parent_author_signature " => $sig ,
" author_signature " => $sig ,
" text " => $body ,
" created_at " => $created ,
" diaspora_handle " => $myaddr ,
" conversation_guid " => $cnv [ " guid " ]
);
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
if ( $item [ " reply " ]) {
$message = $msg ;
$type = " message " ;
} else {
$message = array ( " guid " => $cnv [ " guid " ],
" subject " => $cnv [ " subject " ],
" created_at " => datetime_convert ( " UTC " , " UTC " , $cnv [ 'created' ], 'Y-m-d H:i:s \U\T\C' ),
" message " => $msg ,
" diaspora_handle " => $cnv [ " creator " ],
" participant_handles " => $cnv [ " recips " ]);
$type = " conversation " ;
}
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
return self :: build_and_transmit ( $owner , $contact , $type , $message , false , $item [ " guid " ]);
}
2015-08-09 20:39:11 +02:00
2016-03-17 23:44:18 +01:00
/**
2016-03-18 22:28:20 +01:00
* @ brief Sends profile data
2016-03-17 23:44:18 +01:00
*
* @ param int $uid The user id
*/
2016-07-10 13:11:09 +02:00
public static function send_profile ( $uid , $recips = false ) {
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $uid )
return ;
2015-08-09 20:39:11 +02:00
2016-07-10 13:11:09 +02:00
if ( ! $recips )
$recips = q ( " SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s'
AND `uid` = % d AND `rel` != % d " ,
dbesc ( NETWORK_DIASPORA ),
intval ( $uid ),
intval ( CONTACT_IS_SHARING )
);
2016-03-14 23:11:43 +01:00
if ( ! $recips )
return ;
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
$r = q ( " SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.*, `user`.`prvkey` AS `uprvkey`, `contact`.`addr`
FROM `profile`
INNER JOIN `user` ON `profile` . `uid` = `user` . `uid`
INNER JOIN `contact` ON `profile` . `uid` = `contact` . `uid`
WHERE `user` . `uid` = % d AND `profile` . `is-default` AND `contact` . `self` LIMIT 1 " ,
intval ( $uid )
);
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
if ( ! $r )
return ;
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
$profile = $r [ 0 ];
$handle = $profile [ " addr " ];
$first = (( strpos ( $profile [ 'name' ], ' ' )
? trim ( substr ( $profile [ 'name' ], 0 , strpos ( $profile [ 'name' ], ' ' ))) : $profile [ 'name' ]));
$last = (( $first === $profile [ 'name' ]) ? '' : trim ( substr ( $profile [ 'name' ], strlen ( $first ))));
$large = App :: get_baseurl () . '/photo/custom/300/' . $profile [ 'uid' ] . '.jpg' ;
$medium = App :: get_baseurl () . '/photo/custom/100/' . $profile [ 'uid' ] . '.jpg' ;
$small = App :: get_baseurl () . '/photo/custom/50/' . $profile [ 'uid' ] . '.jpg' ;
$searchable = (( $profile [ 'publish' ] && $profile [ 'net-publish' ]) ? 'true' : 'false' );
if ( $searchable === 'true' ) {
$dob = '1000-00-00' ;
if (( $profile [ 'dob' ]) && ( $profile [ 'dob' ] != '0000-00-00' ))
$dob = (( intval ( $profile [ 'dob' ])) ? intval ( $profile [ 'dob' ]) : '1000' ) . '-' . datetime_convert ( 'UTC' , 'UTC' , $profile [ 'dob' ], 'm-d' );
$about = $profile [ 'about' ];
$about = strip_tags ( bbcode ( $about ));
$location = formatted_location ( $profile );
$tags = '' ;
if ( $profile [ 'pub_keywords' ]) {
$kw = str_replace ( ',' , ' ' , $profile [ 'pub_keywords' ]);
$kw = str_replace ( ' ' , ' ' , $kw );
$arr = explode ( ' ' , $profile [ 'pub_keywords' ]);
if ( count ( $arr )) {
for ( $x = 0 ; $x < 5 ; $x ++ ) {
if ( trim ( $arr [ $x ]))
$tags .= '#' . trim ( $arr [ $x ]) . ' ' ;
}
}
}
$tags = trim ( $tags );
}
2015-08-09 20:39:11 +02:00
2016-03-14 23:11:43 +01:00
$message = array ( " diaspora_handle " => $handle ,
" first_name " => $first ,
" last_name " => $last ,
" image_url " => $large ,
" image_url_medium " => $medium ,
" image_url_small " => $small ,
" birthday " => $dob ,
" gender " => $profile [ 'gender' ],
" bio " => $about ,
" location " => $location ,
" searchable " => $searchable ,
" tag_string " => $tags );
2016-07-10 13:11:09 +02:00
foreach ( $recips as $recip ) {
logger ( " Send updated profile data for user " . $uid . " to contact " . $recip [ " id " ], LOGGER_DEBUG );
2016-03-14 23:11:43 +01:00
self :: build_and_transmit ( $profile , $recip , " profile " , $message , false , " " , true );
2016-07-10 13:11:09 +02:00
}
2015-08-09 20:39:11 +02:00
}
2016-03-19 15:49:47 +01:00
/**
* @ brief Stores the signature for likes that are created on our system
*
* @ param array $contact The contact array of the " like "
* @ param int $post_id The post id of the " like "
*
* @ return bool Success
*/
2016-03-23 22:12:08 +01:00
public static function store_like_signature ( $contact , $post_id ) {
2016-03-19 15:49:47 +01:00
// Is the contact the owner? Then fetch the private key
if ( ! $contact [ 'self' ] OR ( $contact [ 'uid' ] == 0 )) {
logger ( " No owner post, so not storing signature " , LOGGER_DEBUG );
return false ;
}
$r = q ( " SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1 " , intval ( $contact [ 'uid' ]));
if ( ! $r )
return false ;
$contact [ " uprvkey " ] = $r [ 0 ][ 'prvkey' ];
$r = q ( " SELECT * FROM `item` WHERE `id` = %d LIMIT 1 " , intval ( $post_id ));
if ( ! $r )
return false ;
if ( ! in_array ( $r [ 0 ][ " verb " ], array ( ACTIVITY_LIKE , ACTIVITY_DISLIKE )))
return false ;
$message = self :: construct_like ( $r [ 0 ], $contact );
$message [ " author_signature " ] = self :: signature ( $contact , $message );
// In the future we will store the signature more flexible to support new fields.
// Right now we cannot change this since old Friendica versions (prior to 3.5) can only handle this format.
// (We are transmitting this data here via DFRN)
$signed_text = $message [ " positive " ] . " ; " . $message [ " guid " ] . " ; " . $message [ " target_type " ] . " ; " .
$message [ " parent_guid " ] . " ; " . $message [ " diaspora_handle " ];
q ( " INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s') " ,
intval ( $post_id ),
dbesc ( $signed_text ),
dbesc ( $message [ " author_signature " ]),
dbesc ( $message [ " diaspora_handle " ])
);
// This here will replace the lines above, once Diaspora changed its protocol
//q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
// intval($message_id),
// dbesc(json_encode($message))
//);
logger ( 'Stored diaspora like signature' );
return true ;
}
/**
* @ brief Stores the signature for comments that are created on our system
*
* @ param array $item The item array of the comment
* @ param array $contact The contact array of the item owner
* @ param string $uprvkey The private key of the sender
* @ param int $message_id The message id of the comment
*
* @ return bool Success
*/
2016-03-23 22:12:08 +01:00
public static function store_comment_signature ( $item , $contact , $uprvkey , $message_id ) {
2016-03-19 15:49:47 +01:00
if ( $uprvkey == " " ) {
logger ( 'No private key, so not storing comment signature' , LOGGER_DEBUG );
return false ;
}
$contact [ " uprvkey " ] = $uprvkey ;
$message = self :: construct_comment ( $item , $contact );
$message [ " author_signature " ] = self :: signature ( $contact , $message );
// In the future we will store the signature more flexible to support new fields.
// Right now we cannot change this since old Friendica versions (prior to 3.5) can only handle this format.
// (We are transmitting this data here via DFRN)
$signed_text = $message [ " guid " ] . " ; " . $message [ " parent_guid " ] . " ; " .
$message [ " text " ] . " ; " . $message [ " diaspora_handle " ];
q ( " INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s') " ,
intval ( $message_id ),
dbesc ( $signed_text ),
dbesc ( $message [ " author_signature " ]),
dbesc ( $message [ " diaspora_handle " ])
);
// This here will replace the lines above, once Diaspora changed its protocol
//q("INSERT INTO `sign` (`iid`,`signed_text`) VALUES (%d,'%s')",
// intval($message_id),
// dbesc(json_encode($message))
//);
logger ( 'Stored diaspora comment signature' );
return true ;
}
2015-08-09 20:39:11 +02:00
}
2016-03-14 23:11:43 +01:00
?>