Location: PHPKode > projects > CsWebmail > cswebmail-3.10/cswebmail-3.10/include/files.php
<?

$__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&amp;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.' &lt;'.$this->email."&gt;</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?'&#133;':'').'</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&amp;sort='.SORT_BY_SEND_COUNT.'">mail frequency</a>, '.
        '<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&amp;sort='.SORT_BY_NAME.'">name</a>, '.
        '<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&amp;sort='.SORT_BY_NICK.'">nick</a>, '.
        '<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook&amp;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>&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?action=addressbook-edit&entry='.$key.'">edit</a>&nbsp;</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>&nbsp;'.$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>&nbsp;<code style="color:'.$p['color'].'">'.$p['shortcut'].'</code></td>'.
          '<td>&nbsp;'.$p['name'].'</td>'.
          '<td>&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?action=labels-edit&amp;key='.$k.'">edit</a></td>'.
          '</tr>';
    }
    return $res;
  }
}

?>
Return current item: CsWebmail