diff --git sites/all/modules/revisioning/revisioning.module sites/all/modules/revisioning/revisioning.module
index 18e9106..0e4be2b 100755
--- sites/all/modules/revisioning/revisioning.module
+++ sites/all/modules/revisioning/revisioning.module
@@ -10,6 +10,8 @@
 require_once drupal_get_path('module', 'node') .'/node.pages.inc';
 require_once drupal_get_path('module', 'revisioning') .'/revisioning_theme.inc';
 require_once drupal_get_path('module', 'revisioning') .'/revisioning_triggers_actions.inc';
+require_once drupal_get_path('module', 'revisioning') .'/revisioning_api.inc';
+// Note that we don't include Rules integration file - Rules module does it for us automatically.
 
 define('NEW_REVISION_WHEN_NOT_PENDING', 0);
 define('NEW_REVISION_EVERY_SAVE', 1);
@@ -54,6 +56,21 @@ function revisioning_perm() {
 }
 
 /**
+ * Revisioning settings form  
+ *  
+ */
+function revisioning_admin_settings() {
+  $form = array();
+  $form['revision_info_messages'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Print revision information'),
+    '#description' => t('If enabled, information about currently viewed revision will be printed in status messages. Position and appearance of the messages depends on your theme'),
+    '#default_value' => variable_get('revision_info_messages', 1),
+  );
+  return system_settings_form($form);  
+}
+
+/**
  * Implementation of hook_menu().
  *
  * Define new menu items.
@@ -63,6 +80,15 @@ function revisioning_perm() {
 function revisioning_menu() {
   $items = array();
 
+  // Admin settings
+  $items['admin/settings/revisioning'] = array(
+    'title' => 'Revisioning',
+    'description' => 'Change Revisioning settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('revisioning_admin_settings'),
+    'access arguments' => array('administer site configuration'),
+  );
+  
   // Add a tab to the 'I created' tab (defined in module_grants.module)
   $items['accessible-content/i-created/pending'] = array(
     'title' => 'In draft/Pending publication',
@@ -520,34 +546,48 @@ function revisioning_form_node_type_form_alter(&$form, &$form_state) {
  */
 function revisioning_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
   $args = arg();
