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.

543 lines
14 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. <?php
  2. require_once("boot.php");
  3. function notifier_run($argv, $argc){
  4. global $a, $db;
  5. if(is_null($a)){
  6. $a = new App;
  7. }
  8. if(is_null($db)) {
  9. @include(".htconfig.php");
  10. require_once("dba.php");
  11. $db = new dba($db_host, $db_user, $db_pass, $db_data);
  12. unset($db_host, $db_user, $db_pass, $db_data);
  13. }
  14. require_once("session.php");
  15. require_once("datetime.php");
  16. require_once('include/items.php');
  17. require_once('include/bbcode.php');
  18. load_hooks();
  19. if($argc < 3)
  20. return;
  21. $a->set_baseurl(get_config('system','url'));
  22. logger('notifier: invoked: ' . print_r($argv,true));
  23. $cmd = $argv[1];
  24. switch($cmd) {
  25. case 'mail':
  26. default:
  27. $item_id = intval($argv[2]);
  28. if(! $item_id){
  29. return;
  30. }
  31. break;
  32. }
  33. $expire = false;
  34. $top_level = false;
  35. $recipients = array();
  36. $url_recipients = array();
  37. if($cmd === 'mail') {
  38. $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
  39. intval($item_id)
  40. );
  41. if(! count($message)){
  42. return;
  43. }
  44. $uid = $message[0]['uid'];
  45. $recipients[] = $message[0]['contact-id'];
  46. $item = $message[0];
  47. }
  48. elseif($cmd === 'expire') {
  49. $expire = true;
  50. $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
  51. AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP - INTERVAL 10 MINUTE",
  52. intval($item_id)
  53. );
  54. $uid = $item_id;
  55. $item_id = 0;
  56. if(! count($items))
  57. return;
  58. }
  59. else {
  60. // find ancestors
  61. $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
  62. intval($item_id)
  63. );
  64. if((! count($r)) || (! intval($r[0]['parent']))) {
  65. return;
  66. }
  67. $parent_item = $r[0];
  68. $parent_id = intval($r[0]['parent']);
  69. $uid = $r[0]['uid'];
  70. $updated = $r[0]['edited'];
  71. $items = q("SELECT * FROM `item` WHERE `parent` = %d ORDER BY `id` ASC",
  72. intval($parent_id)
  73. );
  74. if(! count($items)) {
  75. return;
  76. }
  77. // avoid race condition with deleting entries
  78. if($items[0]['deleted']) {
  79. foreach($items as $item)
  80. $item['deleted'] = 1;
  81. }
  82. if(count($items) == 1 && $items[0]['uri'] === $items[0]['parent-uri'])
  83. $top_level = true;
  84. }
  85. $r = q("SELECT `contact`.*, `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, `user`.`page-flags`
  86. FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid`
  87. WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
  88. intval($uid)
  89. );
  90. if(! count($r))
  91. return;
  92. $owner = $r[0];
  93. $hub = get_config('system','huburl');
  94. // If this is a public conversation, notify the feed hub
  95. $notify_hub = true;
  96. // fill this in with a single salmon slap if applicable
  97. $slap = '';
  98. if($cmd != 'mail') {
  99. require_once('include/group.php');
  100. $parent = $items[0];
  101. if($parent['type'] === 'remote' && (! $expire)) {
  102. // local followup to remote post
  103. $followup = true;
  104. $notify_hub = false; // not public
  105. $conversant_str = dbesc($parent['contact-id']);
  106. }
  107. else {
  108. $followup = false;
  109. if((strlen($parent['allow_cid']))
  110. || (strlen($parent['allow_gid']))
  111. || (strlen($parent['deny_cid']))
  112. || (strlen($parent['deny_gid']))) {
  113. $notify_hub = false; // private recipients, not public
  114. }
  115. $allow_people = expand_acl($parent['allow_cid']);
  116. $allow_groups = expand_groups(expand_acl($parent['allow_gid']));
  117. $deny_people = expand_acl($parent['deny_cid']);
  118. $deny_groups = expand_groups(expand_acl($parent['deny_gid']));
  119. $conversants = array();
  120. foreach($items as $item) {
  121. $recipients[] = $item['contact-id'];
  122. $conversants[] = $item['contact-id'];
  123. // pull out additional tagged people to notify (if public message)
  124. if($notify_hub && strlen($item['inform'])) {
  125. $people = explode(',',$item['inform']);
  126. foreach($people as $person) {
  127. if(substr($person,0,4) === 'cid:') {
  128. $recipients[] = intval(substr($person,4));
  129. $conversants[] = intval(substr($person,4));
  130. }
  131. else {
  132. $url_recipients[] = substr($person,4);
  133. }
  134. }
  135. }
  136. }
  137. logger('notifier: url_recipients' . print_r($url_recipients,true));
  138. $conversants = array_unique($conversants);
  139. $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups));
  140. $deny = array_unique(array_merge($deny_people,$deny_groups));
  141. $recipients = array_diff($recipients,$deny);
  142. $conversant_str = dbesc(implode(', ',$conversants));
  143. }
  144. $r = q("SELECT * FROM `contact` WHERE `id` IN ( $conversant_str ) AND `blocked` = 0 AND `pending` = 0");
  145. if(count($r))
  146. $contacts = $r;
  147. }
  148. $feed_template = get_markup_template('atom_feed.tpl');
  149. $mail_template = get_markup_template('atom_mail.tpl');
  150. $atom = '';
  151. $slaps = array();
  152. $hubxml = feed_hublinks();
  153. $birthday = feed_birthday($owner['uid'],$owner['timezone']);
  154. if(strlen($birthday))
  155. $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>';
  156. $atom .= replace_macros($feed_template, array(
  157. '$version' => xmlify(FRIENDIKA_VERSION),
  158. '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname'] ),
  159. '$feed_title' => xmlify($owner['name']),
  160. '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00' , ATOM_TIME)) ,
  161. '$hub' => $hubxml,
  162. '$salmon' => '', // private feed, we don't use salmon here
  163. '$name' => xmlify($owner['name']),
  164. '$profile_page' => xmlify($owner['url']),
  165. '$photo' => xmlify($owner['photo']),
  166. '$thumb' => xmlify($owner['thumb']),
  167. '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) ,
  168. '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) ,
  169. '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) ,
  170. '$birthday' => $birthday
  171. ));
  172. if($cmd === 'mail') {
  173. $notify_hub = false; // mail is not public
  174. $atom .= replace_macros($mail_template, array(
  175. '$name' => xmlify($owner['name']),
  176. '$profile_page' => xmlify($owner['url']),
  177. '$thumb' => xmlify($owner['thumb']),
  178. '$item_id' => xmlify($item['uri']),
  179. '$subject' => xmlify($item['title']),
  180. '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)),
  181. '$content' => xmlify($item['body']),
  182. '$parent_id' => xmlify($item['parent-uri'])
  183. ));
  184. }
  185. else {
  186. if($followup) {
  187. foreach($items as $item) { // there is only one item
  188. if(! $item['parent'])
  189. continue;
  190. if($item['id'] == $item_id) {
  191. logger('notifier: followup: item: ' . print_r($item,true), LOGGER_DATA);
  192. $slap = atom_entry($item,'html',$owner,$owner,false);
  193. $atom .= atom_entry($item,'text',$owner,$owner,false);
  194. }
  195. }
  196. }
  197. else {
  198. foreach($items as $item) {
  199. if(! $item['parent'])
  200. continue;
  201. $contact = get_item_contact($item,$contacts);
  202. if(! $contact)
  203. continue;
  204. $atom .= atom_entry($item,'text',$contact,$owner,true);
  205. if(($top_level) && ($notify_hub) && ($item['author-link'] === $item['owner-link']) && (! $expire))
  206. $slaps[] = atom_entry($item,'html',$contact,$owner,true);
  207. }
  208. }
  209. }
  210. $atom .= '</feed>' . "\r\n";
  211. logger('notifier: ' . $atom, LOGGER_DATA);
  212. logger('notifier: slaps: ' . print_r($slaps,true), LOGGER_DATA);
  213. // If this is a public message and pubmail is set on the parent, include all your email contacts
  214. $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
  215. if(! $mail_disabled) {
  216. if((! strlen($parent_item['allow_cid'])) && (! strlen($parent_item['allow_gid']))
  217. && (! strlen($parent_item['deny_cid'])) && (! strlen($parent_item['deny_gid']))
  218. && (intval($parent_item['pubmail']))) {
  219. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
  220. intval($uid),
  221. dbesc(NETWORK_MAIL)
  222. );
  223. if(count($r)) {
  224. foreach($r as $rr)
  225. $recipients[] = $rr['id'];
  226. }
  227. }
  228. }
  229. if($followup)
  230. $recip_str = $parent['contact-id'];
  231. else
  232. $recip_str = implode(', ', $recipients);
  233. $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
  234. dbesc($recip_str)
  235. );
  236. // delivery loop
  237. require_once('include/salmon.php');
  238. if(count($r)) {
  239. foreach($r as $contact) {
  240. if($contact['self'])
  241. continue;
  242. $deliver_status = 0;
  243. switch($contact['network']) {
  244. case 'dfrn':
  245. logger('notifier: dfrndelivery: ' . $contact['name']);
  246. $deliver_status = dfrn_deliver($owner,$contact,$atom);
  247. logger('notifier: dfrn_delivery returns ' . $deliver_status);
  248. if($deliver_status == (-1)) {
  249. logger('notifier: delivery failed: queuing message');
  250. // queue message for redelivery
  251. q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`)
  252. VALUES ( %d, '%s', '%s', '%s') ",
  253. intval($contact['id']),
  254. dbesc(datetime_convert()),
  255. dbesc(datetime_convert()),
  256. dbesc($atom)
  257. );
  258. }
  259. break;
  260. case 'stat':
  261. if($followup && $contact['notify']) {
  262. logger('notifier: slapdelivery: ' . $contact['name']);
  263. $deliver_status = slapper($owner,$contact['notify'],$slap);
  264. if($deliver_status == (-1)) {
  265. // queue message for redelivery
  266. q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`)
  267. VALUES ( %d, '%s', '%s', '%s') ",
  268. intval($contact['id']),
  269. dbesc(datetime_convert()),
  270. dbesc(datetime_convert()),
  271. dbesc($slap)
  272. );
  273. }
  274. }
  275. else {
  276. // only send salmon if public - e.g. if it's ok to notify
  277. // a public hub, it's ok to send a salmon
  278. if((count($slaps)) && ($notify_hub) && (! $expire)) {
  279. logger('notifier: slapdelivery: ' . $contact['name']);
  280. foreach($slaps as $slappy) {
  281. if($contact['notify']) {
  282. $deliver_status = slapper($owner,$contact['notify'],$slappy);
  283. if($deliver_status == (-1)) {
  284. // queue message for redelivery
  285. q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`)
  286. VALUES ( %d, '%s', '%s', '%s') ",
  287. intval($contact['id']),
  288. dbesc(datetime_convert()),
  289. dbesc(datetime_convert()),
  290. dbesc($slappy)
  291. );
  292. }
  293. }
  294. }
  295. }
  296. }
  297. break;
  298. case 'mail':
  299. // WARNING: does not currently convert to RFC2047 header encodings, etc.
  300. $addr = $contact['addr'];
  301. if(! strlen($addr))
  302. break;
  303. if($cmd === 'wall-new' || $cmd === 'comment-new') {
  304. $it = null;
  305. if($cmd === 'wall-new')
  306. $it = $items[0];
  307. else {
  308. $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  309. intval($argv[2]),
  310. intval($uid)
  311. );
  312. if(count($r))
  313. $it = $r[0];
  314. }
  315. if(! $it)
  316. break;
  317. $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
  318. intval($uid)
  319. );
  320. if(! count($local_user))
  321. break;
  322. $reply_to = '';
  323. $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
  324. intval($uid)
  325. );
  326. if($r1 && $r1[0]['reply_to'])
  327. $reply_to = $r1[0]['reply_to'];
  328. $subject = (($it['title']) ? $it['title'] : t("\x28no subject\x29")) ;
  329. $headers = 'From: ' . $local_user[0]['username'] . ' <' . $local_user[0]['email'] . '>' . "\n";
  330. if($reply_to)
  331. $headers .= 'Reply-to: ' . $reply_to . "\n";
  332. $headers .= 'Message-id: <' . $it['uri'] . '>' . "\n";
  333. if($it['uri'] !== $it['parent-uri']) {
  334. $header .= 'References: <' . $it['parent-uri'] . '>' . "\n";
  335. if(! strlen($it['title'])) {
  336. $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' LIMIT 1",
  337. dbesc($it['parent-uri'])
  338. );
  339. if(count($r)) {
  340. $subtitle = $r[0]['title'];
  341. if($subtitle) {
  342. if(strncasecmp($subtitle,'RE:',3))
  343. $subject = $subtitle;
  344. else
  345. $subject = 'Re: ' . $subtitle;
  346. }
  347. }
  348. }
  349. }
  350. $headers .= 'MIME-Version: 1.0' . "\n";
  351. $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
  352. $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
  353. $html = prepare_body($it);
  354. $message = '<html><body>' . $html . '</body></html>';
  355. logger('notifier: email delivery to ' . $addr);
  356. mail($addr, $subject, $message, $headers);
  357. }
  358. break;
  359. case 'dspr':
  360. case 'feed':
  361. case 'face':
  362. default:
  363. break;
  364. }
  365. }
  366. }
  367. // send additional slaps to mentioned remote tags (@foo@example.com)
  368. if($slap && count($url_recipients) && $followup && $notify_hub && (! $expire)) {
  369. foreach($url_recipients as $url) {
  370. if($url) {
  371. logger('notifier: urldelivery: ' . $url);
  372. $deliver_status = slapper($owner,$url,$slap);
  373. // TODO: redeliver/queue these items on failure, though there is no contact record
  374. }
  375. }
  376. }
  377. if((strlen($hub)) && ($notify_hub)) {
  378. $hubs = explode(',', $hub);
  379. if(count($hubs)) {
  380. foreach($hubs as $h) {
  381. $h = trim($h);
  382. if(! strlen($h))
  383. continue;
  384. $params = 'hub.mode=publish&hub.url=' . urlencode($a->get_baseurl() . '/dfrn_poll/' . $owner['nickname'] );
  385. post_url($h,$params);
  386. logger('pubsub: publish: ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
  387. if(count($hubs) > 1)
  388. sleep(7); // try and avoid multiple hubs responding at precisely the same time
  389. }
  390. }
  391. }
  392. if($notify_hub) {
  393. /**
  394. *
  395. * If you have less than 150 dfrn friends and it's a public message,
  396. * we'll just go ahead and push them out securely with dfrn/rino.
  397. * If you've got more than that, you'll have to rely on PuSH delivery.
  398. *
  399. */
  400. $max_allowed = ((get_config('system','maxpubdeliver') === false) ? 150 : intval(get_config('system','maxpubdeliver')));
  401. /**
  402. *
  403. * Only get the bare essentials and go back for the full record.
  404. * If you've got a lot of friends and we grab all the details at once it could exhaust memory.
  405. *
  406. */
  407. $r = q("SELECT `id`, `name` FROM `contact`
  408. WHERE `network` = 'dfrn' AND `uid` = %d AND `blocked` = 0 AND `pending` = 0
  409. AND `rel` != %d ",
  410. intval($owner['uid']),
  411. intval(REL_FAN)
  412. );
  413. if((count($r)) && (($max_allowed == 0) || (count($r) < $max_allowed))) {
  414. foreach($r as $rr) {
  415. /* Don't deliver to folks who have already been delivered to */
  416. if(! in_array($rr['id'], $conversants)) {
  417. $n = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
  418. intval($rr['id'])
  419. );
  420. if(count($n)) {
  421. logger('notifier: dfrnpubdelivery: ' . $n[0]['name']);
  422. $deliver_status = dfrn_deliver($owner,$n[0],$atom);
  423. }
  424. }
  425. else
  426. logger('notifier: dfrnpubdelivery: ignoring ' . $rr['name']);
  427. }
  428. }
  429. }
  430. return;
  431. }
  432. if (array_search(__file__,get_included_files())===0){
  433. echo "run!";
  434. notifier_run($argv,$argc);
  435. killme();
  436. }