trackback.module

Tracking 5.x-1.x branch
  1. drupal
    1. 5 contributions/trackback/trackback.module
    2. 6 contributions/trackback/trackback.module

Functions & methods

NameDescription
spam_delete_trackback
spam_notspam_trackback
spam_publish_trackback
spam_spam_trackback
spam_unpublish_trackback
theme_trackbackModeled after theme_comment(); Code was taken directly from there and then mutilated.
theme_trackbacks
theme_trackback_admin_table
theme_trackback_url
trackback_admin_delete
trackback_admin_delete_submit
trackback_admin_edit
trackback_admin_edit_submit
trackback_admin_overviewMenu callback; present an administrative trackback listing.
trackback_admin_overview_submit
trackback_admin_overview_validate
trackback_admin_table_header
trackback_blockImplementation of hook_block().
trackback_configure
trackback_cron
trackback_delete
trackback_exit
trackback_form_alter
trackback_helpImplementation of hook_help().
trackback_invoke_trackbackInvoke a hook_trackback() operation in all modules.
trackback_link
trackback_load
trackback_menu
trackback_nodeapi
trackback_page
trackback_perm
trackback_receive
trackback_render
trackback_spam
trackback_spam_link
trackback_trackbackImplementation of hook_trackback()
trackback_urls_via_nodebody
trackback_view_page
_trackback_build_content
_trackback_links
_trackback_node_type
_trackback_optional_params
_trackback_path
_trackback_ping
_trackback_send
_trackback_spam_modify
_trackback_url_parsable_content
_trackback_valid_url
_trackback_wd_subject

File

