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.

692 lines
19 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
10 years ago
11 years ago
10 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
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 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_config('config');
  19. load_config('system');
  20. load_hooks();
  21. if($argc < 3)
  22. return;
  23. $a->set_baseurl(get_config('system','url'));
  24. logger('notifier: invoked: ' . print_r($argv,true));
  25. $cmd = $argv[1];
  26. switch($cmd) {
  27. case 'mail':
  28. default:
  29. $item_id = intval($argv[2]);
  30. if(! $item_id){
  31. return;
  32. }
  33. break;
  34. }
  35. $expire = false;
  36. $mail = false;
  37. $fsuggest = false;
  38. $top_level = false;
  39. $recipients = array();
  40. $url_recipients = array();
  41. $normal_mode = true;
  42. if($cmd === 'mail') {
  43. $normal_mode = false;
  44. $mail = true;
  45. $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
  46. intval($item_id)
  47. );
  48. if(! count($message)){
  49. return;
  50. }
  51. $uid = $message[0]['uid'];
  52. $recipients[] = $message[0]['contact-id'];
  53. $item = $message[0];
  54. }
  55. elseif($cmd === 'expire') {
  56. $normal_mode = false;
  57. $expire = true;
  58. $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
  59. AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP - INTERVAL 10 MINUTE",
  60. intval($item_id)
  61. );
  62. $uid = $item_id;
  63. $item_id = 0;
  64. if(! count($items))
  65. return;
  66. }
  67. elseif($cmd === 'suggest') {
  68. $normal_mode = false;
  69. $fsuggest = true;
  70. $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
  71. intval($item_id)
  72. );
  73. if(! count($suggest))
  74. return;
  75. $uid = $suggest[0]['uid'];
  76. $recipients[] = $suggest[0]['cid'];
  77. $item = $suggest[0];
  78. }
  79. else {
  80. // find ancestors
  81. $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
  82. intval($item_id)
  83. );
  84. if((! count($r)) || (! intval($r[0]['parent']))) {
  85. return;
  86. }
  87. $target_item = $r[0];
  88. $parent_id = intval($r[0]['parent']);
  89. $uid = $r[0]['uid'];
  90. $updated = $r[0]['edited'];
  91. $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
  92. FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d ORDER BY `id` ASC",
  93. intval($parent_id)
  94. );
  95. if(! count($items)) {
  96. return;
  97. }
  98. // avoid race condition with deleting entries
  99. if($items[0]['deleted']) {
  100. foreach($items as $item)
  101. $item['deleted'] = 1;
  102. }
  103. if(count($items) == 1 && $items[0]['uri'] === $items[0]['parent-uri'])
  104. $top_level = true;
  105. }
  106. $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
  107. `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
  108. `user`.`page-flags`, `user`.`prvnets`
  109. FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid`
  110. WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
  111. intval($uid)
  112. );
  113. if(! count($r))
  114. return;
  115. $owner = $r[0];
  116. $hub = get_config('system','huburl');
  117. // If this is a public conversation, notify the feed hub
  118. $public_message = true;
  119. // fill this in with a single salmon slap if applicable
  120. $slap = '';
  121. if(! ($mail || $fsuggest)) {
  122. require_once('include/group.php');
  123. $parent = $items[0];
  124. // This is IMPORTANT!!!!
  125. // We will only send a "notify owner to relay" or followup message if the referenced post
  126. // originated on our system by virtue of having our hostname somewhere
  127. // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
  128. // if $parent['wall'] == 1 we will already have the parent message in our array
  129. // and we will relay the whole lot.
  130. // expire sends an entire group of expire messages and cannot be forwarded.
  131. // However the conversation owner will be a part of the conversation and will
  132. // be notified during this run.
  133. // Other DFRN conversation members will be alerted during polled updates.
  134. // Diaspora members currently are not notified of expirations, and other networks have
  135. // either limited or no ability to process deletions. We should at least fix Diaspora
  136. // by stringing togther an array of retractions and sending them onward.
  137. $localhost = $a->get_hostname();
  138. if(strpos($localhost,':'))
  139. $localhost = substr($localhost,0,strpos($localhost,':'));
  140. /**
  141. *
  142. * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes
  143. * have been known to cause runaway conditions which affected several servers, along with
  144. * permissions issues.
  145. *
  146. */
  147. if((! $top_level) && ($parent['wall'] == 0) && (! $expire) && (stristr($target_item['uri'],$localhost))) {
  148. // local followup to remote post
  149. $followup = true;
  150. $public_message = false; // not public
  151. $conversant_str = dbesc($parent['contact-id']);
  152. }
  153. else {
  154. $followup = false;
  155. if((strlen($parent['allow_cid']))
  156. || (strlen($parent['allow_gid']))
  157. || (strlen($parent['deny_cid']))
  158. || (strlen($parent['deny_gid']))) {
  159. $public_message = false; // private recipients, not public
  160. }
  161. $allow_people = expand_acl($parent['allow_cid']);
  162. $allow_groups = expand_groups(expand_acl($parent['allow_gid']));
  163. $deny_people = expand_acl($parent['deny_cid']);
  164. $deny_groups = expand_groups(expand_acl($parent['deny_gid']));
  165. $conversants = array();
  166. foreach($items as $item) {
  167. $recipients[] = $item['contact-id'];
  168. $conversants[] = $item['contact-id'];
  169. // pull out additional tagged people to notify (if public message)
  170. if($public_message && strlen($item['inform'])) {
  171. $people = explode(',',$item['inform']);
  172. foreach($people as $person) {
  173. if(substr($person,0,4) === 'cid:') {
  174. $recipients[] = intval(substr($person,4));
  175. $conversants[] = intval(substr($person,4));
  176. }
  177. else {
  178. $url_recipients[] = substr($person,4);
  179. }
  180. }
  181. }
  182. }
  183. logger('notifier: url_recipients' . print_r($url_recipients,true));
  184. $conversants = array_unique($conversants);
  185. $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups));
  186. $deny = array_unique(array_merge($deny_people,$deny_groups));
  187. $recipients = array_diff($recipients,$deny);
  188. $conversant_str = dbesc(implode(', ',$conversants));
  189. }
  190. $r = q("SELECT * FROM `contact` WHERE `id` IN ( $conversant_str ) AND `blocked` = 0 AND `pending` = 0");
  191. if(count($r))
  192. $contacts = $r;
  193. }
  194. $feed_template = get_markup_template('atom_feed.tpl');
  195. $mail_template = get_markup_template('atom_mail.tpl');
  196. $atom = '';
  197. $slaps = array();
  198. $hubxml = feed_hublinks();
  199. $birthday = feed_birthday($owner['uid'],$owner['timezone']);
  200. if(strlen($birthday))
  201. $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>';
  202. $atom .= replace_macros($feed_template, array(
  203. '$version' => xmlify(FRIENDIKA_VERSION),
  204. '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname'] ),
  205. '$feed_title' => xmlify($owner['name']),
  206. '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00' , ATOM_TIME)) ,
  207. '$hub' => $hubxml,
  208. '$salmon' => '', // private feed, we don't use salmon here
  209. '$name' => xmlify($owner['name']),
  210. '$profile_page' => xmlify($owner['url']),
  211. '$photo' => xmlify($owner['photo']),
  212. '$thumb' => xmlify($owner['thumb']),
  213. '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) ,
  214. '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) ,
  215. '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) ,
  216. '$birthday' => $birthday
  217. ));
  218. if($mail) {
  219. $public_message = false; // mail is not public
  220. $body = fix_private_photos($item['body'],$owner['uid']);
  221. $atom .= replace_macros($mail_template, array(
  222. '$name' => xmlify($owner['name']),
  223. '$profile_page' => xmlify($owner['url']),
  224. '$thumb' => xmlify($owner['thumb']),
  225. '$item_id' => xmlify($item['uri']),
  226. '$subject' => xmlify($item['title']),
  227. '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)),
  228. '$content' => xmlify($body),
  229. '$parent_id' => xmlify($item['parent-uri'])
  230. ));
  231. }
  232. elseif($fsuggest) {
  233. $public_message = false; // suggestions are not public
  234. $sugg_template = get_markup_template('atom_suggest.tpl');
  235. $atom .= replace_macros($sugg_template, array(
  236. '$name' => xmlify($item['name']),
  237. '$url' => xmlify($item['url']),
  238. '$photo' => xmlify($item['photo']),
  239. '$request' => xmlify($item['request']),
  240. '$note' => xmlify($item['note'])
  241. ));
  242. // We don't need this any more
  243. q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1",
  244. intval($item['id'])
  245. );
  246. }
  247. else {
  248. if($followup) {
  249. foreach($items as $item) { // there is only one item
  250. if(! $item['parent'])
  251. continue;
  252. if($item['id'] == $item_id) {
  253. logger('notifier: followup: item: ' . print_r($item,true), LOGGER_DATA);
  254. $slap = atom_entry($item,'html',$owner,$owner,false);
  255. $atom .= atom_entry($item,'text',$owner,$owner,false);
  256. }
  257. }
  258. }
  259. else {
  260. foreach($items as $item) {
  261. if(! $item['parent'])
  262. continue;
  263. // private emails may be in included in public conversations. Filter them.
  264. if(($public_message) && $item['private'])
  265. continue;
  266. $contact = get_item_contact($item,$contacts);
  267. if(! $contact)
  268. continue;
  269. $atom .= atom_entry($item,'text',$contact,$owner,true);
  270. if(($top_level) && ($public_message) && ($item['author-link'] === $item['owner-link']) && (! $expire))
  271. $slaps[] = atom_entry($item,'html',$contact,$owner,true);
  272. }
  273. }
  274. }
  275. $atom .= '</feed>' . "\r\n";
  276. logger('notifier: ' . $atom, LOGGER_DATA);
  277. logger('notifier: slaps: ' . print_r($slaps,true), LOGGER_DATA);
  278. // If this is a public message and pubmail is set on the parent, include all your email contacts
  279. $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
  280. if(! $mail_disabled) {
  281. if((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid']))
  282. && (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid']))
  283. && (intval($target_item['pubmail']))) {
  284. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
  285. intval($uid),
  286. dbesc(NETWORK_MAIL)
  287. );
  288. if(count($r)) {
  289. foreach($r as $rr)
  290. $recipients[] = $rr['id'];
  291. }
  292. }
  293. }
  294. if($followup)
  295. $recip_str = $parent['contact-id'];
  296. else
  297. $recip_str = implode(', ', $recipients);
  298. $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
  299. dbesc($recip_str)
  300. );
  301. require_once('include/salmon.php');
  302. $interval = intval(get_config('system','delivery_interval'));
  303. if(! $interval)
  304. $interval = 2;
  305. // delivery loop
  306. if(count($r)) {
  307. foreach($r as $contact) {
  308. if((! $mail) && (! $fsuggest) && (! $followup) && (! $contact['self'])) {
  309. q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )",
  310. dbesc($cmd),
  311. intval($item_id),
  312. intval($contact['id'])
  313. );
  314. }
  315. }
  316. foreach($r as $contact) {
  317. if($contact['self'])
  318. continue;
  319. // potentially more than one recipient. Start a new process and space them out a bit.
  320. // we will deliver single recipient types of message and email receipients here.
  321. if((! $mail) && (! $fsuggest) && (! $followup)) {
  322. proc_run('php','include/delivery.php',$cmd,$item_id,$contact['id']);
  323. @time_sleep_until(microtime(true) + (float) $interval);
  324. }
  325. $deliver_status = 0;
  326. logger("main delivery by notifier: followup=$followup mail=$mail fsuggest=$fsuggest");
  327. switch($contact['network']) {
  328. case NETWORK_DFRN:
  329. logger('notifier: dfrndelivery: ' . $contact['name']);
  330. $deliver_status = dfrn_deliver($owner,$contact,$atom);
  331. logger('notifier: dfrn_delivery returns ' . $deliver_status);
  332. if($deliver_status == (-1)) {
  333. logger('notifier: delivery failed: queuing message');
  334. // queue message for redelivery
  335. q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`)
  336. VALUES ( %d, '%s', '%s', '%s') ",
  337. intval($contact['id']),
  338. dbesc(datetime_convert()),
  339. dbesc(datetime_convert()),
  340. dbesc($atom)
  341. );
  342. }
  343. break;
  344. case NETWORK_OSTATUS:
  345. // Do not send to otatus if we are not configured to send to public networks
  346. if($owner['prvnets'])
  347. break;
  348. if(get_config('system','ostatus_disabled') || get_config('system','dfrn_only'))
  349. break;
  350. if($followup && $contact['notify']) {
  351. logger('notifier: slapdelivery: ' . $contact['name']);
  352. $deliver_status = slapper($owner,$contact['notify'],$slap);
  353. if($deliver_status == (-1)) {
  354. // queue message for redelivery
  355. q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`)
  356. VALUES ( %d, '%s', '%s', '%s') ",
  357. intval($contact['id']),
  358. dbesc(datetime_convert()),
  359. dbesc(datetime_convert()),
  360. dbesc($slap)
  361. );
  362. }
  363. }
  364. else {
  365. // only send salmon if public - e.g. if it's ok to notify
  366. // a public hub, it's ok to send a salmon
  367. if((count($slaps)) && ($public_message) && (! $expire)) {
  368. logger('notifier: slapdelivery: ' . $contact['name']);
  369. foreach($slaps as $slappy) {
  370. if($contact['notify']) {
  371. $deliver_status = slapper($owner,$contact['notify'],$slappy);
  372. if($deliver_status == (-1)) {
  373. // queue message for redelivery
  374. q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`)
  375. VALUES ( %d, '%s', '%s', '%s') ",
  376. intval($contact['id']),
  377. dbesc(datetime_convert()),
  378. dbesc(datetime_convert()),
  379. dbesc($slappy)
  380. );
  381. }
  382. }
  383. }
  384. }
  385. }
  386. break;
  387. case NETWORK_MAIL:
  388. if(get_config('system','dfrn_only'))
  389. break;
  390. // WARNING: does not currently convert to RFC2047 header encodings, etc.
  391. $addr = $contact['addr'];
  392. if(! strlen($addr))
  393. break;
  394. if($cmd === 'wall-new' || $cmd === 'comment-new') {
  395. $it = null;
  396. if($cmd === 'wall-new')
  397. $it = $items[0];
  398. else {
  399. $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  400. intval($argv[2]),
  401. intval($uid)
  402. );
  403. if(count($r))
  404. $it = $r[0];
  405. }
  406. if(! $it)
  407. break;
  408. $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
  409. intval($uid)
  410. );
  411. if(! count($local_user))
  412. break;
  413. $reply_to = '';
  414. $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
  415. intval($uid)
  416. );
  417. if($r1 && $r1[0]['reply_to'])
  418. $reply_to = $r1[0]['reply_to'];
  419. $subject = (($it['title']) ? $it['title'] : t("\x28no subject\x29")) ;
  420. $headers = 'From: ' . $local_user[0]['username'] . ' <' . $local_user[0]['email'] . '>' . "\n";
  421. if($reply_to)
  422. $headers .= 'Reply-to: ' . $reply_to . "\n";
  423. $headers .= 'Message-id: <' . $it['uri'] . '>' . "\n";
  424. if($it['uri'] !== $it['parent-uri']) {
  425. $header .= 'References: <' . $it['parent-uri'] . '>' . "\n";
  426. if(! strlen($it['title'])) {
  427. $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' LIMIT 1",
  428. dbesc($it['parent-uri'])
  429. );
  430. if(count($r)) {
  431. $subtitle = $r[0]['title'];
  432. if($subtitle) {
  433. if(strncasecmp($subtitle,'RE:',3))
  434. $subject = $subtitle;
  435. else
  436. $subject = 'Re: ' . $subtitle;
  437. }
  438. }
  439. }
  440. }
  441. $headers .= 'MIME-Version: 1.0' . "\n";
  442. $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
  443. $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
  444. $html = prepare_body($it);
  445. $message = '<html><body>' . $html . '</body></html>';
  446. logger('notifier: email delivery to ' . $addr);
  447. mail($addr, $subject, $message, $headers);
  448. }
  449. break;
  450. case NETWORK_DIASPORA:
  451. require_once('include/diaspora.php');
  452. if(get_config('system','dfrn_only') || (! get_config('system','diaspora_enabled')) || (! $normal_mode))
  453. break;
  454. if(! $contact['pubkey'])
  455. break;
  456. if($target_item['verb'] === ACTIVITY_DISLIKE) {
  457. // unsupported
  458. break;
  459. }
  460. elseif(($target_item['deleted']) && ($target_item['verb'] !== ACTIVITY_LIKE)) {
  461. // diaspora delete,
  462. diaspora_send_retraction($target_item,$owner,$contact);
  463. break;
  464. }
  465. elseif($followup) {
  466. // send comments, likes and retractions of likes to owner to relay
  467. diaspora_send_followup($target_item,$owner,$contact);
  468. break;
  469. }
  470. elseif($target_item['parent'] != $target_item['id']) {
  471. // we are the relay - send comments, likes and unlikes to our conversants
  472. diaspora_send_relay($target_item,$owner,$contact);
  473. break;
  474. }
  475. elseif($top_level) {
  476. diaspora_send_status($target_item,$owner,$contact);
  477. break;
  478. }
  479. break;
  480. case NETWORK_FEED:
  481. case NETWORK_FACEBOOK:
  482. if(get_config('system','dfrn_only'))
  483. break;
  484. default:
  485. break;
  486. }
  487. }
  488. }
  489. // send additional slaps to mentioned remote tags (@foo@example.com)
  490. if($slap && count($url_recipients) && ($followup || $top_level) && $public_message && (! $expire)) {
  491. if(! get_config('system','dfrn_only')) {
  492. foreach($url_recipients as $url) {
  493. if($url) {
  494. logger('notifier: urldelivery: ' . $url);
  495. $deliver_status = slapper($owner,$url,$slap);
  496. // TODO: redeliver/queue these items on failure, though there is no contact record
  497. }
  498. }
  499. }
  500. }
  501. if($public_message) {
  502. $r = q("SELECT `id`, `name` FROM `contact`
  503. WHERE `network` in ('%s','%s') AND `uid` = %d AND `blocked` = 0 AND `pending` = 0
  504. AND `rel` != %d order by rand() ",
  505. dbesc(NETWORK_DFRN),
  506. dbesc(NETWORK_DIASPORA),
  507. intval($owner['uid']),
  508. intval(CONTACT_IS_SHARING)
  509. );
  510. if(count($r)) {
  511. logger('pubdeliver: ' . print_r($r,true));
  512. // throw everything into the queue in case we get killed
  513. foreach($r as $rr) {
  514. if((! $mail) && (! $fsuggest) && (! $followup)) {
  515. q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )",
  516. dbesc($cmd),
  517. intval($item_id),
  518. intval($rr['id'])
  519. );
  520. }
  521. }
  522. foreach($r as $rr) {
  523. /* Don't deliver to folks who have already been delivered to */
  524. if(in_array($rr['id'],$conversants)) {
  525. logger('notifier: already delivered id=' . $rr['id']);
  526. continue;
  527. }
  528. if((! $mail) && (! $fsuggest) && (! $followup)) {
  529. logger('notifier: delivery agent: ' . $rr['name'] . ' ' . $rr['id']);
  530. proc_run('php','include/delivery.php',$cmd,$item_id,$rr['id']);
  531. @time_sleep_until(microtime(true) + (float) $interval);
  532. }
  533. }
  534. }
  535. if(strlen($hub)) {
  536. $hubs = explode(',', $hub);
  537. if(count($hubs)) {
  538. foreach($hubs as $h) {
  539. $h = trim($h);
  540. if(! strlen($h))
  541. continue;
  542. $params = 'hub.mode=publish&hub.url=' . urlencode($a->get_baseurl() . '/dfrn_poll/' . $owner['nickname'] );
  543. post_url($h,$params);
  544. logger('pubsub: publish: ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
  545. if(count($hubs) > 1)
  546. sleep(7); // try and avoid multiple hubs responding at precisely the same time
  547. }
  548. }
  549. }
  550. }
  551. return;
  552. }
  553. if (array_search(__file__,get_included_files())===0){
  554. notifier_run($argv,$argc);
  555. killme();
  556. }