Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
zimbra.module 14.49 KiB
<?php
/**
 * @file
 * Implements Zimbra e-mail accounts provisioning.
 */

//////////////////////////////////////////////////////////////////////////////

define('ZIMBRA_ENABLED',        variable_get('zimbra_enabled', FALSE));
define('ZIMBRA_SOAP_URL',       variable_get('zimbra_soap_url', ''));
define('ZIMBRA_DOMAIN',         variable_get('zimbra_domain', ''));
define('ZIMBRA_NAME',           variable_get('zimbra_name', ''));
define('ZIMBRA_PASS',           variable_get('zimbra_pass', ''));
define('ZIMBRA_PASS_CLEAR',     variable_get('zimbra_pass_clear', 0));
define('ZIMBRA_TIMEOUT',        variable_get('zimbra_timeout', 10));
define('ZIMBRA_USER_PASS',      variable_get('zimbra_user_pass', TRUE));
define('ZIMBRA_PROFILE',        'Zimbra e-mail account');
define('ZIMBRA_PROFILE_WEIGHT', 5);
define('ZIMBRA_BATCH_LIMIT',    10);

define('ZIMBRA_SUSPENSION_ENABLED', variable_get('zimbra_suspension_enabled', FALSE));
define('ZIMBRA_STATUS_ACTIVE',      'active');
define('ZIMBRA_STATUS_CLOSED',      'closed');
define('ZIMBRA_STATUS_LOCKED',      'locked');
define('ZIMBRA_STATUS_MAINTENANCE', 'maintenance');
define('ZIMBRA_SUSPENSION_STATUS',   variable_get('zimbra_suspension_status', ZIMBRA_STATUS_CLOSED));

define('ZIMBRA_DEFAULT_USER_PASS_STRENGTH', 12);
define('ZIMBRA_CURLOPT_SSL_VERIFYPEER',     FALSE);
define('ZIMBRA_CURLOPT_SSL_VERIFYHOST',     FALSE);

//////////////////////////////////////////////////////////////////////////////
// Core API hooks

/**
 * Implementation of hook_menu().
 */
function zimbra_menu() {
  return array(
    'admin/settings/zimbra' => array(
      'title' => 'Zimbra',
      'description' => 'Configure Zimbra Provisioning settings.',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('zimbra_admin_settings'),
      'access arguments' => array('administer site configuration'),
      'file' => 'zimbra.admin.inc',
    ),
    'admin/settings/zimbra/configure' => array(
      'title' => 'Settings',
      'type' => MENU_DEFAULT_LOCAL_TASK,
    ),
    'admin/settings/zimbra/create' => array(
      'title' => 'Create',
      'description' => 'Create Zimbra e-mail accounts for all existing users.',
      'type' => MENU_LOCAL_TASK,
      'page callback' => 'drupal_get_form',
      'page arguments' => array('zimbra_admin'),
      'access arguments' => array('administer site configuration'),
      'weight' => 1,
    ),
    'zimbra/create/%user' => array(
      'title' => 'Create',
      'description' => 'Create Zimbra e-mail account.',
      'type' => MENU_CALLBACK,
      'page callback' => 'zimbra_create_account',
      'page arguments' => array(2),
      'access arguments' => array('administer users'),
    ),
  );
}

/**
 * Implementation of hook_init().
 */
function zimbra_init() {
  require_once drupal_get_path('module', 'zimbra') .'/zimbra.inc';
}

/**
 * Implementation of hook_user().
 */
