as with the "LDAP, Postfix & Cyrus" plugin the plesk one creates mail * * users and manages passwords, aliases, forwards and quota from within * * eGroupWare - no need to additionally visit the plesk interface anymore * * ------------------------------------------------------------------------- * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; version 2 of the License. * \***************************************************************************/ /* $Id$ */ include_once(EGW_SERVER_ROOT."/emailadmin/inc/class.defaultimap.inc.php"); class pleskimap extends defaultimap { /** * Label shown in EMailAdmin */ const DESCRIPTION = 'Plesk (Courier)'; /** * @var string $psa_mail_script full path to Plesk's mail.sh (Linux including sudo!) or mail.exe (Windows) interface */ var $psa_mail_script = '/usr/bin/sudo /usr/local/psa/bin/mail.sh'; // 'C:/psa/bin/mail.exe' /** * @var boolean $allways_create_mailbox true = allways create a mailbox on user creation, * false = only if a local email (no forward) is given. To use felamimail you need a mailbox! */ var $allways_create_mailbox = true; /** * @var array $create_folders=array('Send','Trash') folders to automatic create and subscribe on account creation */ var $create_folders = array('Sent','Trash'); /** * @var string/boolean $error string with last error-message or false */ var $error = false; /** * Return description for EMailAdmin * * @return string */ public static function description() { return self::DESCRIPTION; } /** * Create a full mailbox or just forward, depending on the given email address * If email matches the default domain, we create a full mailbox, otherwise we create a forward * * @param array $hookValues * @param string $action='create' * @return boolean true on success, false otherwise */ function addAccount($hookValues,$action='create') { //echo "

pleskimap::addAccount(".print_r($hookValues,true).")

\n"; $defaultDomain = $this->profileData['defaultDomain'] ? $this->profileData['defaultDomain'] : $GLOBALS['egw_info']['server']['mail_suffix']; $localEmail = $hookValues['account_lid'].'@'.$defaultDomain; $aliases = $forwards = array(); // is the given email a local address from our default domain? if (substr($hookValues['account_email'],-1-strlen($defaultDomain)) != '@'.$defaultDomain) { $forwards[] = $hookValues['account_email']; } elseif ($hookValues['account_email'] != $localEmail) { $aliases[] = $hookValues['account_email']; } // add a default alias with Firstname.Lastname if (!in_array($alias=$hookValues['account_firstname'].'.'.$hookValues['account_lastname'],$aliases) && $this->is_email($alias)) { $aliases[] = $alias; } $info = $this->plesk_mail($action,$hookValues['account_lid'],$hookValues['account_passwd'], $action != 'create' && !$aliases ? null : $aliases,$forwards,$this->allways_create_mailbox); if (!$info['SUCCESS']) return false; if ($forwards && !$this->allways_create_mailbox) return true; // no mailbox created, only a forward // create Sent & Trash mailboxes and subscribe them if(($mbox = @imap_open ($this->getMailboxString(),$localEmail,$hookValues['account_passwd']))) { $list = imap_getmailboxes($mbox, $this->getMailboxString(),'INBOX'); $delimiter = isset($list[0]->delimiter) ? $list[0]->delimiter : '.'; imap_subscribe($mbox,$this->getMailboxString('INBOX')); foreach($this->create_folders as $folder) { $mailBoxName = 'INBOX'.$delimiter.$folder; if(imap_createmailbox($mbox,imap_utf7_encode('{'.$this->profileData['imapServer'].'}'.$mailBoxName))) { imap_subscribe($mbox,$this->getMailboxString($mailBoxName)); } } imap_close($mbox); } return true; } function deleteAccount($hookValues) { //echo "

pleskimap::deleteAccount(".print_r($hookValues,true).")

\n"; return $this->plesk_mail('remove',$hookValues['account_lid']); } function updateAccount($hookValues) { //echo "

pleskimap::updateAccount(".print_r($hookValues,true).")

\n"; if($hookValues['account_lid'] != $hookValues['old_loginid']) { $this->error = lang("Plesk can't rename users --> request ignored"); return false; } return $this->addAccount($hookValues,'update'); } /** * Read data from the mail account * * @param string/int $accountID * @return array/boolean with keys mailLocalAddress, mailAlternateAddress, accountStatus, mailRoutingAddress, ... or false if not found */ function getUserData($accountID) { //echo "

pleskimap::getUserData('$accountID')

\n"; if (!($info = $this->plesk_mail('info',$accountID))) return false; //_debug_array($info); $data = array( 'mailLocalAddress' => $info['Mailname'].'@'.$info['Domain'], 'mailAlternateAddress' => $info['Alias(es)'] ? explode(' ',$info['Alias(es)']) : array(), 'accountStatus' => $info['Mailbox'] == 'true' || $info['Redirect'] == 'true' ? 'active' : 'disabled', 'mailRoutingAddress' => $info['Redirect address'] ? explode(' ',$info['Redirect address']) : false, 'deliveryMode' => $info['Redirect'] == 'true' && $info['Mailbox'] == 'false' ? 'forwardOnly' : '', // 'qmailDotMode' => false, // 'deliveryProgramPath' => false, 'quotaLimit' => $info['Mbox quota'] == 'Unlimited' ? '' : $info['Mbox quota']/1024.0, ); //_debug_array($data); return $data; } /** * Save mail account data * * @param string/int $accountID * @param array $accountData with keys mailLocalAddress, mailAlternateAddress, accountStatus, mailRoutingAddress, ... * @return boolean true on success, false otherwise */ function saveUserData($accountID, $accountData) { //echo "

pleskimap::saveUserData('$accountID',".print_r($accountData,true).")

\n"; // not used: $accountData['accountStatus']=='active', $accountData['qmailDotMode'], $accountData['deliveryProgramPath'] $info = $this->plesk_mail('update',$accountID,null, $accountData['mailAlternateAddress'] ? $accountData['mailAlternateAddress'] : array(), $accountData['mailRoutingAddress'] ? $accountData['mailRoutingAddress'] : array(), empty($accountData['deliveryMode']), 1024*(float)$accountData['quotaLimit'],$accountData['accountStatus']=='active'); if (!$info['SUCCSESS']) { if ($info) $this->error = implode(', ',$info); return false; } return true; } /** * call plesk's mail command line interface * * Usage: mail.sh command [options] * * Available commands: * --create or -c @ creates mail account * --update or -u @ updates mail account parameters * --remove or -r @ removes mail account * --info or -i @ retrieves mail account information * --on enables mail service for domain * --off disables mail service for domain * --help or -h displays this help page * * Available options: * -cp_access enables control panel access (default: * true) * -mailbox creates/removes mailbox * -passwd sets mailbox password [see the note * below for details] * -boxpass obsolete alias for option "passwd" * (this option may be removed from * future releases) * -passwd_type specifies the type of mailbox * password, ignored if no password * specified [see the note below for * details] * -mbox_quota limits the mailbox quota to the * desired amount * -boxquota obsolete alias for option "mbox_quota" * (this option may be removed from * future releases) * -aliases : adds or deletes mail * alias(es) to/from mailname * -mgroups : adds or removes mail name * to/from mail group * -redirect switches mail redirect on/off * -rediraddr sets redirect to address (required if * redirect is enabled) * -group switches mail group on/off * -groupmem : adds/removes address(-es) * to/from mail group * -repo : adds/removes file to/from * attachments repository * [deprecated, use * autoresponder.sh] * -autorsp switches all autoresponders on/off * [deprecated, use autoresponder.sh] * -autoname autoresponder name (required for all * autoresponder options) [deprecated, * use autoresponder.sh] * -autostatus switches on/off autoresponder with * specified name (true) [deprecated, * use autoresponder.sh] * -autoreq : or defines the condition * for the autoresponder * to be activated * whether the * specified pattern is * encountered in the * subject or body, or * to respond always * [deprecated, use * autoresponder.sh] * -autosubj the subject line to be set up into * autoresponder ("Re: ") or a custom string * [deprecated, use autoresponder.sh] * -auto_replyto return address that will be set up * into the autoresponder's messages * [deprecated, use autoresponder.sh] * -autotext autoresponder message text * [deprecated, use autoresponder.sh] * -autoatch : adds/removes autoresponder * attachment files * [deprecated, use * autoresponder.sh] * -autofrq defines the maximum number of * responses to a unique e-mail address * per day [deprecated, use * autoresponder.sh] * -autostor defines the number of unique addresses * to be stored for autoresponder * [deprecated, use autoresponder.sh] * -autored defines the e-mail address to forward * all incoming mail to [deprecated, use * autoresponder.sh] * -multiple-sessions allow multiple sessions * * Note: * For security reasons, you can transfer not encrypted passwords via environment * variable PSA_PASSWORD, by specifying the empty value in the command line for * the passwd arguments (like " -passwd ''") and setting the password value in * the PSA_PASSWORD variable. * Similarly, you can transfer the crypted password via the environment variable * PSA_CRYPTED_PASSWORD, by specifying the empty value in the command line for * the passwd arguments (like " -passwd ''") and by setting the password value in * the PSA_CRYPTED_PASSWORD variable. * * Version: psa v7.5.0_build75041208.07 os_SuSE 9.1 * * mail.sh --info account@domain.com * Mailname: account * Domain: domain.com * Alias(es): Firstname.Lastname * CP Access: true * Mailbox: true * Password: geheim * Password type: plain * Mbox quota: Unlimited * Redirect: false * Mailgroup: false * File repository: Empty * Autoresponder: false * Antivirus mail * checking: Disabled * * SUCCESS: Gathering information for 'account@domain.com' complete * * mail.sh --info bogus@domain.com * An error occured during getting mailname information: Mailname 'bogus@domain.com' doesn't exists * * @param string $action 'info', 'create', 'update' or 'remove' * @param string/int $account account_lid or numerical account_id * @param string $password=null string with password or null to not change * @param array $aliases=null array with aliases or null to not change the aliases * @param array $forwards=null array of email address to forward or null to not change * @param boolean $keepLocalCopy=null if forwarding keep a local copy or not, null = dont change * @param int $quota_kb=null mailbox quota in kb * @return boolean/array array with returned values or false otherwise, error-message in $this->error */ function plesk_mail($action,$account,$password=null,$aliases=null,$forwards=null,$keepLocalCopy=null,$quota_kb=null) { //echo "

smtpplesk::plesk_mail('$action','$account','$password',".print_r($aliases,true).",".print_r($forwards,true).",".(is_null($keepLocalCopy)?'':(int)$keepLocalCopy).",$quota_kb)

\n"; $this->error = false; if (is_numeric($account)) { $account_lid = $GLOBALS['egw']->accounts->id2name($account); } elseif ($GLOBALS['egw']->accounts->name2id($account)) { $account_lid = $account; } if (!$account_lid) { $this->error = lang("Account '%1' not found !!!",$account); return false; } if (!in_array($action,array('info','create','update','remove'))) { $this->error = lang("Unsupported action '%1' !!!",$action); return false; } $defaultDomain = $this->profileData['defaultDomain'] ? $this->profileData['defaultDomain'] : $GLOBALS['egw_info']['server']['mail_suffix']; if ($action == 'update' && !($info = $this->plesk_mail('info',$account))) { $action = 'create'; // mail-account does not yet exist --> create it } $localEmail = $account_lid.'@'.$defaultDomain; $script = $this->psa_mail_script . ' --'.$action . ' ' . $localEmail; if ($action != 'info') { // invalidate our cache $GLOBALS['egw']->session->appsession('plesk-email-'.$account_lid,'emailadmin',false); // we dont set passwords shorten then 5 chars, as it only give an error in plesk if (!is_null($password) && $password) { if (strlen($password) < 5 || strpos($password,$account_lid) !== false) { $this->error = lang('Plesk requires passwords to have at least 5 characters and not contain the account-name --> password NOT set!!!'); } else { $script .= ' -passwd \''.str_replace('\'','\\\'',$password).'\' -passwd_type plain'; } } if ($action == 'create' || !is_null($forwards) || !is_null($keepLocalCopy)) { $script .= ' -mailbox '.(!$forwards || $keepLocalCopy ? 'true' : 'false'); } // plesk allows only one forwarding address, we ignore everything but the first if (!is_null($forwards) && (!$forwards || $this->is_email($forwards[0]))) { $script .= ' -redirect '.(!$forwards ? 'false' : 'true -rediraddr '.$forwards[0]); } if ($action == 'update') { if (!is_null($aliases)) { $existing_aliases = explode(' ',$info['Alias(es)']); // without domain! $delete_aliases = array(); foreach($existing_aliases as $alias) { if ($alias && !in_array($alias,$aliases) && !in_array($alias.'@'.$defaultDomain,$aliases)) { $delete_aliases[] = $alias; } } if ($delete_aliases) { $script .= ' -aliases del:'.implode(',',$delete_aliases); } foreach($aliases as $n => $alias) { if (in_array($alias,$existing_aliases) || in_array(str_replace('@'.$defaultDomain,'',$alias),$existing_aliases)) { unset($aliases[$n]); // no change } } } } if (!is_null($aliases) && count($aliases)) { foreach($aliases as $alias) { if (!$this->is_email($alias)) return false; // security precausion } $script .= ' -aliases add:'.str_replace('@'.$defaultDomain,'',implode(',',$aliases)); } if (!is_null($quota_kb) && (int)$quota_kb) { $script .= ' -mbox_quota '.(int)$quota_kb; } } //echo "

$script

\n"; if (!($fp = popen($script.' 2>&1','r'))) { $this->error = lang("Plesk mail script '%1' not found !!!",$this->psa_mail_script); return false; } $values = array(); while(!feof($fp)) { $line = trim(fgets($fp)); list($name,$value) = preg_split('/: */',$line,2); if (!is_null($value) && strpos($name,'An error occured') === false && $name) { $values[$name] = $value; } elseif ($line) { $values[] = $line; } } pclose($fp); if (!$values['SUCCESS']) { $this->error = implode(', ',$values); return false; } return $values; } /** * checks for valid email addresse (local mail address dont need a domain!) * * Important as we run shell scripts with the address and one could try to run arbitrary commands this way!!! * We only allow letters a-z, numbers and the following other chars: _ . - @ * * @return boolean */ function is_email($email) { return preg_match('/^[@a-z0-9_.-]+$/i',$email); } }