<?
$__TMP_FILES__ = array();
/**
* Manager for temporary files
*/
class TempFileManager{
function getTempFile($prefix='tmp'){
$tmp = tempnam("/tmp",$prefix);
$GLOBALS['__TMP_FILES__'][] = $tmp;
return $tmp;
}
function clean(){
foreach($GLOBALS['__TMP_FILES__'] as $tmp){
if(is_writable($tmp)){
unlink($tmp);
}
}
$GLOBALS['__TMP_FILES__'] = array();
}
}
/**
* Zip file creation class. Makes zip files.
*/
class ZipFile{
/**
* Array to store compressed data
*/
var $datasec = array();
/**
* Central directory
*/
var $ctrl_dir = array();
/**
* End of central directory record
*/
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
/**
* Last offset position
*/
var $old_offset = 0;
/**
* Converts an Unix timestamp to a four byte DOS date and time format (date
* in high two bytes, time in low two bytes allowing magnitude comparison).
* @param integer the current Unix timestamp
* @return integer the current date in a four byte DOS format
* @access private
*/
function unix2DosTime($unixtime = 0) {
$timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
if ($timearray['year'] < 1980) {
$timearray['year'] = 1980;
$timearray['mon'] = 1;
$timearray['mday'] = 1;
$timearray['hours'] = 0;
$timearray['minutes'] = 0;
$timearray['seconds'] = 0;
}
return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
}
/**
* Adds "file" to archive
* @param string file contents
* @param string name of the file in the archive (may contains the path)
* @param integer the current timestamp
* @access public
*/
function addFile($data, $name, $time = 0){
$name = str_replace('\\', '/', $name);
$dtime = dechex($this->unix2DosTime($time));
$hexdtime = '\x' . $dtime[6] . $dtime[7]
. '\x' . $dtime[4] . $dtime[5]
. '\x' . $dtime[2] . $dtime[3]
. '\x' . $dtime[0] . $dtime[1];
eval('$hexdtime = "' . $hexdtime . '";');
$fr = "\x50\x4b\x03\x04";
$fr .= "\x14\x00"; // ver needed to extract
$fr .= "\x00\x00"; // gen purpose bit flag
$fr .= "\x08\x00"; // compression method
$fr .= $hexdtime; // last mod time and date
// "local file header" segment
$unc_len = strlen($data);
$crc = crc32($data);
$zdata = gzcompress($data);
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
$c_len = strlen($zdata);
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
$fr .= pack('v', strlen($name)); // length of filename
$fr .= pack('v', 0); // extra field length
$fr .= $name;
// "file data" segment
$fr .= $zdata;
// "data descriptor" segment (optional but necessary if archive is not
// served as file)
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
// add this entry to array
$this -> datasec[] = $fr;
// now add to central directory record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .= "\x00\x00"; // version made by
$cdrec .= "\x14\x00"; // version needed to extract
$cdrec .= "\x00\x00"; // gen purpose bit flag
$cdrec .= "\x08\x00"; // compression method
$cdrec .= $hexdtime; // last mod time & date
$cdrec .= pack('V', $crc); // crc32
$cdrec .= pack('V', $c_len); // compressed filesize
$cdrec .= pack('V', $unc_len); // uncompressed filesize
$cdrec .= pack('v', strlen($name) ); // length of filename
$cdrec .= pack('v', 0 ); // extra field length
$cdrec .= pack('v', 0 ); // file comment length
$cdrec .= pack('v', 0 ); // disk number start
$cdrec .= pack('v', 0 ); // internal file attributes
$cdrec .= pack('V', 32 ); // external file attributes - 'archive' bit set
$cdrec .= pack('V', $this->old_offset ); // relative offset of local header
$this->old_offset += strlen($fr);
$cdrec .= $name;
// optional extra field, file comment goes here
// save to central directory
$this -> ctrl_dir[] = $cdrec;
}
/**
* Dumps out file
* @return string the zipped file
* @access public
*/
function file(){
$data = implode('', $this->datasec);
$ctrldir = implode('', $this->ctrl_dir);
return
$data .
$ctrldir .
$this->eof_ctrl_dir .
pack('v',sizeof($this->ctrl_dir)) . // total number of entries "on this disk"
pack('v',sizeof($this->ctrl_dir)) . // total number of entries overall
pack('V',strlen($ctrldir)) . // size of central dir
pack('V',strlen($data)) . // offset to start of central dir
"\x00\x00"; // .zip file comment length
}
}
/**
* Scanner for viruses
*/
class VirusScanner{
function scan($data,$filename=''){
$ret = array('return'=>false,'message'=>'');
$tmpname = TempFileManager::getTempFile("vscan");
if(file_put_contents($tmpname,$data)){
$ret = shell_exec("clamscan --no-summary --infected --unrar --unzip --tgz $tmpname");
$ret = preg_replace("/^.*:/",'',$ret);
$ret = preg_replace("/\n.*:/","\n",$ret);
if($ret == '')
$ret = "No viruses were found\n";
}
else{
$ret = "System error\n";
}
unlink($tmpname);
return $ret;
}
}
/**
* Converter of doc/ppt/xls/pdf/ps to HTML
*/
class ToHtmlConverter{
function is_supported($mime_type){
$mime_type = strtolower($mime_type);
if($mime_type == 'application/msword' ||
$mime_type == 'application/ms-powerpoint' ||
$mime_type == 'application/vnd.ms-powerpoint' ||
$mime_type == 'application/ms-excel' ||
$mime_type == 'application/vnd.ms-excel')
return 'HTML';
if($mime_type == 'application/pdf' ||
$mime_type == 'application/postscript')
return 'text';
return false;
}
function convert($doc,$mime_type){
if(!ToHtmlConverter::is_supported($mime_type)) return false;
$mime_type = strtolower($mime_type);
$html = false;
$tmpname = TempFileManager::getTempFile('doc');
if(file_put_contents($tmpname,$doc)){
if(eregi('msword',$mime_type)){
$html = shell_exec("wvWare --config=wvHtml.xml --nographics $tmpname");
}
else if(eregi('powerpoint',$mime_type)){
$html = shell_exec("ppthtml $tmpname");
}
else if(eregi('excel',$mime_type)){
$html = shell_exec("xlhtml -nh -fw $tmpname");
$html = str_replace('CELLSPACING="2"','CELLSPACING="0"',$html);
$html ='
<html>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"/>
<style>
body {
margin: 5px 2em 5px 2em;
}
tr:hover td{
border-top: 1px solid #F00;
border-bottom: 1px solid #F00;
background-color: #ccffcc;
cursor: hand;
cursor: pointer;
}
td{
font-size: 11px;
border: 1px solid #999;
}
</style>
<body>
'.$html.'
</body>
</html>';
}
else if(eregi('(pdf|postscript)',$mime_type)){
$html = shell_exec("pstotext $tmpname");
$html =
'<html>'.
'<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"/>'.
'<body><pre>'.
$html.
'</pre></body>'.
'</html>';
}
}
unlink($tmpname);
return $html;
}
}
//////////////////////////////
// Class for email attachment
//////////////////////////////
class Attachment{
var $data;
var $type;
var $primary_type;
var $sub_type;
var $name;
var $if_uploaded;
function Attachment($name,$index){
if(is_uploaded_file($_FILES[$name]['tmp_name'][$index])){
$this->data=file_get_contents($_FILES[$name]['tmp_name'][$index]);
unlink($_FILES[$name]['tmp_name'][$index]);
eregi("(.*)\/(.*)",$_FILES[$name]['type'][$index],$regs);
$this->name = $_FILES[$name]['name'][$index];
$this->type = $_FILES[$name]['type'][$index];
$this->primary_type=get_primary_mime_type($regs[1]);
$this->sub_type = strtoupper($regs[2]);
$this->if_uploaded = true;
}
else
$this->if_uploaded = false;
}
}
///////////////////////////////////////////////////////
// Class for spell check
// src in ~/work/laba/wiki/templates/spell_check.php
///////////////////////////////////////////////////////
class SpellChecker{
function SpellChecker(){}
function good_char($c){
return eregi('[0-9a-z\'/@#$%^&*._:-]',$c);
}
function good_word($w){
return preg_match('/^[a-z]+$/i',$w);
}
function split_text($text){
$len = strlen($text);
$i = 0;
$arr = array();
if($len <= 0)
return $arr;
while($i<$len){
$str = "";
while($i < $len && $this->good_char($text[$i])){
$str .= $text[$i];
$i++;
}
$arr[] = $str;
$str = "";
while($i < $len && !$this->good_char($text[$i])){
$str .= $text[$i];
$i++;
}
$arr[] = $str;
}
return $arr;
}
function ispell2html($word,$spell,$from,$length){
if(ereg("^[\*+]",$spell))
return $word;
else if(ereg("^\#",$spell))
return
'<span class="red">'.$word.'</span>';
else if(ereg("^\&",$spell)){
if(preg_match("/^[&?][^:]*:(.*)/",$spell,$regs)){
$words = array_merge(array($word),preg_split('/[ ,]/',$regs[1]));
$res .= '<input type="hidden" name="from[]" value="'.$from.'"/>';
$res .= '<input type="hidden" name="length[]" value="'.$length.'"/>';
$res .= '<select name="words[]">';
foreach($words as $w)
if($w)
$res .= '<option value="'.$w.'">'.$w.'</option>';
$res .= '</select>';
}
return $res;
}
}
function check_text($text){
$desc = array(0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
);
if($process = proc_open('ispell -a -m -B -S', $desc,$pipes)){
// read first line HACK !!!
fgets($pipes[1],1024);
$index = 0;
foreach($this->split_text($text) as $word){
if($this->good_word($word)){
// write
fputs($pipes[0],$word."\n");
// read
$spell = chop(fgets($pipes[1],1024));
// read empty line
fgets($pipes[1],1024);
$res .= $this->ispell2html($word,$spell,$index,strlen($word));
}
else{
$res .= htmlspecialchars($word);
}
$index += strlen($word);
}
fclose($pipes[0]);
fclose($pipes[1]);
return $res;
}
return $text;
}
function replace_checked($text,$words,$from,$length){
$count = strlen($text);
$res = '';
$k = 0;
for($i=0;$i<$count;$i++){
if($from[$k] == $i){
$res .= $words[$k];
$i += $length[$k]-1;
$k++;
}
else $res .= $text[$i];
}
return $res;
}
}
///////////////////////////////////////////////
// Class for interface to FTP transactions
///////////////////////////////////////////////
$__one_ftp = false;
function getFTP(){
global $__one_ftp;
if(!$__one_ftp)
$__one_ftp = new FTP;
return $__one_ftp;
}
function closeFTP(){
global $__one_ftp;
if($__one_ftp){
$__one_ftp->close();
$__one_ftp = false;
}
}
class FTP{
var $host;
var $ftp;
var $ifconnected;
function FTP(){
$this->ifconnected = false;
foreach($GLOBALS['FTPHOSTS'] as $fh){
$this->ftp = ftp_connect($fh);
if($this->ftp && ftp_login($this->ftp,$GLOBALS['MAIL_USER_NAME'],$GLOBALS['MAIL_USER_PASSWORD'])){
$this->host = $fh;
// ftp_pasv($this->ftp,true);
$this->ifconnected = true;
break;
}
}
}
// Closing of ftp
function close(){
if($this->ifconnected)
ftp_quit($this->ftp);
}
// Reading whole file
function read_file($name){
if(!$this->ifconnected)
return false;
$name = $this->real_file($name);
$tmpname = TempFileManager::getTempFile('ftp');
$old=error_reporting(5);
if(!ftp_get($this->ftp,$tmpname,$name,FTP_BINARY)){
unlink($tmpname);
return false;
}
error_reporting($old);
$tmp = fopen($tmpname,"r");
$data='';
while(!feof($tmp)){
$data .= fread($tmp,1024);
}
fclose($tmp);
unlink($tmpname);
return $data;
}
// Writing file
function write_file($name,$data,$mode="0600"){
if(!$this->ifconnected)
return false;
$name = $this->real_file($name);
$tmpname = TempFileManager::getTempFile('ftp');
$tmp = fopen($tmpname,"w");
fwrite($tmp,$data);
$old=error_reporting(5);
if(!ftp_put($this->ftp,$name,$tmpname,FTP_BINARY)){
unlink($tmpname);
return false;
}
error_reporting($old);
fclose($tmp);
unlink($tmpname);
if($mode) $this->chmod($name,$mode);
return true;
}
// Deleting file
function delete_file($name){
if(!$this->ifconnected)
return false;
$name = $this->real_file($name);
return ftp_delete($this->ftp,$name);
}
// Make directory
function make_directory($name,$mode="0700"){
if(!$this->ifconnected)
return false;
$name = $this->real_file($name);
if(ftp_mkdir($this->ftp,$name)){
if($mode) $this->chmod($name,$mode);
return true;
}
return false;
}
// expands ~/
function real_file($file){
if(eregi('^~/',$file)){
return str_replace('~',$_SESSION['user_homedir'],$file);
}
else
return $file;
}
function chmod($name,$mode="0664"){
$chmod_cmd="CHMOD $mode ".$this->real_file($name);
return ftp_site($this->ftp,"CHMOD $mode ".$this->real_file($name));
}
}
//////////////////////////////////////////
// Class for backuped mail retrieves
//////////////////////////////////////////
class MailBackup{
var $incoming_backup_files;
var $inbox_backup_files;
var $empty;
function MailBackup(){
$this->incoming_backup_files = array();
$this->inbox_backup_files = array();
$this->empty = true;
$dirs = readDirectory(INCOMING_BACKUP_DIR,'dirs');
foreach($dirs as $dir){
if(eregi('[0-9]{1,2}\-[0-9]{1,2}\-[0-9]{1,2}',$dir)){
$fname = INCOMING_BACKUP_DIR.'/'.$dir.'/'.$GLOBALS['MAIL_USER_NAME'].'.gz';
if(file_exists($fname)){
$this->incoming_backup_files[] = $fname;
$this->empty = false;
}
}
}
$dirs = readDirectory(INBOX_BACKUP_DIR,'dirs');
foreach($dirs as $dir){
if(eregi('^Inboxes',$dir)){
$fname = INBOX_BACKUP_DIR.'/'.$dir.'/'.$GLOBALS['MAIL_USER_NAME'].'.gz';
if(file_exists($fname)){
$this->inbox_backup_files[] = $fname;
$this->empty = false;
}
}
}
}
function is_empty(){
return $this->empty;
}
function restore_incoming($date){
if(is_array($date) && count($date)==0)
return;
else if(!is_array($date) && $date)
$date = array($date);
$ftp = getFTP();
if(!$ftp->ifconnected){
return '<b class="red">FTP problem</b>: mail restore failed.';
}
$gzfilename = TempFileManager::getTempFile('backup_gz');
$resfilename = TempFileManager::getTempFile('backup_res');
$file = fopen($gzfilename,'w');
$can_write = false;
$good_date = array();
foreach($this->incoming_backup_files as $bf){
$dir = basename(dirname($bf));
if(in_array($dir,$date)){
$gzip = $ftp->read_file($bf);
fwrite($file,$gzip);
$good_date[] = date('d/m/Y',filemtime($bf));
}
}
fclose($file);
system('gunzip -c '.$gzfilename.' > '.$resfilename);
$file = fopen($resfilename,'r');
while(!feof($file)){
$data .= fread($file,1024);
}
fclose($file);
unlink($gzfilename);unlink($resfilename);
$ftp->write_file($_SESSION['preferences']->getRestoredMailbox(),$data);
$ftp->close();
return 'Restored mails from <b>'.implode(',',$good_date)."</b>";
}
function restore_incoming_range($from,$till){
$ftp = getFTP();
if(!$ftp->ifconnected){
return '<b class="red">FTP problem</b>: mail restore failed.';
}
$gzfilename = TempFileManager::getTempFile('backup_gz');
$resfilename = TempFileManager::getTempFile('backup');
$file = fopen($gzfilename,'w');
$can_write = false;
foreach($this->incoming_backup_files as $bf){
$dir = basename(dirname($bf));
if($dir == $from)
$can_write = true;
if($can_write){
$gzip = $ftp->read_file($bf);
fwrite($file,$gzip);
}
if($dir == $till)
break;
}
fclose($file);
system('gunzip -c '.$gzfilename.' > '.$resfilename);
$file = fopen($resfilename,'r');
while(!feof($file)){
$data .= fread($file,1024);
}
fclose($file);
unlink($gzfilename);unlink($resfilename);
$ftp->write_file($_SESSION['preferences']->getRestoredMailbox(),$data);
$ftp->close();
return 'Restored mails from <b>'.$from.'</b> till <b>'.$till.'</b>';
}
function restore_inbox($dir){
$ftp = getFTP();
if(!$ftp->ifconnected){
return '<b class="red">FTP problem</b> mail restore failed.';
}
$gzfilename = TempFileManager::getTempFile('backup_gz');
$resfilename = TempFileManager::getTempFile('backup');
$file = fopen($gzfilename,'w');
$gzip = $ftp->read_file(INBOX_BACKUP_DIR.'/'.$dir.'/'.$GLOBALS['MAIL_USER_NAME'].'.gz');
fwrite($file,$gzip);
fclose($file);
exec("gunzip -c $gzfilename | tar xO > $resfilename");
$file = fopen($resfilename,'r');
while(!feof($file))
$data .= fread($file,1024);
fclose($file);
unlink($gzfilename);unlink($resfilename);
$ftp->write_file($_SESSION['preferences']->getRestoredMailbox(),$data);
$ftp->close();
return
'Inbox restored from date <b>'.
date('d/m/Y D',filemtime(INBOX_BACKUP_DIR.'/'.$dir.'/'.$GLOBALS['MAIL_USER_NAME'].'.gz')).
'</b>.';
}
function get_presentation(){
include(TMPLPATH.'MailBackup_presentation.php');
}
}
///////////////////////////////////
// Class for some preferences file
///////////////////////////////////
class Preferences{
var $local;
var $prefs;
var $file;
function Preferences($file,$local=true){
$this->file = $file;
$data = null;
if($local){
$this->local = true;
$this->file = get_user_local_dir($GLOBALS['MAIL_USER_NAME']).basename($this->file);
if(!is_readable($this->file)){
$ftp = getFTP();
$data = $ftp->read_file($file);
if($data){
if(!is_dir(dirname($this->file))){
mkdir(dirname($this->file));
}
file_put_contents($this->file,$data);
}
}
else{
$data = file_get_contents($this->file);
}
}
else{
$this->local = false;
$ftp = getFTP();
$data = $ftp->read_file($file);
}
$this->set_default();
if($data) $this->parse($data);
}
function set_default(){}
function load(){}
function parse($data){}
function to_file(){return '';}
function put($key,$val){
$this->prefs[$key] = urlencode($val);
}
function get($key){
$item = $this->prefs[$key];
if(eregi("(%[0-9A-F]{1,2}\+?)*",$item))
$item = urldecode($item);
return $item;
}
function get_presentation(){
reset($this->prefs);
while(list($key) = each($this->prefs)){
$res .= '<tr><td>'.$key.'</td><td><pre>'.$this->get($key).'</pre></td></tr>';
}
return $res;
}
function store($retry=false){
if($this->local){
if(!is_dir(dirname($this->file))){
mkdir(dirname($this->file));
}
file_put_contents($this->file,$this->to_file());
}
else{
$ftp = getFTP();
$val = $ftp->write_file($this->file,$this->to_file());
if(!$val && !$retry){
$dir = dirname($this->file);
$ftp->make_directory($dir);
$this->store(true);
}
}
return $val;
}
}
////////////////////////////////////////
// Class for mailer preferences file:
// in form <key>=<value>
///////////////////////////////////////
class MailerPreferences extends Preferences{
function MailerPreferences($file){
parent::Preferences($file,true);
}
function getName(){return $this->get('name');}
function getTheme(){return $this->get('theme');}
function getCharset(){return $this->get('charset');}
function getSignature($asis=false){
$sig = $this->get('signature');
if(!$asis && strpos($sig,'%q') !== false){
$fortune = rtrim(shell_exec('fortune -s science wisdom computers'));
if($fortune)
$sig = str_replace('%q',$fortune,$sig);
}
return $sig;
}
function getReplyHeader(){return $this->get('reply-header');}
function getMailsPerPage(){return $this->get('mails-per-page');}
function getDefaultView(){return $this->get('default-view');}
function getDisableWarnings(){return $this->get('disable-warnings');}
function getRememberAddresses(){return $this->get('remember-addresses');}
function getUseDispositionNotification(){return $this->get('use-disposition-notification');}
function getUseGnuPG(){return $this->get('use-gnupg');}
function getUseGnuPGSignature(){return $this->get('use-gnupg-signature');}
function getMailDir(){return /*'~/'.*/$this->get('mail-dir');}
function getRestoredMailbox(){
return $this->getMailDir().'/'.$this->get('restored-mailbox');
}
function getFccMailbox(){
return $this->getMailDir().'/'.$this->get('fcc-mailbox');
}
function getDraftMailbox(){
return $this->getMailDir().'/'.$this->get('draft-mailbox');
}
function getMailboxesList(){
$arr = explode(',',$this->prefs['mailboxes-list']);
$ret = array();
foreach($arr as $a)
if($a != '')
$ret[] = eregi_replace('^~/','',$a);
return $ret;
}
function setMailboxesList($list){
if(!is_array($list)){
$list = array($list);
}
$this->prefs['mailboxes-list'] = implode(",",$list);
}
function isFccEnabled(){return $this->get('fcc-enabled') != 'false';}
function isShowSendInfo(){return $this->get('show-send-info') != 'false';}
function set_default(){
$this->prefs = array();
$passwd = yp_passwd($GLOBALS['MAIL_USER_NAME']);
if($passwd){
$name = preg_split('/,/',$passwd[4]);
$name = $name[0];
}
else{
$name = $GLOBALS['MAIL_USER_NAME'];
}
$this->prefs['name'] = $name;
$this->prefs['theme'] = $GLOBALS['DEFAULT_THEME'];
$this->prefs['charset'] = $GLOBALS['DEFAULT_CHARSET'];
$this->prefs['signature'] = '';
$this->prefs['reply-header'] = 'On %d %a wrote:';
$this->prefs['show-send-info'] = 'true';
$this->prefs['fcc-enabled'] = 'true';
$this->prefs['default-view'] = false;
$this->prefs['disable-warnings'] = false;
$this->prefs['remember-addresses'] = false;
$this->prefs['use-disposition-notification'] = false;
$this->prefs['use-gnupg'] = false;
$this->prefs['mails-per-page'] = DEFAULT_MAILS_PER_PAGE;
$this->prefs['mail-dir'] = DEFAULT_MAIL_DIR;
$this->prefs['restored-mailbox'] = DEFAULT_RESTORED_MAILBOX;
$this->prefs['fcc-mailbox'] = DEFAULT_FCC_MAILBOX;
$this->prefs['draft-mailbox'] = DEFAULT_DRAFT_MAILBOX;
$this->prefs['mailboxes-list'] = null;
}
function load(){
$l = $this->prefs['mailboxes-list'];
$this->set_default();
$this->prefs['mailboxes-list'] = $l;
if(get_var('name'))
$this->put('name',get_var('name'));
if(get_var('theme'))
$this->put('theme',get_var('theme'));
if(get_var('charset'))
$this->put('charset',get_var('charset'));
if(get_var('signature'))
$this->put('signature',get_var('signature'));
if(get_var('reply-header'))
$this->put('reply-header',get_var('reply-header'));
if(get_var('default-view'))
$this->put('default-view',get_var('default-view'));
if(get_var('disable-warnings'))
$this->put('disable-warnings',get_var('disable-warnings'));
if(get_var('remember-addresses'))
$this->put('remember-addresses',get_var('remember-addresses'));
if(get_var('use-disposition-notification'))
$this->put('use-disposition-notification',get_var('use-disposition-notification'));
if(get_var('use-gnupg'))
$this->put('use-gnupg',get_var('use-gnupg'));
if(get_var('use-gnupg-signature'))
$this->put('use-gnupg-signature',get_var('use-gnupg-signature'));
$this->put('headers-down',(get_var('headers-down')!=''?'true':'false'));
$this->put('show-send-info',(get_var('show-send-info')!=''?'true':'false'));
$this->put('fcc-enabled',(get_var('fcc-enabled')!=''?'true':'false'));
if(get_var('mails-per-page') && get_var('mails-per-page') > 0)
$this->put('mails-per-page',get_var('mails-per-page'));
if(get_var('mail-dir'))
$this->put('mail-dir',get_var('mail-dir'));
if(get_var('restored-mailbox'))
$this->put('restored-mailbox',get_var('restored-mailbox'));
if(get_var('fcc-mailbox'))
$this->put('fcc-mailbox',get_var('fcc-mailbox'));
if(get_var('draft-mailbox'))
$this->put('draft-mailbox',get_var('draft-mailbox'));
}
function parse($data){
$lines = preg_split("/\n/",$data);
foreach($lines as $line){
if(eregi("^[ \t]*#",$line))
continue;
else if(eregi("(.+)=(.+)",$line,$match)){
$this->prefs[$match[1]] = $match[2];
}
}
}
function to_file(){
$res = "# Automatically generated ".VERSION." config file\n";
$res .= "# Creation time: ".date('H:i:s d/m/Y',time())."\n";
reset($this->prefs);
foreach($this->prefs as $key=>$val){
$res .= $key."=".$val."\n";
}
return $res."\n";
}
function get_edit_presentation(){
include(TMPLPATH.'MailerPreferences_edit_presentation.php');
}
}
############################
# Entry to address book
############################
// additional fields for person
$GLOBALS['ADDITIONAL_FIELDS'] = array('email'=>'Email',
'im'=>'Im',
'phone'=>'Phone',
'mobile'=>'Mobile',
'fax'=>'Fax',
'company'=>'Company',
'title'=>'Title',
'other'=>'Other');
class AddressBookEntry{
var $name;
var $nick;
var $email;
var $comment;
// array where each element is an array where under 'name' is section name
// and under 'fields' is array of arrays where under 'key' is a field key and
// under 'value' is a key's value
var $info;
var $send_count;
function AddressBookEntry(){ }
function load(){
$name = trim(get_var('name'));
$nick = trim(get_var('nick'));
$email = trim(get_var('email'));
$comment = trim(get_var('comment'));
if($name == ''){
Notice::set('Name is a required field.');
return false;
}
if(!is_email($email)){
Notice::set('Valid email address is a required field.');
return false;
}
if($this->email != $email && $_SESSION['addressbook']->email_exists($email)){
Notice::set('<u>'.$email.'</u> already is in your address book.');
return false;
}
$this->name = $name;
$this->nick = $nick;
$this->email = $email;
$this->comment = $comment;
$this->info = array();
$sections = get_var('sections');
if(array_not_empty($sections)){
foreach($sections as $s){
$name = trim($s['name']);
if($name != ''){
$section = array();
if(array_not_empty($s['fields'])){
foreach($s['fields'] as $f){
$key = trim($f['key']);
$value = trim($f['value']);
if($key != '' && $value != ''){
$section[] = array('key'=>$key,'value'=>$value);
}
}
// check email fields
foreach($section as $k=>$pair){
if($pair['key'] == 'email'){
$email = $pair['value'];
// if not email
if(!is_email($email)){
Notice::set('<u>'.$email.'</u> doesn\'t look like email address.');
unset($section[$k]);
}
// if email exists somewhere
else if($_SESSION['addressbook']->email_exists($email)){
Notice::set('<u>'.$email.'</u> already is in your address book.');
unset($section[$k]);
}
}
}
if(array_not_empty($section)){
$this->info[] = array('name'=>$name,'fields'=>$section);
}
}
}
}
}
return true;
}
// i decide that no more emails , only one email !!!
function check(){
if(isset($this->emails) && is_array($this->emails)){
reset($this->emails);
$this->email = current($this->emails);
unset($this->emails);
}
}
function get_csv_format(){
$this->check();
$res .= '"'.$this->name.'","'.$this->get_email().'"'."\r\n";
return $res;
}
function get_pine_format(){
$this->check();
$res = $this->nick."\t".$this->name."\t";
$res .= $this->get_email();
$res .= "\t\t".$this->comment."\n";
/*
$res = $this->nick."\t".$this->name."\t";
$count = count($this->emails);
if($count > 1)
$res .= "(".$this->get_emails_string().")";
else
$res .= $this->get_emails_string();
$res .= "\t\t".$this->comment."\n";
*/
return $res;
}
// vCard entry
function get_vcard_format(){
$res = "BEGIN:VCARD\r\n";
$res .= "VERSION:3.0\r\n";
// $res .= "CLASS:".$this->class."\r\n";
// $res .= "PRODID:-//vCard generator//".VERSION."//EN\r\n";
$res .= "REV:".date('Y-m-d H:i:s')."\r\n";
if(preg_match('/^(.+)\s+(.+)$/',$this->name,$m)){
$res .= "N:".$m[2].';'.$m[1]."\r\n";
}
else
$res .= "FN:".$this->name."\r\n";
if($this->nick != '')
$res .= "NICKNAME:;".$this->nick."\r\n";
$res .= "EMAIL;TYPE=internet,pref:".$this->get_email()."\r\n";
if(array_not_empty($this->info)){foreach($this->info as $section){
if(array_not_empty($section['fields'])){foreach($section['fields'] as $f){
if($f['key'] == 'email'){
$res .= "EMAIL;TYPE=internet:".$f['value']."\r\n";
}
else if($f['key'] == 'phone'){
$res .= "TEL;TYPE=".strtolower($section['name']).",voice:".$f['value']."\r\n";
}
else if($f['key'] == 'mobile'){
$res .= "TEL;TYPE=".strtolower($section['name']).",mobile:".$f['value']."\r\n";
}
else if($f['key'] == 'fax'){
$res .= "TEL;TYPE=".strtolower($section['name']).",fax:".$f['value']."\r\n";
}
}}
}}
$res .= "END:VCARD\r\n";
return $res;
}
// LDIF format entry
function get_ldif_format(){
$res = "dn: cn=".$this->name.",mail=".$this->get_email()."\r\n";
$res .= "objectclass: top\r\n";
$res .= "objectclass: person\r\n";
if(preg_match('/^(.+)\s+(.+)$/',$this->name,$m)){
$res .= "givenName: ".$m[1]."\r\n";
$res .= "sn: ".$m[2]."\r\n";
}
$res .= "cn: ".$this->name."\r\n";
if($this->nick != '')
$res .= "mozillaNickname: ".$this->nick."\r\n";
$res .= "mail:".$this->get_email()."\r\n";
if(array_not_empty($this->info)){foreach($this->info as $section){
if(array_not_empty($section['fields'])){foreach($section['fields'] as $f){
if($f['key'] == 'email'){
// $res .= "email:".$f['value']."\r\n";
}
else if($f['key'] == 'phone'){
$res .= "telephoneNumber: ".$f['value']."\r\n";
}
else if($f['key'] == 'mobile'){
$res .= "mobile: ".$f['value']."\r\n";
}
else if($f['key'] == 'fax'){
$res .= "fax: ".$f['value']."\r\n";
}
}}
}}
$res .= "\r\n\r\n";
return $res;
}
// get mail email
function get_email(){
$this->check();
return $this->email;
}
// get all emails (main and from additional info)
function get_all_emails(){
$emails = array($this->get_email());
if(array_not_empty($this->info)){foreach($this->info as $section){
if(array_not_empty($section['fields'])){foreach($section['fields'] as $f){
if($f['key'] == 'email'){
$emails[] = $f['value'];
}
}}
}}
return $emails;
}
// get all email fields (main and from additional info)
function get_all_email_fields(){
$emails = array(array('email'=>$this->get_email()));
if(array_not_empty($this->info)){foreach($this->info as $section){
if(array_not_empty($section['fields'])){foreach($section['fields'] as $f){
if($f['key'] == 'email'){
$emails[] = array('email'=>$f['value'],'section-name'=>$section['name']);
}
}}
}}
return $emails;
}
// discover additional info for phone numbers
function get_all_phone_numbers(){
$phones = array();
if(array_not_empty($this->info)){foreach($this->info as $section){
if(array_not_empty($section['fields'])){foreach($section['fields'] as $f){
if($f['key'] == 'phone' || $f['key'] == 'mobile'){
$phones[] = $f['value'];
}
}}
}}
return $phones;
}
// if this entry has some email address
function has_email($email){
foreach($this->get_all_emails() as $e){
if($e == $email) return true;
}
return false;
}
function get_name(){
return $this->name;
}
function increase_send_count(){
$this->send_count++;
}
function get_presentation(){
$this->check();
$name = $this->name;
if($this->nick) $name .= ' <span class="gray">('.$this->nick.')</span>';
$emails = array();
foreach($this->get_all_emails() as $email){
$emails[] =
'<a href="'.$_SERVER['PHP_SELF'].'?action=compose&to='.urlencode($this->name.' <'.$email.'>').'">'.
$email.'</a>';
}
$additional = array();
foreach($this->get_all_phone_numbers() as $phone){
$additional[] = htmlspecialchars($phone);
}
if($this->comment)
$additional[] = htmlspecialchars($this->comment);
return
'<td class="nowrap">'.$name.'</td>'.
'<td class="gray">'.
implode(', ',$emails).
((count($additional))?' - '.implode(', ',$additional):'').
'</td>';
}
function get_edit_presentation(){
$this->check();
include(TMPLPATH.'AddressBookEntry_edit_presentation.php');
}
function get_choose_presentation($type){
return
'<td>'.
'<a onclick="parent.choose_one(\''.str_replace("'","\\'",$this->name).' <'.$this->get_email().'>\',\''.$type.'\')" title="click to add"">'.$this->name.' <'.$this->email."></a><br/>\n".
'</td>';
}
function getFullEmail(){
if($this->name)
return $this->name.' <'.$this->email.'>';
else
return $this->email;
}
function search($q){
$js = array();
foreach($this->get_all_email_fields() as $email){
$str = $this->name.($this->nick?' ('.$this->nick.')':'').' <'.$email['email'].'>';
if(stripos($str,$q) !== false){
$res = array('value' => $str,
'affected_value' => $this->name.' <'.$email['email'].'>');
if(!empty($email['section-name']))
$res['info'] = $this->name."'s ".$email['section-name'];
$js[] = $res;
}
}
return $js;
}
}
############################
# List to address book
############################
class AddressBookList extends AddressBookEntry{
var $emails;
function AddressBookList(){
parent::AddressBookEntry();
}
function check(){}
function load(){
$name = get_var('name');
$nick = get_var('nick');
$emails = get_var('emails');
$comment = get_var('comment');
if($name == '' || !array_not_empty($emails)){
return false;
}
$this->name = $name;
$this->nick = $nick;
$this->emails = array();
foreach($emails as $e){
$e = trim($e);
if(is_email($e)) $this->emails[] = $e;
}
$this->comment = $comment;
return true;
}
function get_emails_presentation(){
return implode(', ',$this->emails);
}
function get_presentation(){
$ems_list = $this->get_emails_presentation();
$index=0;
$additional = array();
$add_cdots=false;
foreach($this->emails as $e){
if($index>3){
$add_cdots = true;
break;
}
$small = $e;
if(preg_match('/^(.*)</',$e,$m))
$small = trim($m[1]);
$additional[] = htmlspecialchars($small);
$index++;
}
$name = '<a href="'.$_SERVER['PHP_SELF'].'?action=compose&to='.rawurlencode($ems_list).'">'.$this->name.'</a>';
$name .= ($this->nick?' <span class="gray">('.$this->nick.')</span>':'');
if($this->comment)
$additional[] = htmlspecialchars($this->comment);
return
'<td class="nowrap">'.$name.'</td>'.
'<td><b>'.count($this->emails).' contacts</b> '.
'<span class="gray">'.implode(',',$additional).($add_cdots?'…':'').'</span>'.
'</td>';
}
function get_edit_presentation(){
include(TMPLPATH.'AddressBookList_edit_presentation.php');
}
function get_choose_presentation($type){
return
'<td><table><tr><td>'.
'<a onclick="parent.choose_one(\''.str_replace("'","\\'",$this->get_emails_presentation()).'\',\''.$type.'\')" title="click to add all">'.
$this->name.
'</a></td><td>'.$ems.'</td></tr></table></td>';
}
function search($q){
$js = array();
$str = $this->name.($this->nick?' ('.$this->nick.')':'').' <'.$email.'>';
if(stripos($str,$q) !== false){
$size = count($this->emails);
$js[] = array('value' => $this->name,
'affected_value' => $this->get_emails_presentation(),
'info' => 'group with '.$size.' contact'.($size>1?'s':''));
}
return $js;
}
}
#####################################
# AddressBookEntry compare functions
#####################################
define('SORT_BY_NICK',0);
define('SORT_BY_NAME',1);
define('SORT_BY_SEND_COUNT',2);
define('SORT_BY_EMAIL',3);
function comp_entry_by_nick($o1,$o2){
if(eregi('AddressBookList',get_class($o1)) && eregi('AddressBookEntry',get_class($o2))){
return 1;
}
if(eregi('AddressBookList',get_class($o2)) && eregi('AddressBookEntry',get_class($o1))){
return -1;
}
$cmp1 = $o1->nick?$o1->nick:($o1->name?$o1->name:$o1->email);
$cmp2 = $o2->nick?$o2->nick:($o2->name?$o2->name:$o2->email);
return strcasecmp($cmp1,$cmp2);
}
function comp_entry_by_name($o1,$o2){
if(eregi('AddressBookList',get_class($o1)) && eregi('AddressBookEntry',get_class($o2))){
return 1;
}
if(eregi('AddressBookList',get_class($o2)) && eregi('AddressBookEntry',get_class($o1))){
return -1;
}
$cmp1 = $o1->name?$o1->name:($o1->nick?$o1->nick:$o1->email);
$cmp2 = $o2->name?$o2->name:($o2->nick?$o2->nick:$o2->email);
return strcasecmp($cmp1,$cmp2);
}
function comp_entry_by_send_count($o1,$o2){
if(eregi('AddressBookList',get_class($o1)) && eregi('AddressBookEntry',get_class($o2))){
return 1;
}
if(eregi('AddressBookList',get_class($o2)) && eregi('AddressBookEntry',get_class($o1))){
return -1;
}
if($o1->send_count > $o2->send_count)
return -1;
if($o1->send_count < $o2->send_count)
return 1;
return comp_entry_by_name($o1,$o2);
}
function comp_entry_by_email($o1,$o2){
if(eregi('AddressBookList',get_class($o1)) && eregi('AddressBookEntry',get_class($o2))){
return 1;
}
if(eregi('AddressBookList',get_class($o2)) && eregi('AddressBookEntry',get_class($o1))){
return -1;
}
$cmp1 = $o1->email?$o1->email:$o1->name;
$cmp2 = $o2->email?$o2->email:$o2->name;
return strcasecmp($cmp1,$cmp2);
}
############################
# Address book
############################
class AddressBook extends Preferences{
function AddressBook($file){
parent::Preferences($file,true);
}
function parse($data){
$this->prefs = unserialize($data);
}
function sort($type=SORT_BY_NICK){
if(!is_array($this->prefs))
return;
if($type == SORT_BY_NAME)
$func = 'comp_entry_by_name';
else if($type == SORT_BY_SEND_COUNT)
$func = 'comp_entry_by_send_count';
else if($type == SORT_BY_EMAIL)
$func = 'comp_entry_by_email';
else
$func = 'comp_entry_by_name';
usort($this->prefs,$func);
}
function find($nick){
foreach($this->prefs as $k=>$v)
if($v->nick == $nick) return $v;
return false;
}
function search($query){
$res = array();
foreach($this->prefs as $k=>$v){
$search_result = $v->search($query);
if(array_not_empty($search_result))
foreach($search_result as $sr){
$sr['id'] = $k;
$res[] = $sr;
}
}
return $res;
}
function get_nicks(){
foreach($this->prefs as $k=>$v)
$nicks[] = $v->nick;
return $nicks;
}
function email_exists($email){
foreach($this->prefs as $v){
if(strtolower(get_class($v)) == 'addressbookentry'){
if($v->has_email($email)){
return true;
}
}
}
return false;
}
// update emails in addressbook: add or modify personal
// each entry in emails is array with 'email' and 'personal' keys
function update($emails){
if(array_not_empty($emails)){
$emails = MailParser::parse_emails(implode(',',$emails));
$updated=false;
foreach($emails as $e){
$was=false;
foreach($this->prefs as $k=>$v){
if(strtolower(get_class($v)) == 'addressbookentry'){
foreach($v->get_all_emails() as $ve){
if($ve == $e['email']){
if($e['personal'] != '' && $v->get_name() == ''){
$this->prefs[$k]->name = $e['personal'];
}
$this->prefs[$k]->increase_send_count();
$updated = true;
$was = true;
break;
}
}
}
}
if(!$was){
$a = new AddressBookEntry();
$a->name = $e['personal']?$e['personal']:$e['mailbox'];
$a->email = $e['email'];
$a->increase_send_count();
$this->prefs[] = $a;
$updated = true;
}
}
}
if($updated)
$this->store();
}
function getEntries(){
$entries = array();
foreach($this->prefs as $k=>$v)
if(strtolower(get_class($v)) == 'addressbookentry')
$entries[] = $v;
return $entries;
}
function to_file(){
foreach($this->prefs as $k=>$v)
$this->prefs[$k]->check();
return serialize($this->prefs);
}
function get_csv_format(){
$res = '"Name","E-mail"'."\r\n";
foreach($this->prefs as $p)
if(strtolower(get_class($p)) == 'addressbookentry')
$res .= $p->get_csv_format();
return $res;
}
function get_pine_format(){
$res = '';
foreach($this->prefs as $p)
if(strtolower(get_class($p)) == 'addressbookentry')
$res .= $p->get_pine_format();
return $res;
}
function get_vcard_format(){
$res = '';
foreach($this->prefs as $p)
if(strtolower(get_class($p)) == 'addressbookentry')
$res .= $p->get_vcard_format();
return $res;
}
function get_ldif_format(){
$res = '';
foreach($this->prefs as $p)
if(strtolower(get_class($p)) == 'addressbookentry')
$res .= $p->get_ldif_format();
return $res;
}
// take outlook csv
// $f is file descriptor
function from_csv($f,$delete=false){
$header = fgetcsv($f,100000,",",'"');
$first_name_ind = $family_name_ind = $email_ind = $nick_ind = $name_ind = -1;
foreach($header as $k=>$v){
$v = trim($v);
if(eregi("first name",$v))
$first_name_ind = $k;
else if(eregi("first last",$v) || eregi("last name",$v) || eregi("family name",$v))
$family_name_ind = $k;
else if(eregi('^name$',$v))
$name_ind = $k;
else if(eregi("e-mail address",$v) || eregi('^e-?mail$',$v))
$email_ind = $k;
else if(eregi('^nickname$',$v) || eregi("e-mail display name",$v))
$nick_ind = $k;
}
$data = array();
while($csv=fgetcsv($f,100000,",",'"')){
$d = array();
if($name_ind>=0)
$d['name'] = $csv[$name_ind];
else
$d['name'] = $csv[$first_name_ind].' '.$csv[$family_name_ind];
if(isset($csv[$email_ind]))
$d['email'] = $csv[$email_ind];
if(isset($csv[$nick_ind]))
$d['nick'] = $csv[$nick_ind];
$data[] = $d;
}
$this->import($data,$delete);
}
// take pine addresses
// $f is file descriptor
function from_pine($f,$delete=false){
$lines = array();
$was_address = true;
$was_separated = false;
while($line = fgets($f)){
$line = preg_replace("/[\n\r]*$/",'',$line);
if(preg_match('/^#/',$line) || $line == ''){
$was_address = false;
$was_separated = false;
continue;
}
// extra lines
if(preg_match('/^ /',$line)){
if($was_address || $was_separated){
$lines[count($lines)-1] .= substr($line,3);
$was_separated = true;
}
$was_address = false;
}
else{
$was_address = true;
$was_separated = false;
$lines[] = $line;
}
}
$data = array();
foreach($lines as $line){
list($nick,$name,$email,$comment1,$comment2) = array_map('mime_header_decode',preg_split("/\t/",$line));
$d = array();
if($nick) $d['nick'] = $nick;
if($name) $d['name'] = $name;
if($email){
// list
if(preg_match('/^\((.*)\)$/',$email,$m)){
$d['emails'] = preg_split('/,/',$m[1]);
}
else if(preg_match('/<(.+@.+)>/',$email,$m)){
$d['email'] = $m[1];
}
else
$d['email'] = $email;
}
if($comment1) $d['comment'] .= $comment1;
if($comment2) $d['comment'] .= $comment2;
$data[] = $d;
}
$this->import($data,$delete);
}
// abstract import of data
function import($data,$delete=false){
$new_prefs = array();
$exist_emails = array();
foreach($data as $d){
if(isset($d['name']) || isset($d['nick'])){
// email lists
if(isset($d['emails']) && array_not_empty($d['emails'])){
$e = new AddressBookList();
$e->name = $d['name'];
if(isset($d['nick']) && $d['name'] != $d['nick'])
$e->nick = $d['nick'];
$e->emails = array();
foreach($d['emails'] as $em){
$em = trim($em);
if(is_email($em)) $e->emails[] = $em;
}
if(array_not_empty($e->emails))
$new_prefs[] = $e;
}
else if(is_email($d['email'])){
if(!$delete && $this->email_exists($d['email'])){
$exist_emails[] = $d['email'];
}
else{
$e = new AddressBookEntry();
$e->name = $d['name'];
$e->email = $d['email'];
if(isset($d['nick']) && $d['name'] != $d['nick'])
$e->nick = $d['nick'];
if(isset($d['comment']))
$e->comment = $d['comment'];
$new_prefs[] = $e;
}
}
}
}
if(empty($new_prefs)){
Error::set('No addresses found for import');
return;
}
if($delete)
$this->prefs = $new_prefs;
else
$this->prefs = array_merge($this->prefs,$new_prefs);
if(array_not_empty($exist_emails))
Notice::set(implode(', ',$exist_emails).' are already in your address book');
$this->sort();
}
function load($key=null){
if(is_numeric($key) && isset($this->prefs[$key])){
$this->prefs[$key]->load();
}
else{
if(get_var('is-list') != '')
$e = new AddressBookList();
else
$e = new AddressBookEntry();
if($e->load()){
$this->prefs[] = $e;
}
}
}
function get_entry($num=false,$is_list=false,$load=false){
if(!is_true($num)){
if($is_list){
$e = new AddressBookList();
return $e;
}
else{
$e = new AddressBookEntry();
if($load){
if($e->load())
return $e;
return false;
}
return $e;
}
return false;
}
else if(isset($this->prefs[$num]))
return $this->prefs[$num];
}
function get_presentation(){
if(!$this->prefs || count($this->prefs) == '')
return
'<tr><td colspan="4" class="center"><h2>Empty</h2></td></tr>';
$res .=
'<tr>'.
'<th><input type="checkbox" onclick="setChecked(this.form,\'key\',this.checked);"/></th>'.
'<th colspan="3">'.
'sort by : '.
'<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&sort='.SORT_BY_SEND_COUNT.'">mail frequency</a>, '.
'<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&sort='.SORT_BY_NAME.'">name</a>, '.
'<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&sort='.SORT_BY_NICK.'">nick</a>, '.
'<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&sort='.SORT_BY_EMAIL.'">email</a> '.
'</th>'.
'</tr>';
$was_list = false;
foreach($this->prefs as $key=>$p){
if(!$was_list && eregi('AddressBookList',get_class($p))){
$res .= '<tr><th colspan="6">Lists</th></tr>';;
$was_list = true;
}
$res .= '<tr class="hover">'.
'<td><input type="checkbox" name="key[]" value="'.$key.'" onclick="toggle_checkbox_row(this)"/></td>'.
$p->get_presentation().
'<td> <a href="'.$_SERVER['PHP_SELF'].'?action=addressbook-edit&entry='.$key.'">edit</a> </td>'.
'</tr>';
}
return $res;
}
function get_choose_presentation($type){
if(array_not_empty($this->prefs)){
$res = '';
foreach($this->prefs as $key=>$p)
$res .= '<tr>'.$p->get_choose_presentation($type).'</tr>';
return $res;
}
return
'<tr><td colspan="4" class="center"><h2>Empty</h2></td></tr>';
}
function delete($keys){
$deleted = array();
if(is_array($keys)){
foreach($keys as $k){
if(isset($this->prefs[$k])){
$deleted[] = $this->prefs[$k]->get_name();
unset($this->prefs[$k]);
}
}
}
$new_keys = array();
foreach($this->prefs as $e)
$new_keys[] = $e;
$this->prefs = $new_keys;
if(array_not_empty($deleted)){
Notice::set(implode(', ',$deleted).' deleted from address book.');
}
}
}
///////////////////////////////////
// Class for procmail rule
///////////////////////////////////
$HEADER_FIELDS = array('From/Sender' => 'from',
'To' => 'to',
'Subject' => 'subject');
$CONDITIONS = array('Contains' => 'contains',
'Doesn\'t Contains' => 'not-contains',
'Begins With' => 'begins',
'Ends With' => 'ends',
'Matches' => 'matches',
'Doesn\'t Matches' => 'not-matches');
class ProcmailRule{
var $key;
var $rules;
var $name;
var $description;
var $rule;
function ProcmailRule($name=false,$key=false,$rules=false){
$this->name = $name;
$this->key = $key;
$this->rules = $rules;
if($this->key){
$this->rule = unserialize($this->key);
if(!$rules)
$this->prepare_rules();
$this->prepare_description();
}
else
$this->rule = array();
}
function to_print(){
return
'# '.$this->key."\n".
$this->rules."\n";
}
function get_edit_presentation(){
include(TMPLPATH.'ProcmailRule_edit_presentation.php');
}
function prepare_description(){
$this->description = '';
for($i=0;$i<$this->rule['rules-num'];$i++){
$this->description .= 'Check in <b>';
if($this->rule['header-field'][$i] == 'from')
$this->description .= 'From/Sender';
else if($this->rule['header-field'][$i] == 'to')
$this->description .= 'To';
else if($this->rule['header-field'][$i] == 'subject')
$this->description .= 'Subject';
$this->description .= '</b>, condition is ';
if($this->rule['condition'][$i] == 'begins')
$this->description .= 'begins with';
else if($this->rule['condition'][$i] == 'ends')
$this->description .= 'ends with';
else if($this->rule['condition'][$i] == 'contains')
$this->description .= 'contains';
else if($this->rule['condition'][$i] == 'not-contains')
$this->description .= 'not contains';
else if($this->rule['condition'][$i] == 'matches')
$this->description .= 'matches';
else if($this->rule['condition'][$i] == 'not-matches')
$this->description .= 'not matches';
$this->description .= ' <b>'.$this->rule['pattern'][$i]."</b><br/>\n";
}
$this->description .= 'Action is ';
if($this->rule['rule-action'] == 'discard-email')
$this->description .= 'discard';
else if($this->rule['action'] == 'forward-email')
$this->description .= 'forward to <b>'.$this->rule['action'].'</b>';
else
$this->description .= 'redirect to <b>'.$this->rule['action'].'</b>';
}
function prepare_key(){
$this->key = serialize($this->rule);
}
function prepare_rules(){
$this->rules = ":0 H :\n";
for($i=0;$i<$this->rule['rules-num'];$i++){
$rule = '';
if($this->rule['header-field'][$i] == 'from')
$rule .= '^From:[ ]?';
else if($this->rule['header-field'][$i] == 'to')
$rule .= '^(To|Cc|Bcc):[ ]?';
else if($this->rule['header-field'][$i] == 'subject')
$rule .= '^Subject:[ ]?';
if($this->rule['condition'][$i] == 'begins')
$rule .= '('.preg_quote($this->rule['pattern'][$i]).')';
else if($this->rule['condition'][$i] == 'ends')
$rule .= '('.preg_quote($this->rule['pattern'][$i]).')$';
else if($this->rule['condition'][$i] == 'contains')
$rule .= '.*('.preg_quote($this->rule['pattern'][$i]).').*';
else if($this->rule['condition'][$i] == 'not-contains')
$rule = '!'.$rule.'.*('.preg_quote($this->rule['pattern'][$i]).').*';
else if($this->rule['condition'][$i] == 'matches')
$rule .= $this->rule['pattern'][$i];
else if($this->rule['condition'][$i] == 'not-matches')
$rule = '!'.$rule.'('.$this->rule['pattern'][$i].')';
$this->rules .= "* $rule\n";
}
if($this->rule['rule-action']=='forward-email')
$this->rules .= '!';
$this->rules .= str_replace(' ','\ ',$this->rule['action'])."\n";
}
function load(){
$this->rule = array();
$this->rule['rules-num'] = 0;
$this->name = get_var('name');
$patterns = get_var('pattern');
$header_field = get_var('header-field');
$condition = get_var('condition');
foreach($patterns as $i=>$p){
if($p != ''){
$this->rule['rules-num']++;
$this->rule['header-field'][] = $header_field[$i];
$this->rule['condition'][] = $condition[$i];
$this->rule['pattern'][] = $p;
}
}
$rule_action = get_var('rule-action');
$this->rule['rule-action'] = $rule_action;
if($rule_action == 'move-mbox')
$this->rule['action'] = basename(get_var('move-mbox'));
else if($rule_action == 'forward-email')
$this->rule['action'] = get_var('forward-email');
else if($rule_action == 'discard-email')
$this->rule['action'] = '/dev/null';
$this->prepare_key();
$this->prepare_rules();
$this->prepare_description();
}
function block_email($email){
$this->name = "Blocking $email";
$this->rule['rules-num'] = 1;
$this->rule['header-field'][] = 'from';
$this->rule['condition'][] = 'contains';
$this->rule['pattern'][] = $email;
$this->rule['rule-action'] = 'discard-email';
$this->rule['action'] = '/dev/null';
$this->prepare_key();
$this->prepare_rules();
$this->prepare_description();
}
function get_presentation(){
return '<td>'.$this->name.'</td><td>'.$this->description.'</td>';
}
}
/////////////////////////////////////
// Class for anti spam procmail rule
/////////////////////////////////////
class AntiSpamProcmailRule extends ProcmailRule{
function AntiSpamProcmailRule($name=false,$key=false){
parent::ProcmailRule($name,$key);
}
function get_edit_presentation(){
include(TMPLPATH.'AntiSpamProcmailRule_edit_presentation.php');
}
function prepare_description(){
$this->description = $this->name."<br/>\n";
$this->description .= 'Action is ';
if($this->rule['rule-action'] == 'discard-email')
$this->description .= 'discard';
else if($this->rule['action'] == 'forward-email')
$this->description .= 'forward to <b>'.$this->rule['action'].'</b>';
else
$this->description .= 'redirect to <b>'.$this->rule['action'].'</b>';
}
function prepare_rules(){
//$this->rules = ":0fw\n";
//$this->rules .= "| /usr/bin/spamc -f -d spam -s 256000 -t 20\n\n";
$this->rules = ":0 H :\n";
$this->rules .= "* ^X-Spam-Status: Yes\n";
if($this->rule['rule-action']=='forward-email')
$this->rules .= '!';
$this->rules .= str_replace(' ','\ ',$this->rule['action'])."\n";
}
function load(){
$this->name = get_var('name');
$rule_action = get_var('rule-action');
$this->rule['rule-action'] = $rule_action;
if($rule_action == 'move-mbox')
$this->rule['action'] = basename(get_var('move-mbox'));
else if($rule_action == 'forward-email')
$this->rule['action'] = get_var('forward-email');
else if($rule_action == 'discard-email')
$this->rule['action'] = '/dev/null';
$this->prepare_key();
$this->prepare_rules();
$this->prepare_description();
}
}
/////////////////////////////////////
// Class for vacation message rule
/////////////////////////////////////
class VacationProcmailRule extends ProcmailRule{
function VacationProcmailRule($name=false,$key=false){
parent::ProcmailRule($name,$key);
$this->rule['vacation-message'] =
"I'm on vacation and will not be reading my mail for a while.\n".
"Your mail will be dealt with when I return.";
}
function get_edit_presentation(){
include(TMPLPATH.'VacationProcmailRule_edit_presentation.php');
}
function prepare_description(){
$this->description = $this->name."<br/>\n";
$this->description .= 'Automatic vacation message for each incoming e-mail';
}
function prepare_rules(){
$this->rules = ":0\n";
$this->rules .= "* !^FROM_DAEMON\n";
$this->rules .= "* !^X-Loop: ".$GLOBALS['MAIL_USER_NAME'].'@'.MAILSUFFIX."\n";
$echoed_msg = '';
foreach(preg_split("/\n/",urldecode($this->rule['vacation-message'])) as $line){
$echoed_msg .= '; echo '.escapeshellarg($line);
}
$from = escapeshellarg('From: '.$_SESSION['preferences']->getName().' <'.$GLOBALS['MAIL_USER_NAME'].'@'.MAILSUFFIX.'>');
$xloop = escapeshellarg('X-Loop: '.$GLOBALS['MAIL_USER_NAME'].'@'.MAILSUFFIX);
$this->rules .= '| (formail -r -A'.$from.' -A'.$xloop.' '.$echoed_msg.') | $SENDMAIL -oi -t'."\n";
}
function load(){
$this->name = get_var('name');
$this->rule['vacation-message'] = urlencode(str_replace("\r",'',get_var('vacation-message')));
$this->prepare_key();
$this->prepare_rules();
$this->prepare_description();
}
}
///////////////////////////////////
// Class for procmail file
///////////////////////////////////
class Procmail extends Preferences{
var $separator;
var $rule_separator;
var $initial;
var $inbox_name;
var $anti_spam_rule_name;
var $anti_spam_rule;
var $vacation_rule_name;
var $vacation_rule;
function Procmail($file){
$this->separator =
'# Don\'t modify next lines, it\'s automatly generated procmail rules';
$this->rule_separator = '# rule';
$this->inbox_name = 'INBOX';
$this->anti_spam_rule_name = 'Spam Filtering';
$this->anti_spam_rule = false;
$this->vacation_rule_name = 'Vacation';
$this->vacation_rule = false;
parent::Preferences($file,false);
}
function parse($data){
$lines = preg_split("/\n/",$data);
$was_separator = false;
$this->initial = '';
$count = count($lines);
reset($lines);
for($i=0;$i<$count;$i++){
if(!$was_separator){
if($this->separator == $lines[$i])
$was_separator = true;
else{
$this->initial .= $lines[$i]."\n";
if(!eregi('^#',$lines[$i])){
if(eregi('DEFAULT=\$HOME/([/a-z0-9._-]+)',$lines[$i],$match)){
$this->inbox_name = $match[1];
}
}
}
}
else{
if(eregi('^'.$this->rule_separator.' (.*)',$lines[$i],$match)){
$name = $match[1];
$i++;
if(eregi('^# (.+)',$lines[$i],$match)){
$key = $match[1];
$i++;
$rules = '';
while(!eregi('^'.$this->rule_separator.' (.*)',$lines[$i],$match) && $i<=$count){
$rules .= $lines[$i]."\n";
$i++;
}
$i--;
// old
// $this->prefs[$name] = new ProcmailRule($name,$key,$rules);
//$this->prefs[$name] = new ProcmailRule($name,$key);
if($name == $this->anti_spam_rule_name)
$this->anti_spam_rule = new AntiSpamProcmailRule($this->anti_spam_rule_name,$key);
else if($name == $this->vacation_rule_name)
$this->vacation_rule = new VacationProcmailRule($this->vacation_rule_name,$key);
else
$this->prefs[] = new ProcmailRule($name,$key);
}
}
}
}
}
function to_file(){
if($this->initial)
$res = $this->initial;
else
$res =
'#######################################
# Automaticly generated procmail file
#######################################
VERBOSE=no # verbose log?
SHELL=/bin/sh # shell used to parse commands
SHELLFLAGS=-cf # for csh, don\'t load cshrc!
LOGFILE=$HOME/.procmail.log # procmaillog
LOGABSTRACT=no # log abstracts? (from/subject pairs)
LOCKFILE=$HOME/.procmail.lock # default lock file
LOCKEXT=.lock # appended to lockfiles
LOCKSLEEP=2 # sleep time on semaphores
LOCKTIMEOUT=1024 # timeout before forcing a lock
TIMEOUT=960 # timeout before SIGTERM\'ing a child
MSGPREFIX=mesg. # prefix for messages put in directories
UMASK=077 # umask for files (if o+x, then forced)
NORESRETRY=4 # retries no. on kernel resources denial
SUSPEND=16 # timeout on NORESRETRY
LINEBUF=2048 # internal line buffer length
DELIVERED=no # consider delivered? (yes -> no bounce)
COMSAT=hide@address.com # biff/comsat facility interface
DROPPRIVS=yes # drop suid/sgid privileges?
';
$res .= $this->separator."\n";
$res .= 'MAILDIR=$HOME/'.$_SESSION['preferences']->get('mail-dir')."\n";
if($this->anti_spam_rule){
$res .= $this->rule_separator.' '.$this->anti_spam_rule_name."\n";
$res .= $this->anti_spam_rule->to_print();
}
if($this->vacation_rule){
$res .= $this->rule_separator.' '.$this->vacation_rule_name."\n";
$res .= $this->vacation_rule->to_print();
}
reset($this->prefs);
foreach($this->prefs as $key=>$rule){
$res .= $this->rule_separator." $rule->name\n";
$res .= $rule->to_print();
}
return $res."\n";
}
function load($key=false){
if($key == $this->anti_spam_rule_name){
$this->anti_spam_rule = new AntiSpamProcmailRule($this->anti_spam_rule_name);
$this->anti_spam_rule->load();
}
else if($key == $this->vacation_rule_name){
$this->vacation_rule = new VacationProcmailRule($this->vacation_rule_name);
$this->vacation_rule->load();
}
else{
$e = new ProcmailRule;
$e->load();
if(is_numeric($key))
$this->prefs[$key] = $e;
else
$this->prefs[] = $e;
}
}
function block_email($email){
if(!preg_match('/.+@.+/',$email))
return false;
foreach($this->prefs as $p){
if($p->rule['header-field'][0]=='from' && $p->rule['pattern'][0]==$email){
return false;
break;
}
}
$e = new ProcmailRule;
$e->block_email($email);
$this->prefs[] = $e;
return true;
}
function delete($keys){
if(is_array($keys)){
$reorder = false;
foreach($keys as $k){
if($k == $this->anti_spam_rule_name){
$this->anti_spam_rule = false;
}
else if($k == $this->vacation_rule_name){
$this->vacation_rule = false;
}
else{
unset($this->prefs[$k]);
$reorder = true;
}
}
if($reorder){
$tmp = $this->prefs;
$this->prefs = array();
foreach($tmp as $v)
$this->prefs[] = $v;
}
}
}
function move_up($key){
if($key > 0){
$tmp = $this->prefs[$key-1];
$this->prefs[$key-1] = $this->prefs[$key];
$this->prefs[$key] = $tmp;
}
}
function move_down($key){
if($key < count($this->prefs)-1){
$tmp = $this->prefs[$key+1];
$this->prefs[$key+1] = $this->prefs[$key];
$this->prefs[$key] = $tmp;
}
}
function get_edit_presentation($key=false){
if(!is_true($key)){
$e = new ProcmailRule('Noname '.(count($this->prefs)+1));
$e->get_edit_presentation();
}
else if($key == $this->anti_spam_rule_name){
if($this->anti_spam_rule)
$this->anti_spam_rule->get_edit_presentation();
else{
$e = new AntiSpamProcmailRule($this->anti_spam_rule_name);
$e->get_edit_presentation();
}
}
else if($key == $this->vacation_rule_name){
if($this->vacation_rule)
$this->vacation_rule->get_edit_presentation();
else{
$e = new VacationProcmailRule($this->vacation_rule_name);
$e->get_edit_presentation();
}
}
else if($this->prefs[$key])
$this->prefs[$key]->get_edit_presentation();
}
function get_presentation(){
include(TMPLPATH.'Procmail_presentation.php');
}
}
///////////////////////////////////
// Class for newsrc file
///////////////////////////////////
class Newsrc extends Preferences{
function Newsrc($file){
parent::Preferences($file,true);
}
function parse($data){
$lines = preg_split("/\n/",$data);
reset($lines);
foreach($lines as $line){
/*
if(!eregi('!$',$line) &&
eregi('(.*):',$line,$m))
$this->prefs[] = $m[1];
*/
$line = chop($line);
if($line)
$this->prefs[] = $line;
}
}
function get_groups(){
return $this->prefs;
}
function to_file(){
foreach($this->prefs as $p){
$res .= "$p\n";
}
return $res;
}
function load(){
$group = get_var('group');
if(is_array($group))
foreach($group as $g)
$this->prefs[] = $g;
else
$this->prefs[] = $group;
sort($this->prefs);
}
function delete($keys){
if(is_array($keys))
foreach($keys as $k)
unset($this->prefs[$k]);
else print "zopa $keys";
}
function get_add_list_presentation($query){
$mp = getNNTP();
$groups = $mp->listing($query);
$res = '';
foreach($groups as $g){
$res .= '<input type="checkbox" name="group[]" value="'.$g.'"/> '.$g."<br/>\n";
}
return $res;
}
function get_presentation(){
if(!is_array($this->prefs) || count($this->prefs) == 0)
return '<tr><td class="center"><h2>Empty</h2></td></tr>';
foreach($this->prefs as $key=>$p){
$res .=
'<tr><td><input type="checkbox" name="key[]" value="'.$key.'" onclick="toggle_checkbox_row(this);"/></td>'.
'<td> '.$p.'</td></tr>';
}
return $res;
}
}
///////////////////////////////////
// Class for newsrc file
///////////////////////////////////
class Labels extends Preferences{
function Labels($file){
parent::Preferences($file,true);
}
function parse($data){
$this->prefs = unserialize($data);
}
function set_default(){
$this->prefs = $GLOBALS['DEFAULT_LABELS'];
}
function to_file(){
return serialize($this->prefs);
}
function get_labels(){
return $this->prefs;
}
function name_comparator($a,$b){
return strcmp($a,$b);
}
function load(){
$name = trim(get_var('name'));
$shortcut = trim(get_var('shortcut'));
$color = trim(get_var('color'));
if($name !== ''){
if($shortcut == '') $shortcut = strtolower($name);
if(!preg_match('/^#[0-9a-f]{3}$/i',$color) &&
!preg_match('/^#[0-9a-f]{6}$/i',$color) &&
!preg_match('/^[a-z]{3,}$/i',$color))
$color = '#006633';
$label = array('name'=>$name,'shortcut'=>$shortcut,'color'=>$color);
$id = get_var('key');
if(isset($this->prefs[$id])){
$this->prefs[$id] = $label;
}
else{
$id = $this->make_uniqid();
$this->prefs[$id] = $label;
}
}
usort($this->prefs,'Labels::name_comparator');
}
function make_uniqid(){
$arr = array(1,2,3,4,5,6,7,8,9,0,
'a','e','i','u','o','y',
'b','c','d','f','g','k','l','t','w','q','z','r');
do{
shuffle($arr);
$id = $arr[0].$arr[1].$arr[2].$arr[3].$arr[4];
}while(isset($this->prefs[$id]));
return $id;
}
function find($key){
return $this->prefs[$key];
}
function delete($keys){
if(is_array($keys))
foreach($keys as $k)
unset($this->prefs[$k]);
else print "zopa $keys";
}
function get_presentation(){
if(!array_not_empty($this->prefs))
return '<tr><td class="center" colspan="4"><h2>Empty</h2></td></tr>';
$res = '';
foreach($this->prefs as $k=>$p){
$res .=
'<tr><td><input type="checkbox" name="key[]" value="'.$k.'" onclick="toggle_checkbox_row(this)"/></td>'.
'<td> <code style="color:'.$p['color'].'">'.$p['shortcut'].'</code></td>'.
'<td> '.$p['name'].'</td>'.
'<td> <a href="'.$_SERVER['PHP_SELF'].'?action=labels-edit&key='.$k.'">edit</a></td>'.
'</tr>';
}
return $res;
}
}
?>