2006-04-26 12:28:53 +00:00
< ? php
/*
2012-08-28 08:59:05 +00:00
----------------------------------------------------------------------
AlternC - Web Hosting System
Copyright ( C ) 2000 - 2012 by the AlternC Development Team .
https :// alternc . org /
----------------------------------------------------------------------
LICENSE
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License ( GPL )
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
To read the license please visit http :// www . gnu . org / copyleft / gpl . html
----------------------------------------------------------------------
Purpose of file : Manage Email accounts and aliases .
----------------------------------------------------------------------
2006-04-26 12:28:53 +00:00
*/
2009-09-08 05:29:38 +00:00
2006-04-26 12:28:53 +00:00
/**
2009-09-08 05:29:38 +00:00
* This class handle emails ( pop and / or aliases and even wrapper for internal
* classes ) of hosted users .
2006-04-26 12:28:53 +00:00
*
2012-08-23 18:46:47 +00:00
* @ copyright AlternC - Team 2012 - 09 - 01 http :// alternc . com /
* This class is directly using the following alternc MySQL tables :
* address = any used email address will be defined here , mailbox = pop / imap mailboxes , recipient = redirection from an email to another
* and indirectly the domain class , to know domain names from their id in the DB .
* This class is also defining a few hooks , search -> invoke in the code .
2006-04-26 12:28:53 +00:00
*/
class m_mail {
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
/** domain list for this account
2006-04-26 12:28:53 +00:00
* @ access private
*/
var $domains ;
2012-08-25 10:48:55 +00:00
/* ----------------------------------------------------------------- */
/** If an email has those chars , 'not nice in shell env' ;)
* we don ' t store the email in $mail / u / { user } _domain , but in $mail / _ / { address_id } _domain
* @ access private
*/
var $specialchars = array ( '"' , " ' " , '\\' , '/' );
/* ----------------------------------------------------------------- */
/** If an email has those chars , we will ONLY allow RECIPIENTS , NOT POP / IMAP for DOVECOT !
* Since Dovecot doesn ' t allow those characters
* @ access private
*/
var $forbiddenchars = array ( '"' , " ' " , '\\' , '/' , '?' , '!' , '*' , '$' , '|' , '#' , '+' );
2006-04-26 12:28:53 +00:00
/* ----------------------------------------------------------------- */
2012-08-23 18:46:47 +00:00
/** Number of results for a pager display
* @ access public
2006-04-26 12:28:53 +00:00
*/
2012-08-23 18:46:47 +00:00
var $total ;
2006-04-26 12:28:53 +00:00
2012-10-18 09:22:52 +00:00
// Human server name for help
var $srv_submission ;
var $srv_smtp ;
var $srv_smtps ;
var $srv_imap ;
var $srv_imaps ;
var $srv_pop3 ;
var $srv_pop3s ;
/* ----------------------------------------------------------------- */
/**
* Constructeur
*/
function m_mail () {
global $L_FQDN ;
$this -> srv_submission = variable_get ( 'mail_human_submission' , $L_FQDN , 'Human name for mail server (submission protocol)' );
$this -> srv_smtp = variable_get ( 'mail_human_smtp' , $L_FQDN , 'Human name for mail server (SMTP protocol)' );
$this -> srv_smtps = variable_get ( 'mail_human_smtps' , $L_FQDN , 'Human name for mail server (SMTPS protocol)' );
$this -> srv_imap = variable_get ( 'mail_human_imap' , $L_FQDN , 'Human name for IMAP mail server' );
$this -> srv_imaps = variable_get ( 'mail_human_imaps' , $L_FQDN , 'Human name for IMAPS mail server' );
$this -> srv_pop3 = variable_get ( 'mail_human_pop3' , $L_FQDN , 'Human name for POP3 mail server' );
$this -> srv_pop3s = variable_get ( 'mail_human_pop3s' , $L_FQDN , 'Human name for POP3s mail server' );
}
2013-02-18 10:01:28 +00:00
function hook_menu () {
$obj = array (
'title' => _ ( " Email Addresses " ),
'ico' => 'images/mail.png' ,
'link' => 'toggle' ,
'pos' => 30 ,
'links' => array (),
) ;
foreach ( $this -> enum_domains () as $d ) {
$obj [ 'links' ][] =
array (
'txt' => htmlentities ( $d [ " domaine " ]) . ' ' . htmlentities ( " ( " . $d [ " nb_mail " ] . " ) " ),
'url' => " mail_list.php?domain_id= " . urlencode ( $d [ 'id' ]),
);
}
return $obj ;
}
2012-10-20 13:16:14 +00:00
// FIXME documenter
function catchall_getinfos ( $domain_id ) {
global $dom , $db ;
$rr = array (
2012-10-20 14:41:45 +00:00
'mail_id' => '' ,
2012-10-20 13:16:14 +00:00
'domain' => $dom -> get_domain_byid ( $domain_id ),
'target' => '' ,
'type' => '' ,
);
2012-10-20 14:41:45 +00:00
$db -> query ( " select r.recipients as dst, a.id mail_id from address a, recipient r where a.domain_id = $domain_id and r.address_id = a.id and a.address=''; " );
2012-10-20 13:16:14 +00:00
if ( $db -> next_record ()) {
$rr [ 'target' ] = $db -> f ( 'dst' );
2012-10-20 14:41:45 +00:00
$rr [ 'mail_id' ] = $db -> f ( 'mail_id' );
2012-10-20 13:16:14 +00:00
}
// Does it redirect to a specific mail or to a domain
if ( empty ( $rr [ 'target' ])) {
$rr [ 'type' ] = 'none' ;
} elseif ( substr ( $rr [ 'target' ], 0 , 1 ) == '@' ) {
$rr [ 'type' ] = 'domain' ;
} else {
$rr [ 'type' ] = 'mail' ;
}
return $rr ;
}
function catchall_del ( $domain_id ) {
2012-10-20 14:41:45 +00:00
$catch = $this -> catchall_getinfos ( $domain_id );
if ( empty ( $catch [ 'mail_id' ])) return false ;
return $this -> delete ( $catch [ 'mail_id' ]);
2012-10-20 13:16:14 +00:00
}
function catchall_set ( $domain_id , $target ) {
2012-10-20 14:41:45 +00:00
// target :
$target = rtrim ( $target );
if ( substr_count ( $target , '@' ) == 0 ) { // Pas de @
$target = '@' . $target ;
}
if ( substr ( $target , 0 , 1 ) == '@' ) { // le premier caractere est un @
// FIXME validate domain
} else { // ca doit être un mail
if ( ! filter_var ( $target , FILTER_VALIDATE_EMAIL )) {
$err -> raise ( " mail " , _ ( " The email you entered is syntaxically incorrect " ));
return false ;
}
}
$this -> catchall_del ( $domain_id );
return $this -> create_alias ( $domain_id , '' , $target , " catchall " , true );
2012-10-20 13:16:14 +00:00
}
2012-10-18 09:22:52 +00:00
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
/** get_quota ( hook for quota class ), returns the number of used
* service for a quota - bound service
* @ param $name string the named quota we want
* @ return the number of used service for the specified quota ,
* or false if I ' m not the one for the named quota
*/
2012-08-26 16:11:53 +00:00
function hook_quota_get () {
2012-04-06 10:10:36 +00:00
global $db , $err , $cuid ;
2012-08-26 16:11:53 +00:00
$err -> log ( " mail " , " getquota " );
$q = Array ( " name " => " mail " , " description " => _ ( " Email addresses " ), " used " => 0 );
$db -> query ( " SELECT COUNT(*) AS cnt FROM address a, domaines d WHERE a.domain_id=d.id AND d.compte= $cuid AND a.type=''; " );
if ( $db -> next_record ()) {
$q [ 'used' ] = $db -> f ( " cnt " );
2012-04-06 10:10:36 +00:00
}
2012-08-26 16:11:53 +00:00
return $q ;
2012-04-06 10:10:36 +00:00
}
2009-09-08 05:29:38 +00:00
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
/** Password policy kind used in this class ( hook for admin class )
* @ return array an array of policykey => " policy name (for humans) "
2009-11-30 05:02:53 +00:00
*/
function alternc_password_policy () {
2012-08-23 18:46:47 +00:00
return array ( " pop " => _ ( " Email account password " ));
2009-11-30 05:02:53 +00:00
}
2012-04-06 10:10:36 +00:00
2006-04-26 12:28:53 +00:00
/* ----------------------------------------------------------------- */
2012-08-23 18:46:47 +00:00
/** Returns the list of mail - hosting domains for a user
2009-09-08 05:29:38 +00:00
* @ return array indexed array of hosted domains
2006-04-26 12:28:53 +00:00
*/
2012-08-25 11:01:13 +00:00
function enum_domains ( $uid =- 1 ) {
2012-04-06 10:10:36 +00:00
global $db , $err , $cuid ;
$err -> log ( " mail " , " enum_domains " );
2012-08-25 11:01:13 +00:00
if ( $uid == - 1 ) { $uid = $cuid ; }
2012-10-22 08:58:53 +00:00
$db -> query ( "
SELECT
d . id ,
d . domaine ,
IFNULL ( COUNT ( a . id ), 0 ) as nb_mail
FROM
domaines d LEFT JOIN address a ON ( d . id = a . domain_id AND a . type = '' )
WHERE
d . compte = $uid
GROUP BY
d . id
ORDER BY
d . domaine
;
" );
2012-08-23 18:46:47 +00:00
$this -> enum_domains = array ();
2012-04-06 10:10:36 +00:00
while ( $db -> next_record ()){
$this -> enum_domains [] = $db -> Record ;
2006-04-26 12:28:53 +00:00
}
2012-04-06 10:10:36 +00:00
return $this -> enum_domains ;
}
2009-09-08 05:29:38 +00:00
2012-08-23 18:46:47 +00:00
2012-08-25 15:54:28 +00:00
/* ----------------------------------------------------------------- */
/** available : tells if an email address can be installed in the server
* check the domain part ( is it mine too ), the syntax , and the availability .
* @ param $mail string email to check
* @ return boolean true if the email can be installed on the server
*/
function available ( $mail ){
global $db , $err , $dom ;
$err -> log ( " mail " , " available " );
list ( $login , $domain ) = explode ( " @ " , $mail , 2 );
// Validate the domain ownership & syntax
if ( ! ( $dom_id = $dom -> get_domain_byname ( $domain ))) {
return false ;
}
// Validate the email syntax:
if ( ! filter_var ( $mail , FILTER_VALIDATE_EMAIL )) {
$err -> raise ( " mail " , _ ( " The email you entered is syntaxically incorrect " ));
return false ;
}
// Check the availability
$db -> query ( " SELECT a.id FROM address a WHERE a.domain_id= " . $dom_id . " AND a.address=' " . addslashes ( $login ) . " '; " );
if ( $db -> next_record ()) {
return false ;
} else {
return true ;
}
}
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
2012-04-06 10:10:36 +00:00
/* function used to list every mail address hosted on a domain .
2012-08-23 18:46:47 +00:00
* @ param $dom_id integer the domain id .
* @ param $search string search that string in recipients or address .
* @ param $offset integer skip THAT much emails in the result .
2012-08-25 14:04:38 +00:00
* @ param $count integer return no more than THAT much emails . - 1 for ALL . Offset is ignored then .
2012-08-23 18:46:47 +00:00
* @ result an array of each mail hosted under the domain .
2006-04-26 12:28:53 +00:00
*/
2012-10-18 15:32:04 +00:00
function enum_domain_mails ( $dom_id = null , $search = " " , $offset = 0 , $count = 30 , $show_systemmails = false ){
2012-08-23 18:46:47 +00:00
global $db , $err , $cuid , $hooks ;
2012-04-06 10:10:36 +00:00
$err -> log ( " mail " , " enum_domains_mail " );
2012-08-23 18:46:47 +00:00
$search = trim ( $search );
$where = " a.domain_id= $dom_id " ;
if ( $search ) $where .= " AND (a.address LIKE '% " . addslashes ( $search ) . " %' OR r.recipients LIKE '% " . addslashes ( $search ) . " %') " ;
2012-10-18 15:32:04 +00:00
if ( ! $show_systemmails ) $where .= " AND type='' " ;
2012-08-23 18:46:47 +00:00
$db -> query ( " SELECT count(a.id) AS total FROM address a LEFT JOIN recipient r ON r.address_id=a.id WHERE $where ; " );
$db -> next_record ();
$this -> total = $db -> f ( " total " );
2012-08-25 14:04:38 +00:00
if ( $count !=- 1 ) $limit = " LIMIT $offset , $count " ; else $limit = " " ;
2012-10-20 14:41:45 +00:00
$db -> query ( " SELECT a.id, a.address, a.password, a.`enabled`, a.mail_action, d.domaine AS domain, m.quota, m.quota*1024*1024 AS quotabytes, m.bytes AS used, NOT ISNULL(m.id) AS islocal, a.type, r.recipients, m.lastlogin, a.domain_id
2012-08-23 18:46:47 +00:00
FROM ( address a LEFT JOIN mailbox m ON m . address_id = a . id ) LEFT JOIN recipient r ON r . address_id = a . id , domaines d
2012-10-18 13:21:42 +00:00
WHERE $where AND d . id = a . domain_id $limit ; " );
2012-08-23 18:46:47 +00:00
if ( ! $db -> next_record ()) {
2012-10-18 07:52:54 +00:00
$err -> raise ( " mail " , _ ( " No email found for this query " ));
2012-05-16 15:33:04 +00:00
return false ;
}
2006-04-26 12:28:53 +00:00
$res = array ();
2012-08-23 18:46:47 +00:00
do {
$details = $db -> Record ;
// if necessary, fill the typedata with data from hooks ...
if ( $details [ " type " ]) {
2012-10-20 14:41:45 +00:00
$result = $hooks -> invoke ( " hook_mail_get_details " , array ( $details )); // Will fill typedata if necessary
2012-10-18 15:32:04 +00:00
$details [ " typedata " ] = implode ( " <br /> " , $result );
2012-08-23 18:46:47 +00:00
}
$res [] = $details ;
} while ( $db -> next_record ());
2006-04-26 12:28:53 +00:00
return $res ;
}
2012-08-23 18:46:47 +00:00
2012-10-20 14:41:45 +00:00
function hook_mail_get_details ( $detail ) {
if ( $detail [ 'type' ] == 'catchall' ) return _ ( sprintf ( " Special mail address for catch-all. <a href='mail_manage_catchall.php?domain_id=%s'>Click here to manage it.</a> " , $detail [ 'domain_id' ]));
}
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
2012-08-24 13:37:56 +00:00
/** Function used to insert a new mail into the db
2012-08-23 18:46:47 +00:00
* should be used by the web interface , not by third - party programs .
*
* This function calls the hook " hooks_mail_cancreate "
* which must return FALSE if the user can ' t create this email , and raise and error accordingly
*
* @ param $dom_id integer A domain_id ( owned by the user )
* ( will be the part at the right of the @ in the email )
* @ param $mail string the left part of the email to create ( something @ dom_id )
* @ return an hashtable containing the database id of the newly created mail ,
* or false if an error occured ( $err is filled accordingly )
2012-04-06 10:10:36 +00:00
*/
2012-10-20 14:41:45 +00:00
function create ( $dom_id , $mail , $type = " " , $dontcheck = false ){
2012-08-24 13:37:56 +00:00
global $err , $db , $cuid , $quota , $dom , $hooks ;
2012-10-16 16:37:12 +00:00
$err -> log ( " mail " , " create " , $mail );
2012-08-23 18:46:47 +00:00
// Validate the domain id
if ( ! ( $domain = $dom -> get_domain_byid ( $dom_id ))) {
return false ;
2012-08-19 20:50:47 +00:00
}
2012-08-23 18:46:47 +00:00
// Validate the email syntax:
$m = $mail . " @ " . $domain ;
2012-10-20 14:41:45 +00:00
if ( ! filter_var ( $m , FILTER_VALIDATE_EMAIL ) && ! $dontcheck ) {
2012-08-23 18:46:47 +00:00
$err -> raise ( " mail " , _ ( " The email you entered is syntaxically incorrect " ));
return false ;
2012-04-06 10:10:36 +00:00
}
2012-08-23 18:46:47 +00:00
// Call other classes to check we can create it:
2012-08-25 14:04:38 +00:00
$cancreate = $hooks -> invoke ( " hook_mail_cancreate " , array ( $dom_id , $mail ));
2012-08-23 18:46:47 +00:00
if ( in_array ( false , $cancreate , true )) {
return false ;
2006-04-26 12:28:53 +00:00
}
2012-08-19 20:50:47 +00:00
2012-08-23 18:46:47 +00:00
// Check the quota:
2012-08-19 20:50:47 +00:00
if ( ! $quota -> cancreate ( " mail " )) {
2012-10-18 07:52:54 +00:00
$err -> raise ( " mail " , _ ( " You cannot create email addresses: your quota is over " ));
2012-08-19 20:50:47 +00:00
return false ;
}
2012-08-23 18:46:47 +00:00
// Already exists?
$db -> query ( " SELECT * FROM address WHERE domain_id= " . $dom_id . " AND address=' " . addslashes ( $mail ) . " '; " );
if ( $db -> next_record ()) {
$err -> raise ( " mail " , _ ( " This email address already exists " ));
return false ;
}
// Create it now
2012-10-08 13:07:24 +00:00
$db -> query ( " INSERT INTO address (domain_id, address,type) VALUES ( $dom_id , ' " . addslashes ( $mail ) . " ',' $type '); " );
2012-08-23 18:46:47 +00:00
if ( ! ( $id = $db -> lastid ())) {
$err -> raise ( " mail " , _ ( " An unexpected error occured when creating the email " ));
return false ;
}
return $id ;
}
2012-08-19 20:50:47 +00:00
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
/** function used to get every information we can on a mail
* @ param $mail_id integer
* @ return array a hashtable with all the informations for that email
*/
function get_details ( $mail_id ) {
2012-08-24 13:37:56 +00:00
global $db , $err , $cuid , $hooks ;
2012-08-23 18:46:47 +00:00
$err -> log ( " mail " , " get_details " );
$mail_id = intval ( $mail_id );
2012-08-24 18:21:00 +00:00
// Validate that this email is owned by me...
if ( ! ( $mail = $this -> is_it_my_mail ( $mail_id ))) {
return false ;
}
2012-08-23 18:46:47 +00:00
// We fetch all the informations for that email: these will fill the hastable :
2012-08-25 10:48:55 +00:00
$db -> query ( " SELECT a.id, a.address, a.password, a.enabled, d.domaine AS domain, m.path, m.quota, m.quota*1024*1024 AS quotabytes, m.bytes AS used, NOT ISNULL(m.id) AS islocal, a.type, r.recipients, m.lastlogin, a.mail_action, m.mail_action AS mailbox_action FROM (address a LEFT JOIN mailbox m ON m.address_id=a.id) LEFT JOIN recipient r ON r.address_id=a.id, domaines d WHERE a.id= " . $mail_id . " AND d.id=a.domain_id; " );
2012-08-23 18:46:47 +00:00
if ( ! $db -> next_record ()) return false ;
$details = $db -> Record ;
// if necessary, fill the typedata with data from hooks ...
if ( $details [ " type " ]) {
2012-08-25 14:04:38 +00:00
$result = $hooks -> invoke ( " hook_mail_get_details " , array ( $mail_id )); // Will fill typedata if necessary
2012-08-23 18:46:47 +00:00
$details [ " typedata " ] = implode ( " <br /> " , $result );
}
return $details ;
2006-04-26 12:28:53 +00:00
}
2012-08-23 18:46:47 +00:00
2012-08-24 18:21:00 +00:00
private $isitmy_cache = array ();
2012-08-24 13:37:56 +00:00
/* ----------------------------------------------------------------- */
/** Check if an email is mine ...
*
* @ param $mail_id integer the number of the email to check
* @ return string the complete email address if that ' s mine , false if not
* ( $err is filled accordingly )
*/
function is_it_my_mail ( $mail_id ){
global $err , $db , $cuid ;
$mail_id = intval ( $mail_id );
2012-08-24 18:21:00 +00:00
// cache it (may be called more than one time in the same page).
if ( isset ( $this -> isitmy_cache [ $mail_id ])) return $this -> isitmy_cache [ $mail_id ];
2012-08-24 13:37:56 +00:00
$db -> query ( " SELECT concat(a.address,'@',d.domaine) AS email FROM address a, domaines d WHERE d.id=a.domain_id AND a.id= $mail_id AND d.compte= $cuid ; " );
if ( $db -> next_record ()) {
2012-08-24 18:21:00 +00:00
return $this -> isitmy_cache [ $mail_id ] = $db -> f ( " email " );
2012-08-24 13:37:56 +00:00
} else {
$err -> raise ( " mail " , _ ( " This email is not yours, you can't change anything on it " ));
2012-08-24 18:21:00 +00:00
return $this -> isitmy_cache [ $mail_id ] = false ;
2012-08-24 13:37:56 +00:00
}
}
2012-08-25 14:04:38 +00:00
/* ----------------------------------------------------------------- */
/** Hook called when the DOMAIN class will delete a domain .
*
* @ param $dom integer the number of the email to delete
* @ return true if the email has been properly deleted
* or false if an error occured ( $err is filled accordingly )
*/
function hook_dom_del_mx_domain ( $dom_id ) {
$list = $this -> enum_domain_mails ( $dom_id , " " , 0 , - 1 );
2012-08-25 14:15:03 +00:00
if ( is_array ( $list )) {
foreach ( $list as $one ) {
$this -> delete ( $one [ " id " ]);
}
2012-08-25 14:04:38 +00:00
}
return true ;
}
2013-02-07 15:48:28 +00:00
// return the alternc account's ID of the mail_id
function get_account_by_mail_id ( $mail_id ) {
global $db , $err ;
$db -> query ( " select compte as uid from domaines d, address a where a.domain_id = d.id and a.id = $mail_id " );
if ( ! $db -> next_record ()) {
return false ;
}
return $db -> f ( 'uid' );
}
2012-08-25 14:04:38 +00:00
2012-08-24 13:37:56 +00:00
/* ----------------------------------------------------------------- */
/** Function used to delete a mail from the db
* should be used by the web interface , not by third - party programs .
*
* @ param $mail_id integer the number of the email to delete
* @ return true if the email has been properly deleted
* or false if an error occured ( $err is filled accordingly )
*/
function delete ( $mail_id ){
global $err , $db , $cuid , $quota , $dom , $hooks ;
$err -> log ( " mail " , " delete " );
2012-08-23 18:46:47 +00:00
2012-08-24 13:37:56 +00:00
$mail_id = intval ( $mail_id );
if ( ! $mail_id ) {
$err -> raise ( " mail " , _ ( " The email you entered is syntaxically incorrect " ));
return false ;
}
// Validate that this email is owned by me...
if ( ! ( $mail = $this -> is_it_my_mail ( $mail_id ))) {
return false ;
}
2013-02-07 15:48:28 +00:00
$mailinfos = $this -> get_details ( $mail_id );
$hooks -> invoke ( 'hook_mail_delete' , array ( $mail_id , $mailinfos [ 'address' ] . '@' . $mailinfos [ 'domain' ] ));
2012-08-24 13:37:56 +00:00
// Search for that address:
$db -> query ( " SELECT a.id, a.type, a.mail_action, m.mail_action AS mailbox_action, NOT ISNULL(m.id) AS islocal FROM address a LEFT JOIN mailbox m ON m.address_id=a.id WHERE a.id=' $mail_id '; " );
if ( ! $db -> next_record ()) {
$err -> raise ( " mail " , _ ( " The email %s does not exist, it can't be deleted " ), $mail );
return false ;
}
2012-08-25 10:48:55 +00:00
if ( $db -> f ( " mail_action " ) != " OK " || ( $db -> f ( " islocal " ) && $db -> f ( " mailbox_action " ) != " OK " )) { // will be deleted soon ...
2012-08-24 13:37:56 +00:00
$err -> raise ( " mail " , _ ( " The email %s is already marked for deletion, it can't be deleted " ), $mail );
return false ;
}
$mail_id = $db -> f ( " id " );
if ( $db -> f ( " islocal " )) {
// If it's a pop/imap mailbox, mark it for deletion
$db -> query ( " UPDATE address SET mail_action='DELETE', enabled=0 WHERE id=' $mail_id '; " );
$db -> query ( " UPDATE mailbox SET mail_action='DELETE' WHERE address_id=' $mail_id '; " );
$err -> raise ( " mail " , _ ( " The email %s has been marked for deletion " ), $mail );
} else {
// If it's only aliases, delete it NOW.
$db -> query ( " DELETE FROM address WHERE id=' $mail_id '; " );
$db -> query ( " DELETE FROM mailbox WHERE address_id=' $mail_id '; " );
$db -> query ( " DELETE FROM recipient WHERE address_id=' $mail_id '; " );
$err -> raise ( " mail " , _ ( " The email %s has been successfully deleted " ), $mail );
}
return true ;
}
/* ----------------------------------------------------------------- */
/** Function used to undelete a pending deletion mail from the db
* should be used by the web interface , not by third - party programs .
*
* @ param $mail_id integer the email id
* @ return true if the email has been properly undeleted
* or false if an error occured ( $err is filled accordingly )
*/
function undelete ( $mail_id ){
global $err , $db , $cuid , $quota , $dom , $hooks ;
$err -> log ( " mail " , " undelete " );
$mail_id = intval ( $mail_id );
if ( ! $mail_id ) {
$err -> raise ( " mail " , _ ( " The email you entered is syntaxically incorrect " ));
return false ;
}
// Validate that this email is owned by me...
if ( ! ( $mail = $this -> is_it_my_mail ( $mail_id ))) {
return false ;
}
// Search for that address:
$db -> query ( " SELECT a.id, a.type, a.mail_action, m.mail_action AS mailbox_action, NOT ISNULL(m.id) AS islocal FROM address a LEFT JOIN mailbox m ON m.address_id=a.id WHERE a.id=' $mail_id '; " );
if ( ! $db -> next_record ()) {
$err -> raise ( " mail " , _ ( " The email %s does not exist, it can't be undeleted " ), $mail );
return false ;
}
if ( $db -> f ( " type " ) != " " ) { // Technically special : mailman, sympa ...
$err -> raise ( " mail " , _ ( " The email %s is special, it can't be undeleted " ), $mail );
return false ;
}
if ( $db -> f ( " mailbox_action " ) != " DELETE " || $db -> f ( " mail_action " ) != " DELETE " ) { // will be deleted soon ...
$err -> raise ( " mail " , _ ( " Sorry, deletion of email %s is already in progress, or not marked for deletion, it can't be undeleted " ), $mail );
return false ;
}
$mail_id = $db -> f ( " id " );
if ( $db -> f ( " islocal " )) {
// If it's a pop/imap mailbox, mark it for deletion
2012-08-24 14:52:24 +00:00
$db -> query ( " UPDATE address SET mail_action='OK', `enabled`=1 WHERE id=' $mail_id '; " );
$db -> query ( " UPDATE mailbox SET mail_action='OK' WHERE address_id=' $mail_id '; " );
2012-08-24 13:37:56 +00:00
$err -> raise ( " mail " , _ ( " The email %s has been undeleted " ), $mail );
return true ;
} else {
$err -> raise ( " mail " , _ ( " -- Program Error -- The email %s can't be undeleted " ), $mail );
return false ;
}
}
2012-08-23 18:46:47 +00:00
2012-08-24 18:21:00 +00:00
/* ----------------------------------------------------------------- */
/** set the password of an email address .
* @ param $mail_id integer email ID
* @ param $pass string the new password .
* @ return boolean true if the password has been set , false else , raise an error .
*/
function set_passwd ( $mail_id , $pass ){
global $db , $err , $admin ;
$err -> log ( " mail " , " setpasswd " );
if ( ! ( $email = $this -> is_it_my_mail ( $mail_id ))) return false ;
if ( ! $admin -> checkPolicy ( " pop " , $email , $pass )) return false ;
if ( ! $db -> query ( " UPDATE address SET password=' " . _md5cr ( $pass ) . " ' where id= $mail_id ; " )) return false ;
return true ;
}
/* ----------------------------------------------------------------- */
/** Enables an email address .
* @ param $mail_id integer Email ID
* @ return boolean true if the email has been enabled .
*/
function enable ( $mail_id ){
global $db , $err ;
$err -> log ( " mail " , " enable " );
if ( ! ( $email = $this -> is_it_my_mail ( $mail_id ))) return false ;
if ( ! $db -> query ( " UPDATE address SET `enabled`=1 where id= $mail_id ; " )) return false ;
return true ;
}
/* ----------------------------------------------------------------- */
/** Disables an email address .
* @ param $mail_id integer Email ID
* @ return boolean true if the email has been enabled .
*/
function disable ( $mail_id ){
global $db , $err ;
$err -> log ( " mail " , " disable " );
if ( ! ( $email = $this -> is_it_my_mail ( $mail_id ))) return false ;
if ( ! $db -> query ( " UPDATE address SET `enabled`=0 where id= $mail_id ; " )) return false ;
return true ;
}
/* ----------------------------------------------------------------- */
/** Function used to update an email settings
* should be used by the web interface , not by third - party programs .
*
* @ param $mail_id integer the number of the email to delete
* @ param $islocal boolean is it a POP / IMAP mailbox ?
* @ param $quotamb integer if islocal = 1 , quota in MB
2012-10-20 14:41:45 +00:00
* @ param $recipients string recipients , one mail per line .
2012-08-24 18:21:00 +00:00
* @ return true if the email has been properly edited
* or false if an error occured ( $err is filled accordingly )
*/
2012-10-20 14:41:45 +00:00
function set_details ( $mail_id , $islocal , $quotamb , $recipients , $delivery = " dovecot " , $dontcheck = false ) {
2012-08-24 18:21:00 +00:00
global $err , $db , $cuid , $quota , $dom , $hooks ;
2012-10-08 13:07:24 +00:00
$delivery = mysql_escape_string ( $delivery );
2012-08-24 18:21:00 +00:00
$err -> log ( " mail " , " set_details " );
if ( ! ( $me = $this -> get_details ( $mail_id ))) {
return false ;
}
if ( $me [ " islocal " ] && ! $islocal ) {
// delete pop
$db -> query ( " UPDATE mailbox SET mail_action='DELETE' WHERE address_id= " . $mail_id . " ; " );
}
if ( ! $me [ " islocal " ] && $islocal ) {
// create pop
2012-10-08 13:07:24 +00:00
$path = " " ;
if ( $delivery == " dovecot " ){
$path = ALTERNC_MAIL . " / " . substr ( $me [ " address " ] . " _ " , 0 , 1 ) . " / " . $me [ " address " ] . " _ " . $me [ " domain " ];
}
2012-08-25 10:48:55 +00:00
foreach ( $this -> forbiddenchars as $str ) {
2012-10-08 13:07:24 +00:00
if ( strpos ( $me [ " address " ], $str ) !== false ) {
2012-10-18 07:52:54 +00:00
$err -> raise ( " mail " , _ ( " There is forbidden characters in your email address. You can't make it a POP/IMAP account, you can only use it as redirection to other emails " ));
2012-10-08 13:07:24 +00:00
return false ;
break ;
}
2012-08-25 10:48:55 +00:00
}
foreach ( $this -> specialchars as $str ) {
2012-10-08 13:07:24 +00:00
if ( strpos ( $me [ " address " ], $str ) !== false ) {
$path = ALTERNC_MAIL . " /_/ " . $me [ " id " ] . " _ " . $me [ " domain " ];
break ;
}
2012-08-25 10:48:55 +00:00
}
2012-10-08 13:07:24 +00:00
$db -> query ( " INSERT INTO mailbox SET address_id= $mail_id , delivery=' $delivery ', path=' " . addslashes ( $path ) . " '; " );
2012-08-24 18:21:00 +00:00
}
if ( $me [ " islocal " ] && $islocal && $me [ " mailbox_action " ] == " DELETE " ) {
2012-08-24 18:23:39 +00:00
$db -> query ( " UPDATE mailbox SET mail_action='OK' WHERE mail_action='DELETE' AND address_id= " . $mail_id . " ; " );
2012-08-24 18:21:00 +00:00
}
if ( $islocal ) {
2012-08-25 14:12:41 +00:00
if ( $quotamb != 0 && $quotamb < ( intval ( $me [ " used " ] / 1024 / 1024 ) + 1 )) {
2012-08-25 13:11:48 +00:00
$quotamb = intval ( $me [ " used " ] / 1024 / 1024 ) + 1 ;
2012-10-18 07:52:54 +00:00
$err -> raise ( " mail " , _ ( " You set a quota smaller than the current mailbox size. Since it's not allowed, we set the quota to the current mailbox size " ));
2012-08-25 13:11:48 +00:00
}
2012-08-24 18:21:00 +00:00
$db -> query ( " UPDATE mailbox SET quota= " . intval ( $quotamb ) . " WHERE address_id= " . $mail_id . " ; " );
}
$r = explode ( " \n " , $recipients );
$red = " " ;
foreach ( $r as $m ) {
$m = trim ( $m );
2012-10-20 14:41:45 +00:00
if ( $m && ( filter_var ( $m , FILTER_VALIDATE_EMAIL ) || $dontcheck ) // Recipient Email is valid
2012-08-25 14:04:38 +00:00
&& $m != ( $me [ " address " ] . " @ " . $me [ " domain " ])) { // And not myself (no loop allowed easily ;) )
2012-08-24 18:21:00 +00:00
$red .= $m . " \n " ;
}
}
$db -> query ( " DELETE FROM recipient WHERE address_id= " . $mail_id . " ; " );
if ( $m ) {
$db -> query ( " INSERT INTO recipient SET address_id= " . $mail_id . " , recipients=' " . addslashes ( $red ) . " '; " );
}
return true ;
}
2012-10-08 13:07:24 +00:00
/* ----------------------------------------------------------------- */
/** A wrapper used by mailman class to create it ' s needed addresses
* @ param : $dom_id , the domain id associated to a given address
* @ param : $m , the left part of the mail address being created
* @ param : $delivery , the delivery used to deliver the mail
*/
2012-10-10 13:04:26 +00:00
2012-10-18 12:49:55 +00:00
function add_wrapper ( $dom_id , $m , $delivery ){
2012-10-20 14:41:45 +00:00
global $err , $db , $mail ;
$err -> log ( " mail " , " add_wrapper " , " creating $delivery $m address " );
2012-10-16 16:37:12 +00:00
2012-10-20 14:41:45 +00:00
$mail_id = $mail -> create ( $dom_id , $m , $delivery );
$this -> set_details ( $mail_id , 1 , 0 , '' , $delivery );
// FIXME return error code
2012-10-08 13:07:24 +00:00
}
2012-10-18 12:49:55 +00:00
/* ----------------------------------------------------------------- */
/** A function used to create an alias for a specific address
* @ param : $dom_id , the domain sql identifier
* @ param : $m , the alias we want to create
* @ param : $alias , the already existing aliased address
2012-10-20 14:41:45 +00:00
* @ param : $type , the type of the alias created
2012-10-18 12:49:55 +00:00
*/
2012-10-20 14:41:45 +00:00
function create_alias ( $dom_id , $m , $alias , $type = " " , $dontcheck = false ) {
global $err , $db , $mail ;
$err -> log ( " mail " , " create_alias " , " creating $m alias for $alias type $type " );
2012-10-18 12:49:55 +00:00
2012-10-20 14:41:45 +00:00
$mail_id = $mail -> create ( $dom_id , $m , $type , $dontcheck );
$this -> set_details ( $mail_id , 0 , 0 , $alias , " dovecot " , $dontcheck );
// FIXME return error code
2012-10-18 12:49:55 +00:00
}
2012-10-08 13:07:24 +00:00
/* ----------------------------------------------------------------- */
/** A wrapper used by mailman class to create it ' s needed addresses
* @ param : $mail_id , the mysql id of the mail address we want to delete
* of the email for the current acccount .
*/
function del_wrapper ( $mail_id ){
global $err , $db ;
$err -> log ( " mail " , " del_wrapper " );
$this -> delete ( $mail_id );
}
2012-08-24 18:21:00 +00:00
2012-08-23 18:46:47 +00:00
/* ----------------------------------------------------------------- */
2012-08-25 10:48:55 +00:00
/** Export the mail information of an account
* @ return : str , string containing the complete configuration
* of the email for the current acccount .
2012-08-23 18:46:47 +00:00
*/
2012-08-25 10:48:55 +00:00
function alternc_export_conf () {
global $db , $err , $mail_localbox ;
$err -> log ( " mail " , " export " );
$domain = $this -> enum_domains ();
$str = " <mail> \n " ;
$onepop = false ;
foreach ( $domain as $d ) {
$str .= " <domain> \n <name> " . xml_entities ( $d [ " domain " ]) . " </name> \n " ;
$s = $this -> enum_domain_mails ( $d [ " id " ]);
if ( count ( $s )) {
while ( list ( $key , $val ) = each ( $s )){
$test = $this -> get_details ( $val [ 'id' ]);
$str .= " <address> \n " ;
$str .= " <name> " . xml_entities ( $val [ " address " ]) . " </name> \n " ;
$str .= " <enabled> " . xml_entities ( $val [ " enabled " ]) . " </enabled> \n " ;
if ( is_array ( $val [ " islocal " ])){
$str .= " <islocal>1</islocal> \n " ;
$str .= " <quota> " . $val [ " quota " ] . " </quota> \n " ;
$str .= " <path> " . $val [ " path " ] . " </path> \n " ;
2012-05-21 15:58:20 +00:00
} else {
2012-08-25 10:48:55 +00:00
$str .= " <islocal>0</islocal> \n " ;
2012-05-21 15:58:20 +00:00
}
2012-08-25 10:48:55 +00:00
if ( ! empty ( $val [ " recipients " ])){
$r = explode ( " \n " , $val [ " recipients " ]);
foreach ( $r as $recip ){
2012-05-21 15:58:20 +00:00
$str .= " <recipients> " . $recip . " <recipients> \n " ;
}
}
$str .= " </address> \n " ;
}
}
$str .= " </domain> \n " ;
}
$str .= " </mail> \n " ;
return $str ;
}
2006-04-26 12:28:53 +00:00
2012-08-31 16:00:47 +00:00
/* ----------------------------------------------------------------- */
/**
* Return the list of allowed slave accounts ( secondary - mx )
* @ return array
*/
function enum_slave_account () {
global $db , $err ;
$db -> query ( " SELECT login,pass FROM mxaccount; " );
$res = array ();
while ( $db -> next_record ()) {
$res [] = $db -> Record ;
}
if ( ! count ( $res )) return false ;
return $res ;
}
/* ----------------------------------------------------------------- */
/**
* Check for a slave account ( secondary mx )
* @ param string $login the login to check
* @ param string $pass the password to check
* @ return boolean TRUE if the password is correct , or FALSE if an error occurred .
*/
function check_slave_account ( $login , $pass ) {
global $db , $err ;
$login = mysql_escape_string ( $login );
$pass = mysql_escape_string ( $pass );
$db -> query ( " SELECT * FROM mxaccount WHERE login=' $login ' AND pass=' $pass '; " );
if ( $db -> next_record ()) {
return true ;
}
return false ;
}
2012-10-18 13:25:35 +00:00
/* ----------------------------------------------------------------- */
/** Out ( echo ) the complete hosted domain list :
*/
function echo_domain_list () {
global $db , $err ;
$db -> query ( " SELECT domaine FROM domaines WHERE gesdns=1 ORDER BY domaine " );
while ( $db -> next_record ()) {
echo $db -> f ( " domaine " ) . " \n " ;
}
return true ;
}
2012-08-31 16:00:47 +00:00
/* ----------------------------------------------------------------- */
/**
* Add a slave account that will be allowed to access the mxdomain list
* @ param string $login the login to add
* @ param string $pass the password to add
* @ return boolean TRUE if the account has been created , or FALSE if an error occurred .
*/
function add_slave_account ( $login , $pass ) {
global $db , $err ;
$login = mysql_escape_string ( $login );
$pass = mysql_escape_string ( $pass );
$db -> query ( " SELECT * FROM mxaccount WHERE login=' $login ' " );
if ( $db -> next_record ()) {
2012-10-18 07:52:54 +00:00
$err -> raise ( " mail " , _ ( " The slave MX account was not found " ));
2012-08-31 16:00:47 +00:00
return false ;
}
$db -> query ( " INSERT INTO mxaccount (login,pass) VALUES (' $login ',' $pass ') " );
return true ;
}
/* ----------------------------------------------------------------- */
/**
* Remove a slave account
* @ param string $login the login to delete
*/
function del_slave_account ( $login ) {
global $db , $err ;
$login = mysql_escape_string ( $login );
$db -> query ( " DELETE FROM mxaccount WHERE login=' $login ' " );
return true ;
}
/* ----------------------------------------------------------------- */
/** hook function called by AlternC when a domain is created for
* the current user account using the SLAVE DOMAIN feature
* This function create a CATCHALL to the master domain
2012-10-20 15:14:34 +00:00
* @ param string $domain_id Domain that has just been created
* @ param string $target_domain Master domain
2012-08-31 16:00:47 +00:00
* @ access private
*/
2012-10-20 15:14:34 +00:00
function hook_dom_add_slave_domain ( $domain_id , $target_domain ) {
2012-08-31 16:00:47 +00:00
global $err ;
2012-10-20 15:14:34 +00:00
$err -> log ( " mail " , " hook_dom_add_slave_domain " , $domain_id );
$this -> catchall_set ( $domain_id , '@' . $target_domain );
2012-08-31 16:00:47 +00:00
return true ;
}
2013-02-07 14:58:59 +00:00
/* ----------------------------------------------------------------- */
/** hook function called by AlternC when a domain is created for
* the current user account
* This function create a postmaster mail which is an alias to LOGIN @ FQDN
* wich is a dynamic alias to the alternc ' s account mail
* @ param string $domain_id Domain that has just been created
* @ access private
*/
function hook_dom_add_mx_domain ( $domain_id ) {
global $err , $mem , $L_FQDN ;
$err -> log ( " mail " , " hook_dom_add_mx_domain " , $domain_id );
return $this -> create_alias ( $domain_id , 'postmaster' , $mem -> user [ 'login' ] . '@' . $L_FQDN );
}
2012-08-31 16:00:47 +00:00
2012-09-03 07:36:00 +00:00
/* ----------------------------------------------------------------- */
/** hook function called by AlternC - upnp to know which open
* tcp or udp ports this class requires or suggests
* @ return array a key => value list of port protocol name mandatory values
* @ access private
*/
function hook_upnp_list () {
return array (
" imap " => array ( " port " => 143 , " protocol " => " tcp " , " mandatory " => 1 ),
" imaps " => array ( " port " => 993 , " protocol " => " tcp " , " mandatory " => 1 ),
" pop " => array ( " port " => 110 , " protocol " => " tcp " , " mandatory " => 1 ),
" pops " => array ( " port " => 995 , " protocol " => " tcp " , " mandatory " => 1 ),
" smtp " => array ( " port " => 25 , " protocol " => " tcp " , " mandatory " => 1 ),
" sieve " => array ( " port " => 2000 , " protocol " => " tcp " , " mandatory " => 1 ),
" submission " => array ( " port " => 587 , " protocol " => " tcp " , " mandatory " => 0 ),
);
}
2006-04-26 12:28:53 +00:00
} /* Class m_mail */
2012-04-06 10:10:36 +00:00