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.

919 lines
28 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
9 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
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
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. /**
  3. *
  4. * This is the POST destination for most all locally posted
  5. * text stuff. This function handles status, wall-to-wall status,
  6. * local comments, and remote coments that are posted on this site
  7. * (as opposed to being delivered in a feed).
  8. * Also processed here are posts and comments coming through the
  9. * statusnet/twitter API.
  10. * All of these become an "item" which is our basic unit of
  11. * information.
  12. * Posts that originate externally or do not fall into the above
  13. * posting categories go through item_store() instead of this function.
  14. *
  15. */
  16. require_once('include/crypto.php');
  17. require_once('include/enotify.php');
  18. require_once('include/email.php');
  19. function item_post(&$a) {
  20. if((! local_user()) && (! remote_user()) && (! x($_REQUEST,'commenter')))
  21. return;
  22. require_once('include/security.php');
  23. $uid = local_user();
  24. if(x($_REQUEST,'dropitems')) {
  25. require_once('include/items.php');
  26. $arr_drop = explode(',',$_REQUEST['dropitems']);
  27. drop_items($arr_drop);
  28. $json = array('success' => 1);
  29. echo json_encode($json);
  30. killme();
  31. }
  32. call_hooks('post_local_start', $_REQUEST);
  33. // logger('postinput ' . file_get_contents('php://input'));
  34. logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
  35. $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false);
  36. $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : '');
  37. $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0);
  38. /**
  39. * Is this a reply to something?
  40. */
  41. $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
  42. $parent_uri = ((x($_REQUEST,'parent_uri')) ? trim($_REQUEST['parent_uri']) : '');
  43. $parent_item = null;
  44. $parent_contact = null;
  45. $thr_parent = '';
  46. $parid = 0;
  47. $r = false;
  48. if($parent || $parent_uri) {
  49. if(! x($_REQUEST,'type'))
  50. $_REQUEST['type'] = 'net-comment';
  51. if($parent) {
  52. $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
  53. intval($parent)
  54. );
  55. }
  56. elseif($parent_uri && local_user()) {
  57. // This is coming from an API source, and we are logged in
  58. $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
  59. dbesc($parent_uri),
  60. intval(local_user())
  61. );
  62. }
  63. // if this isn't the real parent of the conversation, find it
  64. if($r !== false && count($r)) {
  65. $parid = $r[0]['parent'];
  66. if($r[0]['id'] != $r[0]['parent']) {
  67. $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1",
  68. intval($parid)
  69. );
  70. }
  71. }
  72. if(($r === false) || (! count($r))) {
  73. notice( t('Unable to locate original post.') . EOL);
  74. if(x($_REQUEST,'return'))
  75. goaway($a->get_baseurl() . "/" . $return_path );
  76. killme();
  77. }
  78. $parent_item = $r[0];
  79. $parent = $r[0]['id'];
  80. // multi-level threading - preserve the info but re-parent to our single level threading
  81. if(($parid) && ($parid != $parent))
  82. $thr_parent = $parent_uri;
  83. if($parent_item['contact-id'] && $uid) {
  84. $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  85. intval($parent_item['contact-id']),
  86. intval($uid)
  87. );
  88. if(count($r))
  89. $parent_contact = $r[0];
  90. }
  91. }
  92. if($parent) logger('mod_post: parent=' . $parent);
  93. $profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
  94. $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0);
  95. $app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : '');
  96. $allow_moderated = false;
  97. // here is where we are going to check for permission to post a moderated comment.
  98. // First check that the parent exists and it is a wall item.
  99. if((x($_REQUEST,'commenter')) && ((! $parent) || (! $parent_item['wall']))) {
  100. notice( t('Permission denied.') . EOL) ;
  101. if(x($_REQUEST,'return'))
  102. goaway($a->get_baseurl() . "/" . $return_path );
  103. killme();
  104. }
  105. // Now check that it is a page_type of PAGE_BLOG, and that valid personal details
  106. // have been provided, and run any anti-spam plugins
  107. // TODO
  108. if((! can_write_wall($a,$profile_uid)) && (! $allow_moderated)) {
  109. notice( t('Permission denied.') . EOL) ;
  110. if(x($_REQUEST,'return'))
  111. goaway($a->get_baseurl() . "/" . $return_path );
  112. killme();
  113. }
  114. // is this an edited post?
  115. $orig_post = null;
  116. if($post_id) {
  117. $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
  118. intval($profile_uid),
  119. intval($post_id)
  120. );
  121. if(! count($i))
  122. killme();
  123. $orig_post = $i[0];
  124. }
  125. $user = null;
  126. $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
  127. intval($profile_uid)
  128. );
  129. if(count($r))
  130. $user = $r[0];
  131. if($orig_post) {
  132. $str_group_allow = $orig_post['allow_gid'];
  133. $str_contact_allow = $orig_post['allow_cid'];
  134. $str_group_deny = $orig_post['deny_gid'];
  135. $str_contact_deny = $orig_post['deny_cid'];
  136. $title = $orig_post['title'];
  137. $location = $orig_post['location'];
  138. $coord = $orig_post['coord'];
  139. $verb = $orig_post['verb'];
  140. $emailcc = $orig_post['emailcc'];
  141. $app = $orig_post['app'];
  142. $body = escape_tags(trim($_REQUEST['body']));
  143. $private = $orig_post['private'];
  144. $pubmail_enable = $orig_post['pubmail'];
  145. }
  146. else {
  147. // if coming from the API and no privacy settings are set,
  148. // use the user default permissions - as they won't have
  149. // been supplied via a form.
  150. if(($api_source)
  151. && (! array_key_exists('contact_allow',$_REQUEST))
  152. && (! array_key_exists('group_allow',$_REQUEST))
  153. && (! array_key_exists('contact_deny',$_REQUEST))
  154. && (! array_key_exists('group_deny',$_REQUEST))) {
  155. $str_group_allow = $user['allow_gid'];
  156. $str_contact_allow = $user['allow_cid'];
  157. $str_group_deny = $user['deny_gid'];
  158. $str_contact_deny = $user['deny_cid'];
  159. }
  160. else {
  161. // use the posted permissions
  162. $str_group_allow = perms2str($_REQUEST['group_allow']);
  163. $str_contact_allow = perms2str($_REQUEST['contact_allow']);
  164. $str_group_deny = perms2str($_REQUEST['group_deny']);
  165. $str_contact_deny = perms2str($_REQUEST['contact_deny']);
  166. }
  167. $title = notags(trim($_REQUEST['title']));
  168. $location = notags(trim($_REQUEST['location']));
  169. $coord = notags(trim($_REQUEST['coord']));
  170. $verb = notags(trim($_REQUEST['verb']));
  171. $emailcc = notags(trim($_REQUEST['emailcc']));
  172. $body = escape_tags(trim($_REQUEST['body']));
  173. $private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0);
  174. if(($parent_item) &&
  175. (($parent_item['private'])
  176. || strlen($parent_item['allow_cid'])
  177. || strlen($parent_item['allow_gid'])
  178. || strlen($parent_item['deny_cid'])
  179. || strlen($parent_item['deny_gid'])
  180. )) {
  181. $private = 1;
  182. }
  183. $pubmail_enable = ((x($_REQUEST,'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && (! $private)) ? 1 : 0);
  184. // if using the API, we won't see pubmail_enable - figure out if it should be set
  185. if($api_source && $profile_uid && $profile_uid == local_user() && (! $private)) {
  186. $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
  187. if(! $mail_disabled) {
  188. $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
  189. intval(local_user())
  190. );
  191. if(count($r) && intval($r[0]['pubmail']))
  192. $pubmail_enabled = true;
  193. }
  194. }
  195. if(! strlen($body)) {
  196. if($preview)
  197. killme();
  198. info( t('Empty post discarded.') . EOL );
  199. if(x($_REQUEST,'return'))
  200. goaway($a->get_baseurl() . "/" . $return_path );
  201. killme();
  202. }
  203. }
  204. // get contact info for poster
  205. $author = null;
  206. $self = false;
  207. if(($_SESSION['uid']) && ($_SESSION['uid'] == $profile_uid)) {
  208. $self = true;
  209. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1",
  210. intval($_SESSION['uid'])
  211. );
  212. }
  213. else {
  214. if((x($_SESSION,'visitor_id')) && (intval($_SESSION['visitor_id']))) {
  215. $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
  216. intval($_SESSION['visitor_id'])
  217. );
  218. }
  219. }
  220. if(count($r)) {
  221. $author = $r[0];
  222. $contact_id = $author['id'];
  223. }
  224. // get contact info for owner
  225. if($profile_uid == $_SESSION['uid']) {
  226. $contact_record = $author;
  227. }
  228. else {
  229. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1",
  230. intval($profile_uid)
  231. );
  232. if(count($r))
  233. $contact_record = $r[0];
  234. }
  235. $post_type = notags(trim($_REQUEST['type']));
  236. if($post_type === 'net-comment') {
  237. if($parent_item !== null) {
  238. if($parent_item['wall'] == 1)
  239. $post_type = 'wall-comment';
  240. else
  241. $post_type = 'remote-comment';
  242. }
  243. }
  244. /**
  245. *
  246. * When a photo was uploaded into the message using the (profile wall) ajax
  247. * uploader, The permissions are initially set to disallow anybody but the
  248. * owner from seeing it. This is because the permissions may not yet have been
  249. * set for the post. If it's private, the photo permissions should be set
  250. * appropriately. But we didn't know the final permissions on the post until
  251. * now. So now we'll look for links of uploaded messages that are in the
  252. * post and set them to the same permissions as the post itself.
  253. *
  254. */
  255. $match = null;
  256. if((! $preview) && preg_match_all("/\[img\](.*?)\[\/img\]/",$body,$match)) {
  257. $images = $match[1];
  258. if(count($images)) {
  259. foreach($images as $image) {
  260. if(! stristr($image,$a->get_baseurl() . '/photo/'))
  261. continue;
  262. $image_uri = substr($image,strrpos($image,'/') + 1);
  263. $image_uri = substr($image_uri,0, strpos($image_uri,'-'));
  264. if(! strlen($image_uri))
  265. continue;
  266. $srch = '<' . intval($profile_uid) . '>';
  267. $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''
  268. AND `resource-id` = '%s' AND `uid` = %d LIMIT 1",
  269. dbesc($srch),
  270. dbesc($image_uri),
  271. intval($profile_uid)
  272. );
  273. if(! count($r))
  274. continue;
  275. $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'
  276. WHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ",
  277. dbesc($str_contact_allow),
  278. dbesc($str_group_allow),
  279. dbesc($str_contact_deny),
  280. dbesc($str_group_deny),
  281. dbesc($image_uri),
  282. intval($profile_uid),
  283. dbesc( t('Wall Photos'))
  284. );
  285. }
  286. }
  287. }
  288. /**
  289. * Next link in any attachment references we find in the post.
  290. */
  291. $match = false;
  292. if((! $preview) && preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",$body,$match)) {
  293. $attaches = $match[1];
  294. if(count($attaches)) {
  295. foreach($attaches as $attach) {
  296. $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1",
  297. intval($profile_uid),
  298. intval($attach)
  299. );
  300. if(count($r)) {
  301. $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'
  302. WHERE `uid` = %d AND `id` = %d LIMIT 1",
  303. dbesc($str_contact_allow),
  304. dbesc($str_group_allow),
  305. dbesc($str_contact_deny),
  306. dbesc($str_group_deny),
  307. intval($profile_uid),
  308. intval($attach)
  309. );
  310. }
  311. }
  312. }
  313. }
  314. // embedded bookmark in post? set bookmark flag
  315. $bookmark = 0;
  316. if(preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",$body,$match,PREG_SET_ORDER)) {
  317. $bookmark = 1;
  318. }
  319. $body = bb_translate_video($body);
  320. /**
  321. * Fold multi-line [code] sequences
  322. */
  323. $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body);
  324. /**
  325. * Look for any tags and linkify them
  326. */
  327. $str_tags = '';
  328. $inform = '';
  329. $tags = get_tags($body);
  330. /**
  331. * add a statusnet style reply tag if the original post was from there
  332. * and we are replying, and there isn't one already
  333. */
  334. if(($parent_contact) && ($parent_contact['network'] === NETWORK_OSTATUS)
  335. && ($parent_contact['nick']) && (! in_array('@' . $parent_contact['nick'],$tags))) {
  336. $body = '@' . $parent_contact['nick'] . ' ' . $body;
  337. $tags[] = '@' . $parent_contact['nick'];
  338. }
  339. if(count($tags)) {
  340. foreach($tags as $tag) {
  341. if(isset($profile))
  342. unset($profile);
  343. if(strpos($tag,'#') === 0) {
  344. if(strpos($tag,'[url='))
  345. continue;
  346. $basetag = str_replace('_',' ',substr($tag,1));
  347. $body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?search=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
  348. $newtag = '#[url=' . $a->get_baseurl() . '/search?search=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
  349. if(! stristr($str_tags,$newtag)) {
  350. if(strlen($str_tags))
  351. $str_tags .= ',';
  352. $str_tags .= $newtag;
  353. }
  354. continue;
  355. }
  356. if(strpos($tag,'@') === 0) {
  357. if(strpos($tag,'[url='))
  358. continue;
  359. $stat = false;
  360. $name = substr($tag,1);
  361. if((strpos($name,'@')) || (strpos($name,'http://'))) {
  362. $newname = $name;
  363. $links = @lrdd($name);
  364. if(count($links)) {
  365. foreach($links as $link) {
  366. if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
  367. $profile = $link['@attributes']['href'];
  368. if($link['@attributes']['rel'] === 'salmon') {
  369. if(strlen($inform))
  370. $inform .= ',';
  371. $inform .= 'url:' . str_replace(',','%2c',$link['@attributes']['href']);
  372. }
  373. }
  374. }
  375. }
  376. else {
  377. $newname = $name;
  378. $alias = '';
  379. $tagcid = 0;
  380. if(strrpos($newname,'+')) {
  381. $tagcid = intval(substr($newname,strrpos($newname,'+') + 1));
  382. if(strpos($name,' '))
  383. $name = substr($name,0,strpos($name,' '));
  384. }
  385. if($tagcid) {
  386. $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  387. intval($tagcid),
  388. intval($profile_uid)
  389. );
  390. }
  391. elseif(strstr($name,'_') || strstr($name,' ')) {
  392. $newname = str_replace('_',' ',$name);
  393. $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1",
  394. dbesc($newname),
  395. intval($profile_uid)
  396. );
  397. }
  398. else {
  399. $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1",
  400. dbesc($name),
  401. dbesc($name),
  402. intval($profile_uid)
  403. );
  404. }
  405. if(count($r)) {
  406. $profile = $r[0]['url'];
  407. if($r[0]['network'] === 'stat') {
  408. $newname = $r[0]['nick'];
  409. $stat = true;
  410. if($r[0]['alias'])
  411. $alias = $r[0]['alias'];
  412. }
  413. else
  414. $newname = $r[0]['name'];
  415. if(strlen($inform))
  416. $inform .= ',';
  417. $inform .= 'cid:' . $r[0]['id'];
  418. }
  419. }
  420. if($profile) {
  421. $body = str_replace('@' . $name, '@' . '[url=' . $profile . ']' . $newname . '[/url]', $body);
  422. $profile = str_replace(',','%2c',$profile);
  423. $newtag = '@[url=' . $profile . ']' . $newname . '[/url]';
  424. if(! stristr($str_tags,$newtag)) {
  425. if(strlen($str_tags))
  426. $str_tags .= ',';
  427. $str_tags .= $newtag;
  428. }
  429. // Status.Net seems to require the numeric ID URL in a mention if the person isn't
  430. // subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both.
  431. if(strlen($alias)) {
  432. $newtag = '@[url=' . $alias . ']' . $newname . '[/url]';
  433. if(! stristr($str_tags,$newtag)) {
  434. if(strlen($str_tags))
  435. $str_tags .= ',';
  436. $str_tags .= $newtag;
  437. }
  438. }
  439. }
  440. }
  441. }
  442. }
  443. $attachments = '';
  444. $match = false;
  445. if(preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$body,$match)) {
  446. foreach($match[2] as $mtch) {
  447. $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1",
  448. intval($profile_uid),
  449. intval($mtch)
  450. );
  451. if(count($r)) {
  452. if(strlen($attachments))
  453. $attachments .= ',';
  454. $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . (($r[0]['filename']) ? $r[0]['filename'] : '') . '"[/attach]';
  455. }
  456. $body = str_replace($match[1],'',$body);
  457. }
  458. }
  459. $wall = 0;
  460. if($post_type === 'wall' || $post_type === 'wall-comment')
  461. $wall = 1;
  462. if(! strlen($verb))
  463. $verb = ACTIVITY_POST ;
  464. $gravity = (($parent) ? 6 : 0 );
  465. // even if the post arrived via API we are considering that it
  466. // originated on this site by default for determining relayability.
  467. $origin = ((x($_REQUEST,'origin')) ? intval($_REQUEST['origin']) : 1);
  468. $notify_type = (($parent) ? 'comment-new' : 'wall-new' );
  469. $uri = item_new_uri($a->get_hostname(),$profile_uid);
  470. $datarray = array();
  471. $datarray['uid'] = $profile_uid;
  472. $datarray['type'] = $post_type;
  473. $datarray['wall'] = $wall;
  474. $datarray['gravity'] = $gravity;
  475. $datarray['contact-id'] = $contact_id;
  476. $datarray['owner-name'] = $contact_record['name'];
  477. $datarray['owner-link'] = $contact_record['url'];
  478. $datarray['owner-avatar'] = $contact_record['thumb'];
  479. $datarray['author-name'] = $author['name'];
  480. $datarray['author-link'] = $author['url'];
  481. $datarray['author-avatar'] = $author['thumb'];
  482. $datarray['created'] = datetime_convert();
  483. $datarray['edited'] = datetime_convert();
  484. $datarray['commented'] = datetime_convert();
  485. $datarray['received'] = datetime_convert();
  486. $datarray['changed'] = datetime_convert();
  487. $datarray['uri'] = $uri;
  488. $datarray['title'] = $title;
  489. $datarray['body'] = $body;
  490. $datarray['app'] = $app;
  491. $datarray['location'] = $location;
  492. $datarray['coord'] = $coord;
  493. $datarray['tag'] = $str_tags;
  494. $datarray['inform'] = $inform;
  495. $datarray['verb'] = $verb;
  496. $datarray['allow_cid'] = $str_contact_allow;
  497. $datarray['allow_gid'] = $str_group_allow;
  498. $datarray['deny_cid'] = $str_contact_deny;
  499. $datarray['deny_gid'] = $str_group_deny;
  500. $datarray['private'] = $private;
  501. $datarray['pubmail'] = $pubmail_enable;
  502. $datarray['attach'] = $attachments;
  503. $datarray['bookmark'] = intval($bookmark);
  504. $datarray['thr-parent'] = $thr_parent;
  505. $datarray['postopts'] = '';
  506. $datarray['origin'] = $origin;
  507. $datarray['moderated'] = $allow_moderated;
  508. /**
  509. * These fields are for the convenience of plugins...
  510. * 'self' if true indicates the owner is posting on their own wall
  511. * If parent is 0 it is a top-level post.
  512. */
  513. $datarray['parent'] = $parent;
  514. $datarray['self'] = $self;
  515. // $datarray['prvnets'] = $user['prvnets'];
  516. if($orig_post)
  517. $datarray['edit'] = true;
  518. else
  519. $datarray['guid'] = get_guid();
  520. // preview mode - prepare the body for display and send it via json
  521. if($preview) {
  522. require_once('include/conversation.php');
  523. $o = conversation(&$a,array(array_merge($contact_record,$datarray)),'search',false,true);
  524. logger('preview: ' . $o);
  525. echo json_encode(array('preview' => $o));
  526. killme();
  527. }
  528. call_hooks('post_local',$datarray);
  529. if(x($datarray,'cancel')) {
  530. logger('mod_item: post cancelled by plugin.');
  531. if($return_path) {
  532. goaway($a->get_baseurl() . "/" . $return_path);
  533. }
  534. $json = array('cancel' => 1);
  535. if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload']))
  536. $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
  537. echo json_encode($json);
  538. killme();
  539. }
  540. if($orig_post) {
  541. $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `edited` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
  542. dbesc($title),
  543. dbesc($body),
  544. dbesc(datetime_convert()),
  545. intval($post_id),
  546. intval($profile_uid)
  547. );
  548. proc_run('php', "include/notifier.php", 'edit_post', "$post_id");
  549. if((x($_REQUEST,'return')) && strlen($return_path)) {
  550. logger('return: ' . $return_path);
  551. goaway($a->get_baseurl() . "/" . $return_path );
  552. }
  553. killme();
  554. }
  555. else
  556. $post_id = 0;
  557. $r = q("INSERT INTO `item` (`guid`, `uid`,`type`,`wall`,`gravity`,`contact-id`,`owner-name`,`owner-link`,`owner-avatar`,
  558. `author-name`, `author-link`, `author-avatar`, `created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`,
  559. `tag`, `inform`, `verb`, `postopts`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin`, `moderated` )
  560. VALUES( '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d )",
  561. dbesc($datarray['guid']),
  562. intval($datarray['uid']),
  563. dbesc($datarray['type']),
  564. intval($datarray['wall']),
  565. intval($datarray['gravity']),
  566. intval($datarray['contact-id']),
  567. dbesc($datarray['owner-name']),
  568. dbesc($datarray['owner-link']),
  569. dbesc($datarray['owner-avatar']),
  570. dbesc($datarray['author-name']),
  571. dbesc($datarray['author-link']),
  572. dbesc($datarray['author-avatar']),
  573. dbesc($datarray['created']),
  574. dbesc($datarray['edited']),
  575. dbesc($datarray['commented']),
  576. dbesc($datarray['received']),
  577. dbesc($datarray['changed']),
  578. dbesc($datarray['uri']),
  579. dbesc($datarray['thr-parent']),
  580. dbesc($datarray['title']),
  581. dbesc($datarray['body']),
  582. dbesc($datarray['app']),
  583. dbesc($datarray['location']),
  584. dbesc($datarray['coord']),
  585. dbesc($datarray['tag']),
  586. dbesc($datarray['inform']),
  587. dbesc($datarray['verb']),
  588. dbesc($datarray['postopts']),
  589. dbesc($datarray['allow_cid']),
  590. dbesc($datarray['allow_gid']),
  591. dbesc($datarray['deny_cid']),
  592. dbesc($datarray['deny_gid']),
  593. intval($datarray['private']),
  594. intval($datarray['pubmail']),
  595. dbesc($datarray['attach']),
  596. intval($datarray['bookmark']),
  597. intval($datarray['origin']),
  598. intval($datarry['moderated'])
  599. );
  600. $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1",
  601. dbesc($datarray['uri']));
  602. if(count($r)) {
  603. $post_id = $r[0]['id'];
  604. logger('mod_item: saved item ' . $post_id);
  605. if($parent) {
  606. // This item is the last leaf and gets the comment box, clear any ancestors
  607. $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ",
  608. dbesc(datetime_convert()),
  609. intval($parent)
  610. );
  611. // Inherit ACL's from the parent item.
  612. $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d
  613. WHERE `id` = %d LIMIT 1",
  614. dbesc($parent_item['allow_cid']),
  615. dbesc($parent_item['allow_gid']),
  616. dbesc($parent_item['deny_cid']),
  617. dbesc($parent_item['deny_gid']),
  618. intval($parent_item['private']),
  619. intval($post_id)
  620. );
  621. if($contact_record != $author) {
  622. notification(array(
  623. 'type' => NOTIFY_COMMENT,
  624. 'notify_flags' => $user['notify-flags'],
  625. 'language' => $user['language'],
  626. 'to_name' => $user['username'],
  627. 'to_email' => $user['email'],
  628. 'item' => $datarray,
  629. 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id,
  630. 'source_name' => $datarray['author-name'],
  631. 'source_link' => $datarray['author-link'],
  632. 'source_photo' => $datarray['author-avatar'],
  633. 'verb' => ACTIVITY_POST,
  634. 'otype' => 'item'
  635. ));
  636. }
  637. // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key
  638. if($self) {
  639. require_once('include/bb2diaspora.php');
  640. $signed_body = html_entity_decode(bb2diaspora($datarray['body']));
  641. $myaddr = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
  642. if($datarray['verb'] === ACTIVITY_LIKE)
  643. $signed_text = $datarray['guid'] . ';' . 'Post' . ';' . $parent_item['guid'] . ';' . 'true' . ';' . $myaddr;
  644. else
  645. $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $myaddr;
  646. $authorsig = base64_encode(rsa_sign($signed_text,$a->user['prvkey'],'sha256'));
  647. q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
  648. intval($post_id),
  649. dbesc($signed_text),
  650. dbesc(base64_encode($authorsig)),
  651. dbesc($myaddr)
  652. );
  653. }
  654. }
  655. else {
  656. $parent = $post_id;
  657. if($contact_record != $author) {
  658. notification(array(
  659. 'type' => NOTIFY_WALL,
  660. 'notify_flags' => $user['notify-flags'],
  661. 'language' => $user['language'],
  662. 'to_name' => $user['username'],
  663. 'to_email' => $user['email'],
  664. 'item' => $datarray,
  665. 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id,
  666. 'source_name' => $datarray['author-name'],
  667. 'source_link' => $datarray['author-link'],
  668. 'source_photo' => $datarray['author-avatar'],
  669. 'verb' => ACTIVITY_POST,
  670. 'otype' => 'item'
  671. ));
  672. }
  673. }
  674. // fallback so that parent always gets set to non-zero.
  675. if(! $parent)
  676. $parent = $post_id;
  677. $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1
  678. WHERE `id` = %d LIMIT 1",
  679. intval($parent),
  680. dbesc(($parent == $post_id) ? $uri : $parent_item['uri']),
  681. dbesc($a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id),
  682. dbesc(datetime_convert()),
  683. intval($post_id)
  684. );
  685. // photo comments turn the corresponding item visible to the profile wall
  686. // This way we don't see every picture in your new photo album posted to your wall at once.
  687. // They will show up as people comment on them.
  688. if(! $parent_item['visible']) {
  689. $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d LIMIT 1",
  690. intval($parent_item['id'])
  691. );
  692. }
  693. }
  694. else {
  695. logger('mod_item: unable to retrieve post that was just stored.');
  696. notify( t('System error. Post not saved.'));
  697. goaway($a->get_baseurl() . "/" . $return_path );
  698. // NOTREACHED
  699. }
  700. // update the commented timestamp on the parent
  701. q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1",
  702. dbesc(datetime_convert()),
  703. dbesc(datetime_convert()),
  704. intval($parent)
  705. );
  706. $datarray['id'] = $post_id;
  707. $datarray['plink'] = $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id;
  708. call_hooks('post_local_end', $datarray);
  709. if(strlen($emailcc) && $profile_uid == local_user()) {
  710. $erecips = explode(',', $emailcc);
  711. if(count($erecips)) {
  712. foreach($erecips as $recip) {
  713. $addr = trim($recip);
  714. if(! strlen($addr))
  715. continue;
  716. $disclaimer = '<hr />' . sprintf( t('This message was sent to you by %s, a member of the Friendica social network.'),$a->user['username'])
  717. . '<br />';
  718. $disclaimer .= sprintf( t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL;
  719. $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
  720. $subject = email_header_encode('[Friendica]' . ' ' . sprintf( t('%s posted an update.'),$a->user['username']),'UTF-8');
  721. $headers = 'From: ' . email_header_encode($a->user['username'],'UTF-8') . ' <' . $a->user['email'] . '>' . "\n";
  722. $headers .= 'MIME-Version: 1.0' . "\n";
  723. $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
  724. $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
  725. $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
  726. $html = prepare_body($datarray);
  727. $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
  728. @mail($addr, $subject, $message, $headers);
  729. }
  730. }
  731. }
  732. // This is a real juggling act on shared hosting services which kill your processes
  733. // e.g. dreamhost. We used to start delivery to our native delivery agents in the background
  734. // and then run our plugin delivery from the foreground. We're now doing plugin delivery first,
  735. // because as soon as you start loading up a bunch of remote delivey processes, *this* page is
  736. // likely to get killed off. If you end up looking at an /item URL and a blank page,
  737. // it's very likely the delivery got killed before all your friends could be notified.
  738. // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting,
  739. // or cut back on plugins which do remote deliveries.
  740. proc_run('php', "include/notifier.php", $notify_type, "$post_id");
  741. logger('post_complete');
  742. // figure out how to return, depending on from whence we came
  743. if($api_source)
  744. return;
  745. if($return_path) {
  746. goaway($a->get_baseurl() . "/" . $return_path);
  747. }
  748. $json = array('success' => 1);
  749. if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload']))
  750. $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
  751. logger('post_json: ' . print_r($json,true), LOGGER_DEBUG);
  752. echo json_encode($json);
  753. killme();
  754. // NOTREACHED
  755. }
  756. function item_content(&$a) {
  757. if((! local_user()) && (! remote_user()))
  758. return;
  759. require_once('include/security.php');
  760. if(($a->argc == 3) && ($a->argv[1] === 'drop') && intval($a->argv[2])) {
  761. require_once('include/items.php');
  762. drop_item($a->argv[2]);
  763. }
  764. }