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.
 
 
 
 
 
 

1046 lines
32 KiB

  1. <?php
  2. require_once("boot.php");
  3. require_once('include/queue_fn.php');
  4. require_once('include/html2plain.php');
  5. /*
  6. * This file was at one time responsible for doing all deliveries, but this caused
  7. * big problems on shared hosting systems, where the process might get killed by the
  8. * hosting provider and nothing would get delivered.
  9. * It now only delivers one message under certain cases, and invokes a queued
  10. * delivery mechanism (include/deliver.php) to deliver individual contacts at
  11. * controlled intervals.
  12. * This has a much better chance of surviving random processes getting killed
  13. * by the hosting provider.
  14. * A lot of this code is duplicated in include/deliver.php until we have time to go back
  15. * and re-structure the delivery procedure based on the obstacles that have been thrown at
  16. * us by hosting providers.
  17. */
  18. /*
  19. * The notifier is typically called with:
  20. *
  21. * proc_run('php', "include/notifier.php", COMMAND, ITEM_ID);
  22. *
  23. * where COMMAND is one of the following:
  24. *
  25. * activity (in diaspora.php, dfrn_confirm.php, profiles.php)
  26. * comment-import (in diaspora.php, items.php)
  27. * comment-new (in item.php)
  28. * drop (in diaspora.php, items.php, photos.php)
  29. * edit_post (in item.php)
  30. * event (in events.php)
  31. * expire (in items.php)
  32. * like (in like.php, poke.php)
  33. * mail (in message.php)
  34. * suggest (in fsuggest.php)
  35. * tag (in photos.php, poke.php, tagger.php)
  36. * tgroup (in items.php)
  37. * wall-new (in photos.php, item.php)
  38. * removeme (in Contact.php)
  39. * relocate (in uimport.php)
  40. *
  41. * and ITEM_ID is the id of the item in the database that needs to be sent to others.
  42. */
  43. function notifier_run(&$argv, &$argc){
  44. global $a, $db;
  45. if(is_null($a)){
  46. $a = new App;
  47. }
  48. if(is_null($db)) {
  49. @include(".htconfig.php");
  50. require_once("include/dba.php");
  51. $db = new dba($db_host, $db_user, $db_pass, $db_data);
  52. unset($db_host, $db_user, $db_pass, $db_data);
  53. }
  54. require_once("include/session.php");
  55. require_once("include/datetime.php");
  56. require_once('include/items.php');
  57. require_once('include/bbcode.php');
  58. require_once('include/email.php');
  59. load_config('config');
  60. load_config('system');
  61. load_hooks();
  62. if($argc < 3)
  63. return;
  64. $a->set_baseurl(get_config('system','url'));
  65. logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
  66. $cmd = $argv[1];
  67. switch($cmd) {
  68. case 'mail':
  69. default:
  70. $item_id = intval($argv[2]);
  71. if(! $item_id){
  72. return;
  73. }
  74. break;
  75. }
  76. $expire = false;
  77. $mail = false;
  78. $fsuggest = false;
  79. $relocate = false;
  80. $top_level = false;
  81. $recipients = array();
  82. $url_recipients = array();
  83. $normal_mode = true;
  84. if($cmd === 'mail') {
  85. $normal_mode = false;
  86. $mail = true;
  87. $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
  88. intval($item_id)
  89. );
  90. if(! count($message)){
  91. return;
  92. }
  93. $uid = $message[0]['uid'];
  94. $recipients[] = $message[0]['contact-id'];
  95. $item = $message[0];
  96. }
  97. elseif($cmd === 'expire') {
  98. $normal_mode = false;
  99. $expire = true;
  100. $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
  101. AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 10 MINUTE",
  102. intval($item_id)
  103. );
  104. $uid = $item_id;
  105. $item_id = 0;
  106. if(! count($items))
  107. return;
  108. }
  109. elseif($cmd === 'suggest') {
  110. $normal_mode = false;
  111. $fsuggest = true;
  112. $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
  113. intval($item_id)
  114. );
  115. if(! count($suggest))
  116. return;
  117. $uid = $suggest[0]['uid'];
  118. $recipients[] = $suggest[0]['cid'];
  119. $item = $suggest[0];
  120. } elseif($cmd === 'removeme') {
  121. $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($item_id));
  122. if (! $r)
  123. return;
  124. $user = $r[0];
  125. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($item_id));
  126. if (! $r)
  127. return;
  128. $self = $r[0];
  129. $r = q("SELECT * FROM `contact` WHERE `self` = 0 AND `uid` = %d", intval($item_id));
  130. if(! $r)
  131. return;
  132. require_once('include/Contact.php');
  133. foreach($r as $contact) {
  134. terminate_friendship($user, $self, $contact);
  135. }
  136. return;
  137. } elseif($cmd === 'relocate') {
  138. $normal_mode = false;
  139. $relocate = true;
  140. $uid = $item_id;
  141. } else {
  142. // find ancestors
  143. $r = q("SELECT * FROM `item` WHERE `id` = %d and visible = 1 and moderated = 0 LIMIT 1",
  144. intval($item_id)
  145. );
  146. if((! count($r)) || (! intval($r[0]['parent']))) {
  147. return;
  148. }
  149. $target_item = $r[0];
  150. $parent_id = intval($r[0]['parent']);
  151. $uid = $r[0]['uid'];
  152. $updated = $r[0]['edited'];
  153. // POSSIBLE CLEANUP --> The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up
  154. if(! $parent_id)
  155. return;
  156. $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
  157. FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d and visible = 1 and moderated = 0 ORDER BY `id` ASC",
  158. intval($parent_id)
  159. );
  160. if(! count($items)) {
  161. return;
  162. }
  163. // avoid race condition with deleting entries
  164. if($items[0]['deleted']) {
  165. foreach($items as $item)
  166. $item['deleted'] = 1;
  167. }
  168. if((count($items) == 1) && ($items[0]['id'] === $target_item['id']) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
  169. logger('notifier: top level post');
  170. $top_level = true;
  171. }
  172. }
  173. $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
  174. `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
  175. `user`.`page-flags`, `user`.`prvnets`
  176. FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
  177. WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
  178. intval($uid)
  179. );
  180. if(! count($r))
  181. return;
  182. $owner = $r[0];
  183. $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false);
  184. $hub = get_config('system','huburl');
  185. // If this is a public conversation, notify the feed hub
  186. $public_message = true;
  187. // Do a PuSH
  188. $push_notify = false;
  189. // fill this in with a single salmon slap if applicable
  190. $slap = '';
  191. // List of OStatus receiptians of follow up messages
  192. $ostatus_recip_str = "";
  193. if(! ($mail || $fsuggest || $relocate)) {
  194. require_once('include/group.php');
  195. $parent = $items[0];
  196. // This is IMPORTANT!!!!
  197. // We will only send a "notify owner to relay" or followup message if the referenced post
  198. // originated on our system by virtue of having our hostname somewhere
  199. // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
  200. // if $parent['wall'] == 1 we will already have the parent message in our array
  201. // and we will relay the whole lot.
  202. // expire sends an entire group of expire messages and cannot be forwarded.
  203. // However the conversation owner will be a part of the conversation and will
  204. // be notified during this run.
  205. // Other DFRN conversation members will be alerted during polled updates.
  206. // Diaspora members currently are not notified of expirations, and other networks have
  207. // either limited or no ability to process deletions. We should at least fix Diaspora
  208. // by stringing togther an array of retractions and sending them onward.
  209. $localhost = str_replace('www.','',$a->get_hostname());
  210. if(strpos($localhost,':'))
  211. $localhost = substr($localhost,0,strpos($localhost,':'));
  212. /**
  213. *
  214. * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes
  215. * have been known to cause runaway conditions which affected several servers, along with
  216. * permissions issues.
  217. *
  218. */
  219. $relay_to_owner = false;
  220. if((! $top_level) && ($parent['wall'] == 0) && (! $expire) && (stristr($target_item['uri'],$localhost))) {
  221. $relay_to_owner = true;
  222. }
  223. if(($cmd === 'uplink') && (intval($parent['forum_mode']) == 1) && (! $top_level)) {
  224. $relay_to_owner = true;
  225. }
  226. // until the 'origin' flag has been in use for several months
  227. // we will just use it as a fallback test
  228. // later we will be able to use it as the primary test of whether or not to relay.
  229. if(! $target_item['origin'])
  230. $relay_to_owner = false;
  231. if($parent['origin'])
  232. $relay_to_owner = false;
  233. if($relay_to_owner) {
  234. logger('notifier: followup', LOGGER_DEBUG);
  235. // local followup to remote post
  236. $followup = true;
  237. $public_message = false; // not public
  238. $conversant_str = dbesc($parent['contact-id']);
  239. $recipients = array($parent['contact-id']);
  240. if ($parent['network'] == NETWORK_OSTATUS) {
  241. logger('Parent is OStatus', LOGGER_DEBUG);
  242. $push_notify = true;
  243. /* $ostatus_recipients = array();
  244. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'", intval($uid), dbesc(NETWORK_OSTATUS));
  245. if(count($r)) {
  246. foreach($r as $rr)
  247. $ostatus_recipients[] = $rr['id'];
  248. $ostatus_recip_str = ", ".implode(', ', $ostatus_recipients);
  249. }
  250. */
  251. // Check if the recipient isn't in your contact list
  252. $r = q("SELECT `url` FROM `contact` WHERE `id` = %d", $parent['contact-id']);
  253. if (count($r)) {
  254. $url_recipients = array();
  255. $thrparent = q("SELECT `author-link` FROM `item` WHERE `uri` = '%s'", dbesc($target_item["thr-parent"]));
  256. if (count($thrparent) AND (normalise_link($r[0]["url"]) != normalise_link($thrparent[0]["author-link"]))) {
  257. require_once("include/Scrape.php");
  258. $probed_contact = probe_url($thrparent[0]["author-link"]);
  259. if ($probed_contact["notify"] != "") {
  260. logger('scrape data for slapper: '.print_r($probed_contact, true));
  261. $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
  262. }
  263. }
  264. }
  265. logger("url_recipients".print_r($url_recipients,true));
  266. }
  267. } else {
  268. $followup = false;
  269. // don't send deletions onward for other people's stuff
  270. if($target_item['deleted'] && (! intval($target_item['wall']))) {
  271. logger('notifier: ignoring delete notification for non-wall item');
  272. return;
  273. }
  274. if((strlen($parent['allow_cid']))
  275. || (strlen($parent['allow_gid']))
  276. || (strlen($parent['deny_cid']))
  277. || (strlen($parent['deny_gid']))) {
  278. $public_message = false; // private recipients, not public
  279. }
  280. $allow_people = expand_acl($parent['allow_cid']);
  281. $allow_groups = expand_groups(expand_acl($parent['allow_gid']),true);
  282. $deny_people = expand_acl($parent['deny_cid']);
  283. $deny_groups = expand_groups(expand_acl($parent['deny_gid']));
  284. // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing
  285. // a delivery fork. private groups (forum_mode == 2) do not uplink
  286. if((intval($parent['forum_mode']) == 1) && (! $top_level) && ($cmd !== 'uplink')) {
  287. proc_run('php','include/notifier.php','uplink',$item_id);
  288. }
  289. $conversants = array();
  290. foreach($items as $item) {
  291. $recipients[] = $item['contact-id'];
  292. $conversants[] = $item['contact-id'];
  293. // pull out additional tagged people to notify (if public message)
  294. if($public_message && strlen($item['inform'])) {
  295. $people = explode(',',$item['inform']);
  296. foreach($people as $person) {
  297. if(substr($person,0,4) === 'cid:') {
  298. $recipients[] = intval(substr($person,4));
  299. $conversants[] = intval(substr($person,4));
  300. }
  301. else {
  302. $url_recipients[] = substr($person,4);
  303. }
  304. }
  305. }
  306. }
  307. logger('notifier: url_recipients' . print_r($url_recipients,true));
  308. $conversants = array_unique($conversants);
  309. $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups));
  310. $deny = array_unique(array_merge($deny_people,$deny_groups));
  311. $recipients = array_diff($recipients,$deny);
  312. $conversant_str = dbesc(implode(', ',$conversants));
  313. }
  314. $r = q("SELECT * FROM `contact` WHERE `id` IN ( $conversant_str ) AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0");
  315. if(count($r))
  316. $contacts = $r;
  317. }
  318. $feed_template = get_markup_template('atom_feed.tpl');
  319. $mail_template = get_markup_template('atom_mail.tpl');
  320. $atom = '';
  321. $slaps = array();
  322. $hubxml = feed_hublinks();
  323. $birthday = feed_birthday($owner['uid'],$owner['timezone']);
  324. if(strlen($birthday))
  325. $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>';
  326. $atom .= replace_macros($feed_template, array(
  327. '$version' => xmlify(FRIENDICA_VERSION),
  328. '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname'] ),
  329. '$feed_title' => xmlify($owner['name']),
  330. '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00' , ATOM_TIME)) ,
  331. '$hub' => $hubxml,
  332. '$salmon' => '', // private feed, we don't use salmon here
  333. '$name' => xmlify($owner['name']),
  334. '$profile_page' => xmlify($owner['url']),
  335. '$photo' => xmlify($owner['photo']),
  336. '$thumb' => xmlify($owner['thumb']),
  337. '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) ,
  338. '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) ,
  339. '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) ,
  340. '$birthday' => $birthday,
  341. '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '<dfrn:community>1</dfrn:community>' : '')
  342. ));
  343. if($mail) {
  344. $public_message = false; // mail is not public
  345. $body = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']);
  346. $atom .= replace_macros($mail_template, array(
  347. '$name' => xmlify($owner['name']),
  348. '$profile_page' => xmlify($owner['url']),
  349. '$thumb' => xmlify($owner['thumb']),
  350. '$item_id' => xmlify($item['uri']),
  351. '$subject' => xmlify($item['title']),
  352. '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)),
  353. '$content' => xmlify($body),
  354. '$parent_id' => xmlify($item['parent-uri'])
  355. ));
  356. } elseif($fsuggest) {
  357. $public_message = false; // suggestions are not public
  358. $sugg_template = get_markup_template('atom_suggest.tpl');
  359. $atom .= replace_macros($sugg_template, array(
  360. '$name' => xmlify($item['name']),
  361. '$url' => xmlify($item['url']),
  362. '$photo' => xmlify($item['photo']),
  363. '$request' => xmlify($item['request']),
  364. '$note' => xmlify($item['note'])
  365. ));
  366. // We don't need this any more
  367. q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1",
  368. intval($item['id'])
  369. );
  370. } elseif($relocate) {
  371. $public_message = false; // suggestions are not public
  372. $sugg_template = get_markup_template('atom_relocate.tpl');
  373. /* get site pubkey. this could be a new installation with no site keys*/
  374. $pubkey = get_config('system','site_pubkey');
  375. if(! $pubkey) {
  376. $res = new_keypair(1024);
  377. set_config('system','site_prvkey', $res['prvkey']);
  378. set_config('system','site_pubkey', $res['pubkey']);
  379. }
  380. $rp = q("SELECT `resource-id` , `scale`, type FROM `photo`
  381. WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid);
  382. $photos = array();
  383. $ext = Photo::supportedTypes();
  384. foreach($rp as $p){
  385. $photos[$p['scale']] = $a->get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']];
  386. }
  387. unset($rp, $ext);
  388. $atom .= replace_macros($sugg_template, array(
  389. '$name' => xmlify($owner['name']),
  390. '$photo' => xmlify($photos[4]),
  391. '$thumb' => xmlify($photos[5]),
  392. '$micro' => xmlify($photos[6]),
  393. '$url' => xmlify($owner['url']),
  394. '$request' => xmlify($owner['request']),
  395. '$confirm' => xmlify($owner['confirm']),
  396. '$notify' => xmlify($owner['notify']),
  397. '$poll' => xmlify($owner['poll']),
  398. '$sitepubkey' => xmlify(get_config('system','site_pubkey')),
  399. //'$pubkey' => xmlify($owner['pubkey']),
  400. //'$prvkey' => xmlify($owner['prvkey']),
  401. ));
  402. $recipients_relocate = q("SELECT * FROM contact WHERE uid = %d AND self = 0 AND network = '%s'" , intval($uid), NETWORK_DFRN);
  403. unset($photos);
  404. } else {
  405. if($followup) {
  406. foreach($items as $item) { // there is only one item
  407. if(! $item['parent'])
  408. continue;
  409. if($item['id'] == $item_id) {
  410. logger('notifier: followup: item: ' . print_r($item,true), LOGGER_DATA);
  411. $slap = atom_entry($item,'html',null,$owner,false);
  412. $atom .= atom_entry($item,'text',null,$owner,false);
  413. }
  414. }
  415. } else {
  416. foreach($items as $item) {
  417. if(! $item['parent'])
  418. continue;
  419. // private emails may be in included in public conversations. Filter them.
  420. if(($public_message) && $item['private'] == 1)
  421. continue;
  422. $contact = get_item_contact($item,$contacts);
  423. if(! $contact)
  424. continue;
  425. if($normal_mode) {
  426. // we only need the current item, but include the parent because without it
  427. // older sites without a corresponding dfrn_notify change may do the wrong thing.
  428. if($item_id == $item['id'] || $item['id'] == $item['parent'])
  429. $atom .= atom_entry($item,'text',null,$owner,true);
  430. } else
  431. $atom .= atom_entry($item,'text',null,$owner,true);
  432. if(($top_level) && ($public_message) && ($item['author-link'] === $item['owner-link']) && (! $expire))
  433. $slaps[] = atom_entry($item,'html',null,$owner,true);
  434. }
  435. }
  436. }
  437. $atom .= '</feed>' . "\r\n";
  438. logger('notifier: ' . $atom, LOGGER_DATA);
  439. logger('notifier: slaps: ' . print_r($slaps,true), LOGGER_DATA);
  440. // If this is a public message and pubmail is set on the parent, include all your email contacts
  441. $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
  442. if(! $mail_disabled) {
  443. if((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid']))
  444. && (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid']))
  445. && (intval($target_item['pubmail']))) {
  446. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
  447. intval($uid),
  448. dbesc(NETWORK_MAIL)
  449. );
  450. if(count($r)) {
  451. foreach($r as $rr)
  452. $recipients[] = $rr['id'];
  453. }
  454. }
  455. }
  456. if($followup)
  457. $recip_str = $parent['contact-id'].$ostatus_recip_str;
  458. else
  459. $recip_str = implode(', ', $recipients);
  460. if ($relocate)
  461. $r = $recipients_relocate;
  462. else
  463. $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
  464. dbesc($recip_str)
  465. );
  466. require_once('include/salmon.php');
  467. $interval = ((get_config('system','delivery_interval') === false) ? 2 : intval(get_config('system','delivery_interval')));
  468. // delivery loop
  469. if(count($r)) {
  470. foreach($r as $contact) {
  471. if((! $mail) && (! $fsuggest) && (!$followup OR ($parent['contact-id'] != $contact['id'])) && (!$relocate) && (! $contact['self'])) {
  472. if(($contact['network'] === NETWORK_DIASPORA) && ($public_message))
  473. continue;
  474. q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )",
  475. dbesc($cmd),
  476. intval($item_id),
  477. intval($contact['id'])
  478. );
  479. }
  480. }
  481. // This controls the number of deliveries to execute with each separate delivery process.
  482. // By default we'll perform one delivery per process. Assuming a hostile shared hosting
  483. // provider, this provides the greatest chance of deliveries if processes start getting
  484. // killed. We can also space them out with the delivery_interval to also help avoid them
  485. // getting whacked.
  486. // If $deliveries_per_process > 1, we will chain this number of multiple deliveries
  487. // together into a single process. This will reduce the overall number of processes
  488. // spawned for each delivery, but they will run longer.
  489. $deliveries_per_process = intval(get_config('system','delivery_batch_count'));
  490. if($deliveries_per_process <= 0)
  491. $deliveries_per_process = 1;
  492. $this_batch = array();
  493. for($x = 0; $x < count($r); $x ++) {
  494. $contact = $r[$x];
  495. if($contact['self'])
  496. continue;
  497. logger("Deliver to ".$contact['url'], LOGGER_DEBUG);
  498. // potentially more than one recipient. Start a new process and space them out a bit.
  499. // we will deliver single recipient types of message and email recipients here.
  500. if((! $mail) && (! $fsuggest) && (!$relocate) && (!$followup OR ($parent['contact-id'] != $contact['id']))) {
  501. $this_batch[] = $contact['id'];
  502. if(count($this_batch) == $deliveries_per_process) {
  503. proc_run('php','include/delivery.php',$cmd,$item_id,$this_batch);
  504. $this_batch = array();
  505. if($interval)
  506. @time_sleep_until(microtime(true) + (float) $interval);
  507. }
  508. continue;
  509. }
  510. // be sure to pick up any stragglers
  511. if(count($this_batch))
  512. proc_run('php','include/delivery.php',$cmd,$item_id,$this_batch);
  513. $deliver_status = 0;
  514. logger("main delivery by notifier: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate");
  515. switch($contact['network']) {
  516. case NETWORK_DFRN:
  517. // perform local delivery if we are on the same site
  518. $basepath = implode('/', array_slice(explode('/',$contact['url']),0,3));
  519. if(link_compare($basepath,$a->get_baseurl())) {
  520. $nickname = basename($contact['url']);
  521. if($contact['issued-id'])
  522. $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
  523. else
  524. $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
  525. $x = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`,
  526. `contact`.`pubkey` AS `cpubkey`,
  527. `contact`.`prvkey` AS `cprvkey`,
  528. `contact`.`thumb` AS `thumb`,
  529. `contact`.`url` as `url`,
  530. `contact`.`name` as `senderName`,
  531. `user`.*
  532. FROM `contact`
  533. INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
  534. WHERE `contact`.`blocked` = 0 AND `contact`.`archive` = 0
  535. AND `contact`.`pending` = 0
  536. AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'
  537. $sql_extra
  538. AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1",
  539. dbesc(NETWORK_DFRN),
  540. dbesc($nickname)
  541. );
  542. if($x && count($x)) {
  543. $write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false);
  544. if((($owner['page-flags'] == PAGE_COMMUNITY) || ($write_flag)) && (! $x[0]['writable'])) {
  545. q("update contact set writable = 1 where id = %d",
  546. intval($x[0]['id'])
  547. );
  548. $x[0]['writable'] = 1;
  549. }
  550. // if contact's ssl policy changed, which we just determined
  551. // is on our own server, update our contact links
  552. $ssl_policy = get_config('system','ssl_policy');
  553. fix_contact_ssl_policy($x[0],$ssl_policy);
  554. // If we are setup as a soapbox we aren't accepting input from this person
  555. if($x[0]['page-flags'] == PAGE_SOAPBOX)
  556. break;
  557. require_once('library/simplepie/simplepie.inc');
  558. logger('mod-delivery: local delivery');
  559. local_delivery($x[0],$atom);
  560. break;
  561. }
  562. }
  563. logger('notifier: dfrndelivery: ' . $contact['name']);
  564. $deliver_status = dfrn_deliver($owner,$contact,$atom);
  565. logger('notifier: dfrn_delivery returns ' . $deliver_status);
  566. if($deliver_status == (-1)) {
  567. logger('notifier: delivery failed: queuing message');
  568. // queue message for redelivery
  569. add_to_queue($contact['id'],NETWORK_DFRN,$atom);
  570. }
  571. break;
  572. case NETWORK_OSTATUS:
  573. // Do not send to ostatus if we are not configured to send to public networks
  574. if($owner['prvnets'])
  575. break;
  576. if(get_config('system','ostatus_disabled') || get_config('system','dfrn_only'))
  577. break;
  578. if($followup && $contact['notify']) {
  579. logger('slapdelivery followup item '.$item_id.' to ' . $contact['name']);
  580. $deliver_status = slapper($owner,$contact['notify'],$slap);
  581. if($deliver_status == (-1)) {
  582. // queue message for redelivery
  583. add_to_queue($contact['id'],NETWORK_OSTATUS,$slap);
  584. }
  585. } else {
  586. // only send salmon if public - e.g. if it's ok to notify
  587. // a public hub, it's ok to send a salmon
  588. if((count($slaps)) && ($public_message) && (! $expire)) {
  589. logger('slapdelivery item '.$item_id.' to ' . $contact['name']);
  590. foreach($slaps as $slappy) {
  591. if($contact['notify']) {
  592. $deliver_status = slapper($owner,$contact['notify'],$slappy);
  593. if($deliver_status == (-1)) {
  594. // queue message for redelivery
  595. add_to_queue($contact['id'],NETWORK_OSTATUS,$slappy);
  596. }
  597. }
  598. }
  599. }
  600. }
  601. break;
  602. case NETWORK_MAIL:
  603. case NETWORK_MAIL2:
  604. if(get_config('system','dfrn_only'))
  605. break;
  606. // WARNING: does not currently convert to RFC2047 header encodings, etc.
  607. $addr = $contact['addr'];
  608. if(! strlen($addr))
  609. break;
  610. if($cmd === 'wall-new' || $cmd === 'comment-new') {
  611. $it = null;
  612. if($cmd === 'wall-new')
  613. $it = $items[0];
  614. else {
  615. $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  616. intval($argv[2]),
  617. intval($uid)
  618. );
  619. if(count($r))
  620. $it = $r[0];
  621. }
  622. if(! $it)
  623. break;
  624. $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
  625. intval($uid)
  626. );
  627. if(! count($local_user))
  628. break;
  629. $reply_to = '';
  630. $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
  631. intval($uid)
  632. );
  633. if($r1 && $r1[0]['reply_to'])
  634. $reply_to = $r1[0]['reply_to'];
  635. $subject = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ;
  636. // only expose our real email address to true friends
  637. if(($contact['rel'] == CONTACT_IS_FRIEND) && (! $contact['blocked']))
  638. if($reply_to) {
  639. $headers = 'From: ' . email_header_encode($local_user[0]['username'],'UTF-8') . ' <' . $reply_to . '>' . "\n";
  640. $headers .= 'Sender: '.$local_user[0]['email']."\n";
  641. } else
  642. $headers = 'From: ' . email_header_encode($local_user[0]['username'],'UTF-8') . ' <' . $local_user[0]['email'] . '>' . "\n";
  643. else
  644. $headers = 'From: ' . email_header_encode($local_user[0]['username'],'UTF-8') . ' <' . t('noreply') . '@' . $a->get_hostname() . '>' . "\n";
  645. //if($reply_to)
  646. // $headers .= 'Reply-to: ' . $reply_to . "\n";
  647. $headers .= 'Message-Id: <' . iri2msgid($it['uri']) . '>' . "\n";
  648. if($it['uri'] !== $it['parent-uri']) {
  649. $headers .= "References: <".iri2msgid($it["parent-uri"]).">";
  650. // If Threading is enabled, write down the correct parent
  651. if (($it["thr-parent"] != "") and ($it["thr-parent"] != $it["parent-uri"]))
  652. $headers .= " <".iri2msgid($it["thr-parent"]).">";
  653. $headers .= "\n";
  654. if(!$it['title']) {
  655. $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
  656. dbesc($it['parent-uri']),
  657. intval($uid));
  658. if(count($r) AND ($r[0]['title'] != ''))
  659. $subject = $r[0]['title'];
  660. else {
  661. $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1",
  662. dbesc($it['parent-uri']),
  663. intval($uid));
  664. if(count($r) AND ($r[0]['title'] != ''))
  665. $subject = $r[0]['title'];
  666. }
  667. }
  668. if(strncasecmp($subject,'RE:',3))
  669. $subject = 'Re: '.$subject;
  670. }
  671. email_send($addr, $subject, $headers, $it);
  672. }
  673. break;
  674. case NETWORK_DIASPORA:
  675. require_once('include/diaspora.php');
  676. if(get_config('system','dfrn_only') || (! get_config('system','diaspora_enabled')))
  677. break;
  678. if($mail) {
  679. diaspora_send_mail($item,$owner,$contact);
  680. break;
  681. }
  682. if(! $normal_mode)
  683. break;
  684. // special handling for followup to public post
  685. // all other public posts processed as public batches further below
  686. if($public_message) {
  687. if($followup)
  688. diaspora_send_followup($target_item,$owner,$contact, true);
  689. break;
  690. }
  691. if(! $contact['pubkey'])
  692. break;
  693. if($target_item['verb'] === ACTIVITY_DISLIKE) {
  694. // unsupported
  695. break;
  696. }
  697. elseif(($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
  698. // send both top-level retractions and relayable retractions for owner to relay
  699. diaspora_send_retraction($target_item,$owner,$contact);
  700. break;
  701. }
  702. elseif($followup) {
  703. // send comments and likes to owner to relay
  704. diaspora_send_followup($target_item,$owner,$contact);
  705. break;
  706. }
  707. elseif($target_item['uri'] !== $target_item['parent-uri']) {
  708. // we are the relay - send comments, likes and relayable_retractions
  709. // (of comments and likes) to our conversants
  710. diaspora_send_relay($target_item,$owner,$contact);
  711. break;
  712. }
  713. elseif(($top_level) && (! $walltowall)) {
  714. // currently no workable solution for sending walltowall
  715. diaspora_send_status($target_item,$owner,$contact);
  716. break;
  717. }
  718. break;
  719. case NETWORK_FEED:
  720. case NETWORK_FACEBOOK:
  721. if(get_config('system','dfrn_only'))
  722. break;
  723. case NETWORK_PUMPIO:
  724. if(get_config('system','dfrn_only'))
  725. break;
  726. default:
  727. break;
  728. }
  729. }
  730. }
  731. // send additional slaps to mentioned remote tags (@foo@example.com)
  732. if($slap && count($url_recipients) && ($followup || $top_level) && $public_message && (! $expire)) {
  733. if(! get_config('system','dfrn_only')) {
  734. foreach($url_recipients as $url) {
  735. if($url) {
  736. logger('notifier: urldelivery: ' . $url);
  737. $deliver_status = slapper($owner,$url,$slap);
  738. // TODO: redeliver/queue these items on failure, though there is no contact record
  739. }
  740. }
  741. }
  742. }
  743. if($public_message) {
  744. $r1 = q("SELECT DISTINCT(`batch`), `id`, `name`,`network` FROM `contact` WHERE `network` = '%s'
  745. AND `uid` = %d AND `rel` != %d group by `batch` ORDER BY rand() ",
  746. dbesc(NETWORK_DIASPORA),
  747. intval($owner['uid']),
  748. intval(CONTACT_IS_SHARING)
  749. );
  750. $r2 = q("SELECT `id`, `name`,`network` FROM `contact`
  751. WHERE `network` in ( '%s', '%s') AND `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
  752. AND `rel` != %d order by rand() ",
  753. dbesc(NETWORK_DFRN),
  754. dbesc(NETWORK_MAIL2),
  755. intval($owner['uid']),
  756. intval(CONTACT_IS_SHARING)
  757. );
  758. $r = array_merge($r2,$r1);
  759. if(count($r)) {
  760. logger('pubdeliver: ' . print_r($r,true), LOGGER_DEBUG);
  761. // throw everything into the queue in case we get killed
  762. foreach($r as $rr) {
  763. if((! $mail) && (! $fsuggest) && (!$followup OR ($parent['contact-id'] != $contact['id']))) {
  764. q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )",
  765. dbesc($cmd),
  766. intval($item_id),
  767. intval($rr['id'])
  768. );
  769. }
  770. }
  771. foreach($r as $rr) {
  772. // except for Diaspora batch jobs
  773. // Don't deliver to folks who have already been delivered to
  774. if(($rr['network'] !== NETWORK_DIASPORA) && (in_array($rr['id'],$conversants))) {
  775. logger('notifier: already delivered id=' . $rr['id']);
  776. continue;
  777. }
  778. if((! $mail) && (! $fsuggest) && (! $followup)) {
  779. logger('notifier: delivery agent: ' . $rr['name'] . ' ' . $rr['id']);
  780. proc_run('php','include/delivery.php',$cmd,$item_id,$rr['id']);
  781. if($interval)
  782. @time_sleep_until(microtime(true) + (float) $interval);
  783. }
  784. }
  785. }
  786. $push_notify = true;
  787. }
  788. if($push_notify AND strlen($hub)) {
  789. $hubs = explode(',', $hub);
  790. if(count($hubs)) {
  791. foreach($hubs as $h) {
  792. $h = trim($h);
  793. if(! strlen($h))
  794. continue;
  795. if ($h === '[internal]') {
  796. // Set push flag for PuSH subscribers to this topic,
  797. // they will be notified in queue.php
  798. q("UPDATE `push_subscriber` SET `push` = 1 " .
  799. "WHERE `nickname` = '%s'", dbesc($owner['nickname']));
  800. logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG);
  801. } else {
  802. $params = 'hub.mode=publish&hub.url=' . urlencode( $a->get_baseurl() . '/dfrn_poll/' . $owner['nickname'] );
  803. post_url($h,$params);
  804. logger('publish for item '.$item_id.' ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
  805. }
  806. if(count($hubs) > 1)
  807. sleep(7); // try and avoid multiple hubs responding at precisely the same time
  808. }
  809. }
  810. // Handling the pubsubhubbub requests
  811. proc_run('php','include/pubsubpublish.php');
  812. }
  813. // If the item was deleted, clean up the `sign` table
  814. if($target_item['deleted']) {
  815. $r = q("DELETE FROM sign where `retract_iid` = %d",
  816. intval($target_item['id'])
  817. );
  818. }
  819. logger('notifier: calling hooks', LOGGER_DEBUG);
  820. if($normal_mode)
  821. call_hooks('notifier_normal',$target_item);
  822. call_hooks('notifier_end',$target_item);
  823. return;
  824. }
  825. if (array_search(__file__,get_included_files())===0){
  826. notifier_run($_SERVER["argv"],$_SERVER["argc"]);
  827. killme();
  828. }