Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2803 lines
88 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. require_once('include/crypto.php');
  3. require_once('include/items.php');
  4. require_once('include/bb2diaspora.php');
  5. require_once('include/contact_selectors.php');
  6. require_once('include/queue_fn.php');
  7. require_once('include/lock.php');
  8. function diaspora_dispatch_public($msg) {
  9. $enabled = intval(get_config('system','diaspora_enabled'));
  10. if(! $enabled) {
  11. logger('mod-diaspora: disabled');
  12. return;
  13. }
  14. $r = q("SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
  15. ( SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s' )
  16. AND `account_expired` = 0 AND `account_removed` = 0 ",
  17. dbesc(NETWORK_DIASPORA),
  18. dbesc($msg['author'])
  19. );
  20. if(count($r)) {
  21. foreach($r as $rr) {
  22. logger('diaspora_public: delivering to: ' . $rr['username']);
  23. diaspora_dispatch($rr,$msg);
  24. }
  25. }
  26. else
  27. logger('diaspora_public: no subscribers');
  28. }
  29. function diaspora_dispatch($importer,$msg,$attempt=1) {
  30. $ret = 0;
  31. $enabled = intval(get_config('system','diaspora_enabled'));
  32. if(! $enabled) {
  33. logger('mod-diaspora: disabled');
  34. return;
  35. }
  36. // php doesn't like dashes in variable names
  37. $msg['message'] = str_replace(
  38. array('<activity_streams-photo>','</activity_streams-photo>'),
  39. array('<asphoto>','</asphoto>'),
  40. $msg['message']);
  41. $parsed_xml = parse_xml_string($msg['message'],false);
  42. $xmlbase = $parsed_xml->post;
  43. logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DEBUG);
  44. if($xmlbase->request) {
  45. $ret = diaspora_request($importer,$xmlbase->request);
  46. }
  47. elseif($xmlbase->status_message) {
  48. $ret = diaspora_post($importer,$xmlbase->status_message,$msg);
  49. }
  50. elseif($xmlbase->profile) {
  51. $ret = diaspora_profile($importer,$xmlbase->profile,$msg);
  52. }
  53. elseif($xmlbase->comment) {
  54. $ret = diaspora_comment($importer,$xmlbase->comment,$msg);
  55. }
  56. elseif($xmlbase->like) {
  57. $ret = diaspora_like($importer,$xmlbase->like,$msg);
  58. }
  59. elseif($xmlbase->asphoto) {
  60. $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg);
  61. }
  62. elseif($xmlbase->reshare) {
  63. $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg);
  64. }
  65. elseif($xmlbase->retraction) {
  66. $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg);
  67. }
  68. elseif($xmlbase->signed_retraction) {
  69. $ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg);
  70. }
  71. elseif($xmlbase->relayable_retraction) {
  72. $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg);
  73. }
  74. elseif($xmlbase->photo) {
  75. $ret = diaspora_photo($importer,$xmlbase->photo,$msg,$attempt);
  76. }
  77. elseif($xmlbase->conversation) {
  78. $ret = diaspora_conversation($importer,$xmlbase->conversation,$msg);
  79. }
  80. elseif($xmlbase->message) {
  81. $ret = diaspora_message($importer,$xmlbase->message,$msg);
  82. }
  83. else {
  84. logger('diaspora_dispatch: unknown message type: ' . print_r($xmlbase,true));
  85. }
  86. return $ret;
  87. }
  88. function diaspora_handle_from_contact($contact_id) {
  89. $handle = False;
  90. logger("diaspora_handle_from_contact: contact id is " . $contact_id, LOGGER_DEBUG);
  91. $r = q("SELECT network, addr, self, url, nick FROM contact WHERE id = %d",
  92. intval($contact_id)
  93. );
  94. if($r) {
  95. $contact = $r[0];
  96. logger("diaspora_handle_from_contact: contact 'self' = " . $contact['self'] . " 'url' = " . $contact['url'], LOGGER_DEBUG);
  97. if($contact['network'] === NETWORK_DIASPORA) {
  98. $handle = $contact['addr'];
  99. // logger("diaspora_handle_from_contact: contact id is a Diaspora person, handle = " . $handle, LOGGER_DEBUG);
  100. }
  101. elseif(($contact['network'] === NETWORK_DFRN) || ($contact['self'] == 1)) {
  102. $baseurl_start = strpos($contact['url'],'://') + 3;
  103. $baseurl_length = strpos($contact['url'],'/profile') - $baseurl_start; // allows installations in a subdirectory--not sure how Diaspora will handle
  104. $baseurl = substr($contact['url'], $baseurl_start, $baseurl_length);
  105. $handle = $contact['nick'] . '@' . $baseurl;
  106. // logger("diaspora_handle_from_contact: contact id is a DFRN person, handle = " . $handle, LOGGER_DEBUG);
  107. }
  108. }
  109. return $handle;
  110. }
  111. function diaspora_get_contact_by_handle($uid,$handle) {
  112. $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND `uid` = %d AND `addr` = '%s' LIMIT 1",
  113. dbesc(NETWORK_DIASPORA),
  114. intval($uid),
  115. dbesc($handle)
  116. );
  117. if($r && count($r))
  118. return $r[0];
  119. $handle_parts = explode("@", $handle);
  120. $nurl_sql = '%%://' . $handle_parts[1] . '%%/profile/' . $handle_parts[0];
  121. $r = q("SELECT * FROM contact WHERE network = '%s' AND uid = %d AND nurl LIKE '%s' LIMIT 1",
  122. dbesc(NETWORK_DFRN),
  123. intval($uid),
  124. dbesc($nurl_sql)
  125. );
  126. if($r && count($r))
  127. return $r[0];
  128. return false;
  129. }
  130. function find_diaspora_person_by_handle($handle) {
  131. $person = false;
  132. $update = false;
  133. $got_lock = false;
  134. $endlessloop = 0;
  135. $maxloops = 10;
  136. do {
  137. $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1",
  138. dbesc(NETWORK_DIASPORA),
  139. dbesc($handle)
  140. );
  141. if(count($r)) {
  142. $person = $r[0];
  143. logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DEBUG);
  144. // update record occasionally so it doesn't get stale
  145. $d = strtotime($person['updated'] . ' +00:00');
  146. if($d < strtotime('now - 14 days'))
  147. $update = true;
  148. }
  149. // FETCHING PERSON INFORMATION FROM REMOTE SERVER
  150. //
  151. // If the person isn't in our 'fcontact' table, or if he/she is but
  152. // his/her information hasn't been updated for more than 14 days, then
  153. // we want to fetch the person's information from the remote server.
  154. //
  155. // Note that $person isn't changed by this block of code unless the
  156. // person's information has been successfully fetched from the remote
  157. // server. So if $person was 'false' to begin with (because he/she wasn't
  158. // in the local cache), it'll stay false, and if $person held the local
  159. // cache information to begin with, it'll keep that information. That way
  160. // if there's a problem with the remote fetch, we can at least use our
  161. // cached information--it's better than nothing.
  162. if((! $person) || ($update)) {
  163. // Lock the function to prevent race conditions if multiple items
  164. // come in at the same time from a person who doesn't exist in
  165. // fcontact
  166. //
  167. // Don't loop forever. On the last loop, try to create the contact
  168. // whether the function is locked or not. Maybe the locking thread
  169. // has died or something. At any rate, a duplicate in 'fcontact'
  170. // is a much smaller problem than a deadlocked thread
  171. $got_lock = lock_function('find_diaspora_person_by_handle', false);
  172. if(($endlessloop + 1) >= $maxloops)
  173. $got_lock = true;
  174. if($got_lock) {
  175. logger('find_diaspora_person_by_handle: create or refresh', LOGGER_DEBUG);
  176. require_once('include/Scrape.php');
  177. $r = probe_url($handle, PROBE_DIASPORA);
  178. // Note that Friendica contacts can return a "Diaspora person"
  179. // if Diaspora connectivity is enabled on their server
  180. if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) {
  181. add_fcontact($r,$update);
  182. $person = ($r);
  183. }
  184. unlock_function('find_diaspora_person_by_handle');
  185. }
  186. else {
  187. logger('find_diaspora_person_by_handle: couldn\'t lock function', LOGGER_DEBUG);
  188. if(! $person)
  189. block_on_function_lock('find_diaspora_person_by_handle');
  190. }
  191. }
  192. } while((! $person) && (! $got_lock) && (++$endlessloop < $maxloops));
  193. // We need to try again if the person wasn't in 'fcontact' but the function was locked.
  194. // The fact that the function was locked may mean that another process was creating the
  195. // person's record. It could also mean another process was creating or updating an unrelated
  196. // person.
  197. //
  198. // At any rate, we need to keep trying until we've either got the person or had a chance to
  199. // try to fetch his/her remote information. But we don't want to block on locking the
  200. // function, because if the other process is creating the record, then when we acquire the lock
  201. // we'll dive right into creating another, duplicate record. We DO want to at least wait
  202. // until the lock is released, so we don't flood the database with requests.
  203. //
  204. // If the person was in the 'fcontact' table, don't try again. It's not worth the time, since
  205. // we do have some information for the person
  206. return $person;
  207. }
  208. function get_diaspora_key($uri) {
  209. logger('Fetching diaspora key for: ' . $uri);
  210. $r = find_diaspora_person_by_handle($uri);
  211. if($r)
  212. return $r['pubkey'];
  213. return '';
  214. }
  215. function diaspora_pubmsg_build($msg,$user,$contact,$prvkey,$pubkey) {
  216. $a = get_app();
  217. logger('diaspora_pubmsg_build: ' . $msg, LOGGER_DATA);
  218. $handle = $user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
  219. // $b64_data = base64_encode($msg);
  220. // $b64url_data = base64url_encode($b64_data);
  221. $b64url_data = base64url_encode($msg);
  222. $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data);
  223. $type = 'application/xml';
  224. $encoding = 'base64url';
  225. $alg = 'RSA-SHA256';
  226. $signable_data = $data . '.' . base64url_encode($type) . '.'
  227. . base64url_encode($encoding) . '.' . base64url_encode($alg) ;
  228. $signature = rsa_sign($signable_data,$prvkey);
  229. $sig = base64url_encode($signature);
  230. $magic_env = <<< EOT
  231. <?xml version='1.0' encoding='UTF-8'?>
  232. <diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env" >
  233. <header>
  234. <author_id>$handle</author_id>
  235. </header>
  236. <me:env>
  237. <me:encoding>base64url</me:encoding>
  238. <me:alg>RSA-SHA256</me:alg>
  239. <me:data type="application/xml">$data</me:data>
  240. <me:sig>$sig</me:sig>
  241. </me:env>
  242. </diaspora>
  243. EOT;
  244. logger('diaspora_pubmsg_build: magic_env: ' . $magic_env, LOGGER_DATA);
  245. return $magic_env;
  246. }
  247. function diaspora_msg_build($msg,$user,$contact,$prvkey,$pubkey,$public = false) {
  248. $a = get_app();
  249. if($public)
  250. return diaspora_pubmsg_build($msg,$user,$contact,$prvkey,$pubkey);
  251. logger('diaspora_msg_build: ' . $msg, LOGGER_DATA);
  252. // without a public key nothing will work
  253. if(! $pubkey) {
  254. logger('diaspora_msg_build: pubkey missing: contact id: ' . $contact['id']);
  255. return '';
  256. }
  257. $inner_aes_key = random_string(32);
  258. $b_inner_aes_key = base64_encode($inner_aes_key);
  259. $inner_iv = random_string(16);
  260. $b_inner_iv = base64_encode($inner_iv);
  261. $outer_aes_key = random_string(32);
  262. $b_outer_aes_key = base64_encode($outer_aes_key);
  263. $outer_iv = random_string(16);
  264. $b_outer_iv = base64_encode($outer_iv);
  265. $handle = $user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
  266. $padded_data = pkcs5_pad($msg,16);
  267. $inner_encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $padded_data, MCRYPT_MODE_CBC, $inner_iv);
  268. $b64_data = base64_encode($inner_encrypted);
  269. $b64url_data = base64url_encode($b64_data);
  270. $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data);
  271. $type = 'application/xml';
  272. $encoding = 'base64url';
  273. $alg = 'RSA-SHA256';
  274. $signable_data = $data . '.' . base64url_encode($type) . '.'
  275. . base64url_encode($encoding) . '.' . base64url_encode($alg) ;
  276. $signature = rsa_sign($signable_data,$prvkey);
  277. $sig = base64url_encode($signature);
  278. $decrypted_header = <<< EOT
  279. <decrypted_header>
  280. <iv>$b_inner_iv</iv>
  281. <aes_key>$b_inner_aes_key</aes_key>
  282. <author_id>$handle</author_id>
  283. </decrypted_header>
  284. EOT;
  285. $decrypted_header = pkcs5_pad($decrypted_header,16);
  286. $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $outer_aes_key, $decrypted_header, MCRYPT_MODE_CBC, $outer_iv);
  287. $outer_json = json_encode(array('iv' => $b_outer_iv,'key' => $b_outer_aes_key));
  288. $encrypted_outer_key_bundle = '';
  289. openssl_public_encrypt($outer_json,$encrypted_outer_key_bundle,$pubkey);
  290. $b64_encrypted_outer_key_bundle = base64_encode($encrypted_outer_key_bundle);
  291. logger('outer_bundle: ' . $b64_encrypted_outer_key_bundle . ' key: ' . $pubkey, LOGGER_DATA);
  292. $encrypted_header_json_object = json_encode(array('aes_key' => base64_encode($encrypted_outer_key_bundle),
  293. 'ciphertext' => base64_encode($ciphertext)));
  294. $cipher_json = base64_encode($encrypted_header_json_object);
  295. $encrypted_header = '<encrypted_header>' . $cipher_json . '</encrypted_header>';
  296. $magic_env = <<< EOT
  297. <?xml version='1.0' encoding='UTF-8'?>
  298. <diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env" >
  299. $encrypted_header
  300. <me:env>
  301. <me:encoding>base64url</me:encoding>
  302. <me:alg>RSA-SHA256</me:alg>
  303. <me:data type="application/xml">$data</me:data>
  304. <me:sig>$sig</me:sig>
  305. </me:env>
  306. </diaspora>
  307. EOT;
  308. logger('diaspora_msg_build: magic_env: ' . $magic_env, LOGGER_DATA);
  309. return $magic_env;
  310. }
  311. /**
  312. *
  313. * diaspora_decode($importer,$xml)
  314. * array $importer -> from user table
  315. * string $xml -> urldecoded Diaspora salmon
  316. *
  317. * Returns array
  318. * 'message' -> decoded Diaspora XML message
  319. * 'author' -> author diaspora handle
  320. * 'key' -> author public key (converted to pkcs#8)
  321. *
  322. * Author and key are used elsewhere to save a lookup for verifying replies and likes
  323. */
  324. function diaspora_decode($importer,$xml) {
  325. $public = false;
  326. $basedom = parse_xml_string($xml);
  327. $children = $basedom->children('https://joindiaspora.com/protocol');
  328. if($children->header) {
  329. $public = true;
  330. $author_link = str_replace('acct:','',$children->header->author_id);
  331. }
  332. else {
  333. $encrypted_header = json_decode(base64_decode($children->encrypted_header));
  334. $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
  335. $ciphertext = base64_decode($encrypted_header->ciphertext);
  336. $outer_key_bundle = '';
  337. openssl_private_decrypt($encrypted_aes_key_bundle,$outer_key_bundle,$importer['prvkey']);
  338. $j_outer_key_bundle = json_decode($outer_key_bundle);
  339. $outer_iv = base64_decode($j_outer_key_bundle->iv);
  340. $outer_key = base64_decode($j_outer_key_bundle->key);
  341. $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv);
  342. $decrypted = pkcs5_unpad($decrypted);
  343. /**
  344. * $decrypted now contains something like
  345. *
  346. * <decrypted_header>
  347. * <iv>8e+G2+ET8l5BPuW0sVTnQw==</iv>
  348. * <aes_key>UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU=</aes_key>
  349. ***** OBSOLETE
  350. * <author>
  351. * <name>Ryan Hughes</name>
  352. * <uri>acct:galaxor@diaspora.pirateship.org</uri>
  353. * </author>
  354. ***** CURRENT
  355. * <author_id>galaxor@diaspora.priateship.org</author_id>
  356. ***** END DIFFS
  357. * </decrypted_header>
  358. */
  359. logger('decrypted: ' . $decrypted, LOGGER_DEBUG);
  360. $idom = parse_xml_string($decrypted,false);
  361. $inner_iv = base64_decode($idom->iv);
  362. $inner_aes_key = base64_decode($idom->aes_key);
  363. $author_link = str_replace('acct:','',$idom->author_id);
  364. }
  365. $dom = $basedom->children(NAMESPACE_SALMON_ME);
  366. // figure out where in the DOM tree our data is hiding
  367. if($dom->provenance->data)
  368. $base = $dom->provenance;
  369. elseif($dom->env->data)
  370. $base = $dom->env;
  371. elseif($dom->data)
  372. $base = $dom;
  373. if(! $base) {
  374. logger('mod-diaspora: unable to locate salmon data in xml ');
  375. http_status_exit(400);
  376. }
  377. // Stash the signature away for now. We have to find their key or it won't be good for anything.
  378. $signature = base64url_decode($base->sig);
  379. // unpack the data
  380. // strip whitespace so our data element will return to one big base64 blob
  381. $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
  382. // stash away some other stuff for later
  383. $type = $base->data[0]->attributes()->type[0];
  384. $keyhash = $base->sig[0]->attributes()->keyhash[0];
  385. $encoding = $base->encoding;
  386. $alg = $base->alg;
  387. $signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg);
  388. // decode the data
  389. $data = base64url_decode($data);
  390. if($public) {
  391. $inner_decrypted = $data;
  392. }
  393. else {
  394. // Decode the encrypted blob
  395. $inner_encrypted = base64_decode($data);
  396. $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv);
  397. $inner_decrypted = pkcs5_unpad($inner_decrypted);
  398. }
  399. if(! $author_link) {
  400. logger('mod-diaspora: Could not retrieve author URI.');
  401. http_status_exit(400);
  402. }
  403. // Once we have the author URI, go to the web and try to find their public key
  404. // (first this will look it up locally if it is in the fcontact cache)
  405. // This will also convert diaspora public key from pkcs#1 to pkcs#8
  406. logger('mod-diaspora: Fetching key for ' . $author_link );
  407. $key = get_diaspora_key($author_link);
  408. if(! $key) {
  409. logger('mod-diaspora: Could not retrieve author key.');
  410. http_status_exit(400);
  411. }
  412. $verify = rsa_verify($signed_data,$signature,$key);
  413. if(! $verify) {
  414. logger('mod-diaspora: Message did not verify. Discarding.');
  415. http_status_exit(400);
  416. }
  417. logger('mod-diaspora: Message verified.');
  418. return array('message' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
  419. }
  420. function diaspora_request($importer,$xml) {
  421. $a = get_app();
  422. $sender_handle = unxmlify($xml->sender_handle);
  423. $recipient_handle = unxmlify($xml->recipient_handle);
  424. if(! $sender_handle || ! $recipient_handle)
  425. return;
  426. $contact = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
  427. if($contact) {
  428. // perhaps we were already sharing with this person. Now they're sharing with us.
  429. // That makes us friends.
  430. if($contact['rel'] == CONTACT_IS_FOLLOWER && $importer['page-flags'] != PAGE_COMMUNITY) {
  431. q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d",
  432. intval(CONTACT_IS_FRIEND),
  433. intval($contact['id']),
  434. intval($importer['uid'])
  435. );
  436. }
  437. // send notification
  438. $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1",
  439. intval($importer['uid'])
  440. );
  441. if((count($r)) && (! $r[0]['hide-friends']) && (! $contact['hidden'])) {
  442. require_once('include/items.php');
  443. $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
  444. intval($importer['uid'])
  445. );
  446. // they are not CONTACT_IS_FOLLOWER anymore but that's what we have in the array
  447. if(count($self) && $contact['rel'] == CONTACT_IS_FOLLOWER) {
  448. $arr = array();
  449. $arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $importer['uid']);
  450. $arr['uid'] = $importer['uid'];
  451. $arr['contact-id'] = $self[0]['id'];
  452. $arr['wall'] = 1;
  453. $arr['type'] = 'wall';
  454. $arr['gravity'] = 0;
  455. $arr['origin'] = 1;
  456. $arr['author-name'] = $arr['owner-name'] = $self[0]['name'];
  457. $arr['author-link'] = $arr['owner-link'] = $self[0]['url'];
  458. $arr['author-avatar'] = $arr['owner-avatar'] = $self[0]['thumb'];
  459. $arr['verb'] = ACTIVITY_FRIEND;
  460. $arr['object-type'] = ACTIVITY_OBJ_PERSON;
  461. $A = '[url=' . $self[0]['url'] . ']' . $self[0]['name'] . '[/url]';
  462. $B = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
  463. $BPhoto = '[url=' . $contact['url'] . ']' . '[img]' . $contact['thumb'] . '[/img][/url]';
  464. $arr['body'] = sprintf( t('%1$s is now friends with %2$s'), $A, $B)."\n\n\n".$Bphoto;
  465. $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $contact['name'] . '</title>'
  466. . '<id>' . $contact['url'] . '/' . $contact['name'] . '</id>';
  467. $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $contact['url'] . '" />' . "\n");
  468. $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $contact['thumb'] . '" />' . "\n");
  469. $arr['object'] .= '</link></object>' . "\n";
  470. $arr['last-child'] = 1;
  471. $arr['allow_cid'] = $user[0]['allow_cid'];
  472. $arr['allow_gid'] = $user[0]['allow_gid'];
  473. $arr['deny_cid'] = $user[0]['deny_cid'];
  474. $arr['deny_gid'] = $user[0]['deny_gid'];
  475. $i = item_store($arr);
  476. if($i)
  477. proc_run('php',"include/notifier.php","activity","$i");
  478. }
  479. }
  480. return;
  481. }
  482. $ret = find_diaspora_person_by_handle($sender_handle);
  483. if((! count($ret)) || ($ret['network'] != NETWORK_DIASPORA)) {
  484. logger('diaspora_request: Cannot resolve diaspora handle ' . $sender_handle . ' for ' . $recipient_handle);
  485. return;
  486. }
  487. $batch = (($ret['batch']) ? $ret['batch'] : implode('/', array_slice(explode('/',$ret['url']),0,3)) . '/receive/public');
  488. $r = q("INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`)
  489. VALUES ( %d, '%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d) ",
  490. intval($importer['uid']),
  491. dbesc($ret['network']),
  492. dbesc($ret['addr']),
  493. datetime_convert(),
  494. dbesc($ret['url']),
  495. dbesc(normalise_link($ret[