-//drupal_set_message("'$op': " . implode('/', $args), 'error');
-
-  $edit_user_profile = ($args[0] == 'user') && ($args[2] == 'edit') && !empty($args[3]);
-  if (!($args[0] == 'node' || $edit_user_profile)) {
-    // Only interested in URIs starting with /node or /user/<uid>/edit/<content_type>
-    return;
-  }
+  switch ($op) {
+    case 'prepare':
+    case 'presave':
+    case 'insert':
+    case 'update':
+      $edit_user_profile = ($args[0] == 'user') && ($args[2] == 'edit') && !empty($args[3]);
+      if (!($args[0] == 'node' || $edit_user_profile)) {
+        // Only interested in URIs starting with /node or /user/<uid>/edit/<content_type>
+        return;
+      }
 
-  if ($args[1] == 'add') {
-    // /node/add/<content_type>; there is no 'add' for user profiles, only 'edit'
-    _handle_new($node, $op); // 'presave', 'insert'
-    return;
-  }
-  // Must have nid (when editing node) or uid (when editing user profile)
-  if (!is_numeric($args[1])) {
-    return;
-  }
-  if (end($args) == 'edit' || $edit_user_profile) {
-    // node/<nid>/edit, node/<nid>/revisions/<vid>/edit, user/<uid>/edit
-    _handle_edit($node, $op); // 'prepare', 'presave', 'update'
-    return;
-  }
-  if ($op == 'alter') { // called just after $node object is fully built for display
-    if (module_grants_node_revision_access('view revisions', $node)) {
-      if (!$teaser && $node->nid == $args[1]) { // don't show msg on page with many nodes
-        drupal_set_message(_get_node_info_msg($node));
+      if ($args[1] == 'add') {
+        // /node/add/<content_type>; there is no 'add' for user profiles, only 'edit'
+        _handle_new($node, $op); // 'presave', 'insert'
+        return;
       }
-    }
+      
+      // Must have nid (when editing node) or uid (when editing user profile)
+      if (!is_numeric($args[1])) {
+        return;
+      }
+      if (end($args) == 'edit' || $edit_user_profile) {
+        // node/<nid>/edit, node/<nid>/revisions/<vid>/edit, user/<uid>/edit
+        _handle_edit($node, $op); // 'prepare', 'presave', 'update'
+        return;
+      }
+      break;
+      
+    // called just after $node object is fully built for display
+    case 'alter':  
+      if (module_grants_node_revision_access('view revisions', $node)) {
+        if (!$teaser && $node->nid == $args[1]) { // don't show msg on page with many nodes
+          if (variable_get('revision_info_messages', 1) == 1) {
+            drupal_set_message(_get_node_info_msg($node));
+          }  
+        }
+      }
+      break;
+    
+    case 'delete revision':
+      module_invoke_all('revisionapi', 'post delete', $node);
+      break; 
   }
 }
 
@@ -663,10 +703,9 @@ function revisioning_publish_confirm($form_state, $node) {
  */
 function revisioning_publish_confirm_submit($form, &$form_state) {
   $nid   = $form_state['values']['node_id'];
-  $title = $form_state['values']['title'];
   $vid   = $form_state['values']['revision'];
-  $type  = $form_state['values']['type'];
-  _revisioning_publish_revision($nid, $vid, $title, $type);
+  _revisioning_publish_revision($nid, $vid);
+  drupal_set_message(t('Revision has been published.'));
   // Redirect to the same page as unpublish and revert
   $form_state['redirect'] = "node/$nid/revisions";
 }
@@ -692,14 +731,30 @@ function revisioning_unpublish_confirm_submit($form, &$form_state) {
   $nid   = $form_state['values']['node_id'];
   $title = check_plain($form_state['values']['title']);
   $type  = check_plain($form_state['values']['type']);
-  db_query("UPDATE {node} SET status=0 WHERE nid=%d", $nid);
-  cache_clear_all();
+  _revisioning_unpublish_revision($nid);
   drupal_set_message(t('%title has been unpublished.', array('%title' => $title)));
-  watchdog('content', 'Unpublished @type %title', array('@type' => $type, '%title' => $title), WATCHDOG_NOTICE, l(t('view'), "node/$nid"));
   // Redirect to the same page as publish and revert
   $form_state['redirect'] = "node/$nid/revisions";
-  // Invoke the revisioning trigger passing 'unpublish' as the operation
-  module_invoke_all('revisioning', 'unpublish');
+}
+
+/**
+ * Implementation of hook_form_FORM_ID_alter(), see
+ * node.pages.inc/node_revision_delete_confirm()
+ * 
+ * We only add "pre" submit handler, because "post delete" event is already available via hook_nodeapi() 
+ */
+function revisioning_form_node_revision_delete_confirm_alter(&$form, &$form_state) {
+  array_unshift($form['#submit'], 'revisioning_revision_delete_confirm_pre_submit');
+}
+
+/**
+ * Submission "pre" handler for the node_revision_delete_confirm form.
+ * 
+ * Runs BEFORE the existing delete function in node.pages.inc
+ */
+function revisioning_revision_delete_confirm_pre_submit($form, &$form_state) {
+  $node = $form['#node_revision'];
+  module_invoke_all('revisionapi', 'pre delete', $node);
 }
 
 /**
@@ -711,18 +766,29 @@ function revisioning_form_node_revision_revert_confirm_alter(&$form, &$form_stat
   if (_get_number_of_pending_revisions($node->nid) > 0) {
     drupal_set_message(t('There is a pending revision. Are you sure you want to revert to an archived revision?'), 'warning');
   }
-  $form['#submit'][] = 'revisioning_revert_confirm_submit';
+  array_unshift($form['#submit'], 'revisioning_revert_confirm_pre_submit');
+  $form['#submit'][] = 'revisioning_revert_confirm_post_submit';
 }
 
 /**
- * Submission handler for the revert_confirm form.
+ * Submission "pre" handler the revert_confirm form.
+ * 
+ * Runs BEFORE the existing revert function in node.pages.inc
+ */
+function revisioning_revert_confirm_pre_submit($form, &$form_state) {
+  $node = $form['#node_revision'];
+  module_invoke_all('revisionapi', 'pre revert', $node);
+}
+
+
+/**
+ * Submission "post" handler for the revert_confirm form.
  *
- * Forward on to the existing revert function in node.pages.inc, then triggers
- * a 'revert' event that may be actioned upon.
+ * Runs AFTER the existing revert function in node.pages.inc
  *
  * Note:
  * It would be nice if publish and revert were symmetrical operations and that
- * node_revision_revert_cofirm_submit didn't save a copy of the revision (under
+ * node_revision_revert_confirm_submit didn't save a copy of the revision (under
  * a new vid), as this has the side-effect of making all "pending" revisions
  * "old". This is because the definition of "pending" is:
  * "node_vid > current_vid".
@@ -730,172 +796,10 @@ function revisioning_form_node_revision_revert_confirm_alter(&$form, &$form_stat
  * such as vid (or a timestamp) that changes everytime a piece of code executes
  * a node_save.
  */
-function revisioning_revert_confirm_submit($form, &$form_state) {
+function revisioning_revert_confirm_post_submit($form, &$form_state) {
   $node = $form['#node_revision'];
-  // Make sure the node gets published, i.e. has its status flag set
-  db_query("UPDATE {node} SET status=1 WHERE nid=%d", $node->nid);
-  cache_clear_all();
-  // Invoke the revisioning trigger passing 'revert' as the operation
-  module_invoke_all('revisioning', 'revert');
-}
-
-/**
- * Make the supplied revision of the node current and publish it.
- *
- * @param $nid
- *   The id of the node
- * @param $vid
- *   The id of the revision that is to be made current
- * @param $title
- *   The title of the revision that is to be made current
- * @param $type
- *   The node's content type (eg "story"), supplied only to make watchdog msg
- *   consistent with the node.module watchdog msgs.
- */
-function _revisioning_publish_revision($nid, $vid, $title, $type) {
-  // Update node table, making sure the "published" (ie. status) flag is set
-  db_query("UPDATE {node} SET vid=%d, title='%s', status=1 WHERE nid=%d", $vid, $title, $nid);
-  cache_clear_all();
-  drupal_set_message(t('Revision has been published.'));
-  watchdog('content', 'Published rev #%revision of @type %title', array('@type' => check_plain($type), '%title' => check_plain($title), '%revision' => $vid), WATCHDOG_NOTICE, l(t('view'), "node/$nid/revisions/$vid/view"));
-  // Invoke the revisioning trigger passing 'publish' as the operation
-  module_invoke_all('revisioning', 'publish');
-}
-
-/**
- * Find the most recent pending revision and make it current, unless it already is.
- *
- * @param $node
- *   The node object whose latest pending revision is to be published
- */
-function revisioning_publish_latest_revision($node) {
-  // Get latest pending revision or take the current provided it's UNpublished
-  $latest_pending = array_shift(_get_pending_revisions($node->nid));
-  if (!$latest_pending) {
-    if (!$node->status && $node->vid == get_current_revision_id($node->nid)) {
-      $latest_pending = $node;
-    }
-  }
-  if ($latest_pending) {
-    _revisioning_publish_revision($node->nid, $latest_pending->vid, $latest_pending->title, $latest_pending->type);
-  }
-  else {
-    drupal_set_message(t('"!title" has no pending revision to be published.', array('!title' => $node->title)), 'warning');
-  }
-}
-
-/**
- * Return a count of the number of revisions newer than the supplied vid.
- *
- * @param $vid
- *  The reference vid.
- * @param $nid
- *  The id of the node.
- * @return
- *  integer
- */
-function _get_number_of_revisions_newer_than($vid, $nid) {
-  return db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>%d AND n.nid=%d)", $vid, $nid));
-}
-
-/**
- * Return a count of the number of revisions newer than the current revision.
- *
- * @param $nid
- *  The id of the node.
- * @return
- *  integer
- */
-function _get_number_of_pending_revisions($nid) {
-  return db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>n.vid AND n.nid=%d)", $nid));
-}
-
-/**
- * Retrieve a list of revisions with a vid greater than the current.
- *
- * @param $nid
- *  The node id to retrieve.
- * @return
- *  An array of revisions (latest first), each containing vid, title and
- *  content type.
- */
-function _get_pending_revisions($nid) {
-  $sql = "SELECT r.vid, r.title, n.type FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>n.vid AND n.nid=%d) ORDER BY r.vid DESC";
-  $result = db_query($sql, $nid);
-  $revisions = array();
-  while ($revision = db_fetch_object($result)) {
-    $revisions[$revision->vid] = $revision;
-  }
-  return $revisions;
-}
-
-/**
- * Retrieve a list of all revisions (archive, current, pending) belonging to
- * the supplied node.
- *
- * @param $nid
- *  The node id to retrieve.
- * @param $include_taxonomy_terms
- *  Whether to also retrieve the taxonomy terms for each revision
- * @return
- *  An array of revision objects, each with published flag, log message, vid,
- *  title, timestamp and name of user that created the revision
- */
-function _get_all_revisions_for_node($nid, $include_taxonomy_terms = FALSE) {
-  $sql_select = 'SELECT n.type, n.status, r.vid, r.title, r.log, r.uid, r.timestamp, u.name';
-  $sql_from   = ' FROM {node_revisions} r LEFT JOIN {node} n ON n.vid=r.vid INNER JOIN {users} u ON u.uid=r.uid';
-  $sql_where  = ' WHERE r.nid=%d ORDER BY r.vid DESC';
-  if ($include_taxonomy_terms) {
-    $sql_select .= ', td.name AS term';
-    $sql_from .= ' LEFT JOIN {term_node} tn ON r.vid=tn.vid LEFT JOIN {term_data} td ON tn.tid=td.tid';
-    $sql_where .= ', term ASC';
-  }
-  $sql = $sql_select . $sql_from . $sql_where;
-  $result = db_query($sql, $nid);
-  $revisions = array();
-  while ($revision = db_fetch_object($result)) {
-    if (empty($revisions[$revision->vid])) {
-      $revisions[$revision->vid] = $revision;
-    }
-    elseif ($include_taxonomy_terms) {
-      // If a revision has more than one taxonomy term, these will be returned
-      // by the query as seperate objects differing only in their term fields.
-      $existing_revision = $revisions[$revision->vid];
-      $existing_revision->term .= '/'. $revision->term;
-    }
-  }
-  return $revisions;
-}
-
-/**
- * Return a string with details about the node that is about to be displayed.
- *
- * Called from revisioning_nodeapi().
- *
- * @param $node
- *  The node that is about to be viewed
- * @return
- *  A translatable message containing details about the node
- */
-function _get_node_info_msg($node) {
-  // Get username for the revision, not the creator of the node
-  $revision_author = user_load($node->revision_uid);
-  $placeholder_data =
-    array('@content_type' => $node->type,
-          '%title' => $node->title,
-          '!author' => theme('username', $revision_author),
-          '@date' => format_date($node->revision_timestamp, 'small'));
-  $current_vid = get_current_revision_id($node->nid);
-  $is_pending = ($node->vid > $current_vid) || (!$node->status && get_number_of_revisions($node->nid) == 1);
-  if ($is_pending) {
-    $msg = t('Displaying <em>pending</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data);
-  }
-  else {
-    $msg = ($current_vid == $node->vid) && $node->status
-      ? t('Displaying <em>current, published</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data)
-      : t('Displaying <em>archived</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data);
-  }
-  return $msg;
+  _revisioning_publish_node($node->nid);
+  module_invoke_all('revisionapi', 'post revert', $node);
 }
 
 /**
@@ -935,20 +839,6 @@ function generate_node_links_according_to_permissions($node, $link_type = 0) {
 }
 
 /**
- * Return whether the node has a pending revision, that is a revision newer
- * than the current OR when there's only one revision, whether that revision is
- * unpublished.
- *
- * @param $node
- * @return
- *  TRUE, if the node has a pending revision.
- */
-function _is_pending($node) {
-  return ($node->vid > get_current_revision_id($node->nid)) ||
-    (!$node->status && get_number_of_revisions($node->nid) == 1) ;
-}
-
-/**
  * Implementation of hook_token_values().
  */
 function revisioning_token_values($type, $object = NULL, $options = array()) {
diff --git sites/all/modules/revisioning/revisioning.rules.inc sites/all/modules/revisioning/revisioning.rules.inc
new file mode 100644
index 0000000..32819a7
--- /dev/null
+++ sites/all/modules/revisioning/revisioning.rules.inc
@@ -0,0 +1,254 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Rules integration for Revisioning module
+ *
+ */
+
+
+/********************************* Rules Conditions *****************************************/
+
+/*
+ * Implementation of hook_rules_condition_info()
+ */
+function revisioning_rules_condition_info() {
+  return array(
+    'revisioning_node_has_pending' => array(
+      'label' => t('Content has pending revision'),
+      'arguments' => array(
+        'node' => array('type' => 'node', 'label' => t('Content'))
+      ),
+      'help' => t('Evaluates to TRUE, if the node has one or more pending revision'),
+      'module' => 'Revisioning',
+    ),
+    'revisioning_condition_revision_is' => array(
+      'label' => t('Content revision is'),
+      'arguments' => array(
+        'node' => array('type' => 'node', 'label' => t('Content'))
+      ),
+      'help' => t('Evaluates to TRUE, if revision is one of selected types'),
+      'module' => 'Revisioning',
+    ),
+  );
+}
+
+/*
+ * Condition: Check for pending revisions of the node
+ */
+function revisioning_node_has_pending($node, $settings) {
+  $pending = _get_number_of_pending_revisions($node->nid);
+  if ($pending > 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*
+ * Condition: Check for pending revisions of the node
+ */
+function revisioning_condition_revision_is($node, $settings) {
+  $type = _revisioning_revision_is($node);
+  if (in_array($type, $settings['revision_type'])) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*
+ *  Check for content types - Configuration form
+ *  
+ */
+function revisioning_condition_revision_is_form($settings = array(), &$form) {
+  $form['settings']['revision_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Is one of'),
+    '#options' => _revisioning_revision_states(),
+    '#multiple' => TRUE,
+    '#default_value' => isset($settings['revision_type']) ? $settings['revision_type'] : array(),
+    '#required' => TRUE,
+  );
+}
+
+/**
+ * Label callback for "revisioning_revision_is" condition
+ */
+function revisioning_condition_revision_is_label($settings, $argument_labels) {
+  $names = array_intersect_key(_revisioning_revision_states(), $settings['revision_type']);
+  return t('Revision status of @node is: @type', $argument_labels + array('@type' => implode(' or ', $names)));
+}
+
+/**
+ * Label callback for "revisioning_node_has_pending" condition
+ */
+function revisioning_node_has_pending_label($settings, $argument_labels) {
+  return t('Content "@node" has pending revision(s)', $argument_labels);
+}
+
+
+/********************************* Rules Events *********************************************/
+
+/**
+ * Implementation of hook_rules_event_info()
+ */
+function revisioning_rules_event_info() {
+  $default = array(
+    'module' => 'Revisioning',
+    'arguments' =>  _revisioning_rules_event_arguments(),
+    'redirect' => TRUE,
+  );
+  $events = array(
+    'revisioning_post_unpublish' => $default + array(
+      'label' => t('Node has been unpublished'),
+    ),
+    'revisioning_post_publish' => $default + array(
+      'label' => t('Pending revision has been published'),
+    ),
+    'revisioning_post_revert' => $default + array(
+      'label' => t('Node has been reverted to revision'),
+    ),
+    'revisioning_pre_delete' => $default + array(
+      'label' => t('Node revision is going to be deleted'),
+    ),
+    'revisioning_pre_revert' => $default + array(
+      'label' => t('Node is going to be reverted to revision'),
+    ),
+  );
+  return $events;
+}
+
+/**
+ * Returns arguments suitable for using it with a node
+ */
+function _revisioning_rules_event_arguments() {
+  return array(
+    'node' => array(
+      'type' => 'node',
+      'label' => t('target revision of operation'), 
+    ),
+    'current_revision' => array(
+      'type' => 'node',
+      'label' => t('current revision of target content'),
+      'handler' => 'revisioning_events_argument_current_revision'
+     ),
+    'author' => array(
+      'type' => 'user',
+      'label' => t('content author'),
+      'handler' => 'rules_events_argument_node_author'
+     ),
+    'user' => array(
+      'type' => 'user',
+      'label' => t('acting user'),
+      'handler' => 'rules_events_argument_global_user'
+     ),
+  );
+}
+
+/**
+ * Current revision event argument handler
+ */
+function revisioning_events_argument_current_revision($node) {
+  $current_vid = get_current_revision_id($node->nid);
+  if ($node->vid != $current_vid) {
+    $current = node_load($node->nid, $current_vid);
+    return $current;
+  }
+  return $node;
+}
+
+/********************************* Rules Actions *********************************************/
+
+/**
+ * Returns arguments suitable for using it with a node
+ */
+function _revisioning_rules_action_arguments() {
+  return array(
+    'node' => array(
+      'type' => 'node', 
+      'label' => t('content')
+    ),
+    'current_revision' => array(
+      'type' => 'node',
+      'label' => t('current revision'),
+      'handler' => 'revisioning_events_argument_current_revision'
+     ),
+    'author' => array(
+      'type' => 'user',
+      'label' => t('content author'),
+      'handler' => 'rules_events_argument_node_author'
+     ),
+    'user' => array(
+      'type' => 'user',
+      'label' => t('acting user'),
+      'handler' => 'rules_events_argument_global_user'
+     ),
+  );
+}
+
+/**
+* Implementation of hook_rules_action_info().
+*/
+function revisioning_rules_action_info() {
+  $default = array(
+    'module' => 'Revisioning',
+  );
+  
+  return array(
+    'revisioning_rules_action_publish_latest' => $default + array(
+      'label' => t('Publish the most recent pending revision'),
+      'arguments' => array(
+        'node' => array('type' => 'node','label' => t('content')),
+      ),
+    ),
+    
+    'revisioning_rules_action_load_current' => $default + array(
+      'label' => t('Load current revision of content'),
+      'arguments' => array(
+        'node' => array('type' => 'node','label' => t('content')),
+      ),
+      'new variables' => array(
+        'loaded_current_revision' => array(
+          'type' => 'node',
+          'label' => t('Loaded current revision of content'),
+          'save' => FALSE,
+          'label callback' => 'revisioning_rules_loaded_current_label',
+        ),
+      ),
+    ),
+     
+  );
+}
+
+/**
+ * Label callback for "revisioning_rules_action_load_current" action.
+ */
+function revisioning_rules_action_load_current_label($settings, $argument_labels) {  
+  return t('Load current revision of "@node"', $argument_labels);
+}
+
+/**
+ * Label callback for "loaded_current_revision" variable.
+ */
+function revisioning_rules_loaded_current_label($settings, $argument_labels) {
+  return t('Loaded current revision of "@node"', $argument_labels);
+}
+
+/**
+ * Action: load current revision of provided node
+ */
+function revisioning_rules_action_load_current($node) {
+  $current_vid = get_current_revision_id($node->nid);
+  if ($node->vid != $current_vid) {
+    $current = node_load($node->nid, $current_vid);
+    return array('loaded_current_revision' => $current);
+  }
+  return array('loaded_current_revision' => $node);
+}
+
+/**
+ * Action: publish most recent pending revision.
+ */
+function revisioning_rules_action_publish_latest($node) {
+  $published = _revisioning_publish_latest_revision($node);
+}
diff --git sites/all/modules/revisioning/revisioning_api.inc sites/all/modules/revisioning/revisioning_api.inc
new file mode 100644
index 0000000..097a61e
--- /dev/null
+++ sites/all/modules/revisioning/revisioning_api.inc
@@ -0,0 +1,442 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * API functions of Revisioning module
+ * 
+ * Reusable functions that do all dirty job go here. 
+ *
+ */
+
+define('REVISION_ARCHIVED', 0);
+define('REVISION_CURRENT', 1);
+define('REVISION_PENDING', 2);
+
+/**
+ * Naming convention Revisioning uses:
+ * 
+ * Pending 
+ *   - revision with (vid > current_vid) of ANY node
+ *     OR single revision of UNPUBLISHED node 
+ * 
+ * Current, published
+ *   - revision with (vid == current_vid) of PUBLISHED node
+ * 
+ * Archived
+ *   - all other revisions, i.e. 
+ *     revision with (vid < current_vid) of ANY node 
+ *     OR revision with (vid == current_vid) of UNPUBLISHED node 
+ *   
+ * Note: this is subject to change if Revisioning is going to store 
+ * revision states independently from vid number (e.g. in different table).
+ * 
+ * These are ordinary revision states. We can provide additional states for internal use (not for display
+ * to ordinary users so we don't confuse them), e.g. for using in Rules. 
+ */
+ 
+/**
+ * Return revision state(s)
+ * 
+ * @param $state
+ *  optional state id, as defined in revisioning_api.inc
+ * @return
+ *  if $state is provided, state name. Otherwise, state names array keyed by state id.
+ */
+function _revisioning_revision_states($state = NULL) {
+  $states = array(
+    REVISION_PENDING  => t('Pending'),
+    REVISION_CURRENT  => t('Current, published'),
+    REVISION_ARCHIVED => t('Archived'),
+  );
+  return empty($state) ? $states : $states[$state];
+}
+
+/**
+ * Implementation of hook_revisionapi()
+ * 
+ * Act on various revision events.
+ * 
+ * @param $op
+ *  Operation 
+ * @param $node
+ *  Node of current operation (loaded with vid of the operation).
+ * 
+ * "Pre" operations can be useful to get values before they are lost or changed: for example,  
+ * for saving backup of revision before it's deleted.
+ * Also, for "pre" operations vetoing mechanics could be implemented, so it would be possible to veto
+ * operation via hook_revisionapi(). For example, when hook is returning FALSE, operation is vetoed.
+ *  
+ * Yet unused operations are commented out, to serve as default implementation reference. 
+ *  
+ * @TODO: Add more operations if needed. 
+ */
+function revisioning_revisionapi($op, &$node) {
+  switch ($op) {
+    case 'pre revert':
+      // Invoke corresponding Rules event
+      if (module_exists('rules')) {
+        rules_invoke_event('revisioning_pre_revert', $node);
+      }
+      break;
+      
+    case 'post revert':
+      // Invoke the revisioning trigger passing 'revert' as the operation
+      if (module_exists('trigger')) {
+        module_invoke_all('revisioning', 'revert');
+      }
+      // Invoke corresponding Rules event
+      if (module_exists('rules')) {
+        rules_invoke_event('revisioning_post_revert', $node);
+      }
+      break;
+      
+    case 'pre publish':
+      // Invoke corresponding Rules event
+      if (module_exists('rules')) {
+        rules_invoke_event('revisioning_pre_publish', $node);
+      }       
+      break;
+      
+    case 'post publish':
+      // Invoke the revisioning trigger passing 'publish' as the operation
+      if (module_exists('trigger')) {
+        module_invoke_all('revisioning', 'publish');
+      }
+      // Invoke corresponding Rules event
+      if (module_exists('rules')) {
+        rules_invoke_event('revisioning_post_publish', $node);
+      }
+      break;
+
+    // Not yet implemented: do we really need it ?
+    //case 'pre unpublish':
+          
+    case 'post unpublish':
+      // Invoke the revisioning trigger passing 'unpublish' as the operation
+      if (module_exists('trigger')) {
+        module_invoke_all('revisioning', 'unpublish');
+      }
+      // Invoke corresponding Rules event
+      if (module_exists('rules')) {
+        rules_invoke_event('revisioning_post_unpublish', $node);
+      }
+      break;
+    
+    case 'pre delete':
+      // Invoke corresponding Rules event
+      if (module_exists('rules')) {
+        rules_invoke_event('revisioning_pre_delete', $node);
+      }
+      break;
+      
+    case 'post delete':
+      break;
+  }
+}
+
+/**
+ * Revert node to selected revision and publish node. 
+ * 
+ * This is same as "revert" operation in Revisioning terms:
+ * "core revert" + "publish" = "revisioning revert"
+ * 
+ * @param $node:
+ *  Target $node object (loaded with target revision) or nid of target node
+ * @param $vid:
+ *  Optional vid of revision to revert to, if provided $node is not object.
+ * 
+ * @TODO: Should we give "revisioning revert" better name ? Core "revert" does not 
+ * publish node, so this involves some ambiguity, I think.
+ *   
+ */
+function _revisioning_revertpublish_revision(&$node, $vid = NULL) {
+  $node_revision = is_object($node) ? $node : node_load($node, $vid);
+  module_invoke_all('revisionapi', 'pre revert', $node_revision);
+  _revisioning_revert_revision($node_revision);
+  _revisioning_publish_node($node_revision);
+  module_invoke_all('revisionapi', 'post revert', $node_revision);
+}
+
+/**
+ * Revert node to selected revision without publishing it
+ *  
+ * This is same as node_revision_revert_confirm_submit() in node_pages.inc, except it doesn't put any messages 
+ * on screen. Also it doesn't publish node, as usual Revisioning "revert" operation does.  
+ * This way we provide smaller and reusable (for example, in actions) function.
+ * 
+ * @param $node:
+ *  Target $node object (loaded with target revision) or nid of target node 
+ * @param $vid:
+ *  optional vid of revision to revert to, if provided $node is not object.
+ * 
+ */
+function _revisioning_revert_revision(&$node, $vid = NULL) {
+  $node_revision = is_object($node) ? $node : node_load($node, $vid);
+  $node_revision->revision = 1;
+  $node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp)));
+  if (module_exists('taxonomy')) {
+    $node_revision->taxonomy = array_keys($node_revision->taxonomy);
+  }
+  node_save($node_revision);
+  watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));  
+}
+
+/**
+ * Publish node, without calling node_save()
+ * 
+ * @param $node:
+ *  Target $node object or nid of target node 
+ */
+function _revisioning_publish_node($node) {
+  $nid = is_object($node) ? $node->nid : $node;
+  db_query("UPDATE {node} SET status=1 WHERE nid=%d", $nid);
+  cache_clear_all();
+}
+
+/**
+ * Unpublish node, without calling node_save()
+ * 
+ * @param $node:
+ *  Target $node object or nid of target node 
+ */
+function _revisioning_unpublish_node($node) {
+  $nid = is_object($node) ? $node->nid : $node;
+  db_query("UPDATE {node} SET status=0 WHERE nid=%d", $nid);
+  cache_clear_all();
+}
+
+/**
+ * Delete selected revision of node, provided it's not current.
+ *
+ * This is same as node_revision_delete_confirm_submit() in node_pages.inc, except it doesn't put any messages 
+ * on screen. This way it becomes reusable (for example, in actions).
+ * Since we are calling nodeapi as in node_revision_delete_confirm_submit(), we invoke our "post delete" 
+ * revisionapi hook in nodeapi. This way revisionapi hooks work same way both with "delete revision" submit handler, and 
+ * when this function is called, and we don't invoke revisionapi "post delete" hook twice.
+ * 
+ * @param $node:
+ *  Target $node object (loaded with target revision) or nid of target node 
+ * @param $vid:
+ *  optional vid of revision to delete, if provided $node is not object.
+ * 
+ * @TODO: Insert check to prevent deletion of current revision of node.
+ */
+function _revisioning_delete_revision(&$node, $vid = NULL) {
+  $node_revision = is_object($node) ? $node : node_load($node, $vid);
+  module_invoke_all('revisionapi', 'pre delete', $node_revision);
+  db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node_revision->nid, $node_revision->vid);
+  node_invoke_nodeapi($node_revision, 'delete revision');
+  watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));    
+}
+
+
+/**
+ * Unpublish revision.
+ * 
+ * Function name comes from convention Revisioning uses: since we work with revisions, we think
+ * of it as unpublishing revision, even while unpublishing applies to the whole node.
+ * 
+ * @param $node:
+ *  Target $node object or nid of target node 
+ * 
+ * @TODO: Shouldn't we invoke hook_nodeapi('update'..) too, since we are updating node ? 
+ */
+function _revisioning_unpublish_revision(&$node) {
+  $node_revision = is_object($node) ? $node : node_load($node);
+  module_invoke_all('revisionapi', 'pre unpublish', $node_revision);
+  _revisioning_unpublish_node($node_revision->nid);
+  watchdog('content', 'Unpublished @type %title', array('@type' => $node_revision->type, '%title' => $node_revision->title), WATCHDOG_NOTICE, l(t('view'), "node/$node_revision->nid"));
+  module_invoke_all('revisionapi', 'post unpublish', $node_revision);
+}
+
+/**
+ * Make the supplied revision of the node current and publish it.
+ * 
+ * Currently it's caller responsibility to provide proper revision.
+ *
+ * @param $node:
+ *  Target $node object (loaded with target revision) or nid of target node 
+ * @param $vid:
+ *  optional vid of revision to make current, if provided $node is not object. 
+ *
+ * @TODO: Shouldn't we invoke hook_nodeapi('update'..) too, since we are updating node ?
+ */
+function _revisioning_publish_revision(&$node, $vid = NULL) {
+  $node_revision = is_object($node) ? $node : node_load($node, $vid);
+  module_invoke_all('revisionapi', 'pre publish', $node_revision);
+  // Update node table, making sure the "published" (ie. status) flag is set
+  db_query("UPDATE {node} SET vid=%d, title='%s', status=1 WHERE nid=%d", $node_revision->vid, $node_revision->title, $node_revision->nid);
+  cache_clear_all();
+  watchdog('content', 'Published rev #%revision of @type %title', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid), WATCHDOG_NOTICE, l(t('view'), "node/$node_revision->nid/revisions/$node_revision->vid/view"));
+  module_invoke_all('revisionapi', 'post publish', $node_revision);
+}
+
+/**
+ * Find the most recent pending revision, make it current, unless it already is, and publish node.
+ *
+ * @param $node
+ *   The node object whose latest pending revision is to be published
+ * @return
+ *   TRUE if operation was successful, FALSE if there is no pending revision to publish
+ */
+function _revisioning_publish_latest_revision(&$node) {
+  // Get latest pending revision or take the current provided it's UNpublished
+  $latest_pending = array_shift(_get_pending_revisions($node->nid));
+  if (!$latest_pending) {
+    if (!$node->status && $node->vid == get_current_revision_id($node->nid)) {
+      $latest_pending = $node;
+    }
+  }
+  if ($latest_pending) {
+    _revisioning_publish_revision($node->nid, $latest_pending->vid);
+    return TRUE; 
+  }
+  return FALSE;
+}
+
+/**
+ * Return a count of the number of revisions newer than the supplied vid.
+ *
+ * @param $vid
+ *  The reference vid.
+ * @param $nid
+ *  The id of the node.
+ * @return
+ *  integer
+ */
+function _get_number_of_revisions_newer_than($vid, $nid) {
+  return db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>%d AND n.nid=%d)", $vid, $nid));
+}
+
+/**
+ * Return a count of the number of revisions newer than the current revision.
+ *
+ * @param $nid
+ *  The id of the node.
+ * @return
+ *  integer
+ */
+function _get_number_of_pending_revisions($nid) {
+  return db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>n.vid AND n.nid=%d)", $nid));
+}
+
+/**
+ * Retrieve a list of revisions with a vid greater than the current.
+ *
+ * @param $nid
+ *  The node id to retrieve.
+ * @return
+ *  An array of revisions (latest first), each containing vid, title and
+ *  content type.
+ */
+function _get_pending_revisions($nid) {
+  $sql = "SELECT r.vid, r.title, n.type FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>n.vid AND n.nid=%d) ORDER BY r.vid DESC";
+  $result = db_query($sql, $nid);
+  $revisions = array();
+  while ($revision = db_fetch_object($result)) {
+    $revisions[$revision->vid] = $revision;
+  }
+  return $revisions;
+}
+
+
+/**
+ * Return whether the node has a pending revision, that is a revision newer
+ * than the current OR when there's only one revision, whether that revision is
+ * unpublished.
+ *
+ * @param $node
+ * @return
+ *  TRUE, if the node has a pending revision.
+ */
+function _is_pending($node) {
+  return ($node->vid > get_current_revision_id($node->nid)) ||
+    (!$node->status && get_number_of_revisions($node->nid) == 1) ;
+}
+
+/**
+ * Retrieve a list of all revisions (archive, current, pending) belonging to
+ * the supplied node.
+ *
+ * @param $nid
+ *  The node id to retrieve.
+ * @param $include_taxonomy_terms
+ *  Whether to also retrieve the taxonomy terms for each revision
+ * @return
+ *  An array of revision objects, each with published flag, log message, vid,
+ *  title, timestamp and name of user that created the revision
+ */
+function _get_all_revisions_for_node($nid, $include_taxonomy_terms = FALSE) {
+  $sql_select = 'SELECT n.type, n.status, r.vid, r.title, r.log, r.uid, r.timestamp, u.name';
+  $sql_from   = ' FROM {node_revisions} r LEFT JOIN {node} n ON n.vid=r.vid INNER JOIN {users} u ON u.uid=r.uid';
+  $sql_where  = ' WHERE r.nid=%d ORDER BY r.vid DESC';
+  if ($include_taxonomy_terms) {
+    $sql_select .= ', td.name AS term';
+    $sql_from .= ' LEFT JOIN {term_node} tn ON r.vid=tn.vid LEFT JOIN {term_data} td ON tn.tid=td.tid';
+    $sql_where .= ', term ASC';
+  }
+  $sql = $sql_select . $sql_from . $sql_where;
+  $result = db_query($sql, $nid);
+  $revisions = array();
+  while ($revision = db_fetch_object($result)) {
+    if (empty($revisions[$revision->vid])) {
+      $revisions[$revision->vid] = $revision;
+    }
+    elseif ($include_taxonomy_terms) {
+      // If a revision has more than one taxonomy term, these will be returned
+      // by the query as seperate objects differing only in their term fields.
+      $existing_revision = $revisions[$revision->vid];
+      $existing_revision->term .= '/'. $revision->term;
+    }
+  }
+  return $revisions;
+}
+
+/**
+ * Return revision type of supplied node
+ * 
+ * @param &$node
+ *  Node object to check
+ * @return 
+ *  Revision type
+ */
+function _revisioning_revision_is(&$node) {
+  if (_is_pending($node)) {
+    return REVISION_PENDING;
+  }
+  $current_vid = get_current_revision_id($node->nid);
+  return ($current_vid == $node->vid) && $node->status ? REVISION_CURRENT : REVISION_ARCHIVED;  
+}
+
+/**
+ * Return a string with details about the node that is about to be displayed.
+ *
+ * Called from revisioning_nodeapi().
+ *
+ * @param $node
+ *  The node that is about to be viewed
+ * @return
+ *  A translatable message containing details about the node
+ */
+function _get_node_info_msg($node) {
+  // Get username for the revision, not the creator of the node
+  $revision_author = user_load($node->revision_uid);
+  $placeholder_data = array(
+    '@content_type' => $node->type,
+    '%title' => $node->title,
+    '!author' => theme('username', $revision_author),
+    '@date' => format_date($node->revision_timestamp, 'small'),
+  );
+  $revision_type = _revisioning_revision_is($node);
+  switch ($revision_type) {
+    case REVISION_PENDING:
+      return t('Displaying <em>pending</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data);
+  
+    case REVISION_CURRENT:
+      return t('Displaying <em>current, published</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data);
+    
+    case REVISION_ARCHIVED:
+      return t('Displaying <em>archived</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data);
+  }
+}
diff --git sites/all/modules/revisioning/revisioning_triggers_actions.inc sites/all/modules/revisioning/revisioning_triggers_actions.inc
index 8f2818d..185b995 100755
--- sites/all/modules/revisioning/revisioning_triggers_actions.inc
+++ sites/all/modules/revisioning/revisioning_triggers_actions.inc
@@ -91,5 +91,9 @@ function revisioning_publish_latest_revision_action(&$node, $context = array())
   watchdog('revisioning',
     'Executing publish_latest_revision action for @type %title', array('@type' => $type, '%title' => $node->title),
     WATCHDOG_NOTICE, l(t('view'), "node/$node->nid"));
-  revisioning_publish_latest_revision($node);
+  if (_revisioning_publish_latest_revision($node)) {
+    drupal_set_message(t('Revision has been published.'));
+  } else {
+    drupal_set_message(t('"!title" has no pending revision to be published.', array('!title' => $node->title)), 'warning');
+  }
 }
diff --git sites/all/modules/workflow_panes/workflow_panes.module sites/all/modules/workflow_panes/workflow_panes.module
index ae23c34..9f8ca93 100644
--- sites/all/modules/workflow_panes/workflow_panes.module
+++ sites/all/modules/workflow_panes/workflow_panes.module
@@ -6,8 +6,8 @@
 function workflow_panes_menu() {
   $items = array();
   $items['admin/settings/workflow_panes'] = array(
-    'title' => t('Workflow Panes'),
-    'description' => t('Change settings.'),
+    'title' => 'Workflow Panes',
+    'description' => 'Change settings.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('workflow_panes_admin_settings'),
     'access arguments' => array('administer site configuration'),
