View source  
  <?php
define('SUBSCRIPTION_NOT_FOUND', 1000);
define('SUBSCRIPTION_KEY_MISMATCH', 1100);
define('SUBSCRIPTION_EXPIRED', 1200);
define('SUBSCRIPTION_REPLAY_ATTACK', 1300);
define('SUBSCRIPTION_KEY_NOT_FOUND', 1400);
define('SUBSCRIPTION_MESSAGE_FUTURE', 1500);
define('SUBSCRIPTION_MESSAGE_EXPIRED', 1600);
define('SUBSCRIPTION_MESSAGE_INVALID', 1700);
define('SUBSCRIPTION_VALIDATION_ERROR', 1800);
define('SUBSCRIPTION_PROVISION_ERROR', 9000);
define('SUBSCRIPTION_MESSAGE_LIFETIME', 15 * 60);
function acquia_agent_menu() {
  $items['admin/settings/acquia-agent'] = array(
    'title' => 'Acquia Network settings',
    'description' => 'Connect your site to the Acquia Network.',
    'page callback' => 'acquia_agent_settings_page',
    'file' => 'acquia_agent.pages.inc',
    'access arguments' => array(
      'administer site configuration',
    ),
  );
  $items['admin/settings/acquia-agent/refresh-status'] = array(
    'title' => 'Manual update check',
    'page callback' => 'acquia_agent_refresh_status',
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}
function acquia_agent_init() {
  if (arg(2) != 'acquia-agent' && empty($_POST) && user_access('administer site configuration') && !acquia_agent_has_credentials()) {
    $message = t('Get a <a href="@acquia-free">free 30 day trial</a> of Drupal support, enhanced content search, comment spam blocking and more. If you have an Acquia Network subscription, <a href="@settings">connect now</a>.', array(
      '@acquia-free' => url('admin/settings/acquia-agent'),
      '@settings' => url('admin/settings/acquia-agent/connection'),
    ));
    if (arg(0) == 'admin') {
      $message .= '<br />' . t('To turn this message off, disable the Acquia Network Connector <a href="@admin-modules">modules</a>.', array(
        '@admin-modules' => url('admin/build/modules', array(
          'fragment' => 'system-modules',
        )),
      ));
    }
    drupal_set_message($message, 'warning', FALSE);
  }
}
function acquia_agent_theme() {
  return array(
    'acquia_agent_banner_form' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'file' => 'acquia_agent.pages.inc',
    ),
  );
}
function acquia_agent_check_subscription($params = array()) {
  
  $subscription = FALSE;
  if (!acquia_agent_has_credentials()) {
    
    variable_del('acquia_subscription_data');
  }
  else {
    
    acquia_agent_load_versions();
    if (IS_ACQUIA_DRUPAL) {
      $params['version'] = ACQUIA_DRUPAL_VERSION;
      $params['series'] = ACQUIA_DRUPAL_SERIES;
      $params['branch'] = ACQUIA_DRUPAL_BRANCH;
      $params['revision'] = ACQUIA_DRUPAL_REVISION;
    }
    
    if (module_exists('acquia_search')) {
      $result = db_query("SELECT name, info FROM {system} WHERE name IN ('acquia_search', 'apachesolr')");
      while ($data = db_fetch_object($result)) {
        if ($info = unserialize($data->info)) {
          
          $params['search_version'][$data->name] = isset($info['version']) ? (string) $info['version'] : (string) $info['core'];
        }
      }
    }
    $data = acquia_agent_call('acquia.agent.subscription', $params);
    $subscription['timestamp'] = time();
    if ($errno = xmlrpc_errno()) {
      switch ($errno) {
        case SUBSCRIPTION_NOT_FOUND:
        case SUBSCRIPTION_EXPIRED:
          variable_del('acquia_subscription_data');
          break;
      }
    }
    elseif (acquia_agent_valid_response($data)) {
      $subscription += $data['result']['body'];
      variable_set('acquia_subscription_data', $subscription);
      
    }
    else {
      watchdog('acquia agent', 'HMAC validation error: <pre>@data</pre>', array(
        '@data' => print_r($data, TRUE),
      ), WATCHDOG_ERROR);
    }
  }
  return $subscription;
}
function acquia_agent_report_xmlrpc_error() {
  drupal_set_message(t('Error: @message (@errno)', array(
    '@message' => xmlrpc_error_msg(),
    '@errno' => xmlrpc_errno(),
  )), 'error');
}
function acquia_agent_update_status_alter(&$projects) {
  if (!($subscription = acquia_agent_has_update_service())) {
    
    return;
  }
  foreach ($projects as $project => $project_info) {
    if ($project == 'drupal') {
      if (isset($subscription['update'])) {
        $projects[$project]['status'] = $subscription['update']['status'];
        $projects[$project]['releases'] = $subscription['update']['releases'];
        $projects[$project]['recommended'] = $subscription['update']['recommended'];
        $projects[$project]['latest_version'] = $subscription['update']['latest_version'];
        
        unset($projects[$project]['security updates']);
      }
      else {
        $projects[$project]['status'] = UPDATE_NOT_CHECKED;
        $projects[$project]['reason'] = t('No information available from the Acquia Network');
        unset($projects[$project]['releases']);
        unset($projects[$project]['recommended']);
      }
      $projects[$project]['link'] = 'http://acquia.com/products-services/acquia-drupal';
      $projects[$project]['title'] = 'Acquia Drupal';
      $projects[$project]['existing_version'] = ACQUIA_DRUPAL_VERSION;
      $projects[$project]['install_type'] = 'official';
      unset($projects[$project]['extra']);
    }
    elseif ($project_info['datestamp'] == 'acquia drupal') {
      $projects['drupal']['includes'][$project] = $project_info['title'];
      unset($projects[$project]);
    }
  }
}
function acquia_agent_system_info_alter(&$info) {
  if (!($subscription = acquia_agent_has_update_service())) {
    
    return;
  }
  if (isset($info['acquia'])) {
    
    $info['datestamp'] = 'acquia drupal';
  }
}
function acquia_agent_has_update_service() {
  
  acquia_agent_load_versions();
  $subscription = acquia_agent_settings('acquia_subscription_data');
  if (!IS_ACQUIA_DRUPAL || empty($subscription['active']) || isset($subscription['update_service']) && empty($subscription['update_service'])) {
    
    return FALSE;
  }
  return $subscription;
}
function acquia_agent_menu_alter(&$items) {
  if (isset($items['admin/reports/updates/check'])) {
    $items['admin/reports/updates/check']['page callback'] = 'acquia_agent_manual_status';
  }
}
function acquia_agent_refresh_status() {
  
  if (module_exists('acquia_spi')) {
    acquia_spi_send_profile_info();
  }
  
  acquia_agent_check_subscription();
  
  drupal_goto('admin/settings/acquia-agent');
}
function acquia_agent_manual_status() {
  
  if (module_exists('acquia_spi')) {
    acquia_spi_send_profile_info();
  }
  
  acquia_agent_check_subscription();
  
  update_manual_status();
}
function acquia_agent_cron() {
  
  acquia_agent_check_subscription();
}
function acquia_agent_watchdog($log_entry) {
  
  $cron_failure_messages = array(
    'Cron has been running for more than an hour and is most likely stuck.',
    'Attempting to re-run cron while it is already running.',
  );
  if (in_array($log_entry['message'], $cron_failure_messages, TRUE)) {
    acquia_agent_check_subscription();
  }
}
function acquia_agent_admin_menu() {
  
  $links[] = array(
    'title' => 'acquia_subscription_status',
    'path' => 'http://acquia.com',
    'weight' => -80,
    'parent_path' => '<root>',
    'options' => array(
      'extra class' => 'admin-menu-action acquia-subscription-status',
      'html' => TRUE,
    ),
  );
  return $links;
}
function acquia_agent_translated_menu_link_alter(&$item, $map) {
  global $user;
  if (empty($user->uid) || $item['module'] != 'admin_menu') {
    return;
  }
  if ($item['title'] == 'acquia_subscription_status') {
    if (acquia_agent_subscription_is_active()) {
      $subscription = acquia_agent_settings('acquia_subscription_data');
      $icon = '<img src="' . base_path() . 'misc/watchdog-ok.png" height="10" alt="ok" />';
      $item['title'] = t("!icon Subscription active (expires !date)", array(
        '!icon' => $icon,
        '!date' => format_date(strtotime($subscription['expiration_date']['value']), 'small'),
      ));
      $item['localized_options']['extra class'] .= " acquia-active-subscription";
      $item['localized_options']['attributes']['title'] = $subscription['product']['view'];
      $item['href'] = $subscription['href'];
    }
    else {
      $icon = '<img src="' . base_path() . 'misc/watchdog-error.png" height="10" alt="error" />';
      $item['title'] = t("!icon Subscription not active", array(
        '!icon' => $icon,
      ));
      $item['localized_options']['extra class'] .= " acquia-inactive-subscription";
      $item['href'] = 'http://acquia.com/network';
    }
  }
}
function acquia_agent_theme_registry_alter(&$theme_registry) {
  if (isset($theme_registry['admin_menu_icon'])) {
    $theme_registry['admin_menu_icon']['function'] = 'acquia_agent_menu_icon';
  }
}
function acquia_agent_menu_icon() {
  return '<img class="admin-menu-icon" src="' . base_path() . drupal_get_path('module', 'acquia_agent') . '/acquia_drupal.ico" height = "16" alt="" />';
}
function acquia_agent_valid_credentials($identifier, $key, $acquia_network_address = NULL) {
  $data = acquia_agent_call('acquia.agent.validate', array(), $identifier, $key, $acquia_network_address);
  return (bool) $data['result'];
}
function acquia_agent_call($method, $params, $identifier = NULL, $key = NULL, $acquia_network_address = NULL) {
  $path = drupal_get_path('module', 'acquia_agent');
  require_once $path . '/acquia_agent_streams.inc';
  $acquia_network_address = acquia_agent_network_address($acquia_network_address);
  $host = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : '';
  $data = array(
    'authenticator' => _acquia_agent_authenticator($params, $identifier, $key),
    'host' => $host,
    'body' => $params,
  );
  $data['result'] = _acquia_agent_request($acquia_network_address, $method, $data);
  return $data;
}
function acquia_agent_connection_error_message() {
  $errno = xmlrpc_errno();
  if ($errno) {
    switch ($errno) {
      case SUBSCRIPTION_NOT_FOUND:
        return t('The identifier you have provided does not exist in the Acquia Network or is expired. Please make sure you have used the correct value and try again.');
        break;
      case SUBSCRIPTION_EXPIRED:
        return t('Your Acquia Network subscription has expired. Please renew your subscription so that you can resume using Acquia Network services.');
        break;
      case SUBSCRIPTION_MESSAGE_FUTURE:
        return t('Your server is unable to communicate with the Acquia Network due to a problem with your clock settings. For security reasons, we reject messages that are more than @time ahead of the actual time recorded by our servers. Please fix the clock on your server and try again.', array(
          '@time' => format_interval(SUBSCRIPTION_MESSAGE_LIFETIME),
        ));
        break;
      case SUBSCRIPTION_MESSAGE_EXPIRED:
        return t('Your server is unable to communicate with the Acquia Network due to a problem with your clock settings. For security reasons, we reject messages that are more than @time older than the actual time recorded by our servers. Please fix the clock on your server and try again.', array(
          '@time' => format_interval(SUBSCRIPTION_MESSAGE_LIFETIME),
        ));
        break;
      case SUBSCRIPTION_VALIDATION_ERROR:
        return t('The identifier and key you have provided for the Acquia Network do not match. Please make sure you have used the correct values and try again.');
        break;
      default:
        return t('There is an error communicating with the Acquia Network at this time. Please check your identifier and key and try again.');
        break;
    }
  }
  return FALSE;
}
function acquia_agent_network_address($acquia_network_address = NULL) {
  if (empty($acquia_network_address)) {
    $acquia_network_address = acquia_agent_settings('acquia_network_address');
  }
  
  $uri = parse_url($acquia_network_address);
  $port = isset($uri['port']) ? ':' . $uri['port'] : '';
  $path = isset($uri['path']) ? $uri['path'] : '';
  $acquia_network_address = $uri['host'] . $port . $path;
  
  if (in_array('ssl', stream_get_transports(), TRUE) && !defined('ACQUIA_DEVELOPMENT_NOSSL')) {
    
    $acquia_network_address = 'https://' . $acquia_network_address;
  }
  else {
    $acquia_network_address = 'http://' . $acquia_network_address;
  }
  $acquia_network_address .= '/xmlrpc.php';
  return $acquia_network_address;
}
function acquia_agent_has_credentials() {
  return (bool) (variable_get('acquia_identifier', FALSE) && variable_get('acquia_key', FALSE));
}
function acquia_agent_subscription_is_active() {
  $active = FALSE;
  
  if (acquia_agent_has_credentials()) {
    $subscription = acquia_agent_settings('acquia_subscription_data');
    
    if (isset($subscription['timestamp']) && time() - $subscription['timestamp'] > 60 * 60 * 24) {
      $subscription = acquia_agent_check_subscription(array(
        'no_heartbeat' => 1,
      ));
    }
    $active = !empty($subscription['active']);
  }
  return $active;
}
function acquia_agent_settings($variable_name) {
  switch ($variable_name) {
    case 'acquia_identifier':
      return variable_get('acquia_identifier', '');
    case 'acquia_key':
      return variable_get('acquia_key', '');
    case 'acquia_network_address':
      return variable_get('acquia_network_address', 'https://rpc.acquia.com');
    case 'acquia_subscription_data':
      return variable_get('acquia_subscription_data', array(
        'active' => FALSE,
      ));
  }
}
function acquia_agent_random_bytes($count) {
  static $random_state;
  
  if (empty($random_state)) {
    $random_state = getmypid();
  }
  $output = '';
  
  if ($fh = @fopen('/dev/urandom', 'rb')) {
    $output = fread($fh, $count);
    fclose($fh);
  }
  
  while (strlen($output) < $count) {
    $random_state = md5(microtime() . mt_rand() . $random_state);
    $output .= pack('H*', md5(mt_rand() . $random_state));
  }
  return substr($output, 0, $count);
}
function acquia_agent_load_versions() {
  
  include_once 'acquia_agent_drupal_version.inc';
}
function acquia_agent_form_system_modules_alter(&$form, &$form_state) {
  if (isset($form['description']['acquia_search'])) {
    $subscription = acquia_agent_settings('acquia_subscription_data');
    if (!module_exists('acquia_search') && empty($subscription['active'])) {
      $form['status']['#disabled_modules'][] = 'acquia_search';
      $text = 'Acquia Search requires an <a href="@network-url">Acquia Network subscription</a>';
      $message = t($text, array(
        '@network-url' => 'http://acquia.com/products-services/acquia-search',
      ));
      $form['description']['acquia_search']['#value'] = '<div style="padding-left:5px; margin:8px 0px" class="messages warning" id="acquia-agent-no-search">' . $message . '</div>' . $form['description']['acquia_search']['#value'];
    }
  }
}