3 define("_multiping_when_active", 1);
4 define("_multiping_when_taxonomy", 2);
5 define("_multiping_when_nodetype", 4);
6 define("_multiping_when_frontpage", 8);
9 function _multiping_get_settings($defaults = FALSE
) {
10 static
$settings = NULL
;
11 static
$default_settings = array(
13 'time_between_pings' => '10',
14 'pingatonce' => false
,
17 // Defaults requested?
19 return $default_settings;
21 // merge settings from variable table with defaults
22 if ($settings == NULL
) {
23 $settings = variable_get('multiping', array());
24 foreach ($default_settings as
$key => $value) {
25 if (is_array($value)) {
26 $settings[$key] = isset($settings[$key]) ?
array_merge($value, $settings[$key]) : $value;
28 else if (!isset($settings[$key])) {
29 $settings[$key] = $value;
39 * Implementation of hook_menu().
41 function multiping_menu() {
43 $items['admin/settings/multiping'] = array(
44 'title' => 'Ping services',
45 'description' => 'Configure when to ping which sites',
46 'page callback' => 'multiping_admin',
47 'page arguments' => array(),
48 'access callback' => 'user_access',
49 'access arguments' => array('admin pings'),
50 'type' => MENU_NORMAL_ITEM
,
52 $items['admin/settings/multiping/pingall'] = array(
53 'title' => 'Ping all',
54 'page callback' => 'multiping_pingall',
55 'access arguments' => array('admin pings'),
56 'type' => MENU_NORMAL_ITEM
,
58 $items['admin/settings/multiping/new'] = array(
59 'title' => 'New ping service',
60 'page callback' => 'drupal_get_form',
61 'page arguments' => array('multiping_edit_service', '0'),
62 'access arguments' => array('admin pings'),
63 'type' => MENU_CALLBACK
,
65 $items['admin/settings/multiping/%/edit'] = array(
66 'title' => 'Edit ping service',
67 'page callback' => 'drupal_get_form',
68 'page arguments' => array('multiping_edit_service', 3),
69 'access arguments' => array('admin pings'),
70 'type' => MENU_CALLBACK
,
72 $items['admin/settings/multiping/%/ping'] = array(
73 'title' => 'Ping service',
74 'page arguments' => array(3),
75 'page callback' => 'multiping_ping',
76 'access arguments' => array('admin pings'),
77 'type' => MENU_CALLBACK
,
79 $items['admin/settings/multiping/%/delete'] = array(
80 'title' => 'Delete ping service',
81 'page arguments' => array(3),
82 'page callback' => 'multiping_delete',
83 'access arguments' => array('admin pings'),
84 'type' => MENU_CALLBACK
,
90 * Implementation of hook_perm().
92 function multiping_perm() {
93 return array('admin pings');
96 function _multiping_doping($pingservice) {
100 $name=variable_get('site_name', '');
101 $slogan=variable_get('site_slogan', '');
102 if (strlen($slogan)>0)
103 $name="$name - $slogan";
105 if (module_exists('taxonomy')
106 && ($pingservice->whentoping
& _multiping_when_taxonomy
)
107 && count($pingservice->voc
)>0 && $pingservice->submitmainrss
==0) {
108 // Taxonomy module exists, "ping only for nodes with taxonomy",
109 // Some taxonomy elements are actually selected, "main rss" override is off
110 $voc=unserialize($pingservice->voc
);
111 $rss_url="$base_url/taxonomy/term/".
implode("+", $voc).
"/0/feed";
114 $rss_url="$base_url/rss.xml";
116 // Ping! Check service method
117 if ($pingservice->method
&& strlen($pingservice->method
)>0) {
118 //watchdog("Multiping","XML ping: ".$pingservice->url);
119 $result = xmlrpc($pingservice->url
, $pingservice->method
, $name, $base_url, $rss_url);
122 $pingurl=strtr($pingservice->url
, array(
123 "%name" => urlencode($name),
124 "%url" => urlencode("$base_url/"),
125 "%rss" => urlencode($rss_url))
127 $result = drupal_http_request($pingurl);
128 //watchdog("Multiping","Non-XML ping: ".$pingurl." Result: ".$result->code." Data: '".$result->data."'");
129 if ($result->code
==200) {
130 if (strpos($result->data
, "1")==0)
134 else $result = FALSE
;
136 // On success: Update timestamp
138 db_query("UPDATE {multiping} SET lastping=%d WHERE id=%d", time(), $pingservice->id
);
143 function _multiping_checkpings() {
144 $settings=_multiping_get_settings();
145 $result = db_query('SELECT * FROM {multiping}');
146 while ($row = db_fetch_object($result)) {
147 // Ping service active?
148 if (! ($row->whentoping
& _multiping_when_active
)) {
151 // Default query: Published nodes only
152 $sql_from="{node} n";
153 $sql_where="n.status>0";
154 // Taxonomy selection
155 if (module_exists('taxonomy') && ($row->whentoping
& _multiping_when_taxonomy
)) {
156 // Find most recent date for nodes with given taxonomy
157 $voc=unserialize($row->voc
);
158 $sql_from="$sql_from, {term_node} t";
159 $sql_where="$sql_where AND t.nid=n.nid AND (t.tid=" .
implode(" OR t.tid=", $voc) .
")";
161 // Nodetype selection
162 if ($row->whentoping
& _multiping_when_nodetype
) {
163 $nodetype=unserialize($row->nodetypes
);
164 $sql_where="$sql_where AND (n.type='".
implode("' OR n.type='", $nodetype).
"')";
166 // Promoted to front page?
167 if ($row->whentoping
& _multiping_when_frontpage
) {
168 $sql_where="$sql_where AND n.promote>0";
170 //watchdog("debug","Multiping ".$row->name.": SELECT * FROM ".$sql_from." WHERE ".$sql_where);
171 // Get max creation and modification time
173 $res_time = db_query('SELECT max(created) FROM {'.
$sql_from.
'} WHERE '.
$sql_where);
174 $row_time = db_fetch_array($res_time);
175 if ($row_time) $max_created=$row_time['max(created)'];
177 $res_time = db_query('SELECT max(changed) FROM {'.
$sql_from.
'} WHERE '.
$sql_where);
178 $row_time = db_fetch_array($res_time);
179 if ($row_time) $max_changed=$row_time['max(changed)'];
180 if ($max_created>$max_changed)
181 $lastmodified = $max_created; else
182 $lastmodified = $max_changed;
183 //watchdog("Multiping","lastmodified=".$lastmodified);
184 // Check wether to ping service
185 if ($lastmodified>$row->lastping
) {
186 // With every failure, exponentially increase retry time
187 $retry_time=$settings['global']['time_between_pings']*pow(1.5,$row->failcount
);
188 if ($retry_time>24*60) // Retry at least once a day
190 if ($row->lastping
+60*$retry_time>time()) {
191 // Timeout not yet reached
192 watchdog("Multiping", "Timeout for service @name not yet reached", array('@name' => $row->name
));
193 } elseif (_multiping_doping($row)) {
194 watchdog("Multiping", 'Successfully notified %site.', array('%site' => $row->name
));
195 db_query("UPDATE {multiping} SET failcount='0' WHERE id=%d",$row->id
);
197 watchdog("Multiping", 'Failed to notify %site.', array('%site' => $row->name
), WATCHDOG_WARNING
);
198 db_query("UPDATE {multiping} SET failcount='%d' WHERE id=%d",
199 ($row->failcount
)+1,$row->id
);
207 * Implementation of hook_cron().
208 * Check if sites need to be pinged.
210 function multiping_cron() {
211 watchdog("Multiping","Cron run",array(),WATCHDOG_DEBUG
);
212 _multiping_checkpings();
217 * Implementation of hook_nodeapi().
218 * If pingatonce is set, check pings.
220 function multiping_nodeapi(&$node, $op, $a3=NULL
, $a4=NULL
) {
221 //drupal_set_message("op=".$op);
222 //watchdog("Multiping","op=$op");
226 $settings=_multiping_get_settings();
227 if ($settings['global']['pingatonce'])
228 _multiping_checkpings();
234 function multiping_edit_service($form_state, $id) {
238 $edit['url']='http://';
239 $edit['method']='weblogUpdates.ping';
240 $edit['when_active']=1;
241 $edit['when_taxonomy']=0;
242 $edit['when_nodetype']=0;
243 $edit['when_frontpage']=0;
244 $edit['submitmainrss']=1;
246 $edit['nodetype']='';
248 $result = db_query('SELECT * FROM {multiping} WHERE id=%d',$id);
249 $row = db_fetch_object($result);
251 $edit['name']=$row->name
;
252 $edit['url']=$row->url
;
253 $edit['method']=$row->method
;
254 $edit['when_active']=(($row->whentoping
& _multiping_when_active
) > 0);
255 $edit['when_taxonomy']=(($row->whentoping
& _multiping_when_taxonomy
) > 0);
256 $edit['when_nodetype']=(($row->whentoping
& _multiping_when_nodetype
) > 0);
257 $edit['when_frontpage']=(($row->whentoping
& _multiping_when_frontpage
) > 0);
258 $edit['submitmainrss']=$row->submitmainrss
;
259 $edit['voc']=unserialize($row->voc
);
260 $edit['nodetype']=unserialize($row->nodetypes
);
262 watchdog("Multiping","Query for id=@id returned 0 rows", array('@id' => $id), WATCHDOG_WARNING
);
271 $form['name'] = array(
272 '#type' => 'textfield',
273 '#title' => t('Site name'),
274 '#default_value' => $edit['name'],
277 '#description' => t('Displayed name of the site to be pinged'),
278 '#attributes' => NULL
,
281 $form['url'] = array(
282 '#type' => 'textfield',
283 '#title' => t('URL'),
284 '#default_value' => $edit['url'],
287 '#description' => t('URL of the ping service. '.
288 'The following replacements will be done:<br />'.
289 '%name - Site name (and slogan)<br />'.
290 '%url - Site base URL<br />'.
291 '%rss - URL of RSS feed'),
292 '#attributes' => NULL
,
295 /* Todo: Submit which RSS feed? Whole feed or a feed containing only
296 items of the selected taxonomies? */
297 $form['method'] = array(
298 '#type' => 'textfield',
299 '#title' => t('Method name'),
300 '#default_value' => $edit['method'],
303 '#description' => t('If this is an XML service: Name of the method to be called'),
304 '#attributes' => NULL
,
305 '#required' => FALSE
,
307 $options = array('1' => t('Always ping'), '0' => t('Don\'t ping'));
308 if (module_exists('taxonomy')) {
309 $options['2']=t('Ping only for nodes with the following taxonomy');
311 $form['when_active'] = array(
312 '#type' => 'checkbox',
313 '#title' => t('Service active'),
314 '#default_value' => $edit['when_active'],
315 '#description' => t('Activate or deactivate this service'),
317 if (module_exists('taxonomy')) {
318 $form['when_taxonomy'] = array(
319 '#type' => 'checkbox',
320 '#title' => t('Ping only for selected taxonomies'),
321 '#default_value' => $edit['when_taxonomy'],
322 '#description' => t('Send a ping only if the node belongs to one of the follwing categories'),
324 $form['voc'] = array(
326 '#title' => t('Taxonomy terms when to ping'),
327 '#default_value' => $edit['voc'],
328 '#options' => taxonomy_form_all(),
330 '#description' => t('Ping this service if any of the taxonomy terms selected above matches the respective node'),
332 $form['submitmainrss'] = array(
333 '#type' => 'checkbox',
334 '#title' => t('Send main RSS feed in ping'),
335 '#default_value' => $edit['submitmainrss'],
336 '#description' => t('If checked, the main RSS feed is sent; otherwise, an RSS feed containing only articles from the selected taxonomies is used.'),
339 $form['when_nodetype'] = array(
340 '#type' => 'checkbox',
341 '#title' => t('Ping only for selected node types'),
342 '#default_value' => $edit['when_nodetype'],
343 '#description' => t('Send a ping only if the node is one of the following node types'),
345 $form['nodetype'] = array(
347 '#title' => t('Node types when to ping'),
348 '#default_value' => $edit['nodetype'],
349 '#options' => node_get_types('names'),
351 '#description' => t('Ping this service if any of the node types selected above matches the respective node'),
353 $form['when_frontpage'] = array(
354 '#type' => 'checkbox',
355 '#title' => t('Ping only for nodes promoted to front page'),
356 '#default_value' => $edit['when_frontpage'],
357 '#description' => t('Send a ping only if the node is promoted to the front page'),
359 $form['submit'] = array(
361 '#value' => t('Submit'),
367 function multiping_edit_service_submit($form_id, &$form_state) {
368 $edit = $form_state['values']; // TODO: Is this ok? http://drupal.org/node/144132#process-params
369 if ($edit['form_id']=='multiping_edit_service') {
370 $edit['id'] = ($edit['id'] && is_numeric($edit['id'])) ?
$edit['id'] : 0;
371 $edit['name'] = ($edit['name']) ?
$edit['name'] : '(no name)';
372 $edit['url'] = ($edit['url']) ?
$edit['url'] : 'http://localhost/';
373 $edit['method'] = ($edit['method']) ?
$edit['method'] : '';
374 $edit['submitmainrss'] = ($edit['submitmainrss']) ?
$edit['submitmainrss'] : 0; // Not present if false!
375 if ($edit['submitmainrss']>0) $edit['submitmainrss']=1;
376 $whentoping=$edit['when_active']*_multiping_when_active
+
377 $edit['when_taxonomy']*_multiping_when_taxonomy
+
378 $edit['when_nodetype']*_multiping_when_nodetype
+
379 $edit['when_frontpage']*_multiping_when_frontpage
;
380 if ($edit['id']==0) {
381 db_query("INSERT INTO {multiping} (name,url,method,whentoping,submitmainrss,voc,nodetypes) ".
382 "VALUES ('%s','%s','%s','%s','%s','%s','%s')",$edit['name'],$edit['url'],
383 $edit['method'],$whentoping,$edit['submitmainrss'],
384 serialize($edit['voc']),serialize($edit['nodetype']));
386 db_query("UPDATE {multiping} SET name='%s',url='%s',method='%s',whentoping='%s',submitmainrss='%s',voc='%s',nodetypes='%s' ".
387 "WHERE id=%d",$edit['name'],$edit['url'],$edit['method'],$whentoping,$edit['submitmainrss'],serialize($edit['voc']),serialize($edit['nodetype']),$edit['id']);
390 drupal_set_message("Changes saved.");
391 #drupal_goto("admin/settings/multiping");
392 $form_state['redirect']="admin/settings/multiping";
396 function multiping_settings() {
398 $settings=_multiping_get_settings();
399 $form['global']['time_between_pings'] = array(
400 '#type' => 'textfield',
401 '#title' => t('Time between pings'),
402 '#default_value' => $settings['global']['time_between_pings'],
405 '#description' => t('Minimum number of minutes between two pings to same site'),
406 '#attributes' => NULL
,
409 $form['pingatonce'] = array(
410 '#type' => 'checkbox',
411 '#title' => t('Ping after post'),
412 '#default_value' => $settings['global']['pingatonce'],
413 '#description' => t('Ping directly after post/update (instead of pinging during the cron job runs)'),
415 $form['submit'] = array(
417 '#value' => t('Submit'),
423 function multiping_settings_submit($form_id, &$form_state) {
424 $edit = $form_state['values']; // TODO: Is this ok? http://drupal.org/node/144132#process-params
425 if ($edit['form_id']=='multiping_settings') {
426 $settings=_multiping_get_settings();
427 $settings['global']['time_between_pings']=$edit['time_between_pings'];
428 $settings['global']['pingatonce']=$edit['pingatonce'];
429 variable_set('multiping', $settings);
431 drupal_set_message("Changes saved.");
432 #drupal_goto("admin/settings/multiping");
433 $form_state['redirect']="admin/settings/multiping";
438 * Menu callback: Admin page
440 function multiping_admin() {
443 $output .
= drupal_get_form('multiping_settings', $form);
444 // Table with services
445 $header = array(t('Name'), t('Last update'), array('data' => t('Operations'), 'colspan' => '3'));
446 $result = db_query('SELECT * FROM {multiping} ORDER BY id');
447 while ($row = db_fetch_object($result)) {
448 if ($row->lastping
==0)
449 $lastping=t('never'); else
450 $lastping=format_date($row->lastping
,'small');
454 l(t('edit'),"admin/settings/multiping/".
$row->id.
"/edit"),
455 l(t('ping'),"admin/settings/multiping/".
$row->id.
"/ping"),
456 l(t('delete'),"admin/settings/multiping/".
$row->id.
"/delete")
459 $output .
= theme('table',$header,$rows);
461 $output .
= "<p>".
l(t('Add service'),"admin/settings/multiping/new").
"</p>";
466 function multiping_pingall() {
467 $output = "<p>".
t("Running all pings...").
"</p>";
468 $header = array(t('Name'), t('Status'));
469 $result = db_query('SELECT * FROM {multiping} ORDER BY id');
470 while ($row = db_fetch_object($result)) {
471 $rows[] = array($row->name
,_multiping_doping($row) ?
t('Ok') : t('Failed'));
473 $output .
= theme('table',$header,$rows);
474 $output .
= "<p>".
l(t('Return'),"admin/settings/multiping").
"</p>";
479 function multiping_ping($id) {
480 watchdog("Multiping","ping @id", array('@id' => $id));
481 if (!is_numeric($id)) {
485 drupal_set_message("Not yet implemented","warning");
486 drupal_goto("admin/settings/multiping");
490 function multiping_delete($id) {
491 watchdog("Multiping","delete @id", array('@id' => $id));
492 if (!is_numeric($id)) {
496 db_query("DELETE FROM {multiping} WHERE id=%d",intval($id));
497 drupal_set_message("Service deleted.");
498 drupal_goto("admin/settings/multiping");