View source
  1. <?php
  2. /**
  3. * Implementation of hook_help().
  4. */
  5. function trackback_help($section) {
  6. switch ($section) {
  7. case 'admin/help#trackback':
  8. $output = '<p>'. t('The trackback module allows users to give a blog post a contextual link to another. A context is made because the trackbacking poster is, in theory, writing about something mentioned on another blogger\'s trackbacked post. Using the trackback URL accompanying each post, another website can send a ping to your website. Once received, the trackback will show up on the trackback page accompanying the post. It also includes auto-discovery, spam moderation queues, and the ability to manually ping another site.') .'</p>';
  9. $output .= '<p>'. t('If trackback autodisovery is enabled on your website, someone need only visit your post via a link from another website post to have trackback <em>discover</em> the linking site and create the trackback. Trackback auto-discovery also works internally within a website, automatically creating connections between pages which link to each other. To manually send a ping to another site, edit your post and use the trackback URL field at the bottom of the edit page to submit the trackback URL for the post on the other site. Once you enter submit, your website will ping the other site for you. With trackback autodiscovery enabled, your site will attempt to do this automatically without your intervention.') .'</p>';
  10. $output .= '<p>'. t('To enable the moderation queue, go to the administer trackbacks page and select the configure tab. To view, approve, or delete trackbacks awaiting moderation, go to the administer trackbacks page and select the approval queue. To administer the trackback settings for a particular content type go to that content types administration page.') .'</p>';
  11. $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@trackback">Trackback page</a>.', array('@trackback' => 'http://www.drupal.org/handbook/modules/trackback')) .'</p>';
  12. return $output;
  13. }
  14. }
  15. function trackback_page($nid = NULL) {
  16. if (is_numeric($nid) and $node = node_load($nid) and !empty($node->can_receive)) {
  17. $output[] = '<?xml version="1.0" encoding="utf-8"?>';
  18. $output[] = '<response>';
  19. $trackback = trackback_receive($node);
  20. if (empty($trackback->error)) {
  21. $trackback->trid = db_next_id('{trackback_received}_trid');
  22. db_query("INSERT INTO {trackback_received} (trid, nid, created, site, name, subject, url, excerpt, status) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $trackback->trid, $trackback->nid, $trackback->created, $trackback->site, $trackback->name, $trackback->subject, $trackback->url, $trackback->excerpt, $trackback->status);
  23. trackback_invoke_trackback($trackback, 'insert');
  24. watchdog('trackback', t('Added trackback %subject.', array('%subject' => $trackback->subject)), WATCHDOG_NOTICE, _trackback_path($trackback, t('view trackback')));
  25. $output[] = '<error>0</error>';
  26. }
  27. else {
  28. $output[] = '<error>1</error>';
  29. $output[] = '<message>'. $trackback->error .'</message>';
  30. }
  31. $output[] = '</response>';
  32. header('Content-Type: text/xml');
  33. print implode("\n", $output) ."\n";
  34. }
  35. else {
  36. drupal_goto();
  37. }
  38. }
  39. function trackback_receive($node) {
  40. $trackback = new stdClass();
  41. if (!_trackback_valid_url($_REQUEST['url'])) {
  42. $trackback->error = t('Missing TrackBack url.');
  43. }
  44. elseif (variable_get('trackback_reject_oneway', 0)) {
  45. $reply = drupal_http_request($_REQUEST['url']);
  46. if (!empty($reply->error)) {
  47. $trackback->error = t('Could not retrieve the sender page.');
  48. }
  49. elseif (stristr($reply->data, $GLOBALS['base_url'] .'/') === FALSE) {
  50. $trackback->error = t('The sender page does not refer to recipient site.');
  51. }
  52. }
  53. if (empty($trackback->error)) {
  54. $trackback->nid = $node->nid;
  55. $trackback->created = time();
  56. $trackback->site = $_SERVER['REMOTE_ADDR'];
  57. list($name, $subject, $excerpt) = _trackback_optional_params('blog_name', 'title', 'excerpt');
  58. $trackback->name = strip_tags($name ? $name : $_REQUEST['url']);
  59. $trackback->subject = $subject ? $subject : $_REQUEST['url'];
  60. $trackback->url = $_REQUEST['url'];
  61. $trackback->excerpt = strlen($excerpt) > 255 ? truncate_utf8($excerpt, 252) .'...' : $excerpt;
  62. $trackback->status = (variable_get('trackback_moderation', 0) == 0) ? 1 : 0;
  63. trackback_invoke_trackback($trackback, 'receive');
  64. }
  65. return $trackback;
  66. }
  67. function _trackback_valid_url($url) {
  68. $uc = '[a-z0-9;/?:@&=+$,_.!~*\'()%-]';
  69. return preg_match('`^(http|https)://'. $uc .'+(#'. $uc .'*)?$`i', $url);
  70. }
  71. function _trackback_optional_params() {
  72. $args = func_get_args();
  73. foreach ($args as $i) {
  74. $params[] = isset($_REQUEST[$i]) ? $_REQUEST[$i] : '';
  75. }
  76. if (preg_match('/;\s*charset=([^\s;]+)/i', $_SERVER['CONTENT_TYPE'], $match)) {
  77. $charset = $match[1];
  78. }
  79. else {
  80. $utf8 = '/^(?:[\s\x21-\x7F]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}|[\xF8-\xFB][\x80-\xBF]{4}|[\xFC-\xFD][\x80-\xBF]{5})*$/';
  81. $sample = implode(' ', $params);
  82. if (!preg_match($utf8, $sample)) {
  83. global $locale;
  84. $defaults = array(
  85. 'be' => 5, 'cs' => 2, 'el' => 7, 'hr' => 2, 'hu' => 2, 'pl' => 2,
  86. 'ro' => 2, 'ru' => 5, 'sk' => 2, 'sl' => 2, 'tr' => 9, 'uk' => 5,
  87. 'ja' => array('ISO-2022-JP', 'EUC-JP', 'SJIS'),
  88. 'ko' => array('ISO-2022-KR', 'EUC-KR'),
  89. 'zh-hans' => array('HZ', 'EUC-CN'),
  90. 'zh-hant' => array('BIG-5', 'EUC-TW')
  91. );
  92. if ($charset = $defaults[$locale] and is_array($charset)) {
  93. if (function_exists('mb_detect_encoding')) {
  94. $charset = @mb_detect_encoding($sample, $charset);
  95. }
  96. else {
  97. foreach ($charset as $charset) {
  98. if (drupal_convert_to_utf8($sample, $charset) != '') break;
  99. $charset = NULL;
  100. }
  101. }
  102. }
  103. if (!$charset) {
  104. $charset = 'ISO-8859-1'; // or 'ISO-8859-15'
  105. }
  106. elseif (!is_string($charset)) {
  107. $charset = 'ISO-8859-'. $charset;
  108. }
  109. }
  110. }
  111. if ($charset && strcasecmp($charset, 'UTF-8') != 0) {
  112. foreach ($params as $i => $t) {
  113. if ($t != '') {
  114. $t = drupal_convert_to_utf8($t, $charset);
  115. if ($t != '') {
  116. $params[$i] = $t;
  117. }
  118. }
  119. }
  120. }
  121. return $params;
  122. }
  123. /**
  124. * Invoke a hook_trackback() operation in all modules.
  125. *
  126. * @param &$trackback
  127. * A trackback object.
  128. * @param $op
  129. * A string containing the name of the trackback operation.
  130. * @return
  131. * The returned value of the invoked hooks.
  132. */
  133. function trackback_invoke_trackback(&$trackback, $op) {
  134. $return = array();
  135. foreach (module_implements('trackback') as $name) {
  136. $function = $name .'_trackback';
  137. $result = $function($trackback, $op);
  138. if (isset($result)) {
  139. if (is_array($result)) {
  140. $return = array_merge($return, $result);
  141. }
  142. else {
  143. $return[] = $result;
  144. }
  145. }
  146. }
  147. return $return;
  148. }
  149. /**
  150. * Implementation of hook_trackback()
  151. */
  152. function trackback_trackback(&$trackback, $op) {
  153. switch ($op) {
  154. case 'receive':
  155. // drop silently if this is from a known spammer IP address
  156. if (variable_get('trackback_spam_filter', 1)) {
  157. module_invoke('spam', 'ip_filter', 'trackback', 0);
  158. }
  159. break;
  160. case 'insert':
  161. if (variable_get('trackback_spam_filter', 1)) {
  162. // invoke spam.module's spam filter
  163. module_invoke('spam', 'content_filter', 'trackback', $trackback->trid, $trackback->subject .' '. $trackback->url, $trackback->excerpt);
  164. }
  165. break;
  166. case 'delete':
  167. if (module_exists('spam')) {
  168. db_query("DELETE FROM {spam_tracker} WHERE source='trackback' AND id=%d", $trackback->trid);
  169. spam_log(SPAM_LOG, t('spam_delete_trackback: deleted trackback "%subject".', array('%subject' => $trackback->subject)), 'trackback', $trackback->trid);
  170. }
  171. break;
  172. }
  173. }
  174. /**
  175. * Modeled after theme_comment();
  176. * Code was taken directly from there and then mutilated.
  177. *
  178. */
  179. function theme_trackback($trackback, $links = NULL) {
  180. $output = '<div class="trackback" id="trackback-'. $trackback->trid ."\">\n";
  181. $output .= '<div class="title">'. l($trackback->subject, $trackback->url) ."</div>\n";
  182. $output .= '<div class="author">'. t('from %sitename on %date', array('%sitename' => $trackback->name, '%date' => format_date($trackback->created))) ."</div>\n";
  183. $output .= '<div class="content">'. check_markup($trackback->excerpt) ."</div>\n";
  184. if ($links) {
  185. $output .= '<div class="links">'. theme('links', $links) ."</div>\n";
  186. }
  187. $output .= "</div>\n";
  188. return $output;
  189. }
  190. function theme_trackbacks($trackbacks) {
  191. $output = '<div id="trackbacks">'."\n";
  192. $output .= $trackbacks ."\n";
  193. $output .= '</div>'."\n";
  194. return $output;
  195. }
  196. function theme_trackback_url($url) {
  197. return '<div id="trackback-url">'. theme('box', t('Trackback URL for this post:'), $url) .'</div>';
  198. }
  199. function trackback_render($node) {
  200. $result = db_query('SELECT * FROM {trackback_received} WHERE nid=%d AND status=1 ORDER BY created DESC', $node->nid);
  201. if ($tb = db_fetch_object($result)) {
  202. $link = (user_access('administer trackbacks') || node_access('update', $node));
  203. $received = '';
  204. do {
  205. $received .= theme('trackback', $tb, $link ? module_invoke_all('link', 'trackback', $tb, FALSE) : array());
  206. } while ($tb = db_fetch_object($result));
  207. return theme('trackbacks', $received);
  208. }
  209. }
  210. function trackback_form_alter($form_id, &$form) {
  211. if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
  212. $form['workflow']['trackback'] = array(
  213. '#type' => 'radios',
  214. '#title' => t('Trackbacks'),
  215. '#options' => array(t('Disabled'), t('Enabled')),
  216. '#default_value' => _trackback_node_type($form['#node_type']->type),
  217. '#description' => t('Enable trackbacks for this node type.')
  218. );
  219. }
  220. else if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
  221. $node = $form['#node'];
  222. if (_trackback_node_type($node->type)) {
  223. $form['trackback'] = array(
  224. '#type' => 'fieldset',
  225. '#title' => t('Trackbacks'),
  226. '#collapsible' => TRUE
  227. );
  228. $form['trackback']['can_receive'] = array(
  229. '#type' => 'checkbox',
  230. '#title' => t('Allow Trackbacks'),
  231. '#default_value' => isset($node->can_receive) ? $node->can_receive : 1,
  232. '#description' => t('Allow other posts to send trackbacks to this content.')
  233. );
  234. $form['trackback']['trackback_urls'] = array(
  235. '#type' => 'textarea',
  236. '#title' => t('Send Trackbacks'),
  237. '#default_value' => isset($node->trackback_urls) ? $node->trackback_urls : '',
  238. '#cols' => 80,
  239. '#rows' => 4,
  240. '#description' => t('Enter one URL per line for each trackback you wish to send.')
  241. );
  242. // if there are any past successful trackbacks from this posting, add them to the node editing page.
  243. // if there are any past unsuccessful trackbacks from this posting, add checkmarks to enable resending them
  244. $past_successes_listing = array();
  245. $options = array();
  246. $result = db_query('SELECT url, successful FROM {trackback_sent} WHERE nid = %d', $node->nid);
  247. while ($url = db_fetch_object($result)) {
  248. if ($url->successful) {
  249. $past_successes_listing[] = $url->url;
  250. }
  251. else {
  252. $options[$url->url] = $url->url;
  253. }
  254. }
  255. // add listing of successfully trackbacked URLs
  256. if (count($past_successes_listing)) {
  257. $form['trackback'][] = array(
  258. '#value' => theme('item_list', $past_successes_listing, t('Successful URLs'))
  259. );
  260. //t('These URLs have been successfuly pinged by this post.')
  261. }
  262. // add listing of unsuccessfully trackbacked URLs
  263. if (count($options)) {
  264. $form['trackback']['trackback_urls_to_retry'] = array(
  265. '#type' => 'checkboxes',
  266. '#title' => t('Unsuccessful URLs'),
  267. '#default_value' => array(),
  268. '#options' => $options,
  269. '#description' => t('Attempts to ping these URLs with this post have failed. Mark a check next to the trackback URLs you wish to retry for this post.')
  270. );
  271. }
  272. }
  273. }
  274. }
  275. function trackback_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  276. switch ($op) {
  277. case 'load':
  278. if (_trackback_node_type($node->type)) {
  279. $q = db_fetch_object(db_query('SELECT * FROM {trackback_node} WHERE nid=%d', $node->nid));
  280. return array('can_receive' => $q ? $q->can_receive : 1);
  281. }
  282. break;
  283. case 'view':
  284. if (isset($node->can_receive) && empty($node->in_preview)) {
  285. $node->content['trackback'] = array('#weight' => 12);
  286. if ($node->can_receive) {
  287. $url = url('node/'. $node->nid, NULL, NULL, TRUE);
  288. $tb_url = url('trackback/'. $node->nid, NULL, NULL, TRUE);
  289. $autodetect = "\n<!--\n";
  290. $autodetect .= '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">'."\n";
  291. $autodetect .= '<rdf:Description rdf:about="'. $url .'" dc:identifier="'. $url .'" dc:title="'. strtr(check_plain($node->title), array('--' => '&mdash;')) .'" trackback:ping="'. $tb_url .'" />'."\n";
  292. $autodetect .= '</rdf:RDF>';
  293. $autodetect .= "\n-->\n";
  294. $node->content['trackback']['autodetect'] = array('#value' => $autodetect, '#weight' => -2);
  295. if (!$teaser) {
  296. $node->content['trackback']['url'] = array('#value' => theme('trackback_url', $tb_url), '#weight' => -1);
  297. }
  298. }
  299. if (!$teaser && variable_get('trackback_view', 0) == 0) {
  300. $node->content['trackback']['received'] = array('#value' => trackback_render($node));
  301. }
  302. }
  303. break;
  304. case 'validate':
  305. if (!empty($node->trackback_urls)) {
  306. foreach (explode("\n", $node->trackback_urls) as $url) {
  307. $url = trim($url);
  308. if ($url && !_trackback_valid_url($url)) {
  309. form_set_error('trackback_urls', t('The trackback url %url is not a valid url.', array('%url' => $url)));
  310. }
  311. }
  312. }
  313. break;
  314. case 'insert':
  315. case 'update':
  316. if (_trackback_node_type($node->type)) {
  317. global $_trackback_ping_node;
  318. $_trackback_ping_node = drupal_clone($node);
  319. $cron = ($node->status && variable_get('trackback_auto_detection_enabled', 0) == 2);
  320. db_query("UPDATE {trackback_node} SET awaiting_cron=%d, can_receive=%d WHERE nid=%d", $cron, $node->can_receive, $node->nid);
  321. if (!db_affected_rows()) {
  322. db_query("INSERT INTO {trackback_node}(nid, awaiting_cron, can_receive) VALUES(%d, %d, %d)", $node->nid, $cron, $node->can_receive);
  323. }
  324. }
  325. break;
  326. case 'delete':
  327. if (module_exists('spam')) {
  328. db_query("DELETE FROM {spam_tracker} USING ({spam_tracker}, {trackback_received}) WHERE {spam_tracker}.source='trackback' AND {spam_tracker}.id={trackback_received}.trid AND {trackback_received}.nid=%d", $node->nid);
  329. }
  330. db_query("DELETE FROM {trackback_node} WHERE nid=%d", $node->nid);
  331. db_query("DELETE FROM {trackback_sent} WHERE nid=%d", $node->nid);
  332. db_query("DELETE FROM {trackback_received} WHERE nid=%d", $node->nid);
  333. break;
  334. }
  335. }
  336. function trackback_exit() {
  337. global $_trackback_ping_node;
  338. if ($_trackback_ping_node) {
  339. _trackback_send($_trackback_ping_node);
  340. }
  341. }
  342. function _trackback_links($tb, $edit = FALSE) {
  343. static $spam;
  344. if (!isset($spam)) {
  345. $spam = module_exists('spam');
  346. }
  347. if (!$edit) {
  348. $links['trackback_edit'] = array(
  349. 'title' => t('edit'),
  350. 'href' => 'admin/content/trackback/edit/'. $tb->trid
  351. );
  352. }
  353. $links['trackback_delete'] = array(
  354. 'title' => t('delete'),
  355. 'href' => 'admin/content/trackback/delete/'. $tb->trid
  356. );
  357. if ($spam) {
  358. $links = array_merge($links, trackback_spam_link($tb));
  359. }
  360. return $links;
  361. }
  362. function trackback_link($type, $node = NULL, $teaser = FALSE) {
  363. $links = array();
  364. switch ($type) {
  365. case 'node':
  366. if ($teaser && isset($node->can_receive)) {
  367. $count = db_result(db_query("SELECT count(*) FROM {trackback_received} WHERE nid=%d AND status=1", $node->nid));
  368. if ($count) {
  369. $links[] = array(
  370. 'title' => format_plural($count, '1 trackback', '@count trackbacks'),
  371. 'href' => _trackback_path($node),
  372. 'fragment' => 'trackbacks'
  373. );
  374. }
  375. }
  376. break;
  377. case 'trackback':
  378. $links = _trackback_links($node, $teaser);
  379. break;
  380. }
  381. return $links;
  382. }
  383. function _trackback_path($obj, $text = NULL, $attrib = array()) {
  384. static $prefix;
  385. if (!isset($prefix)) {
  386. $prefix = variable_get('trackback_view', 0) == 1 ? '/trackback' : '';
  387. }
  388. if (!isset($text)) {
  389. return 'node/'. $obj->nid . $prefix;
  390. }
  391. if ($obj->status) {
  392. return l($text, 'node/'. $obj->nid . $prefix, $attrib, NULL, 'trackback-'. $obj->trid);
  393. }
  394. return l($text, 'admin/content/trackback/edit/'. $obj->trid, $attrib);
  395. }
  396. function _trackback_build_content($node, $teaser = FALSE) {
  397. unset($node->can_receive);
  398. return node_build_content($node, $teaser);
  399. }
  400. function trackback_menu($may_cache = FALSE) {
  401. $items = array();
  402. if ($may_cache) {
  403. $access = user_access('administer trackbacks');
  404. $items[] = array('path' => 'trackback', 'title' => t('Trackbacks'),
  405. 'callback' => 'trackback_page', 'access' => user_access('access content'),
  406. 'type' => MENU_DYNAMIC);
  407. $items[] = array('path' => 'admin/content/trackback', 'title' => t('Trackbacks'),
  408. 'description' => t('List and edit site trackbacks and the trackback moderation queue.'),
  409. 'callback' => 'drupal_get_form', 'access' => $access,
  410. 'callback arguments' => array('trackback_admin_overview'));
  411. // Tabs:
  412. $items[] = array('path' => 'admin/content/trackback/list', 'title' => t('List'),
  413. 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
  414. $items[] = array('path' => 'admin/content/trackback/settings', 'title' => t('Settings'),
  415. 'callback' => 'drupal_get_form', 'access' => $access,
  416. 'callback arguments' => array('trackback_configure'),
  417. 'type' => MENU_LOCAL_TASK, 'weight' => 10);
  418. // Subtabs:
  419. $items[] = array('path' => 'admin/content/trackback/list/new', 'title' => t('New trackbacks'),
  420. 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
  421. $items[] = array('path' => 'admin/content/trackback/list/approval', 'title' => t('Approval queue'),
  422. 'callback' => 'drupal_get_form', 'access' => $access,
  423. 'callback arguments' => array('trackback_admin_overview', 'approval'),
  424. 'type' => MENU_LOCAL_TASK);
  425. if (module_exists('spam')) {
  426. $items[] = array('path' => 'admin/content/trackback/list/spam', 'title' => t('Spam'),
  427. 'callback' => 'drupal_get_form', 'access' => $access,
  428. 'callback arguments' => array('trackback_admin_overview', 'spam'),
  429. 'type' => MENU_LOCAL_TASK, 'weight' => 10
  430. );
  431. }
  432. }
  433. else {
  434. if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'trackback' && is_numeric(arg(4))) {
  435. $trackback = trackback_load(arg(4));
  436. if (isset($trackback->nid)) {
  437. $item = array();
  438. switch (arg(3)) {
  439. case 'delete':
  440. $item = array('title' => t('Delete trackback'),
  441. 'callback arguments' => array('trackback_admin_delete', $trackback));
  442. break;
  443. case 'edit':
  444. $item = array('title' => t('Moderate trackback'),
  445. 'callback arguments' => array('trackback_admin_edit', $trackback));
  446. break;
  447. }
  448. if ($item) {
  449. $item += array('path' => 'admin/content/trackback/'. arg(3) .'/'. arg(4),
  450. 'callback' => 'drupal_get_form',
  451. 'access' => (user_access('administer trackbacks') || node_access('update', node_load($trackback->nid))),
  452. 'type' => MENU_CALLBACK);
  453. $items[] = $item;
  454. }
  455. }
  456. }
  457. elseif (arg(0) == 'node' && is_numeric(arg(1))) {
  458. $node = node_load(arg(1));
  459. if ($node->nid && isset($node->can_receive) && variable_get('trackback_view', 0) == 1) {
  460. $access = (node_access('view', $node) && db_result(db_query('SELECT count(*) FROM {trackback_received} WHERE nid=%d AND status=1', $node->nid)));
  461. $items[] = array('path' => 'node/'. arg(1) .'/trackback', 'title' => t('Trackbacks'),
  462. 'callback' => 'trackback_view_page',
  463. 'callback arguments' => array($node),
  464. 'access' => $access,
  465. 'weight' => 2,
  466. 'type' => MENU_LOCAL_TASK);
  467. }
  468. }
  469. }
  470. return $items;
  471. }
  472. function trackback_perm() {
  473. return array('administer trackbacks');
  474. }
  475. function trackback_view_page($node) {
  476. drupal_set_title(check_plain($node->title));
  477. return trackback_render($node);
  478. }
  479. /**
  480. * Menu callback; present an administrative trackback listing.
  481. */
  482. function trackback_admin_overview($type = 'new') {
  483. $spam_module_exists = module_exists('spam');
  484. $operations = array();
  485. if ($type == 'new') {
  486. $operations['spam_unpublish_trackback'] = t('Unpublish the selected trackbacks');
  487. }
  488. else {
  489. $operations['spam_publish_trackback'] = t('Publish the selected trackbacks');
  490. }
  491. if ($spam_module_exists) {
  492. $operations['spam_spam_trackback'] = t('Mark the selected trackbacks as spam');
  493. $operations['spam_notspam_trackback'] = t('Mark the selected trackbacks as not spam');
  494. }
  495. $operations['spam_delete_trackback'] = t('Delete the selected trackbacks (no confirmation)');
  496. $form = array();
  497. $form['update'] = array(
  498. '#type' => 'fieldset',
  499. '#title' => t('Update options'),
  500. 'operations' => array('#type' => 'value', '#value' => $operations)
  501. );
  502. $form['update']['operation'] = array(
  503. '#prefix' => '<div class="container-inline">',
  504. '#type' => 'select',
  505. '#options' => $operations
  506. );
  507. $form['update']['op'] = array(
  508. '#type' => 'submit',
  509. '#value' => t('Update trackbacks'),
  510. '#suffix' => '</div>'
  511. );
  512. $form['trackbacks'] = array('#theme' => 'trackback_admin_table');
  513. $form['trackbacks']['header'] = array(
  514. '#type' => 'value',
  515. '#value' => trackback_admin_table_header($type, $spam_module_exists)
  516. );
  517. $status = ($type == 'approval') ? 0 : 1;
  518. if ($spam_module_exists) {
  519. $spam_threshold = (int)variable_get('spam_threshold', 80);
  520. $sql = 'SELECT tr.*, s.probability FROM {trackback_received} tr LEFT JOIN {spam_tracker} s ON s.source = \'trackback\' AND tr.trid = s.id WHERE '. ($type == 'spam' ? 's.probability >= '. $spam_threshold : 'tr.status = '. $status);
  521. }
  522. else {
  523. $sql = 'SELECT tr.* FROM {trackback_received} tr WHERE tr.status = '. $status;
  524. }
  525. $sql .= tablesort_sql($form['trackbacks']['header']['#value']);
  526. $result = pager_query($sql, 50);
  527. $form['trackbacks']['status'] = array('#tree' => TRUE);
  528. while ($trackback = db_fetch_object($result)) {
  529. $form['trackbacks']['status'][$trackback->trid] = array('#type' => 'checkbox');
  530. $form['trackbacks'][$trackback->trid] = array();
  531. $form['trackbacks'][$trackback->trid][] = array('#value' => _trackback_path($trackback, $trackback->subject, array('title' => truncate_utf8($trackback->excerpt, 128))) .' '. theme('mark', node_mark($trackback->nid, $trackback->created)));
  532. $form['trackbacks'][$trackback->trid][] = array('#value' => drupal_substr($trackback->name, 0, 15) .'...');
  533. $form['trackbacks'][$trackback->trid][] = array('#value' => $trackback->site);
  534. if ($spam_module_exists) {
  535. if ($type == 'spam') {
  536. $form['trackbacks'][$trackback->trid][] = array('#value' => $trackback->status != 0 ? t('Published') : t('Not published'));
  537. }
  538. else {
  539. $form['trackbacks'][$trackback->trid][] = array('#value' => $trackback->probability >= $spam_threshold ? t('Spam') : t('Not Spam'));
  540. }
  541. }
  542. $form['trackbacks'][$trackback->trid][] = array('#value' => format_date($trackback->created, 'small'));
  543. $form['trackbacks'][$trackback->trid][] = array('#value' => l(t('edit'), 'admin/content/trackback/edit/'. $trackback->trid));
  544. $form['trackbacks'][$trackback->trid][] = array('#value' => l(t('delete'), 'admin/content/trackback/delete/'. $trackback->trid));
  545. }
  546. $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
  547. return $form;
  548. }
  549. function trackback_admin_overview_validate($form_id, $form_values) {
  550. $form_values['status'] = array_diff((array)$form_values['status'], array(0));
  551. if (count($form_values['status']) == 0) {
  552. form_set_error('', t('Please select one or more trackbacks to perform the update on.'));
  553. drupal_goto($_GET['q']);
  554. }
  555. }
  556. function trackback_admin_overview_submit($form_id, $form_values) {
  557. if (isset($form_values['operations'][$form_values['operation']])) {
  558. $function = $form_values['operation'];
  559. foreach ($form_values['status'] as $trid => $value) {
  560. if ($value) {
  561. $function($trid);
  562. }
  563. }
  564. drupal_set_message(t('The update has been performed.'));
  565. }
  566. }
  567. function trackback_admin_table_header($type, $spam_module_exists) {
  568. $header = array();
  569. $header[] = theme('table_select_header_cell');
  570. $header[] = array('data' => t('Subject'), 'field' => 'tr.subject');
  571. $header[] = array('data' => t('Author'), 'field' => 'tr.name');
  572. $header[] = array('data' => t('Host'), 'field' => 'tr.site');
  573. if ($spam_module_exists) {
  574. if ($type == 'spam') {
  575. $header[] = array('data' => t('Status'), 'field' => 'tr.status');
  576. }
  577. else {
  578. $header[] = array('data' => t('Spam'), 'field' => 's.probability');
  579. }
  580. }
  581. $header[] = array('data' => t('Time'), 'field' => 'created', 'sort' => 'desc');
  582. $header[] = array('data' => t('Operations') , 'colspan' => '2');
  583. return $header;
  584. }
  585. function theme_trackback_admin_table($form) {
  586. $header = $form['header']['#value'];
  587. $rows = array();
  588. foreach (element_children($form['status']) as $key) {
  589. $row = array(drupal_render($form['status'][$key]));
  590. foreach (element_children($form[$key]) as $column_key) {
  591. $row[] = drupal_render($form[$key][$column_key]);
  592. }
  593. $rows[] = $row;
  594. }
  595. if (count($rows) == 0) {
  596. $rows[] = array(array('data' => t('No trackbacks available.'), 'colspan' => count($header)));
  597. }
  598. return theme('table', $header, $rows);
  599. }
  600. function _trackback_send($node) {
  601. $urls = array();
  602. if (!empty($node->trackback_urls)) {
  603. foreach (explode("\n", $node->trackback_urls) as $url) {
  604. if ($url = trim($url)) {
  605. $urls[$url] = TRUE;
  606. }
  607. }
  608. }
  609. if ($node->status && variable_get('trackback_auto_detection_enabled', 0) == 1) {
  610. $urls += trackback_urls_via_nodebody($node);
  611. }
  612. $retry = array();
  613. if (isset($node->trackback_urls_to_retry)) {
  614. $retry = array_diff($node->trackback_urls_to_retry, array(0));
  615. }
  616. _trackback_ping($node, $urls, $retry);
  617. }
  618. function trackback_urls_via_nodebody($node) {
  619. $trackback_urls = array();
  620. // First, grab anything that looks like a url from the body of the node.
  621. $node = _trackback_build_content(drupal_clone($node));
  622. $content = drupal_render($node->content);
  623. $pattern = '((?:http|https)://[a-z0-9;/?:@&=+#$,_.!~*()%-]+)';
  624. if (variable_get('trackback_link_only', 0)) {
  625. $content = strip_tags($content, '<a>'); // remove comment.
  626. $pattern = '<a\s+[^>]*href\s*=\s*(?:"|\')'. $pattern;
  627. }
  628. if (preg_match_all('`'. $pattern .'`i', $content, $parsed_urls)) {
  629. $parsed_urls = array_unique($parsed_urls[1]);
  630. foreach ($parsed_urls as $url) {
  631. // Now, send http HEAD requests so we can see if the content type is something that *might* contain autodetection text.
  632. // In other words, check if Content-Type of each URL is text based rather than digital.
  633. $url = html_entity_decode($url, ENT_QUOTES);
  634. if (_trackback_url_parsable_content($url)) {
  635. //Finally, download each page, scan each, and compile a list of all the trackback URLs listed in the first RDF of each scanned page.
  636. $reply = drupal_http_request($url);
  637. if (empty($reply->error)) {
  638. $url = preg_replace('/.*<rdf:RDF.*trackback:ping="([^"]+)".*<\/rdf:RDF>.*/s', '\1', $reply->data);
  639. if (_trackback_valid_url($url)) {
  640. $trackback_urls[$url] = FALSE;
  641. }
  642. }
  643. }
  644. }
  645. }
  646. return $trackback_urls;
  647. }
  648. // Since autodetection might encounter a link to a media file, we first want to make a
  649. // simple 'HEAD' HTTP request instead of an actual GET. This results in having to make
  650. // an extra drupal_http_request() later for an actual GET, but it is worth it considering
  651. // the strong likelihood that auto-detection may encounter a URL that links to a media file.
  652. function _trackback_url_parsable_content($url) {
  653. global $base_url;
  654. if (!strstr($url, $base_url)) {
  655. $http_reply = drupal_http_request($url, array(), 'HEAD');
  656. $content_type = $http_reply->headers['Content-Type'];
  657. return (substr_count($content_type, 'text/html') || substr_count($content_type, 'application/xhtml+xml') || substr_count($content_type, 'application/xml') || substr_count($content_type, 'text/xml'));
  658. }
  659. }
  660. function trackback_cron() {
  661. // query for all nodes where
  662. $result = db_query('SELECT t.nid, n.status FROM {trackback_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE t.awaiting_cron = 1');
  663. while ($node = db_fetch_object($result)) {
  664. // First things first, let's unset the 'awaiting_cron' bit in the {trackback_node} table.
  665. db_query('UPDATE {trackback_node} SET awaiting_cron = 0 WHERE nid = %d', $node->nid);
  666. if ($node->status) {
  667. $node = node_load($node->nid);
  668. _trackback_ping($node, trackback_urls_via_nodebody($node));
  669. }
  670. }
  671. }
  672. // Code that adds configurability for trackback features.
  673. function _trackback_node_type($type) {
  674. static $types = array('story', 'forum', 'blog');
  675. return variable_get('trackback_'. $type, in_array($type, $types) ? 1 : 0);
  676. }
  677. function _trackback_ping($node, $urls, $force = array()) {
  678. if ($urls) {
  679. $result = db_query('SELECT url FROM {trackback_sent} WHERE nid=%d', $node->nid);
  680. while ($sent = db_fetch_object($result)) {
  681. unset($urls[$sent->url]);
  682. }
  683. }
  684. $urls += $force;
  685. if ($urls) {
  686. $node = _trackback_build_content($node, TRUE);
  687. $excerpt = drupal_render($node->content);
  688. $excerpt = preg_replace(array('/<p\b/i', '/<div\b/i'), array("\n\$0", ' $0'), $excerpt);
  689. $params = array(
  690. 'title' => $node->title,
  691. 'excerpt' => truncate_utf8(trim(strip_tags($excerpt)), 255),
  692. 'blog_name' => variable_get('site_name', ''),
  693. 'url' => url('node/'. $node->nid, NULL, NULL, TRUE)
  694. );
  695. $query = array();
  696. foreach ($params as $key => $value) {
  697. $query[] = $key .'='. urlencode($value);
  698. }
  699. $query = implode('&', $query);
  700. foreach ($urls as $url => $type) {
  701. $reply = drupal_http_request($url, array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'), 'POST', $query);
  702. $succ = 0;
  703. if (empty($reply->error) && preg_match('|<error>([0-9]+)</error>|', $reply->data, $match)) {
  704. $succ = $match[1] ? 0 : 1;
  705. }
  706. db_query("UPDATE {trackback_sent} SET successful=%d WHERE nid=%d AND url='%s'", $succ, $node->nid, $url);
  707. if (!db_affected_rows()) {
  708. db_query("INSERT INTO {trackback_sent} (nid, url, successful) VALUES (%d, '%s', %d)", $node->nid, $url, $succ);
  709. }
  710. }
  711. }
  712. }
  713. function trackback_configure() {
  714. $form = array();
  715. $form['trackback_auto_detection_enabled'] = array(
  716. '#type' => 'radios',
  717. '#title' => t('Auto-detection'),
  718. '#default_value' => variable_get('trackback_auto_detection_enabled', 0),
  719. '#options' => array(t('Disabled'), t('Enabled'), t('Run auto-detection on cron')),
  720. '#description' => t('If auto-detection is enabled, each URL in any posted content (whether in textile, link, or plain-text form) will be checked for a trackback URL upon submission. For each URL in the body of the posted content, trackback will check to see if that URL accepts trackbacks from other sites. If a URL accepts trackbacks, trackback will ping the trackback URL found on that page if one has been posted at that URL.<br>*note: This has the potential to take a very long time depending on the amount of links you have in your posts. Using the \'Run auto-detection on cron\' option delays the most time consuming part of the process to when cron is run on the site. This speeds perfomance when editing and creating content, but delays trackbacks until cron is run.')
  721. );
  722. $form['trackback_link_only'] = array(
  723. '#type' => 'checkbox',
  724. '#title' => t('Link only'),
  725. '#default_value' => variable_get('trackback_link_only', 0),
  726. '#description' => t('If checked, auto-detection will check link only.')
  727. );
  728. $form['trackback_moderation'] = array(
  729. '#type' => 'radios',
  730. '#title' => t('Trackback moderation'),
  731. '#default_value' => variable_get('trackback_moderation', 0),
  732. '#options' => array(t('Disabled'), t('Enabled')),
  733. '#description' => t('Enabling moderation forces every received trackback to be approved before it will appear on your site. The moderation queue can then be viewed on the !linked_page.', array('!linked_page' => l(t('trackback administration page'), 'admin/content/trackback/list/approval')))
  734. );
  735. $form['trackback_reject_oneway'] = array(
  736. '#type' => 'radios',
  737. '#title' => t('Reject one-way trackbacks'),
  738. '#default_value' => variable_get('trackback_reject_oneway', 0),
  739. '#options' => array(t('Disabled'), t('Enabled')),
  740. '#description' => t('If enabled, trackbacks that the sender page does not refer to your site will be rejected.')
  741. );
  742. $form['trackback_view'] = array(
  743. '#type' => 'radios',
  744. '#title' => t('Location of received trackbacks'),
  745. '#default_value' => variable_get('trackback_view', 0),
  746. '#options' => array(t('Display below post'), t('Display on separate page'), t('Display in block'))
  747. );
  748. return system_settings_form($form);
  749. }
  750. function trackback_spam($op, $a2, $a3, $a4) {
  751. $return = array();
  752. switch ($op) {
  753. case 'filter_settings':
  754. $return['group']['trackback_spam_filter'] = array(
  755. '#type' => 'checkbox',
  756. '#title' => t('Filter trackbacks'),
  757. '#default_value' => variable_get('trackback_spam_filter', 1),
  758. '#description' => t('Enable this option to filter new trackbacks as they are posted, determining whether or not they are spam.')
  759. );
  760. break;
  761. case 'page':
  762. if (arg(1) == 'trackback') {
  763. $trackback = trackback_load($a2);
  764. $return = array(
  765. 'old' => spam_load('trackback', $a2),
  766. 'header' => $trackback->subject .' '. $trackback->url,
  767. 'body' => $trackback->excerpt,
  768. 'goto' => _trackback_path($trackback),
  769. 'goto_fragment' => 'trackbacks'
  770. );
  771. }
  772. break;
  773. }
  774. return $return;
  775. }
  776. function trackback_admin_delete($tb) {
  777. return confirm_form(array('trackback' => array('#type' => 'value', '#value' => $tb)),
  778. t('Are you sure you want to delete the trackback %title?', array('%title' => $tb->subject)),
  779. _trackback_path($tb), t('This action cannot be undone.'), t('Delete'), t('Cancel'));
  780. }
  781. function trackback_admin_delete_submit($form_id, $form_values) {
  782. $tb = $form_values['trackback'];
  783. trackback_delete($tb);
  784. return array(_trackback_path($tb), NULL, 'trackbacks');
  785. }
  786. function trackback_admin_edit($tb) {
  787. $node = _trackback_build_content(node_load($tb->nid), TRUE);
  788. $node->teaser = drupal_render($node->content);
  789. $form = array('trackback' => array('#type' => 'value', '#value' => $tb));
  790. $form['preview'] = array(
  791. '#prefix' => '<div class="preview">',
  792. '#value' => theme('trackback', $tb, module_invoke_all('link', 'trackback', $tb, TRUE)),
  793. '#suffix' => '</div>'
  794. );
  795. $form['status'] = array(
  796. '#type' => 'radios',
  797. '#title' => t('Status'),
  798. '#default_value' => $tb->status,
  799. '#options' => array(1 => t('Published'), 0 => t('Not published'))
  800. );
  801. $form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
  802. $form['node'] = array(
  803. '#value' => theme('box', t('This trackback is in response to: '), theme('node', $node, TRUE, FALSE))
  804. );
  805. return $form;
  806. }
  807. function trackback_admin_edit_submit($form_id, $form_values) {
  808. $status = $form_values['status'];
  809. $tb = $form_values['trackback'];
  810. db_query("UPDATE {trackback_received} SET status = %d WHERE trid = %d", $status, $tb->trid);
  811. if ($status != $tb->status) {
  812. drupal_set_message($status ? t('The trackback is now published.') : t('The trackback was un-published'));
  813. }
  814. return 'admin/content/trackback';
  815. }
  816. function trackback_spam_link($trackback) {
  817. $output = array();
  818. if (!variable_get('trackback_spam_filter', 1)) {
  819. return $output;
  820. }
  821. $p = db_fetch_object(db_query("SELECT probability FROM {spam_tracker} WHERE id = %d AND source = 'trackback'", $trackback->trid));
  822. $spam = array(
  823. 'href' => 'spam/trackback/'. $trackback->trid .'/spam',
  824. 'title' => t('mark as spam')
  825. );
  826. $notspam = array(
  827. 'href' => 'spam/trackback/'. $trackback->trid .'/notspam',
  828. 'title' => t('mark as not spam')
  829. );
  830. $access = user_access('access spam');
  831. $admin = user_access('administer spam');
  832. if (variable_get('spam_display_probability', 0)) {
  833. if (variable_get('spam_log_level', SPAM_LOG)) {
  834. $prob = l($p->probability, 'admin/content/spam/logs/trackback/'. $trackback->trid);
  835. }
  836. else {
  837. $prob = $p->probability;
  838. }
  839. $prob = ' ('. $prob .')';
  840. }
  841. if (!$p->probability && $admin) {
  842. $output['spam-spam'] = $spam;
  843. $output['spam-notspam'] = $notspam;
  844. }
  845. else if ($p->probability < variable_get('spam_threshold', 80)) {
  846. if ($access) {
  847. $output['spam-probability'] = array('title' => t('not spam') . $prob, 'html' => TRUE);
  848. }
  849. if ($admin) {
  850. $output['spam-spam'] = $spam;
  851. }
  852. }
  853. else {
  854. if ($access) {
  855. $output['spam-probability'] = array('title' => t('spam') . $prob, 'html' => TRUE);
  856. }
  857. if ($admin) {
  858. $output['spam-notspam'] = $notspam;
  859. }
  860. }
  861. return $output;
  862. }
  863. /**
  864. * Implementation of hook_block().
  865. */
  866. function trackback_block($op = 'list', $delta = 0, $edit = array()) {
  867. if ($op == 'list') {
  868. $blocks[0]['info'] = t('Recent trackbacks');
  869. if (variable_get('trackback_view', 0) == 2) {
  870. $blocks[1]['info'] = t('Trackbacks');
  871. }
  872. return $blocks;
  873. }
  874. if ($delta == 0) {
  875. switch ($op) {
  876. case 'configure':
  877. $form['trackback_display_number'] = array(
  878. '#type' => 'select',
  879. '#title' => t('Number of trackbacks to display'),
  880. '#default_value' => variable_get('trackback_display_number', 10),
  881. '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)),
  882. '#description' => t('How many trackbacks are displayed in the recent trackbacks block')
  883. );
  884. return $form;
  885. case 'save':
  886. variable_set('trackback_display_number', $edit['trackback_display_number']);
  887. break;
  888. case 'view':
  889. $result = db_query_range('SELECT * FROM {trackback_received} WHERE status=1 ORDER BY created DESC', 0, variable_get('trackback_display_number', 10));
  890. $items = array();
  891. while ($tb = db_fetch_object($result)) {
  892. $items[] = _trackback_path($tb, truncate_utf8($tb->subject, 128, FALSE, TRUE)) .'<br />'. t('%time ago', array('%time' => format_interval(time() - $tb->created)));
  893. }
  894. $block['subject'] = t('Recent trackbacks');
  895. $block['content'] = theme('item_list', $items);
  896. return $block;
  897. }
  898. }
  899. else if ($op == 'view' && variable_get('trackback_view', 0) == 2) {
  900. if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  901. $node = node_load(arg(1));
  902. if (isset($node->can_receive) and node_access('view', $node) and $block['content'] = trackback_render($node)) {
  903. $block['subject'] = t('Trackbacks');
  904. return $block;
  905. }
  906. }
  907. }
  908. }
  909. function trackback_delete($trackback) {
  910. db_query('DELETE FROM {trackback_received} WHERE trid=%d', $trackback->trid);
  911. trackback_invoke_trackback($trackback, 'delete');
  912. watchdog('trackback', t('Deleted trackback %subject. The trackback was posted to !link.', array('%subject' => $trackback->subject, '!link' => l(url('node/'. $trackback->nid, NULL, NULL, TRUE), 'node/'. $trackback->nid))));
  913. }
  914. function trackback_load($trid) {
  915. return db_fetch_object(db_query('SELECT * FROM {trackback_received} WHERE trid=%d', $trid));
  916. }
  917. function _trackback_wd_subject($tb, $key = '!subject') {
  918. return array($key => l($tb->subject, 'admin/content/trackback/edit/'. $tb->trid));
  919. }
  920. /** spam module support functions **/
  921. function spam_publish_trackback($trid) {
  922. $trackback = trackback_load($trid);
  923. db_query('UPDATE {trackback_received} SET status = 1 WHERE trid = %d', $trackback->trid);
  924. cache_clear_all();
  925. watchdog('spam', t('Spam: published trackback <em>!subject</em>', _trackback_wd_subject($trackback)), WATCHDOG_NOTICE, _trackback_path($trackback, t('view trackback')));
  926. if (module_exists('spam')) {
  927. spam_log(SPAM_LOG, t('spam_publish_trackback: published trackback "%subject".', array('%subject' => $trackback->subject)), 'trackback', $trackback->trid);
  928. }
  929. }
  930. function spam_unpublish_trackback($trid) {
  931. $trackback = trackback_load($trid);
  932. db_query('UPDATE {trackback_received} SET status = 0 WHERE trid = %d', $trackback->trid);
  933. cache_clear_all();
  934. watchdog('spam', t('Spam: unpublished trackback <em>!subject</em>', _trackback_wd_subject($trackback)), WATCHDOG_NOTICE, _trackback_path($trackback, t('view trackback')));
  935. if (module_exists('spam')) {
  936. spam_log(SPAM_LOG, t('spam_unpublish_trackback: unpublished trackback "%subject".', array('%subject' => $trackback->subject)), 'trackback', $trackback->trid);
  937. }
  938. }
  939. function spam_delete_trackback($trid) {
  940. if ($trackback = trackback_load($trid)) {
  941. trackback_delete($trackback);
  942. }
  943. }
  944. function _trackback_spam_modify($tb, $spam) {
  945. $tokens = spam_tokenize($tb->subject .' '. $tb->url, 'header*');
  946. $tokens = array_merge($tokens, spam_tokenize($tb->excerpt));
  947. spam_tokens_unsave($tokens, $spam);
  948. spam_tokens_save($tokens, $spam);
  949. $prob = $spam ? 99 : 1;
  950. db_query("UPDATE {spam_tracker} SET probability=%d, timestamp=%d WHERE source='trackback' AND id=%d", $prob, time(), $tb->trid);
  951. spam_default_actions('trackback', $tb->trid, $tb->subject, $tb->excerpt, $prob, NULL, FALSE);
  952. }
  953. function spam_notspam_trackback($trid) {
  954. $trackback = trackback_load($trid);
  955. _trackback_spam_modify($trackback, 0);
  956. watchdog('spam', t('Spam: marked trackback <em>!subject</em> as not spam.', _trackback_wd_subject($trackback)), WATCHDOG_NOTICE, _trackback_path($trackback, t('view trackback')));
  957. spam_log(SPAM_LOG, t('trackback manually marked as not spam'), 'trackback', $trackback->trid);
  958. }
  959. function spam_spam_trackback($trid) {
  960. $trackback = trackback_load($trid);
  961. _trackback_spam_modify($trackback, 1);
  962. watchdog('spam', t('Spam: marked trackback <em>!subject</em> as spam.', _trackback_wd_subject($trackback)), WATCHDOG_NOTICE, _trackback_path($trackback, t('view trackback')));
  963. spam_log(SPAM_LOG, t('trackback manually marked as spam'), 'trackback', $trackback->trid);
  964. }
  965. /** end of spam module support functions */