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.
 
 
 
 
 
 

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