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'];
}
}
}