function zimbra_user($op, &$edit, &$account, $category = NULL) {
  if (ZIMBRA_ENABLED && _zimbra_user_check($account)) {
    switch ($op) {
      case 'view':
        if (user_access('administer users')) {
          $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
          if (zimbra_login($zimbra)) {
            $id = zimbra_get_id($zimbra, $account->name);
            $account->content[t(LDAPAUTH_PROFILE)] = array(
             '#type' => 'user_profile_category',
             '#title' => t(ZIMBRA_PROFILE),
             '#attributes' => array('class' => 'zimbra-entry'),
             '#weight' => ZIMBRA_PROFILE_WEIGHT,
             'zimbra_id' => array('#type' => 'user_profile_item', '#title' => t('ID'), '#value' => $id ? $id : l(t('create'), 'zimbra/create/'. $account->uid, array('query' => drupal_get_destination())), '#weight' => 1),
            );
          }
        }
        break;
      case 'insert':
        $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
        if (zimbra_login($zimbra)) {
          _zimbra_create_account($zimbra, $edit['name'], ZIMBRA_USER_PASS ? $edit['pass'] : user_password(ZIMBRA_DEFAULT_USER_PASS_STRENGTH));
        }
        break;
      case 'delete':
        $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
        if (zimbra_login($zimbra) && ($id = zimbra_get_id($zimbra, $account->name)) && ($result = zimbra_delete($zimbra, $id, $account->name))) {
          watchdog('zimbra', 'Zimbra account for %name was deleted.', array('%name' => $account->name));
        }
        else if (!isset($result) || $result === FALSE) {
          watchdog('zimbra', 'Zimbra account for %name was not deleted.', array('%name' => $account->name), WATCHDOG_ERROR);
          drupal_set_message(t('Zimbra e-mail account for %name was not deleted. Please contact site administrator.', array('%name' => $account->name)), 'error');
        }
        break;
      case 'submit':
        if (isset($edit['name']) && $account->name != $edit['name'] && $account->uid > 1) {
          $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
          if (zimbra_login($zimbra) && ($id = zimbra_get_id($zimbra, $account->name)) && ($result = zimbra_rename($zimbra, $id, $account->name, $edit['name']))) {
            watchdog('zimbra', 'Zimbra account for %name was renamed to %name_new.', array('%name' => $account->name, '%name_new' => $edit['name']));
          }
          else if (!isset($result) || $result === FALSE) {
            watchdog('zimbra', 'Zimbra account for %name was not renamed to %name_new.', array('%name' => $account->name, '%name_new' => $edit['name']), WATCHDOG_ERROR);
            drupal_set_message(t('Zimbra e-mail account for %name was not renamed to %name_new. Please contact site administrator.', array('%name' => $account->name, '%name_new' => $edit['name'])), 'error');
          }
        }
        if (ZIMBRA_USER_PASS && !empty($edit['pass']) && $account->uid > 1) {
          $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
          if (zimbra_login($zimbra) && ($id = zimbra_get_id($zimbra, $account->name)) && ($result = zimbra_set_pass($zimbra, $id, $account->name, $edit['pass']))) {
            watchdog('zimbra', 'Zimbra account password for %name was set.', array('%name' => $account->name));
          }
          else if (!isset($result) || $result === FALSE) {
            watchdog('zimbra', 'Zimbra account password for %name was not set.', array('%name' => $account->name), WATCHDOG_ERROR);
            drupal_set_message(t('Zimbra e-mail account password for %name was not set. Please contact site administrator.', array('%name' => $account->name)), 'error');
          }
        }
        break;
      case 'update':
        if (ZIMBRA_SUSPENSION_ENABLED && isset($edit['status']) && $edit['status'] != $account->status) {
          $status = $edit['status'] == 1 ? ZIMBRA_STATUS_ACTIVE : ZIMBRA_SUSPENSION_STATUS;
          $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
          if (zimbra_login($zimbra) && ($id = zimbra_get_id($zimbra, $account->name)) && ($result = zimbra_change_status($zimbra, $id, $status))) {
            watchdog('zimbra', 'Zimbra account status for %name has been changed to %status.', array('%name' => $account->name, '%status' => $status));
          }
          else if (!isset($result) || $result === FALSE) {
            watchdog('zimbra', 'Zimbra account status for %name has not been changed to %status.', array('%name' => $account->name, '%status' => $status), WATCHDOG_ERROR);
            drupal_set_message(t('Zimbra e-mail account status for %name has not been changed to %status. Please contact site administrator.', array('%name' => $account->name, '%status' => $status)), 'error');
          }
        }
        break;
    }
  }
}

//////////////////////////////////////////////////////////////////////////////
// Menu callback functions

/**
 * Zimbra admin form.
 */
function zimbra_admin() {
  $form['zimbra'] = array(
    '#type' => 'fieldset',
    '#title' => t('Create zimbra accounts'),
    '#description' => t('Create Zimbra e-mail accounts for all existing users.'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['zimbra']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Create'),
  );

  return $form;
}

/**
 * Zimbra admin form submit.
 */
function zimbra_admin_submit($form, &$form_state) {
  $batch = array(
    'operations' => array(
      array('zimbra_account_create_batch_process', array()),
    ),
    'finished' => 'zimbra_account_create_batch_finished',
    'title' => t('Processing zimbra account creation'),
    'init_message' => t('Zimbra account creation is starting.'),
    'progress_message' => t('Processing...'),
    'error_message' => t('Zimbra account creation has encountered an error.'),
  );
  batch_set($batch);
}

/**
 * Batch Operation Callback.
 */
function zimbra_account_create_batch_process(&$context) {
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(uid) FROM {users} WHERE uid > 1'));
    $context['sandbox']['current_uid'] = 1;
  }

  $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
  if (zimbra_login($zimbra)) {
    $result = db_query_range("SELECT uid FROM {users} WHERE uid > %d ORDER BY uid ASC", $context['sandbox']['current_uid'], 0, ZIMBRA_BATCH_LIMIT);
    while ($row = db_fetch_array($result)) {
      $account = user_load($row['uid']);
      $context['sandbox']['progress']++;
      $context['sandbox']['current_uid'] = $account->uid;
      $context['message'] = t('Inspecting %name.', array('%name' => $account->name));
      unset($created);
      if (_zimbra_user_check($account) && ($created = zimbra_create($zimbra, $account->name, user_password(ZIMBRA_DEFAULT_USER_PASS_STRENGTH)))) {
        $context['results'][] = theme('username', $account);
        watchdog('zimbra', 'A new zimbra account for %name was created.', array('%name' => $account->name), WATCHDOG_ERROR);
      }
      else if ($created === FALSE) {
        watchdog('zimbra', 'A new zimbra account for %name was not created.', array('%name' => $account->name), WATCHDOG_ERROR);
      }
    }
  }
  else {
    $context['sandbox']['progress'] = $context['sandbox']['max'];
    drupal_set_message(t('Cannot login to the Zimbra server.'), 'error');
  }

  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}

