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.

1303 lines
40 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 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
10 years ago
11 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
11 years ago
11 years ago
  1. <?php
  2. /*
  3. * This is the POST destination for most all locally posted
  4. * text stuff. This function handles status, wall-to-wall status,
  5. * local comments, and remote coments that are posted on this site
  6. * (as opposed to being delivered in a feed).
  7. * Also processed here are posts and comments coming through the
  8. * statusnet/twitter API.
  9. *
  10. * All of these become an "item" which is our basic unit of
  11. * information.
  12. *
  13. * Posts that originate externally or do not fall into the above
  14. * posting categories go through item_store() instead of this function.
  15. */
  16. require_once 'include/crypto.php';
  17. require_once 'include/enotify.php';
  18. require_once 'include/email.php';
  19. require_once 'include/tags.php';
  20. require_once 'include/files.php';
  21. require_once 'include/threads.php';
  22. require_once 'include/text.php';
  23. require_once 'include/items.php';
  24. require_once 'include/Scrape.php';
  25. require_once 'include/diaspora.php';
  26. require_once 'include/Contact.php';
  27. function item_post(App $a) {
  28. if ((! local_user()) && (! remote_user()) && (! x($_REQUEST, 'commenter'))) {
  29. return;
  30. }
  31. require_once 'include/security.php';
  32. $uid = local_user();
  33. if (x($_REQUEST, 'dropitems')) {
  34. $arr_drop = explode(',', $_REQUEST['dropitems']);
  35. drop_items($arr_drop);
  36. $json = array('success' => 1);
  37. echo json_encode($json);
  38. killme();
  39. }
  40. call_hooks('post_local_start', $_REQUEST);
  41. // logger('postinput ' . file_get_contents('php://input'));
  42. logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
  43. $api_source = ((x($_REQUEST, 'api_source') && $_REQUEST['api_source']) ? true : false);
  44. $message_id = ((x($_REQUEST, 'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : '');
  45. $return_path = ((x($_REQUEST, 'return')) ? $_REQUEST['return'] : '');
  46. $preview = ((x($_REQUEST, 'preview')) ? intval($_REQUEST['preview']) : 0);
  47. /*
  48. * Check for doubly-submitted posts, and reject duplicates
  49. * Note that we have to ignore previews, otherwise nothing will post
  50. * after it's been previewed
  51. */
  52. if (!$preview && x($_REQUEST, 'post_id_random')) {
  53. if (x($_SESSION, 'post-random') && $_SESSION['post-random'] == $_REQUEST['post_id_random']) {
  54. logger("item post: duplicate post", LOGGER_DEBUG);
  55. item_post_return(App::get_baseurl(), $api_source, $return_path);
  56. } else {
  57. $_SESSION['post-random'] = $_REQUEST['post_id_random'];
  58. }
  59. }
  60. // Is this a reply to something?
  61. $parent = ((x($_REQUEST, 'parent')) ? intval($_REQUEST['parent']) : 0);
  62. $parent_uri = ((x($_REQUEST, 'parent_uri')) ? trim($_REQUEST['parent_uri']) : '');
  63. $parent_item = null;
  64. $parent_contact = null;
  65. $thr_parent = '';
  66. $parid = 0;
  67. $r = false;
  68. $objecttype = null;
  69. if ($parent || $parent_uri) {
  70. $objecttype = ACTIVITY_OBJ_COMMENT;
  71. if (! x($_REQUEST, 'type')) {
  72. $_REQUEST['type'] = 'net-comment';
  73. }
  74. if ($parent) {
  75. $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
  76. intval($parent)
  77. );
  78. } elseif ($parent_uri && local_user()) {
  79. // This is coming from an API source, and we are logged in
  80. $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
  81. dbesc($parent_uri),
  82. intval(local_user())
  83. );
  84. }
  85. // if this isn't the real parent of the conversation, find it
  86. if (dbm::is_result($r)) {
  87. $parid = $r[0]['parent'];
  88. $parent_uri = $r[0]['uri'];
  89. if ($r[0]['id'] != $r[0]['parent']) {
  90. $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1",
  91. intval($parid)
  92. );
  93. }
  94. }
  95. if (! dbm::is_result($r)) {
  96. notice( t('Unable to locate original post.') . EOL);
  97. if (x($_REQUEST, 'return')) {
  98. goaway($return_path);
  99. }
  100. killme();
  101. }
  102. $parent_item = $r[0];
  103. $parent = $r[0]['id'];
  104. // multi-level threading - preserve the info but re-parent to our single level threading
  105. //if(($parid) && ($parid != $parent))
  106. $thr_parent = $parent_uri;
  107. if ($parent_item['contact-id'] && $uid) {
  108. $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  109. intval($parent_item['contact-id']),
  110. intval($uid)
  111. );
  112. if (dbm::is_result($r)) {
  113. $parent_contact = $r[0];
  114. }
  115. // If the contact id doesn't fit with the contact, then set the contact to null
  116. $thrparent = q("SELECT `author-link`, `network` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($thr_parent));
  117. if (dbm::is_result($thrparent) AND ($thrparent[0]["network"] === NETWORK_OSTATUS)
  118. AND (normalise_link($parent_contact["url"]) != normalise_link($thrparent[0]["author-link"]))) {
  119. $parent_contact = get_contact_details_by_url($thrparent[0]["author-link"]);
  120. if (!isset($parent_contact["nick"])) {
  121. require_once 'include/Scrape.php';
  122. $probed_contact = probe_url($thrparent[0]["author-link"]);
  123. if ($probed_contact["network"] != NETWORK_FEED) {
  124. $parent_contact = $probed_contact;
  125. $parent_contact["nurl"] = normalise_link($probed_contact["url"]);
  126. $parent_contact["thumb"] = $probed_contact["photo"];
  127. $parent_contact["micro"] = $probed_contact["photo"];
  128. $parent_contact["addr"] = $probed_contact["addr"];
  129. }
  130. }
  131. logger('no contact found: ' . print_r($thrparent, true), LOGGER_DEBUG);
  132. } else {
  133. logger('parent contact: ' . print_r($parent_contact, true), LOGGER_DEBUG);
  134. }
  135. if ($parent_contact["nick"] == "") {
  136. $parent_contact["nick"] = $parent_contact["name"];
  137. }
  138. }
  139. }
  140. if ($parent) {
  141. logger('mod_item: item_post parent=' . $parent);
  142. }
  143. $profile_uid = ((x($_REQUEST, 'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
  144. $post_id = ((x($_REQUEST, 'post_id')) ? intval($_REQUEST['post_id']) : 0);
  145. $app = ((x($_REQUEST, 'source')) ? strip_tags($_REQUEST['source']) : '');
  146. $extid = ((x($_REQUEST, 'extid')) ? strip_tags($_REQUEST['extid']) : '');
  147. $object = ((x($_REQUEST, 'object')) ? $_REQUEST['object'] : '');
  148. // Check for multiple posts with the same message id (when the post was created via API)
  149. if (($message_id != '') AND ($profile_uid != 0)) {
  150. $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
  151. dbesc($message_id),
  152. intval($profile_uid)
  153. );
  154. if (dbm::is_result($r)) {
  155. logger("Message with URI ".$message_id." already exists for user ".$profile_uid, LOGGER_DEBUG);
  156. return;
  157. }
  158. }
  159. $allow_moderated = false;
  160. // here is where we are going to check for permission to post a moderated comment.
  161. // First check that the parent exists and it is a wall item.
  162. if ((x($_REQUEST, 'commenter')) && ((! $parent) || (! $parent_item['wall']))) {
  163. notice(t('Permission denied.') . EOL) ;
  164. if (x($_REQUEST, 'return')) {
  165. goaway($return_path);
  166. }
  167. killme();
  168. }
  169. /*
  170. * Now check that it is a page_type of PAGE_BLOG, and that valid personal details
  171. * have been provided, and run any anti-spam plugins
  172. */
  173. if ((! can_write_wall($a, $profile_uid)) && (! $allow_moderated)) {
  174. notice(t('Permission denied.') . EOL) ;
  175. if (x($_REQUEST, 'return')) {
  176. goaway($return_path);
  177. }
  178. killme();
  179. }
  180. // is this an edited post?
  181. $orig_post = null;
  182. if ($post_id) {
  183. $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
  184. intval($profile_uid),
  185. intval($post_id)
  186. );
  187. if (! dbm::is_result($i)) {
  188. killme();
  189. }
  190. $orig_post = $i[0];
  191. }
  192. $user = null;
  193. $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
  194. intval($profile_uid)
  195. );
  196. if (dbm::is_result($r)) {
  197. $user = $r[0];
  198. }
  199. if ($orig_post) {
  200. $str_group_allow = $orig_post['allow_gid'];
  201. $str_contact_allow = $orig_post['allow_cid'];
  202. $str_group_deny = $orig_post['deny_gid'];
  203. $str_contact_deny = $orig_post['deny_cid'];
  204. $location = $orig_post['location'];
  205. $coord = $orig_post['coord'];
  206. $verb = $orig_post['verb'];
  207. $objecttype = $orig_post['object-type'];
  208. $emailcc = $orig_post['emailcc'];
  209. $app = $orig_post['app'];
  210. $categories = $orig_post['file'];
  211. $title = notags(trim($_REQUEST['title']));
  212. $body = escape_tags(trim($_REQUEST['body']));
  213. $private = $orig_post['private'];
  214. $pubmail_enable = $orig_post['pubmail'];
  215. $network = $orig_post['network'];
  216. $guid = $orig_post['guid'];
  217. $extid = $orig_post['extid'];
  218. } else {
  219. /*
  220. * if coming from the API and no privacy settings are set,
  221. * use the user default permissions - as they won't have
  222. * been supplied via a form.
  223. */
  224. /// @TODO use x($_REQUEST, 'foo') here
  225. if (($api_source)
  226. && (! array_key_exists('contact_allow', $_REQUEST))
  227. && (! array_key_exists('group_allow', $_REQUEST))
  228. && (! array_key_exists('contact_deny', $_REQUEST))
  229. && (! array_key_exists('group_deny', $_REQUEST))) {
  230. $str_group_allow = $user['allow_gid'];
  231. $str_contact_allow = $user['allow_cid'];
  232. $str_group_deny = $user['deny_gid'];
  233. $str_contact_deny = $user['deny_cid'];
  234. } else {
  235. // use the posted permissions
  236. $str_group_allow = perms2str($_REQUEST['group_allow']);
  237. $str_contact_allow = perms2str($_REQUEST['contact_allow']);
  238. $str_group_deny = perms2str($_REQUEST['group_deny']);
  239. $str_contact_deny = perms2str($_REQUEST['contact_deny']);
  240. }
  241. $title = notags(trim($_REQUEST['title']));
  242. $location = notags(trim($_REQUEST['location']));
  243. $coord = notags(trim($_REQUEST['coord']));
  244. $verb = notags(trim($_REQUEST['verb']));
  245. $emailcc = notags(trim($_REQUEST['emailcc']));
  246. $body = escape_tags(trim($_REQUEST['body']));
  247. $network = notags(trim($_REQUEST['network']));
  248. $guid = get_guid(32);
  249. item_add_language_opt($_REQUEST);
  250. $postopts = $_REQUEST['postopts'] ? $_REQUEST['postopts'] : "";
  251. $private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0);
  252. if ($user['hidewall']) {
  253. $private = 2;
  254. }
  255. // If this is a comment, set the permissions from the parent.
  256. if ($parent_item) {
  257. // for non native networks use the network of the original post as network of the item
  258. if (($parent_item['network'] != NETWORK_DIASPORA)
  259. AND ($parent_item['network'] != NETWORK_OSTATUS)
  260. AND ($network == "")) {
  261. $network = $parent_item['network'];
  262. }
  263. $str_contact_allow = $parent_item['allow_cid'];
  264. $str_group_allow = $parent_item['allow_gid'];
  265. $str_contact_deny = $parent_item['deny_cid'];
  266. $str_group_deny = $parent_item['deny_gid'];
  267. $private = $parent_item['private'];
  268. }
  269. $pubmail_enable = ((x($_REQUEST, 'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && (! $private)) ? 1 : 0);
  270. // if using the API, we won't see pubmail_enable - figure out if it should be set
  271. if ($api_source && $profile_uid && $profile_uid == local_user() && (! $private)) {
  272. $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
  273. if (! $mail_disabled) {
  274. $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
  275. intval(local_user())
  276. );
  277. if (dbm::is_result($r) && intval($r[0]['pubmail'])) {
  278. $pubmail_enabled = true;
  279. }
  280. }
  281. }
  282. if (! strlen($body)) {
  283. if ($preview) {
  284. killme();
  285. }
  286. info(t('Empty post discarded.') . EOL );
  287. if (x($_REQUEST, 'return')) {
  288. goaway($return_path);
  289. }
  290. killme();
  291. }
  292. }
  293. if (strlen($categories)) {
  294. // get the "fileas" tags for this post
  295. $filedas = file_tag_file_to_list($categories, 'file');
  296. }
  297. // save old and new categories, so we can determine what needs to be deleted from pconfig
  298. $categories_old = $categories;
  299. $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category');
  300. $categories_new = $categories;
  301. if (strlen($filedas)) {
  302. // append the fileas stuff to the new categories list
  303. $categories .= file_tag_list_to_file($filedas, 'file');
  304. }
  305. // get contact info for poster
  306. $author = null;
  307. $self = false;
  308. $contact_id = 0;
  309. if ((local_user()) && (local_user() == $profile_uid)) {
  310. $self = true;
  311. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1",
  312. intval($_SESSION['uid']));
  313. } elseif(remote_user()) {
  314. if (is_array($_SESSION['remote'])) {
  315. foreach ($_SESSION['remote'] as $v) {
  316. if ($v['uid'] == $profile_uid) {
  317. $contact_id = $v['cid'];
  318. break;
  319. }
  320. }
  321. }
  322. if ($contact_id) {
  323. $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
  324. intval($contact_id)
  325. );
  326. }
  327. }
  328. if (dbm::is_result($r)) {
  329. $author = $r[0];
  330. $contact_id = $author['id'];
  331. }
  332. // get contact info for owner
  333. if ($profile_uid == local_user()) {
  334. $contact_record = $author;
  335. } else {
  336. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1",
  337. intval($profile_uid)
  338. );
  339. if (dbm::is_result($r)) {
  340. $contact_record = $r[0];
  341. }
  342. }
  343. $post_type = notags(trim($_REQUEST['type']));
  344. if ($post_type === 'net-comment' && $parent_item !== null) {
  345. if ($parent_item['wall'] == 1) {
  346. $post_type = 'wall-comment';
  347. } else {
  348. $post_type = 'remote-comment';
  349. }
  350. }
  351. /*
  352. * When a photo was uploaded into the message using the (profile wall) ajax
  353. * uploader, The permissions are initially set to disallow anybody but the
  354. * owner from seeing it. This is because the permissions may not yet have been
  355. * set for the post. If it's private, the photo permissions should be set
  356. * appropriately. But we didn't know the final permissions on the post until
  357. * now. So now we'll look for links of uploaded messages that are in the
  358. * post and set them to the same permissions as the post itself.
  359. */
  360. $match = null;
  361. if ((! $preview) && preg_match_all("/\[img([\=0-9x]*?)\](.*?)\[\/img\]/",$body,$match)) {
  362. $images = $match[2];
  363. if (count($images)) {
  364. $objecttype = ACTIVITY_OBJ_IMAGE;
  365. foreach ($images as $image) {
  366. if (! stristr($image,App::get_baseurl() . '/photo/')) {
  367. continue;
  368. }
  369. $image_uri = substr($image,strrpos($image,'/') + 1);
  370. $image_uri = substr($image_uri,0, strpos($image_uri,'-'));
  371. if (! strlen($image_uri)) {
  372. continue;
  373. }
  374. $srch = '<' . intval($contact_id) . '>';
  375. $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''
  376. AND `resource-id` = '%s' AND `uid` = %d LIMIT 1",
  377. dbesc($srch),
  378. dbesc($image_uri),
  379. intval($profile_uid)
  380. );
  381. if (! dbm::is_result($r)) {
  382. continue;
  383. }
  384. $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'
  385. WHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ",
  386. dbesc($str_contact_allow),
  387. dbesc($str_group_allow),
  388. dbesc($str_contact_deny),
  389. dbesc($str_group_deny),
  390. dbesc($image_uri),
  391. intval($profile_uid),
  392. dbesc( t('Wall Photos'))
  393. );
  394. }
  395. }
  396. }
  397. /*
  398. * Next link in any attachment references we find in the post.
  399. */
  400. $match = false;
  401. if ((! $preview) && preg_match_all("/\[attachment\](.*?)\[\/attachment\]/", $body, $match)) {
  402. $attaches = $match[1];
  403. if (count($attaches)) {
  404. foreach ($attaches as $attach) {
  405. $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1",
  406. intval($profile_uid),
  407. intval($attach)
  408. );
  409. if (dbm::is_result($r)) {
  410. $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'
  411. WHERE `uid` = %d AND `id` = %d",
  412. dbesc($str_contact_allow),
  413. dbesc($str_group_allow),
  414. dbesc($str_contact_deny),
  415. dbesc($str_group_deny),
  416. intval($profile_uid),
  417. intval($attach)
  418. );
  419. }
  420. }
  421. }
  422. }
  423. // embedded bookmark or attachment in post? set bookmark flag
  424. $bookmark = 0;
  425. $data = get_attachment_data($body);
  426. if (preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $body, $match, PREG_SET_ORDER) OR isset($data["type"])) {
  427. $objecttype = ACTIVITY_OBJ_BOOKMARK;
  428. $bookmark = 1;
  429. }
  430. $body = bb_translate_video($body);
  431. // Fold multi-line [code] sequences
  432. $body = preg_replace('/\[\/code\]\s*\[code\]/ism', "\n", $body);
  433. $body = scale_external_images($body, false);
  434. // Setting the object type if not defined before
  435. if (!$objecttype) {
  436. $objecttype = ACTIVITY_OBJ_NOTE; // Default value
  437. require_once 'include/plaintext.php';
  438. $objectdata = get_attached_data($body);
  439. if ($post["type"] == "link") {
  440. $objecttype = ACTIVITY_OBJ_BOOKMARK;
  441. } elseif ($post["type"] == "video") {
  442. $objecttype = ACTIVITY_OBJ_VIDEO;
  443. } elseif ($post["type"] == "photo") {
  444. $objecttype = ACTIVITY_OBJ_IMAGE;
  445. }
  446. }
  447. // Look for any tags and linkify them
  448. $str_tags = '';
  449. $inform = '';
  450. $tags = get_tags($body);
  451. /*
  452. * add a statusnet style reply tag if the original post was from there
  453. * and we are replying, and there isn't one already
  454. */
  455. if ($parent AND ($parent_contact['network'] == NETWORK_OSTATUS)) {
  456. $contact = '@[url=' . $parent_contact['url'] . ']' . $parent_contact['nick'] . '[/url]';
  457. if (!in_array($contact,$tags)) {
  458. $body = $contact . ' ' . $body;
  459. $tags[] = $contact;
  460. }
  461. $toplevel_contact = "";
  462. $toplevel_parent = q("SELECT `contact`.* FROM `contact`
  463. INNER JOIN `item` ON `item`.`contact-id` = `contact`.`id` AND `contact`.`url` = `item`.`author-link`
  464. WHERE `item`.`id` = `item`.`parent` AND `item`.`parent` = %d", intval($parent));
  465. if (dbm::is_result($toplevel_parent)) {
  466. $toplevel_contact = '@' . $toplevel_parent[0]['nick'] . '+' . $toplevel_parent[0]['id'];
  467. } else {
  468. $toplevel_parent = q("SELECT `author-link`, `author-name` FROM `item` WHERE `id` = `parent` AND `parent` = %d", intval($parent));
  469. $toplevel_contact = '@[url=' . $toplevel_parent[0]['author-link'] . ']' . $toplevel_parent[0]['author-name'] . '[/url]';
  470. }
  471. if (!in_array($toplevel_contact, $tags)) {
  472. $tags[] = $toplevel_contact;
  473. }
  474. }
  475. $tagged = array();
  476. $private_forum = false;
  477. if (count($tags)) {
  478. foreach ($tags as $tag) {
  479. if (strpos($tag, '#') === 0) {
  480. continue;
  481. }
  482. /*
  483. * If we already tagged 'Robert Johnson', don't try and tag 'Robert'.
  484. * Robert Johnson should be first in the $tags array
  485. */
  486. $fullnametagged = false;
  487. /// @TODO $tagged is initialized above if() block and is not filled, maybe old-lost code?
  488. foreach ($tagged as $nextTag) {
  489. if (stristr($nextTag, $tag . ' ')) {
  490. $fullnametagged = true;
  491. break;
  492. }
  493. }
  494. if ($fullnametagged) {
  495. continue;
  496. }
  497. $success = handle_tag($a, $body, $inform, $str_tags, (local_user()) ? local_user() : $profile_uid , $tag, $network);
  498. if ($success['replaced']) {
  499. $tagged[] = $tag;
  500. }
  501. if (is_array($success['contact']) && intval($success['contact']['prv'])) {
  502. $private_forum = true;
  503. $private_id = $success['contact']['id'];
  504. }
  505. }
  506. }
  507. if (($private_forum) && (! $parent) && (! $private)) {
  508. // we tagged a private forum in a top level post and the message was public.
  509. // Restrict it.
  510. $private = 1;
  511. $str_contact_allow = '<' . $private_id . '>';
  512. }
  513. $attachments = '';
  514. $match = false;
  515. if (preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$body,$match)) {
  516. foreach ($match[2] as $mtch) {
  517. $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1",
  518. intval($profile_uid),
  519. intval($mtch)
  520. );
  521. if (dbm::is_result($r)) {
  522. if (strlen($attachments)) {
  523. $attachments .= ',';
  524. }
  525. $attachments .= '[attach]href="' . App::get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . (($r[0]['filename']) ? $r[0]['filename'] : '') . '"[/attach]';
  526. }
  527. $body = str_replace($match[1],'',$body);
  528. }
  529. }
  530. $wall = 0;
  531. if ($post_type === 'wall' || $post_type === 'wall-comment') {
  532. $wall = 1;
  533. }
  534. if (! strlen($verb)) {
  535. $verb = ACTIVITY_POST ;
  536. }
  537. if ($network == "") {
  538. $network = NETWORK_DFRN;
  539. }
  540. $gravity = (($parent) ? 6 : 0 );
  541. // even if the post arrived via API we are considering that it
  542. // originated on this site by default for determining relayability.
  543. $origin = ((x($_REQUEST, 'origin')) ? intval($_REQUEST['origin']) : 1);
  544. $notify_type = (($parent) ? 'comment-new' : 'wall-new' );
  545. $uri = (($message_id) ? $message_id : item_new_uri($a->get_hostname(),$profile_uid, $guid));
  546. // Fallback so that we alway have a thr-parent
  547. if (!$thr_parent) {
  548. $thr_parent = $uri;
  549. }
  550. $datarray = array();
  551. $datarray['uid'] = $profile_uid;
  552. $datarray['type'] = $post_type;
  553. $datarray['wall'] = $wall;
  554. $datarray['gravity'] = $gravity;
  555. $datarray['network'] = $network;
  556. $datarray['contact-id'] = $contact_id;
  557. $datarray['owner-name'] = $contact_record['name'];
  558. $datarray['owner-link'] = $contact_record['url'];
  559. $datarray['owner-avatar'] = $contact_record['thumb'];
  560. $datarray['owner-id'] = get_contact($datarray['owner-link'], 0);
  561. $datarray['author-name'] = $author['name'];
  562. $datarray['author-link'] = $author['url'];
  563. $datarray['author-avatar'] = $author['thumb'];
  564. $datarray['author-id'] = get_contact($datarray['author-link'], 0);
  565. $datarray['created'] = datetime_convert();
  566. $datarray['edited'] = datetime_convert();
  567. $datarray['commented'] = datetime_convert();
  568. $datarray['received'] = datetime_convert();
  569. $datarray['changed'] = datetime_convert();
  570. $datarray['extid'] = $extid;
  571. $datarray['guid'] = $guid;
  572. $datarray['uri'] = $uri;
  573. $datarray['title'] = $title;
  574. $datarray['body'] = $body;
  575. $datarray['app'] = $app;
  576. $datarray['location'] = $location;
  577. $datarray['coord'] = $coord;
  578. $datarray['tag'] = $str_tags;
  579. $datarray['file'] = $categories;
  580. $datarray['inform'] = $inform;
  581. $datarray['verb'] = $verb;
  582. $datarray['object-type'] = $objecttype;
  583. $datarray['allow_cid'] = $str_contact_allow;
  584. $datarray['allow_gid'] = $str_group_allow;
  585. $datarray['deny_cid'] = $str_contact_deny;
  586. $datarray['deny_gid'] = $str_group_deny;
  587. $datarray['private'] = $private;
  588. $datarray['pubmail'] = $pubmail_enable;
  589. $datarray['attach'] = $attachments;
  590. $datarray['bookmark'] = intval($bookmark);
  591. $datarray['thr-parent'] = $thr_parent;
  592. $datarray['postopts'] = $postopts;
  593. $datarray['origin'] = $origin;
  594. $datarray['moderated'] = $allow_moderated;
  595. $datarray['gcontact-id'] = get_gcontact_id(array("url" => $datarray['author-link'], "network" => $datarray['network'],
  596. "photo" => $datarray['author-avatar'], "name" => $datarray['author-name']));
  597. $datarray['object'] = $object;
  598. /*
  599. * These fields are for the convenience of plugins...
  600. * 'self' if true indicates the owner is posting on their own wall
  601. * If parent is 0 it is a top-level post.
  602. */
  603. $datarray['parent'] = $parent;
  604. $datarray['self'] = $self;
  605. // $datarray['prvnets'] = $user['prvnets'];
  606. $datarray['parent-uri'] = ($parent == 0) ? $uri : $parent_item['uri'];
  607. $datarray['plink'] = App::get_baseurl() . '/display/' . urlencode($datarray['guid']);
  608. $datarray['last-child'] = 1;
  609. $datarray['visible'] = 1;
  610. if ($orig_post) {
  611. $datarray['edit'] = true;
  612. }
  613. // Search for hashtags
  614. item_body_set_hashtags($datarray);
  615. // preview mode - prepare the body for display and send it via json
  616. if ($preview) {
  617. require_once 'include/conversation.php';
  618. // We set the datarray ID to -1 because in preview mode the dataray
  619. // doesn't have an ID.
  620. $datarray["id"] = -1;
  621. $o = conversation($a,array(array_merge($contact_record,$datarray)),'search', false, true);
  622. logger('preview: ' . $o);
  623. echo json_encode(array('preview' => $o));
  624. killme();
  625. }
  626. call_hooks('post_local',$datarray);
  627. if (x($datarray, 'cancel')) {
  628. logger('mod_item: post cancelled by plugin.');
  629. if ($return_path) {
  630. goaway($return_path);
  631. }
  632. $json = array('cancel' => 1);
  633. if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
  634. $json['reload'] = App::get_baseurl() . '/' . $_REQUEST['jsreload'];
  635. }
  636. echo json_encode($json);
  637. killme();
  638. }
  639. // Fill the cache field
  640. put_item_in_cache($datarray);
  641. if ($orig_post) {
  642. $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `attach` = '%s', `file` = '%s', `rendered-html` = '%s', `rendered-hash` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d",
  643. dbesc($datarray['title']),
  644. dbesc($datarray['body']),
  645. dbesc($datarray['tag']),
  646. dbesc($datarray['attach']),
  647. dbesc($datarray['file']),
  648. dbesc($datarray['rendered-html']),
  649. dbesc($datarray['rendered-hash']),
  650. dbesc(datetime_convert()),
  651. dbesc(datetime_convert()),
  652. intval($post_id),
  653. intval($profile_uid)
  654. );
  655. create_tags_from_item($post_id);
  656. create_files_from_item($post_id);
  657. update_thread($post_id);
  658. // update filetags in pconfig
  659. file_tag_update_pconfig($uid,$categories_old,$categories_new,'category');
  660. proc_run(PRIORITY_HIGH, "include/notifier.php", 'edit_post', $post_id);
  661. if ((x($_REQUEST, 'return')) && strlen($return_path)) {
  662. logger('return: ' . $return_path);
  663. goaway($return_path);
  664. }
  665. killme();
  666. } else {
  667. $post_id = 0;
  668. }
  669. q("COMMIT");
  670. q("START TRANSACTION;");
  671. $r = q("INSERT INTO `item` (`guid`, `extid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`,
  672. `owner-name`,`owner-link`,`owner-avatar`, `owner-id`,
  673. `author-name`, `author-link`, `author-avatar`, `author-id`,
  674. `created`, `edited`, `commented`, `received`, `changed`,
  675. `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`,
  676. `tag`, `inform`, `verb`, `object-type`, `postopts`,
  677. `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`,
  678. `pubmail`, `attach`, `bookmark`,`origin`, `moderated`, `file`,
  679. `rendered-html`, `rendered-hash`, `gcontact-id`, `object`,
  680. `parent`, `parent-uri`, `plink`, `last-child`, `visible`)
  681. VALUES('%s', '%s', %d, '%s', %d, %d, '%s', %d,
  682. '%s', '%s', '%s', %d,
  683. '%s', '%s', '%s', %d,
  684. '%s', '%s', '%s', '%s', '%s',
  685. '%s', '%s', '%s', '%s', '%s', '%s', '%s',
  686. '%s', '%s', '%s', '%s', '%s',
  687. '%s', '%s', '%s', '%s', %d,
  688. %d, '%s', %d, %d, %d, '%s',
  689. '%s', '%s', %d, '%s',
  690. %d, '%s', '%s', %d, %d)",
  691. dbesc($datarray['guid']),
  692. dbesc($datarray['extid']),
  693. intval($datarray['uid']),
  694. dbesc($datarray['type']),
  695. intval($datarray['wall']),
  696. intval($datarray['gravity']),
  697. dbesc($datarray['network']),
  698. intval($datarray['contact-id']),
  699. dbesc($datarray['owner-name']),
  700. dbesc($datarray['owner-link']),
  701. dbesc($datarray['owner-avatar']),
  702. intval($datarray['owner-id']),
  703. dbesc($datarray['author-name']),
  704. dbesc($datarray['author-link']),
  705. dbesc($datarray['author-avatar']),
  706. intval($datarray['author-id']),
  707. dbesc($datarray['created']),
  708. dbesc($datarray['edited']),
  709. dbesc($datarray['commented']),
  710. dbesc($datarray['received']),
  711. dbesc($datarray['changed']),
  712. dbesc($datarray['uri']),
  713. dbesc($datarray['thr-parent']),
  714. dbesc($datarray['title']),
  715. dbesc($datarray['body']),
  716. dbesc($datarray['app']),
  717. dbesc($datarray['location']),
  718. dbesc($datarray['coord']),
  719. dbesc($datarray['tag']),
  720. dbesc($datarray['inform']),
  721. dbesc($datarray['verb']),
  722. dbesc($datarray['object-type']),
  723. dbesc($datarray['postopts']),
  724. dbesc($datarray['allow_cid']),
  725. dbesc($datarray['allow_gid']),
  726. dbesc($datarray['deny_cid']),
  727. dbesc($datarray['deny_gid']),
  728. intval($datarray['private']),
  729. intval($datarray['pubmail']),
  730. dbesc($datarray['attach']),
  731. intval($datarray['bookmark']),
  732. intval($datarray['origin']),
  733. intval($datarray['moderated']),
  734. dbesc($datarray['file']),
  735. dbesc($datarray['rendered-html']),
  736. dbesc($datarray['rendered-hash']),
  737. intval($datarray['gcontact-id']),
  738. dbesc($datarray['object']),
  739. intval($datarray['parent']),
  740. dbesc($datarray['parent-uri']),
  741. dbesc($datarray['plink']),
  742. intval($datarray['last-child']),
  743. intval($datarray['visible'])
  744. );
  745. if (dbm::is_result($r)) {
  746. $r = q("SELECT LAST_INSERT_ID() AS `item-id`");
  747. if (dbm::is_result($r)) {
  748. $post_id = $r[0]['item-id'];
  749. } else {
  750. $post_id = 0;
  751. }
  752. } else {
  753. logger('mod_item: unable to create post.');
  754. $post_id = 0;
  755. }
  756. if ($post_id == 0) {
  757. q("COMMIT");
  758. logger('mod_item: unable to retrieve post that was just stored.');
  759. notice(t('System error. Post not saved.') . EOL);
  760. goaway($return_path);
  761. // NOTREACHED
  762. }
  763. logger('mod_item: saved item ' . $post_id);
  764. $datarray["id"] = $post_id;
  765. item_set_last_item($datarray);
  766. // update filetags in pconfig
  767. file_tag_update_pconfig($uid,$categories_old,$categories_new,'category');
  768. if ($parent) {
  769. // This item is the last leaf and gets the comment box, clear any ancestors
  770. $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d AND `last-child` AND `id` != %d",
  771. dbesc(datetime_convert()),
  772. intval($parent),
  773. intval($post_id)
  774. );
  775. // update the commented timestamp on the parent
  776. q("UPDATE `item` SET `visible` = 1, `commented` = '%s', `changed` = '%s' WHERE `id` = %d",
  777. dbesc(datetime_convert()),
  778. dbesc(datetime_convert()),
  779. intval($parent)
  780. );
  781. if ($contact_record != $author) {
  782. notification(array(
  783. 'type' => NOTIFY_COMMENT,
  784. 'notify_flags' => $user['notify-flags'],
  785. 'language' => $user['language'],
  786. 'to_name' => $user['username'],
  787. 'to_email' => $user['email'],
  788. 'uid' => $user['uid'],
  789. 'item' => $datarray,
  790. 'link' => App::get_baseurl().'/display/'.urlencode($datarray['guid']),
  791. 'source_name' => $datarray['author-name'],
  792. 'source_link' => $datarray['author-link'],
  793. 'source_photo' => $datarray['author-avatar'],
  794. 'verb' => ACTIVITY_POST,
  795. 'otype' => 'item',
  796. 'parent' => $parent,
  797. 'parent_uri' => $parent_item['uri']
  798. ));
  799. }
  800. // Store the comment signature information in case we need to relay to Diaspora
  801. Diaspora::store_comment_signature($datarray, $author, ($self ? $user['prvkey'] : false), $post_id);
  802. } else {
  803. $parent = $post_id;
  804. $r = q("UPDATE `item` SET `parent` = %d WHERE `id` = %d",
  805. intval($parent),
  806. intval($post_id));
  807. if ($contact_record != $author) {
  808. notification(array(
  809. 'type' => NOTIFY_WALL,
  810. 'notify_flags' => $user['notify-flags'],
  811. 'language' => $user['language'],
  812. 'to_name' => $user['username'],
  813. 'to_email' => $user['email'],
  814. 'uid' => $user['uid'],
  815. 'item' => $datarray,
  816. 'link' => App::get_baseurl().'/display/'.urlencode($datarray['guid']),
  817. 'source_name' => $datarray['author-name'],
  818. 'source_link' => $datarray['author-link'],
  819. 'source_photo' => $datarray['author-avatar'],
  820. 'verb' => ACTIVITY_POST,
  821. 'otype' => 'item'
  822. ));
  823. }
  824. }
  825. call_hooks('post_local_end', $datarray);
  826. if (strlen($emailcc) && $profile_uid == local_user()) {
  827. $erecips = explode(',', $emailcc);
  828. if (count($erecips)) {
  829. foreach ($erecips as $recip) {
  830. $addr = trim($recip);
  831. if (! strlen($addr)) {
  832. continue;
  833. }
  834. $disclaimer = '<hr />' . sprintf( t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username'])
  835. . '<br />';
  836. $disclaimer .= sprintf( t('You may visit them online at %s'), App::get_baseurl() . '/profile/' . $a->user['nickname']) . EOL;
  837. $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
  838. if (!$datarray['title']=='') {
  839. $subject = email_header_encode($datarray['title'], 'UTF-8');
  840. } else {
  841. $subject = email_header_encode('[Friendica]' . ' ' . sprintf( t('%s posted an update.'), $a->user['username']), 'UTF-8');
  842. }
  843. $link = '<a href="' . App::get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
  844. $html = prepare_body($datarray);
  845. $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
  846. include_once 'include/html2plain.php';
  847. $params = array (
  848. 'fromName' => $a->user['username'],
  849. 'fromEmail' => $a->user['email'],
  850. 'toEmail' => $addr,
  851. 'replyTo' => $a->user['email'],
  852. 'messageSubject' => $subject,
  853. 'htmlVersion' => $message,
  854. 'textVersion' => html2plain($html.$disclaimer),
  855. );
  856. Emailer::send($params);
  857. }
  858. }
  859. }
  860. if ($post_id == $parent) {
  861. add_thread($post_id);
  862. } else {
  863. update_thread($parent, true);
  864. }
  865. q("COMMIT");
  866. create_tags_from_item($post_id);
  867. create_files_from_item($post_id);
  868. // Insert an item entry for UID=0 for global entries.
  869. // We now do it in the background to save some time.
  870. // This is important in interactive environments like the frontend or the API.
  871. // We don't fork a new process since this is done anyway with the following command
  872. proc_run(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), "include/create_shadowentry.php", $post_id);
  873. // Call the background process that is delivering the item to the receivers
  874. proc_run(PRIORITY_HIGH, "include/notifier.php", $notify_type, $post_id);
  875. logger('post_complete');
  876. item_post_return(App::get_baseurl(), $api_source, $return_path);
  877. // NOTREACHED
  878. }
  879. function item_post_return($baseurl, $api_source, $return_path) {
  880. // figure out how to return, depending on from whence we came
  881. if ($api_source) {
  882. return;
  883. }
  884. if ($return_path) {
  885. goaway($return_path);
  886. }
  887. $json = array('success' => 1);
  888. if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
  889. $json['reload'] = $baseurl . '/' . $_REQUEST['jsreload'];
  890. }
  891. logger('post_json: ' . print_r($json,true), LOGGER_DEBUG);
  892. echo json_encode($json);
  893. killme();
  894. }
  895. function item_content(App $a) {
  896. if ((! local_user()) && (! remote_user())) {
  897. return;
  898. }
  899. require_once 'include/security.php';
  900. $o = '';
  901. if (($a->argc == 3) && ($a->argv[1] === 'drop') && intval($a->argv[2])) {
  902. $o = drop_item($a->argv[2], !is_ajax());
  903. if (is_ajax()) {
  904. // ajax return: [<item id>, 0 (no perm) | <owner id>]
  905. echo json_encode(array(intval($a->argv[2]), intval($o)));
  906. killme();
  907. }
  908. }
  909. return $o;
  910. }
  911. /**
  912. * This function removes the tag $tag from the text $body and replaces it with
  913. * the appropiate link.
  914. *
  915. * @param App $a Application instance @TODO is unused in this function's scope (excluding included files)
  916. * @param unknown_type $body the text to replace the tag in
  917. * @param string $inform a comma-seperated string containing everybody to inform
  918. * @param string $str_tags string to add the tag to
  919. * @param integer $profile_uid
  920. * @param string $tag the tag to replace
  921. * @param string $network The network of the post
  922. *
  923. * @return boolean true if replaced, false if not replaced
  924. */
  925. function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") {
  926. require_once 'include/Scrape.php';
  927. require_once 'include/socgraph.php';
  928. $replaced = false;
  929. $r = null;
  930. //is it a person tag?
  931. if (strpos($tag, '@') === 0) {
  932. //is it already replaced?
  933. if (strpos($tag, '[url=')) {
  934. //append tag to str_tags
  935. if (!stristr($str_tags, $tag)) {
  936. if (strlen($str_tags)) {
  937. $str_tags .= ',';
  938. }
  939. $str_tags .= $tag;
  940. }
  941. // Checking for the alias that is used for OStatus
  942. $pattern = "/@\[url\=(.*?)\](.*?)\[\/url\]/ism";
  943. if (preg_match($pattern, $tag, $matches)) {
  944. $r = q("SELECT `alias`, `name` FROM `contact` WHERE `nurl` = '%s' AND `alias` != '' AND `uid` = 0",
  945. normalise_link($matches[1]));
  946. if (!dbm::is_result($r)) {
  947. $r = q("SELECT `alias`, `name` FROM `gcontact` WHERE `nurl` = '%s' AND `alias` != ''",
  948. normalise_link($matches[1]));
  949. }
  950. if (dbm::is_result($r)) {
  951. $data = $r[0];
  952. } else {
  953. $data = probe_url($matches[1]);
  954. }
  955. if ($data["alias"] != "") {
  956. $newtag = '@[url=' . $data["alias"] . ']' . $data["name"] . '[/url]';
  957. if (!stristr($str_tags, $newtag)) {
  958. if (strlen($str_tags)) {
  959. $str_tags .= ',';
  960. }
  961. $str_tags .= $newtag;
  962. }
  963. }
  964. }
  965. return $replaced;
  966. }
  967. $stat = false;
  968. //get the person's name
  969. $name = substr($tag, 1);
  970. // Sometimes the tag detection doesn't seem to work right
  971. // This is some workaround
  972. $nameparts = explode(" ", $name);
  973. $name = $nameparts[0];
  974. // Try to detect the contact in various ways
  975. if ((strpos($name, '@')) || (strpos($name, 'http://'))) {
  976. // Is it in format @user@domain.tld or @http://domain.tld/...?
  977. // First check the contact table for the address
  978. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network`, `notify` FROM `contact`
  979. WHERE `addr` = '%s' AND `uid` = %d AND
  980. (`network` != '%s' OR (`notify` != '' AND `alias` != ''))
  981. LIMIT 1",
  982. dbesc($name),
  983. intval($profile_uid),
  984. dbesc(NETWORK_OSTATUS)
  985. );
  986. // Then check in the contact table for the url
  987. if (!dbm::is_result($r)) {
  988. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network`, `notify` FROM `contact`
  989. WHERE `nurl` = '%s' AND `uid` = %d AND
  990. (`network` != '%s' OR (`notify` != '' AND `alias` != ''))
  991. LIMIT 1",
  992. dbesc(normalise_link($name)),
  993. intval($profile_uid),
  994. dbesc(NETWORK_OSTATUS)
  995. );
  996. }
  997. // Then check in the global contacts for the address
  998. if (!dbm::is_result($r)) {
  999. $r = q("SELECT `url`, `nick`, `name`, `alias`, `network`, `notify` FROM `gcontact`
  1000. WHERE `addr` = '%s' AND (`network` != '%s' OR (`notify` != '' AND `alias` != ''))
  1001. LIMIT 1",
  1002. dbesc($name),
  1003. dbesc(NETWORK_OSTATUS)
  1004. );
  1005. }
  1006. // Then check in the global contacts for the url
  1007. if (!dbm::is_result($r)) {
  1008. $r = q("SELECT `url`, `nick`, `name`, `alias`, `network`, `notify` FROM `gcontact`
  1009. WHERE `nurl` = '%s' AND (`network` != '%s' OR (`notify` != '' AND `alias` != ''))
  1010. LIMIT 1",
  1011. dbesc(normalise_link($name)),
  1012. dbesc(NETWORK_OSTATUS)
  1013. );
  1014. }
  1015. if (!dbm::is_result($r)) {
  1016. $probed = probe_url($name);
  1017. if ($result['network'] != NETWORK_PHANTOM) {
  1018. update_gcontact($probed);
  1019. $r = q("SELECT `url`, `name`, `nick`, `network`, `alias`, `notify` FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
  1020. dbesc(normalise_link($probed["url"])));
  1021. }
  1022. }
  1023. } else {
  1024. $r = false;
  1025. if (strrpos($name, '+')) {
  1026. // Is it in format @nick+number?
  1027. $tagcid = intval(substr($name, strrpos($name, '+') + 1));
  1028. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network` FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  1029. intval($tagcid),
  1030. intval($profile_uid)
  1031. );
  1032. }
  1033. // select someone by attag or nick and the name passed in the current network
  1034. if(!dbm::is_result($r) AND ($network != ""))
  1035. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network` FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `network` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1",
  1036. dbesc($name),
  1037. dbesc($name),
  1038. dbesc($network),
  1039. intval($profile_uid)
  1040. );
  1041. //select someone from this user's contacts by name in the current network
  1042. if (!dbm::is_result($r) AND ($network != "")) {
  1043. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network` FROM `contact` WHERE `name` = '%s' AND `network` = '%s' AND `uid` = %d LIMIT 1",
  1044. dbesc($name),
  1045. dbesc($network),
  1046. intval($profile_uid)
  1047. );
  1048. }
  1049. // select someone by attag or nick and the name passed in
  1050. if(!dbm::is_result($r)) {
  1051. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network` FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1",
  1052. dbesc($name),
  1053. dbesc($name),
  1054. intval($profile_uid)
  1055. );
  1056. }
  1057. // select someone from this user's contacts by name
  1058. if(!dbm::is_result($r)) {
  1059. $r = q("SELECT `id`, `url`, `nick`, `name`, `alias`, `network` FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1",
  1060. dbesc($name),
  1061. intval($profile_uid)
  1062. );
  1063. }
  1064. }
  1065. if (dbm::is_result($r)) {
  1066. if (strlen($inform) AND (isset($r[0]["notify"]) OR isset($r[0]["id"]))) {
  1067. $inform .= ',';
  1068. }
  1069. if (isset($r[0]["id"])) {
  1070. $inform .= 'cid:' . $r[0]["id"];
  1071. } elseif (isset($r[0]["notify"])) {
  1072. $inform .= $r[0]["notify"];
  1073. }
  1074. $profile = $r[0]["url"];
  1075. $alias = $r[0]["alias"];
  1076. $newname = $r[0]["nick"];
  1077. if (($newname == "") OR (($r[0]["network"] != NETWORK_OSTATUS) AND ($r[0]["network"] != NETWORK_TWITTER)
  1078. AND ($r[0]["network"] != NETWORK_STATUSNET) AND ($r[0]["network"] != NETWORK_APPNET))) {
  1079. $newname = $r[0]["name"];
  1080. }
  1081. }
  1082. //if there is an url for this persons profile
  1083. if (isset($profile) AND ($newname != "")) {
  1084. $replaced = true;
  1085. // create profile link
  1086. $profile = str_replace(',', '%2c', $profile);
  1087. $newtag = '@[url=' . $profile . ']' . $newname . '[/url]';
  1088. $body = str_replace('@' . $name, $newtag, $body);
  1089. // append tag to str_tags
  1090. if (! stristr($str_tags, $newtag)) {
  1091. if (strlen($str_tags)) {
  1092. $str_tags .= ',';
  1093. }
  1094. $str_tags .= $newtag;
  1095. }
  1096. /*
  1097. * Status.Net seems to require the numeric ID URL in a mention if the person isn't
  1098. * subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both.
  1099. */
  1100. if (strlen($alias)) {
  1101. $newtag = '@[url=' . $alias . ']' . $newname . '[/url]';
  1102. if (! stristr($str_tags, $newtag)) {
  1103. if (strlen($str_tags)) {
  1104. $str_tags .= ',';
  1105. }
  1106. $str_tags .= $newtag;
  1107. }
  1108. }
  1109. }
  1110. }
  1111. return array('replaced' => $replaced, 'contact' => $r[0]);
  1112. }