/**
 * Batch 'finished' callback.
 */
function zimbra_account_create_batch_finished($success, $results, $operations) {
  if ($success) {
    if (!empty($results)) {
      drupal_set_message(t('Zimbra accounts were created for following users.') . theme('item_list', $results));
    }
    else {
      drupal_set_message(t('No new zimbra accounts were created.'));
    }
  }
  else {
    $error_operation = reset($operations);
    drupal_set_message(t('An error occurred while processing %error. Please contact site administrator.', array('%error' => $error_operation[0])), 'error');
  }
}

/**
 * Menu callback.
 */
function zimbra_create_account($account) {
  $zimbra = new ZimbraSoapClient(ZIMBRA_SOAP_URL);
  if (zimbra_login($zimbra) && _zimbra_create_account($zimbra, $account->name)) {
    drupal_set_message(t('A new zimbra e-mail account for %name was created.', array('%name' => $name)));
  }
  drupal_goto();
}

/**
 * Creates Zimbra account.
 */
function _zimbra_create_account(&$zimbra, $name, $pass = NULL) {
  $pass = isset($pass) ? $pass : user_password(ZIMBRA_DEFAULT_USER_PASS_STRENGTH);
  if ($result = zimbra_create($zimbra, $name, $pass)) {
    watchdog('zimbra', 'A new zimbra account was created for %name.', array('%name' => $name));
  }
  else if ($result === FALSE) {
    watchdog('zimbra', 'A new zimbra account for %name was not created.', array('%name' => $name), WATCHDOG_ERROR);
    drupal_set_message(t('A new zimbra e-mail account for %name was not created.', array('%name' => $name)), 'error');
  }
  return $result;
}

//////////////////////////////////////////////////////////////////////////////
// Zimbra API functions

/**
 * Login to zimbra.
 */
function zimbra_login(&$zimbra) {
  return $zimbra->login(ZIMBRA_NAME, ZIMBRA_PASS);
}

/**
 * Creates zimbra account.
 *
 * Returns TRUE if account was created, FALSE if failed and NULL if the account already existed.
 */
function zimbra_create(&$zimbra, $name, $pass) {
  if ($result = $zimbra->execute('CreateAccountRequest', array('name' => array('value' => $name .'@'. ZIMBRA_DOMAIN), 'password' => array('value' => $pass)))) {
    return TRUE;
  }
  else if (($notice_strings = _zimbra_notice_strings()) && preg_match($notice_strings['CreateAccountRequest'], $zimbra->error())) {
    return;
  }
  else {
    return FALSE;
  }
}

/**
 * Get zimbra account id.
 */
function zimbra_get_id(&$zimbra, $name) {
  $result = $zimbra->execute('GetAccountInfoRequest', array('account' => array('value' => $name .'@'. ZIMBRA_DOMAIN, 'attr' => array('by' => 'name'))));
  if ($result) {
    return $result['a'][0];
  }
  else {
    watchdog('zimbra', 'Zimbra account information for %name is not available.', array('%name' => $name), WATCHDOG_ERROR);
    return FALSE;
  }
}

/**
 * Delete zimbra account.
 */
function zimbra_delete(&$zimbra, $id, $name) {
  return $zimbra->execute('DeleteAccountRequest', array('id' => array('value' => $id)));
}

/**
 * Rename zimbra account.
 */
function zimbra_rename(&$zimbra, $id, $name, $name_new) {
  return $zimbra->execute('RenameAccountRequest', array('id' => array('value' => $id), 'newName' => array('value' => $name_new .'@'. ZIMBRA_DOMAIN)));
}

/**
 * Set zimbra password.
 */
function zimbra_set_pass(&$zimbra, $id, $name, $pass) {
  return $zimbra->execute('SetPasswordRequest', array('id' => array('value' => $id), 'newPassword' => array('value' => $pass)));
}

/**
 * Change zimbra status.
 */
function zimbra_change_status(&$zimbra, $id, $status) {
  return $zimbra->execute('ModifyAccountRequest', array('id' => array('value' => $id), 'a' => array('value' => $status, 'attr' => array('n' => 'zimbraAccountStatus'))));;
}

//////////////////////////////////////////////////////////////////////////////
// Auxiliary functions

/**
 * This function returns array of zimbra functions and error matching strings.
 * If string is matched, notice is logged instead of the error.
 */
function _zimbra_notice_strings() {
  return array('CreateAccountRequest' => '/^email address already exists: /');
}

/**
 * Checks if a Zimbra account should be created for this user.
 */
function _zimbra_user_check(&$account) {
  if (!isset($account->uid))
    return FALSE;

  $module = db_result(db_query('SELECT module FROM {authmap} WHERE uid = %d', $account->uid));
  $module = !empty($module) ? $module : 'local';
  return in_array($module, variable_get('zimbra_auth_modules', array('local' => 'local')), TRUE);
}