Location: PHPKode > projects > CsWebmail > cswebmail-3.10/cswebmail-3.10/include/mail.php
<?
if(VALID_DOCUMENT != 1) die('what?');

//////////////////////
// Class for mailbox
//////////////////////
class MBox{
  var $name;
  var $name_print;
  var $num_msgs;
  var $recent_msgs;
  var $new_msgs;
  var $size;
  function MBox($name,$name_print=false,$without_info=false){
    $this->name = $name;
    if($name_print)
      $this->name_print = $name_print;
    else
      $this->name_print = basename($this->name);
    
    if(!$without_info){
      $this->refresh();
    }
  }
  function getMP(){
    return getIMAP();
  }
  function refresh(){
    $mp = $this->getMP();
    try{ $status = $mp->status($this->name); }
    catch(Exception $e){
      Notice::set($e->getMessage());
    }
    
    if($status === null){
      return;
    }
    $this->valid = true;
    
    $this->num_msgs = $status['messages'];
    $this->recent_msgs = $status['recent'];
    $this->new_msgs = $status['unseen'];
    $this->size = $status['size'];
  }
  // Deleting all keys from mailbox
  function delete($keys){
    $mp =$this->getMP();
    $res = $mp->delete_messages($this->name,$keys);
    if(is_array($keys)){
      sort($keys);
      $res .= "Messages <b>".implode(", ",$keys).
         "</b> deleted from <b>".$this->name."</b>\n";
    }
    else if(is_numeric($keys))
      $res .= "Message <b>$keys</b> deleted from <b>".$this->name."</b>\n";
    return $res;
  }
  function rename($name){
    $this->name = $name;
    $this->name_print = basename($name);
  }
  function append($msg){
    $mp = $this->getMP();
    $mp->append($this->name,$msg);
  }
  // moving all keys to another mailbox
  function move($keys,$mailbox){
    $mp = $this->getMP();
    $mp->move_messages($this->name,$mailbox,$keys);
    if(is_array($keys)){
      reset($keys);
      sort($keys);
      $strkeys = implode(",",$keys);
    }
    else
      $strkeys = $keys;
    $res = "Messages <b>$strkeys</b> moved from <b>".$this->name."</b> to <b>".$mailbox."</b>\n";
    return $res;
  }
  // copying all keys to another mailbox
  function copy($keys,$mailbox){
    $mp = $this->getMP();
    $mp->copy_messages($this->name,$mailbox,$keys);
    if(is_array($keys)){
      reset($keys);
      sort($keys);
      $strkeys = implode(",",$keys);
    }
    else
      $strkeys = $keys;
    $res = "Messages <b>$strkeys</b> copied from <b>".$this->name."</b> to <b>".$mailbox."</b>\n";
    return $res;
  }
  function setLabel($label,$keys,$set=true){
    $mp = $this->getMP();
    $mp->select($this->name);
    
    if(!is_array($keys) && $keys) $keys = array($keys);
    
    if(is_array($keys)){
      foreach($keys as $k){
        $mp->store_flag($this->name,$k,$label,$set);
      }
      reset($keys);
      sort($keys);
      $strkeys = implode(',',$keys);

      $label_name = $label;
      if(is_object($_SESSION['labels'])){
        $l = $_SESSION['labels']->find($label);
        $label_name = $l['name'];
      }
      if($set)
        $res = "Messages $this->name[<b>$strkeys</b>] labeled with &laquo;<b>$label_name</b>&raquo;\n";
      else
        $res = "Label &laquo;<b>$label_name</b>&raquo; removed from $this->name[<b>$strkeys</b>] \n";
    }
    return $res;
  }
  function print_table_row(){
    if(get_var('mailbox') == $this->name)
      $class = 'checked';
    print '<tr><td class="'.$class.'" style="padding-right: 8px">';
    $this->print_row();
    print '</td></tr>';
  }
  function print_row(){
    print 
       '<a href="'.$_SERVER['PHP_SELF'].'?action=show-folder&amp;mailbox='.$this->name.'"'.
       ($this->num_msgs>0?
        (' title="total: '.$this->num_msgs.
         ($this->recent_msgs>0?' recent: '.$this->recent_msgs:'').
         ($this->new_msgs>0?' new: '.$this->new_msgs:'').
         ($this->size>0?' size: '.bytes2string($this->size,0):'').'"'):
        (is_numeric($this->num_msgs)&&$this->num_msgs==0?' title="empty"':'')).
       '>'.$this->name_print.'</a>'.
       ($this->new_msgs>0?' <span class="red">('.$this->new_msgs.')</span>':'');
  }
  function get_info(){
    if($this->num_msgs === 0) return '0';
    return
      '<span class="gray">'.$this->num_msgs.'</span>'.
      ($this->new_msgs>0?'|<span class="red">'.$this->new_msgs.'</span>':'');
  }
}
# NNTPMBox
class NNTPMBox extends MBox{
  function NNTPMBox($name,$name_print=false){
    parent::MBox($name,$name_print,true);
  }
  function getMP(){
    return getNNTP();
  }
}
//////////////////////////////////////
// Getting only names for mailboxes
//////////////////////////////////////
function get_mailboxes_names($except=false){
  $names = array();
  foreach($_SESSION['mboxes']->boxes as $box){
    if(eregi("^MBox$",get_class($box)) &&
       $except != $box->name)
      $names[$box->name_print] = $box->name;
  }
  //asort($names);
  return $names;
  
  $imap = getIMAP();
  $arr_boxes=array($_SESSION['procmail']->inbox_name);
  $arr_boxes=array_merge($arr_boxes,$imap->listing($_SESSION['preferences']->getMailDir().'/%'));
  
  foreach($arr_boxes as $box){
    if($box){
      $name = $box;
      if(eregi($_SESSION['procmail']->inbox_name.'$',$name))
        $names['INBOX'] = $name;
      else if(eregi($_SESSION['preferences']->getFccMailbox().'$',$name))
        $names['Sent Mails'] = $name;
      else if(eregi($_SESSION['preferences']->getDraftMailbox().'$',$name))
        $names['Postponed Mails'] = $name;
      else if(eregi($_SESSION['preferences']->getRestoredMailbox().'$',$name))
        $names['Restored Mails'] = $name;
      else
        $names[basename($name)] = $name;
    }
  }
  asort($names);
  return $names;
}
////////////////////////
// Class for mailboxes
////////////////////////
class MBoxes{
  var $boxes;
  var $names;
  var $categories;
  function MBoxes(){
    $this->refresh();
  }
  function refresh(){
    $this->boxes = array();
    $this->names = array();
    $this->categories = array();
    
    $imap = getIMAP();
    $exists_names = array();;
    foreach($imap->listing($_SESSION['preferences']->getMailDir().'/*') as $l){
      $exists_names[$l] = true;
    }
    // Inbox    
    $mailbox = new MBox($_SESSION['procmail']->inbox_name,'INBOX');
    $this->boxes[$mailbox->name] = $mailbox;
    $this->names[] = $mailbox->name;
    $this->categories['inbox'] = $mailbox->name;
    
    // Special
    if($exists_names[$_SESSION['preferences']->getFccMailbox()]){
      $mailbox = new MBox($_SESSION['preferences']->getFccMailbox(),'Sent Mails');
      if($mailbox->valid){
        $this->boxes[$mailbox->name] = $mailbox;
        $this->names[] = $mailbox->name;
        $this->categories['special'][] = $mailbox->name;
      }
    }
    if($exists_names[$_SESSION['preferences']->getDraftMailbox()]){
      $mailbox = new MBox($_SESSION['preferences']->getDraftMailbox(),'Postponed Mails');
      if($mailbox->valid){
        $this->boxes[$mailbox->name] = $mailbox;
        $this->names[] = $mailbox->name;
        $this->categories['special'][] = $mailbox->name;
      }
    }
    if($exists_names[$_SESSION['preferences']->getRestoredMailbox()]){
      $mailbox = new MBox($_SESSION['preferences']->getRestoredMailbox(),'Restored Mails');
      if($mailbox->valid){
        $this->boxes[$mailbox->name] = $mailbox;
        $this->names[] = $mailbox->name;
        $this->categories['special'][] = $mailbox->name;
      }
    }
    // additional
    $add = $_SESSION['preferences']->getMailboxesList();
    if(array_not_empty($add)){
      foreach($add as $name){
        if($exists_names[$name]){
          $mailbox = new MBox($name);
          if($mailbox->valid){
            $this->boxes[$mailbox->name] = $mailbox;
            $this->names[] = $mailbox->name;
            $this->categories['additional'][] = $mailbox->name;
          }
        }
      }
    }
    // news
    if(array_not_empty($_SESSION['newsrc']->get_groups())){
      foreach($_SESSION['newsrc']->get_groups() as $group){
        $mailbox = new NNTPMBox($group);
        $this->boxes[$mailbox->name] = $mailbox;
        $this->names[] = $mailbox->name;
        $this->categories['news'][] = $mailbox->name;
      }
    }
  }
  // Creating MailHeaders
  function createMailHeaders($mailbox='INBOX',$sort_order=SORT_BY_DATE,$start_page=1,$update=true){
    $mbox = $this->find($mailbox);
    if($mbox){
      if($mbox->name == $_SESSION['preferences']->getFccMailbox())
        return new SentMailHeaders($mbox->name,$sort_order,$start_page);
      else if($mbox->name == $_SESSION['preferences']->getDraftMailbox())
        return new DraftMailHeaders($mbox->name,$sort_order,$start_page);
      else if(eregi('^NNTPMBox$',get_class($mbox)))
        return new NNTPMailHeaders($mbox->name,$sort_order);
      else
        return new MailHeaders($mbox->name,$mbox->name_print,$sort_order,$start_page);
    }
    else
      return false;
  }
  // Searching for mailbox
  function find($name){
    if(isset($this->boxes[$name]))
      return $this->boxes[$name];
    return null;
  }
  // Searching for query
  function query($query,$type,$subject,$email,$body,$boxes){
    $mp = getImap();
    $all_headers = $mp->search($query,$type,$subject,$email,$body,$boxes);
    $qheaders = array();
    foreach($all_headers as $mbox=>$headers){
      foreach($headers as $h){
        $header = new MailHeader($mbox,$h);
        $qheader = new QueryMailHeader($header);
        $qheaders[] = $qheader;
      }
    }
    return new QueryMailHeaders($query,$qheaders);
  }
  // Searching for labels
  function getLabeled($label,$boxes){
    $mp = getImap();
    $all_headers = $mp->search_label($label,$boxes);
    $lheaders = array();
    foreach($all_headers as $mbox=>$headers){
      foreach($headers as $h){
        $header = new MailHeader($mbox,$h);
        $lheader = new LabelMailHeader($header);
        $lheaders[] = $lheader;
      }
    }
    return new LabelMailHeaders($label,$lheaders);
  }
  // Deleting of mailbox
  function delete($names){
    if(!is_array($names))
      $names = array($names);
    $for_delete = array();
    foreach($this->boxes as $box){
      foreach($names as $name){
        if($box->name == $name){
          $for_delete[] = $name;
        }
      }
    }
    $deleted = array();
    foreach($for_delete as $d){
      $mbox = $this->find($d);
      $mp = $mbox->getMP();
      if($mp->delete($d)){
        $res .= "Mailbox <b>$d</b> deleted.\n";
        $deleted[] = $d;
      }
      else
        $res .= "Can't delete <b>$d</b>.\n";
    }
    // cleanup
    reset($this->boxes);
    foreach($this->boxes as $key=>$box){
      foreach($deleted as $d){
        if($box->name == $d){
          unset($this->boxes[$key]);
        }
      }
    }
    foreach($this->names as $k=>$n){
      foreach($deleted as $d){
        if($n == $d){
          unset($this->names[$k]);
        }
      }
    }
    if($this->categories['special']){
      foreach($this->categories['special'] as $k=>$n){
        foreach($deleted as $d){
          if($n == $d){
            unset($this->categories['special'][$k]);
          }
        }
      }
    }
    if($this->categories['additional']){
      foreach($this->categories['additional'] as $k=>$n){
        foreach($deleted as $d){
          if($n == $d){
            unset($this->categories['additional'][$k]);
          }
        }
      }
    }
    return $res;
  }
  // Creating of new mailbox
  function create($name){
    if($this->find($name))
      return false;
    $mp = getIMAP();
    try{ $mp->create($name);}
    catch(Exception $e){ return $e->getMessage(); }
    
    if($name == $_SESSION['preferences']->getFccMailbox()){
      $mailbox = new MBox($_SESSION['preferences']->getFccMailbox(),'Sent Mails');
      $this->categories['special'][] = $mailbox->name;
    }
    else if($name == $_SESSION['preferences']->getDraftMailbox()){
      $mailbox = new MBox($_SESSION['preferences']->getDraftMailbox(),'Postponed Mails');
      $this->categories['special'][] = $mailbox->name;
    }
    else if($name == $_SESSION['preferences']->getRestoredMailbox()){
      $mailbox = new MBox($_SESSION['preferences']->getRestoredMailbox(),'Restored Mails');
      $this->categories['special'][] = $mailbox->name;
    }
    else{
      $mailbox = new MBox($name);
      $this->categories['additional'][] = $mailbox->name;
    }
    $this->names[] = $mailbox->name;
    $this->boxes[$mailbox->name] = $mailbox;
    
    return "Mailbox $name created.";
  }
  // Renaming of old mailbox
  function rename($name,$new_name){
    $old = $this->find($name);
    if(!$old)
      return false;
    $mp = getIMAP();
    $mp->rename($name,$new_name);
    
    unset($this->boxes[$name]);
    $old->rename($new_name);
    $this->boxes[$new_name] = $old;
  }
  function get_tree(){
    $imap = getIMAP();
    $list = $imap->listing($_SESSION['preferences']->getMailDir().'/*');
    sort($list);
    
    $tree = array();
    foreach($list as $l){
      $path = explode('/',$l);
      $count = count($path);

      $next = &$tree; $i=0;
      foreach($path as $p){
        if($i<$count-1){
          if(!$next[$p])
            $next[$p] = array();
          $next = &$next[$p];
        }
        else
          $next[$p] = $l;
        $i++;
      }
    }
    return $tree;
  }
  
  function get_choose_folders_presentation($tree=false,$key='',$margin=''){
    $res = '';
    if(!$tree){
      $tree = $this->get_tree();
      $first=true;
    }
    if(is_array($tree)){
      while(count($tree) == 1){
        list($cur_key,$cur) = each($tree);
        if(is_array($cur)){
          $tree = &$cur;
          $key .= $cur_key.'/';
        }
        else
          break;
      }
      $res .= '<tr><td colspan="2" width="100%">'.$margin.'<b>'.$key."</b></td></tr>\n";
      if(is_array($tree)){
        foreach($tree as $k=>$t){
          $new_margin = str_replace('&mdash;','&nbsp;',str_replace('|','&nbsp;',$margin)).'&nbsp;&nbsp;|&mdash;&mdash;';
          $res .= $this->get_choose_folders_presentation($t,$k,$new_margin);
        }
        $res .= "\n";
      }
      else{
        $new_margin = str_replace('&mdash;','&nbsp;',str_replace('|','&nbsp;',$margin)).'&nbsp;&nbsp;|&mdash;&mdash;';
        $res .= $this->get_choose_folders_presentation($tree,basename($tree),$new_margin);
      }
    }
    else if($tree!=$_SESSION['procmail']->inbox_name){
      $mbox = $this->find($tree);
      $res .=
        '<tr>'.
        '<td width="100%" class="nowrap">'.
        $margin.
        (($tree!=$_SESSION['preferences']->getFccMailbox() &&
          $tree!=$_SESSION['preferences']->getDraftMailbox() &&
          $tree!=$_SESSION['preferences']->getRestoredMailbox())?
         '<input type="checkbox" name="boxes[]" value="'.$tree.'" '.($mbox!==null?'checked="checked"':'').'/>':
         '&nbsp;').
        ' '.$key.' '.
        ($mbox!==null?'<sup>'.$mbox->get_info().'</sup>':'').
        '</td>'.
        '<td class="right nowrap">'.
        ($mbox!=null?
         '<a href="'.$_SERVER['PHP_SELF'].'?action=folders-show-rename&amp;mailbox='.$tree.'">rename</a>'.
         '&nbsp;'.
         '<a href="'.$_SERVER['PHP_SELF'].'?action=folders-empty&amp;mailbox='.$tree.'">empty</a>'.
         '&nbsp;'.
         '<a href="'.$_SERVER['PHP_SELF'].'?action=folders-delete&amp;mailbox='.$tree.'" class="confirm">delete</a>':
         '').
        "</td></tr>\n";
    }
    if($first)
      return '<table width="100%" class="transparent">'.$res.'</table>';
    return $res;
  }

  function get_simple_choose_folders_presentation($tree=false,$key='',$margin=''){
    $res = '';
    if(!$tree){
      $tree = $this->get_tree();
    }
    if(is_array($tree)){
      while(count($tree) == 1){
        list($cur_key,$cur) = each($tree);
        if(is_array($cur)){
          $tree = &$cur;
          $key .= $cur_key.'/';
        }
        else
          break;
      }
      $res .= $margin.'<b>'.$key."</b>\n";
      if(is_array($tree)){
        foreach($tree as $k=>$t){
          $new_margin = str_replace('&mdash;','&nbsp;',str_replace('|','&nbsp;',$margin)).'&nbsp;|&mdash;';
          $res .= $this->get_simple_choose_folders_presentation($t,$k,$new_margin);
        }
        $res .= "\n";
      }
      else{
        $new_margin = str_replace('&mdash;','&nbsp;',str_replace('|','&nbsp;',$margin)).'&nbsp;|&mdash;';
        $res .= $this->get_simple_choose_folders_presentation($tree,basename($tree),$new_margin);
      }
    }
    else if($tree!=$_SESSION['procmail']->inbox_name){
      $res .=
         $margin.
         (($tree!=$_SESSION['preferences']->getFccMailbox() &&
           $tree!=$_SESSION['preferences']->getDraftMailbox() &&
           $tree!=$_SESSION['preferences']->getRestoredMailbox())?
          '<input type="checkbox" name="boxes[]" value="'.$tree.'"'.($this->find($tree)?' checked="checked"':'').'/>':
          '&nbsp;').
         ' '.$key.
        '&nbsp;<span style="'.SMALL_STYLE.'">'.
        '<a href="'.$_SERVER['PHP_SELF'].'?action=folders-empty&amp;mailbox='.$tree.'">empty</a>'.
        '</span>'.
        "<br/>\n";
    }
    return $res;
  }
}
//////////////////////////
// Class for mail header
//////////////////////////
class MailHeader{
  var $mbox_name;
  var $key;
  var $date;
  var $id;
  var $mime_type;
  var $charset;
  var $reference;
  var $to_personals;
  var $to_mail_addresses;
  var $to_count;
  var $cc_personals;
  var $cc_mail_addresses;
  var $cc_count;
  var $bcc_personals;
  var $bcc_mail_addresses;
  var $bcc_count;
  var $from_personal;
  var $from_mail_address;
  var $newsgroups;
  var $subject;
  var $is_unseen;
  var $is_deleted;
  var $is_answered;
  var $is_urgent;
  var $size;
  var $labels;
  var $message_id;
  var $notification;
  var $_header;
  function MailHeader($mbox_name,&$header){
    $this->_header = $header;
    $this->mbox_name=$mbox_name;
    $this->key=$header['key'];
    $this->date = $header['date'];
    $this->id = $header['message-id'];
    $this->reference = $header['in-reply-to'];
    $this->mime_type = $header['content-type']['mime-type'];
   
    if(isset($header['content-type']['charset']))
      $this->charset = $header['content-type']['charset'];
    else if(is_object($_SESSION['preferences']))
      $this->charset = $_SESSION['preferences']->getCharset();
    
    // to
    $this->to_count = 0;
    if(is_array($header['to'])){
      reset($header['to']);
      // to addresses
      foreach($header['to'] as $to){
        if($to['mailbox']!='' && $to['host']!='')
          $this->to_mail_addresses[] = $to['mailbox']."@".$to['host'];
        else if($to['mailbox']!='')
          $this->to_mail_addresses[] = $to['mailbox'];
        else
          $this->to_mail_addresses[] = '';
        
        $this->to_personals[] = $to['personal-decoded'];
        $this->to_count++;
      }
    }
    // cc
    $this->cc_count = 0;
    if(is_array($header['cc'])){
      reset($header['cc']);
      // to addresses
      foreach($header['cc'] as $cc){
        if($cc['mailbox']!='' && $cc['host']!='')
          $this->cc_mail_addresses[] = $cc['mailbox']."@".$cc['host'];
        else if($cc['mailbox']!='')
          $this->cc_mail_addresses[] = $cc['mailbox'];
        else
          $this->cc_mail_addresses[] = '';
        $this->cc_personals[] = $cc['personal-decoded'];
        $this->cc_count++;
      }
    }
    // bcc
    $this->bcc_count = 0;
    if(is_array($header['bcc'])){
      reset($header['bcc']);
      // to addresses
      foreach($header['bcc'] as $bcc){
        if($bcc['mailbox']!='' && $bcc['host']!='')
          $this->bcc_mail_addresses[] = $bcc['mailbox']."@".$bcc['host'];
        else if($bcc['mailbox']!='')
          $this->bcc_mail_addresses[] = $bcc['mailbox'];
        else
          $this->bcc_mail_addresses[] = '';
        $this->bcc_personals[] = $bcc['personal-decoded'];
        $this->bcc_count++;
      }
    }
    // from address
    if(isset($header['from'][0])){
      $this->from_mail_address = $header['from'][0]['mailbox']."@".$header['from'][0]['host'];
      if($header['from'][0]['personal'] != ''){
        $this->from_personal = $header['from'][0]['personal-decoded'];
      }
    }
    // newsgroups
    if($header['newsgroups']){
      $this->newsgroups =  $header['newsgroups'];
    }
    // subject
    if($header['subject-decoded'] != ''){
      $this->subject = $header['subject-decoded'];
      if(isset($this->charset) && $header['subject-charset'] == 'default'){
        $this->subject = to_default_charset($this->subject,$this->charset);
      }
      if(isset($header['subject-charset']) &&
         $header['subject-charset'] != 'default' &&
         !isset($this->charset)){
          $this->charset = $header['subject-charset'];
      }
    }
    else
      $this->subject = "none";

    
    $this->is_unseen = ($header['unseen'] || $header['recent']);
    $this->is_deleted = $header['deleted'];
    $this->is_answered = $header['answered'];
    $this->is_urgent = strtolower($header['priority']) == 'urgent';
    $this->size = $header['size'];

    if(array_not_empty($header['flags'])){
      $this->labels = array();
      foreach($header['flags'] as $f){
        if($f){
          foreach($_SESSION['labels']->get_labels() as $k=>$l){
            if($f == $k){
              $this->labels[] = $k;
            }
          }
        }
      }
    }
    if(isset($header['notification'])){
      $this->notification = $header['notification'];
    }
    if(isset($header['message-id'])){
      $this->message_id = $header['message-id'];
    }
  }
  function has_attachment(){
    return $this->mime_type === 'multipart/mixed';
  }
  function is_encrypted(){
    return $this->mime_type === 'multipart/encrypted';
  }
  function is_signed(){
    return $this->mime_type === 'multipart/signed';
  }
  function labels_print(){
    $label_properties = $_SESSION['labels']->get_labels();
    $lbs = array();
    if($this->is_answered){
      $lbs[] = '<span style="color: red" title="Answered">A</span>';
    }
    if($this->is_urgent){
      $lbs[] = '<span style="color: red;font-weight: bold;" title="Urgent">!</span>';
    }
    foreach($this->labels as $l){
      $lbs[] =
        sprintf('<span style="color: %s" title="%s">%s</span>',
                $label_properties[$l]['color'],
                $label_properties[$l]['name'],
                $label_properties[$l]['shortcut']);
    }
    return (array_not_empty($lbs)?'<span class="labels">'.implode(',',$lbs).'&nbsp;</span>':'');
  }
  function cut_string($str){
    if(strlen($str) > 405){
      $res = preg_split("/\n/",wordwrap($str,45));
      return $res[0];
    }
    return $str;
  }
  function address_print($personal,$address,$iffull,$ifcut=false){
    $personal = trim(preg_replace('/\S+@\S+/','',$personal));
    if($iffull){
      if($personal != '' && $address=='')
        $res = $personal;
      else if($personal != '')
        $res = $personal." <".$address.">";
      else
        $res = $address;
    }
    else{
      if($personal != '')
        $res = $personal;
      else
        $res = preg_replace('/(@.+)$/','',$address);
    }
    
    return htmlspecialchars(($ifcut)?$this->cut_string($res):$res);
  }
  function to_print($index,$iffull=false,$ifcut=true){
    if(is_array($this->to_personals))
      reset($this->to_personals);
    if(is_array($this->to_mail_addresses))
      reset($this->to_mail_addresses);
    return $this->address_print($this->to_personals[$index],
                                $this->to_mail_addresses[$index],
                                $iffull);
  }
  function cc_print($index,$iffull=false,$ifcut=true){
    if(is_array($this->cc_personals))
      reset($this->cc_personals);
    if(is_array($this->cc_mail_addresses))
      reset($this->cc_mail_addresses);
    return $this->address_print($this->cc_personals[$index],
                                $this->cc_mail_addresses[$index],
                                $iffull);
  }
  function bcc_print($index,$iffull=false,$ifcut=true){
    if(is_array($this->bcc_personals))
      reset($this->bcc_personals);
    if(is_array($this->bcc_mail_addresses))
      reset($this->bcc_mail_addresses);
    return $this->address_print($this->bcc_personals[$index],
                                $this->bcc_mail_addresses[$index],
                                $iffull);
  }
  function from_print($iffull=false,$ifcut=true){
    return $this->address_print($this->from_personal,
                                $this->from_mail_address,
                                $iffull);
  }
  function get_from_address(){
    if($this->from_personal)
      return $this->from_personal.' <'.$this->from_mail_address.'>';
    else
      return $this->from_mail_address;
    return '';
  }
  function get_tos_presentation($iffull=false){
    $recipients = array();
    for($i=0;$i<$this->to_count;$i++)
      $recipients[] = '<nobr title="'.$this->to_print($i,true).'">'.$this->to_print($i,$iffull).'</nobr>';
    return implode(', ',$recipients);
  }
  function get_ccs_presentation($iffull=false){
    $recipients = array();
    for($i=0;$i<$this->cc_count;$i++)
      $recipients[] = '<nobr title="'.$this->cc_print($i,true).'">'.$this->cc_print($i,$iffull).'</nobr>';
    return implode(', ',$recipients);
  }
  function get_bccs_presentation($iffull=false){
    $recipients = array();
    for($i=0;$i<$this->bcc_count;$i++)
      $recipients[] = '<nobr title="'.$this->bcc_print($i,true).'">'.$this->bcc_print($i,$iffull).'</nobr>';
    return implode(', ',$recipients);
  }
  function get_all_recepients_presentation($iffull=false){
    $recipients = array();
    for($i=0;$i<$this->to_count;$i++)
      $recipients[] = '<nobr title="'.$this->to_print($i,true).'">'.$this->to_print($i,$iffull).'</nobr>';
    for($i=0;$i<$this->cc_count;$i++)
      $recipients[] = '<nobr title="'.$this->cc_print($i,true).'">'.$this->cc_print($i,$iffull).'(:cc)</nobr>';
    for($i=0;$i<$this->bcc_count;$i++)
      $recipients[] = '<nobr title="'.$this->bcc_print($i,true).'">'.$this->bcc_print($i,$iffull).'(:bcc)</nobr>';
    if(array_not_empty($recipients))
      return implode(', ',$recipients);
    else return 'undisclosed recipients';
  }
  function subject_print(){
      return $this->subject_short_print(false);
  }
  function subject_short_print($ifcut=true){
    $subj = html_entity_decode($this->subject,ENT_NOQUOTES,$GLOBALS['DEFAULT_CHARSET']);
    
    $strlen = strlen($subj);
    $subj = ($ifcut)?$this->cut_string($subj):$subj;
    $add_raquo = ($strlen!=strlen($subj));
    
    $subj = htmlspecialchars($subj);
    
    if($add_raquo) $subj .= " &raquo;";
    
    return $subj;
  }
  function human_date_print(){
    $time = time();
    $diff = $time - $this->date;
    if($diff < 61)
      return '1 minute ago';
    if($diff < 1800)
      return ceil($diff/60).' minutes ago';
    if($diff < 2700)
      return '&frac12; hour ago';
    if($diff < 3600)
      return '&frac34; hour ago';
    if($diff < 7200)
      return '1 hour ago';
    if($diff < 10800)
      return ceil($diff/(3600)).' hours ago';
    if($diff < 86400 && date('j',$this->date) == date('j',$time))// if <24 hours and this day and 
      return date('H:i',$this->date);
    if($diff < 15552000 && date('Y',$this->date) == date('Y',$time))// if <half year and this year
      return date('M d',$this->date);
    return date('M d, Y',$this->date);
  }
  function date_print($iffull=false){
    if($iffull)
      return date('r',$this->date);
    else{
      $time = time();
      $diff = $time - $this->date;
      if($diff < 86400 && date('j',$this->date) == date('j',$time))// if <24 hours and this day and 
        return date('H:i',$this->date);
      if($diff < 15552000 && date('Y',$this->date) == date('Y',$time))// if <falf year and this year
        return date('M d',$this->date);
      return date('M d, Y',$this->date);
    }
  }
  function print_table_row(){
    include(TMPLPATH.'MailHeader_table_row.php');
  }
  function print_thread_table_row($papa=false,$sons_count=0){
    include(TMPLPATH.'MailHeader_thread_table_row.php');
  }
}
/////////////////////////////
// Class for mail headers
/////////////////////////////
class MailHeaders{
  var $headers;
  var $count;
  var $name;
  var $name_print;
  var $sort_order;
  var $mailboxes_list;
  
  var $is_pages;
  var $num_of_pages;
  var $num_of_messages;
  var $current_page;
  var $has_next_page;
  var $has_prev_page;
  function MailHeaders($name,$name_print,$sort_order=false,$start_page=1){
    $this->name = $name;
    $this->name_print = $name_print;
    $this->sort_order = $sort_order;
    $this->mailboxes_list = get_mailboxes_names($name);
    
    $mp = $this->getMP();
    $status = $mp->status($this->name);
    $this->num_of_messages = $status['messages'];
    $this->current_page = $start_page;
    if($this->num_of_messages > $_SESSION['preferences']->getMailsPerPage() && $start_page>0){
      $this->is_pages = true;
      $this->num_of_pages = ceil($this->num_of_messages/$_SESSION['preferences']->getMailsPerPage());
      $this->current_page = min($this->num_of_pages,$start_page);

      $res = $this->get_page_from_count($this->current_page);
      $headers = $mp->sorted_headers($this->name,$this->sort_order,$res['from'],$res['count']);
    }
    else
      $headers = $mp->sorted_headers($this->name,$this->sort_order);

    $this->count = count($headers);
    $this->headers = array();
    foreach($headers as $k=>$h){
      $hh = $this->createMailHeader($this->name,$headers[$k]);
      $this->headers[$hh->key] = $hh;
    }
  }
  function getMP(){
    return getIMAP($GLOBALS['MAIL_USER_NAME'],$GLOBALS['MAIL_USER_PASSWORD']);
  }
  // factory for headers
  function createMailHeader($name,&$header){
    return new MailHeader($name,$header);
  }
  function get_header($key){
    return $this->headers[$key];
  }
  function print_presentation(){
    include(TMPLPATH.'MailHeaders_presentation.php');
  }
  function init_threads(){
    if(isset($this->threads)) return;
    $this->threads = array();
    $this->threads_count = array();

    $mp = $this->getMP();
    Cache::initThreads($this->name);
    $threads = Cache::getThreads($this->name);
    // we need sort threads as headers was sorted
    foreach($this->headers as $k=>$h){
      foreach($threads['threads'] as $k=>$ids){
        if($h->key == $ids[0]){
          foreach($ids as $id){
            $header = $this->get_header($id);
            if(!$header){
              $header = $this->createMailHeader($this->name,$mp->get_header($this->name,$id));
              $this->headers[$header->key] = $header;
            }
            $this->threads[$k][] = $header;
          }
          $this->threads_count[$k] = $threads['count'][$k];
          unset($threads['threads'][$k]);
        }
      }
    }
    /*
    foreach($this->headers as $header){
      $subject = strtolower(preg_replace(array('/re:/i','/fwd?:/i','/[\s()!,.]/'),
                                         array('','',''),
                                         $header->subject));
      $this->threads[$subject][] = $header;
      $this->threads_count[$subject]++;
    }
    */
  }
  function get_page_from_count($page_num){
    $res = array();
    $res['from'] = $this->num_of_messages-($_SESSION['preferences']->getMailsPerPage()*$page_num)+1;
    $res['count'] = $_SESSION['preferences']->getMailsPerPage()-1;
    if($res['from'] <= 0){
      $res['from'] = 1;
      $res['count'] = $this->num_of_messages%$_SESSION['preferences']->getMailsPerPage()-1;
    }
    return $res;
  }
  function print_pages_row(){
    if($this->is_pages){
      $pages = '<u>Pages</u>: ';
      for($i=1;$i<=$this->num_of_pages;$i++){
        if($i == $this->current_page)
          $pages .= " <b>$i</b> ";
        else{
          $res = $this->get_page_from_count($i);
          $pages .=
             ' <a href="'.$_SERVER['PHP_SELF'].'?action=show-folder&amp;mailbox='.$this->name.
             ($this->sort_order?'&amp;sort_order='.$this->sort_order:'').
             '&amp;start_page='.$i.'" title="'.$res['from'].' - '.($res['from']+$res['count']).'"'.
             '>'.$i.'</a>';
        }
      }
      print '<tr><td colspan="6">'.$pages.'</td></tr>';
    }
  }
  function print_controls_row($move=true){
    include(TMPLPATH.'MailHeaders_controls_row.php');
  }
}
/////////////////////////////
// Class for mail headers thread
/////////////////////////////
class MailHeadersThread{
  var $mailbox_name;
  var $key;
  var $thread;
  function MailHeadersThread($mp,$mailbox_name,$key){
    $this->mp = $mp;
    $this->mailbox_name = $mailbox_name;
    $this->key = $key;
    $threads = Cache::getThreads($this->mailbox_name);
    foreach($threads['tree'] as $tree){
      if(in_array_recursive($this->key,$tree)){
        $this->thread = $tree;
        break;
      }
    }
  }
  function has_thread(){ return isset($this->thread); }
  function get_presentation($type=false,$tree=-1){
    if($type == 'preview')
      $action = 'preview-mail';
    else
      $action = 'read-mail';
    if($tree == -1) $tree = $this->thread;
    $was_ol=false;
    $res = '';
    foreach($tree as $t){
      if(is_array($t)){
        $res .= '<div style="margin-left:15px;">';
        $res .= $this->get_presentation($type,$t);
        $res .= '</div>';
      }
      else{
        $header = $this->mp->get_header($this->mailbox_name,$t);
        $h = new MailHeader($this->mailbox_name,$header);
        $res .= $h->key.'. ';
        if($h->key == $this->key){
          $res .= '<i class="gray">'.$h->subject_print().', '.$h->from_print().', '.$h->human_date_print().'</i>';
        }
        else{
          $res .= '<a href="index.php?action='.$action.'&mailbox='.$this->mailbox_name.'&mailkey='.$t.'">';
          $res .= $h->subject_print();
          $res .= '</a> ';
          $res .= '<i>'.$h->from_print().', '.$h->human_date_print().'</i>';
        }
        if($h->has_attachment()){
          $res .= ' <img src="./images/attachment.gif" alt="attachment"/>';
        }
        $res .= '<br/>';
      }
    }
    $res .= '';
    return $res;
  }
}

/////////////////////////////
// Class for nntp mail headers
/////////////////////////////
class NNTPMailHeader extends MailHeader{

  function NNTPMailHeader($name,&$header){
    parent::MailHeader($name,$header);
  }
  function print_table_row(){
    include(TMPLPATH.'NNTPMailHeader_table_row.php');
  }
}
class NNTPMailHeaders extends MailHeaders{
  function NNTPMailHeaders($name,$sort_order=SORT_BY_NUMBER){
    parent::MailHeaders($name,$name,$sort_order,-1);
  }
  function getMP(){
    return getNNTP();
  }
  // factory for headers
  function createMailHeader($name,&$header){
    return new NNTPMailHeader($name,$header);
  }
  function print_presentation(){
    include(TMPLPATH.'NNTPMailHeaders_presentation.php');
  }
}
///////////////////////////////////////
// Sub-classes for query mail headers
///////////////////////////////////////
class QueryMailHeader extends MailHeader{
  function QueryMailHeader(&$header){
    parent::MailHeader($header->mbox_name,$header->_header);
  }
  function print_table_row(){
    include(TMPLPATH.'QueryMailHeader_table_row.php');
  }
}
class QueryMailHeaders extends MailHeaders{
  function QueryMailHeaders($name,&$headers){
    $this->name = $name;
    $this->headers = $headers;
    $this->count = count($headers);
    $this->mailboxes_list = get_mailboxes_names();
  }
  function print_presentation(){
    include(TMPLPATH.'QueryMailHeaders_presentation.php');
  }
  function print_controls_row($move=true){
    include(TMPLPATH.'QueryMailHeaders_controls_row.php');
  }
}
/////////////////////////////////////
// Sub-classes for sent mail headers
/////////////////////////////////////
class SentMailHeader extends MailHeader{
  var $tocc;
  function SentMailHeader($mbox_name,&$header){
    parent::MailHeader($mbox_name,$header);
    $max_count=3;
    $count = 0;
    $tocc = array();
    for($i=0;$i<$this->to_count;$i++){
      if($count<$max_count)
        $tocc[] = $this->to_print($i,false,false);
      $count++;
    }
    for($i=0;$i<$this->cc_count;$i++){
      if($count<$max_count)
        $tocc[] = $this->cc_print($i,false,false);
      $count++;
    }
    if($count>$max_count)
      $tocc[] = '&#133;';
    $this->tocc = implode(', ',$tocc).(($count>$max_count)?'&#133;':'');
  }
  function print_table_row(){
    include(TMPLPATH.'SentMailHeader_table_row.php');
  }
}
class SentMailHeaders extends MailHeaders{
  function SentMailHeaders($name,$sort_order=SORT_BY_NUMBER,$start_page=1){
    parent::MailHeaders($name,'Sent Mails',$sort_order,$start_page);
  }
  // factory for headers
  function createMailHeader($name,&$header){
    return new SentMailHeader($name,$header);
  }
  function print_presentation(){
    include(TMPLPATH.'SentMailHeaders_presentation.php');
  }
}
/////////////////////////////////////
// Sub-classes for draft mail headers
/////////////////////////////////////
class DraftMailHeader extends SentMailHeader{
  function DraftMailHeader($mbox_name,&$header){
    parent::SentMailHeader($mbox_name,$header);
  }
  function print_table_row(){
    include(TMPLPATH.'DraftMailHeader_table_row.php');
  }
}
class DraftMailHeaders extends SentMailHeaders{
  function DraftMailHeaders($name,$sort_order=SORT_BY_NUMBER,$start_page){
    parent::MailHeaders($name,'Draft',$sort_order,$start_page);
  }
  // factory for headers
  function createMailHeader($name,&$header){
    return new DraftMailHeader($name,$header);
  }
}
///////////////////////////////////////
// Sub-classes for labeled mail headers
///////////////////////////////////////
class LabelMailHeader extends MailHeader{
  function LabelMailHeader(&$header){
    parent::MailHeader($header->mbox_name,$header->_header);
  }
  function print_table_row(){
    include(TMPLPATH.'LabelMailHeader_table_row.php');
  }
}
class LabelMailHeaders extends MailHeaders{
  function LabelMailHeaders($label,&$headers){
    $this->label = $label;
    $this->name = $label;
    foreach($_SESSION['labels']->get_labels() as $k=>$v){
      if($k == $label){
        $this->name = $v['name'];
        $this->color = $v['color'];
        break;
      }
    }
    $this->headers = $headers;
    $this->count = count($headers);
  }
  function print_presentation(){
    include(TMPLPATH.'LabelMailHeaders_presentation.php');
  }
}

///////////////////////////////
// Class for part of mail
///////////////////////////////
class MailPart{
  var $plain_header;
  var $part;
  var $body;
  var $size;
  var $mime_type;
  var $parent_mime_type;
  var $filename;
  var $ifattach;
  var $charset;
  function MailPart($key,&$part){
    $this->plain_headers = $part['header']['all'];
    
    $this->part = $key;

    if($part['body']){
      if(eregi('base64',$part['header']['encoding']))
        $this->body = imap_base64($part['body']);
      else if(eregi('quoted-printable',$part['header']['encoding']))
        $this->body = imap_qprint($part['body']);
      else
        $this->body = $part['body'];
      $this->size = strlen($this->body)*3/4;
    }
    else{
      $this->body = $part['body'];
      $this->size = 0;
    }

    $this->cid = $part['header']['content-id'];

    $this->mime_type = $part['header']['content-type']['mime-type'];
    
    // if we have disposition
    if($part['header']['content-disposition']){
      if($part['header']['content-disposition']['attachment'])
        $this->ifattach = true;
      if($part['header']['content-disposition']['filename']){
        $arr = imap_string_decode($part['header']['content-disposition']['filename']);
        $this->filename = $arr['decoded'];
        if($this->filename == '')
          $this->filename = $part['header']['content-disposition']['filename'];
        // small hack for wrong mime types
        if($this->filename != ''){
          if(!preg_match('@image/@i',$this->mime_type)){
            if(preg_match('/\.jpe?g/i',$this->filename)){
              $this->mime_type = 'image/jpeg';
            }
            else if(preg_match('/\.gif/i',$this->filename)){
              $this->mime_type = 'image/gif';
            }
            else if(preg_match('/\.png/i',$this->filename)){
              $this->mime_type = 'image/png';
            }
          }
        }
      }
    }
    else
      $this->ifattach = false;
    
    if($part['header']['content-type']['charset'] &&
       !eregi('us-ascii',$part['header']['content-type']['charset'])){
      $this->charset = $part['header']['content-type']['charset'];
    }
    
    // untitled file
    if($this->filename == ''){
      if($part['header']['content-type']['name']){
        $arr = imap_string_decode($part['header']['content-type']['name']);
        $this->filename = $arr['decoded'];
        if($this->filename == "")
          $this->filename = $this->filename = $part['header']['content-type']['name'];
      }
      else if($this->if_rfc822())
        $this->filename = 'RFC-822 Message';
    }
    
    // mime type hacks
    if(!$this->mime_type)
      $this->mime_type = 'text/plain';
    else if($this->mime_type === 'application/octet-stream'){
      if(preg_match('/\\.html?$/i',$this->filename) &&
         preg_match('/<(html|body|table)[^>]*>/i',$this->body)){
        $this->mime_type = 'text/html';
      }
    }
    
    // default charset
    if(!isset($this->charset)){
      if(is_object($_SESSION['preferences']))
        $this->charset = $_SESSION['preferences']->getCharset();
      else
        $this->charset = $GLOBALS['DEFAULT_CHARSET'];
    }
  }
  function get_charset(){
    return $this->charset;
  }
  // get body converted to default charset
  function get_body(){
    return to_default_charset($this->body,$this->charset);
  }
  // get "safe" html body 
  function get_safe_body(){
      require_once(INCPATH.'safe_html.php');
      $safehtml =& new HTML_Safe();
      return $safehtml->parse($this->get_body());
  }
  // if we can show part
  function if_printable(){
    return
      !$this->ifattach &&
      $this->mime_type == 'text/html' ||
      ($this->mime_type == 'text/plain' && !$this->if_multipart()) ||
      $this->mime_type == 'message/delivery-status';
  }
  function if_simple_printable(){
    return
      !$this->ifattach &&
      $this->mime_type == 'text/plain' ||
      ($this->mime_type == 'text/html' && !$this->if_multipart()) ||
      $this->mime_type == 'message/delivery-status';
  }
  function if_multipart(){
    return $this->parent_mime_type == 'multipart/alternative';
  }
  function if_text_multipart(){
    return $this->mime_type == 'text/plain' && $this->if_multipart();
  }
  function if_pgp_signature(){
    return $this->mime_type == 'application/pgp-signature';
  }
  function if_pgp_encrypted(){
    return $this->mime_type == 'application/pgp-encrypted';
  }
  function if_rfc822(){
    return $this->mime_type == 'message/rfc822';
  }
  function if_attachment(){
    return
      !$this->if_printable() &&
      strpos('multipart',$this->mime_type)===false &&
      strpos('message/disposition-notification',$this->mime_type)===false &&
      strpos('application/pgp-encrypted',$this->mime_type)===false &&
      !$this->if_text_multipart();
  }
  function if_for_forward(){
    // debug($this->ifattach);
    return
      ($this->if_attachment() && !$this->if_pgp_signature()) ||
      ($this->if_printable() && !$this->if_multipart());
  }
  function nohtml($str){
    return preg_replace('/&amp;#([0-9]*);/','&#$1;',htmlspecialchars($str));
  }
  function nbsp($str){
    return str_replace('  ',' &nbsp;',$str);
  }
  function handle_replies($text,$wrap=false){
    $lines = preg_split("/\n/",$text);
    $res = '';
    foreach($lines as $l){
      // print htmlspecialchars($l)."<br/>";
      if(eregi("^((>[ ]*)+)(.*)",$l,$m)){
        $depth = strlen(str_replace(' ','',$m[1]));
        
        if($wrap) $tmp = wordwrap($this->nohtml($l."\n"),100);
        else $tmp = $this->nohtml($l."\n");
        
        $res2 = explode("\n",$tmp);
        if(count($res2)==1){
          $res2 = $tmp;
        }
        else{
          $was_empty=false;
          foreach($res2 as $k=>$v) if($v==''){unset($res2[$k]);$was_empty=true;}
          $res2 = implode("\n".$this->nohtml($m[1]),$res2);
          if($was_empty)
            $res2 .= "\n";
        }
        $res .= '<span class="replies'.((($depth-1)%9)+1).'">'.$this->nbsp($res2).'</span>';
      }
      else{
        if($wrap) $res .= $this->nbsp(wordwrap($this->nohtml($l."\n"),100));
        else $res .= $this->nbsp($this->nohtml($l."\n"));
      }
    }
    return nl2br($res);
  }
  // find part number by content id
  function find_part_by_cid($cid){
    foreach($this->read_mail->parts as $p){
      if($cid === $p->cid)
        return $p->part;
    }
    return false;
  }
  // creating thumbnail for image
  function get_thumbnail(){
    if($this->thumbnail) return $this->thumbnail;
    if(strpos($this->mime_type,'image/') !== 0) return null;
    
    $tmpname = TempFileManager::getTempFile('thumb');
    if(file_put_contents($tmpname,$this->body)){
      $size = @getimagesize($tmpname);
      $w = $size[0];
      $h = $size[1];
      if($w > 180 || $h > 180){
        $out = execute_process("convert -size 180x180 $tmpname\[0\] -resize 180x180 +profile '*' -");
        if($out['return'] != 0){
          $this->thumbnail = file_get_content('./images/mime-type/image.gif');
        }
        else
          $this->thumbnail = $out['stdout'];
      }
      else
        $this->thumbnail = $this->body;
    }
    unlink($tmpname);
    return $this->thumbnail;
  }
  // simle presentation
  function get_simple_presentation($mailbox,$mailkey){
    $res = '';
    if($this->if_printable() || $this->if_text_multipart()){
      $text = '';
      if(eregi('text/html',$this->mime_type)){
        $text = html2text($this->get_body(),LINE_WIDTH,true);
      }
      else{
        $text = match_links(
                  htmlspecialchars(
                    wordwrap(
                      trim(preg_replace("/(\s+\n){3,}/",'',$this->get_body())),LINE_WIDTH)));
      }
      
      $res .= nl2br($text);
    }
    else if($this->if_attachment()){
      if($this->filename)
        $res .= '<b>'.h($this->filename).'</b> ';
      $res .= '<i>'.$this->mime_type.'</i><br/>';
      if($this->size > 0)
        $res .= bytes2string($this->size).' ';

      if($this->if_pgp_signature() && isset($this->signature_info)){
        if(isset($this->signature_info['error']))
          $res .= '<div style="'.RED_STYLE.'">'.nl2br(h($this->signature_info['error'])).'</div>';
        else
          $res .= '<div>'.nl2br(h($this->signature_info['info'])).'</div>';
      }

      if($this->need_gpg_passphrase){
        $res .= '<hr/>';
        $res .= '<form action="'.$_SERVER['PHP_SELF'].'" method="post">';
        $res .= '<input type="hidden" name="mailbox" value="'.$mailbox.'"/>';
        $res .= '<input type="hidden" name="mailkey" value="'.$mailkey.'"/>';
        $res .= '<input type="hidden" name="action" value="gnupg-verify-passphrase"/>';
        $res .= 'Enter private key passphrase<br/>in order to decrypt:';
        $res .= '<br/>';
        $res .= '<input type="password" name="password"/>';
        $res .= '&nbsp;';
        $res .= '<input value="ok" type="submit"/>';
        $res .= '<br/>';
        $res .= '</form>';
    }
      
      // we show images/html in browser
      if(eregi('text/',$this->mime_type) || eregi('image/',$this->mime_type)){
        $res .= ' '.
          '<a href="'.$_SERVER['PHP_SELF']."?action=view-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey".
          "&amp;part=".$this->part.'&amp;'.sid().'">view</a>';
      }
      $res .= ' <a href="'.$_SERVER['PHP_SELF'].'?action=get-part&amp;'.
        "mailbox=$mailbox&amp;mailkey=$mailkey&amp;part=".$this->part.'&amp;'.sid().'" '.
        'title="click to save">download</a>';
    }
    return $res;
  }
  // regular presentation
  function get_presentation($mailbox,$mailkey,$for_print=false){
    $res = '';
    if($this->if_printable()){
      if(eregi('text/html',$this->mime_type)){
        require_once(INCPATH.'safe_html.php');
        $safehtml =& new HTML_Safe();
        
        $res .= '<div class="message">';
        $res .= $safehtml->parse($this->get_body());
        
        // $res = preg_replace('/<([\/]?)html/i','<\\1xhtml',$this->get_body());
        // $res = preg_replace('/<([\/]?)body/i','<\\1div',$res);
        $res = preg_replace('/<a href="mailto:([^"?]+)"/i',
                            '<a href="'.$_SERVER['PHP_SELF'].'?action=compose&to=$1&'.sid().'" '.
                            'title="compose mail to $1"',
                            $res);
        if(preg_match_all('/(src|background)="cid:([^"]*)"/i',$res,$match)){
          foreach($match[2] as $m){
            $p = $this->find_part_by_cid($m);
            if($p){
              $res = preg_replace('/(src|background)="cid:'.preg_quote($m).'"/i',
                                  '$1="'.$_SERVER['PHP_SELF'].
                                  "?action=get-part&mailbox=$mailbox&mailkey=$mailkey&part=".$p.'"',$res);
            }
          }
        }
        $res .= '</div>';
      }
      else if($for_print){
          $res .= '<div class="message mono">'.$this->handle_replies(trim($this->get_body())).'</div>';
      }
      else{
          $res .= '<div class="message mono">';
          $res .= match_links($this->handle_replies(trim($this->get_body())));
          $res .= '</div>';
      }
      // add 'save' link
      if(!$for_print){
        if($this->if_multipart()){
          $res .=
            '<a href="'.$_SERVER['PHP_SELF'].
            "?action=view-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey&amp;part=".previous_part($this->part).'" title="click save as ..." class="small">'.
            'view text part</a> &nbsp; ';
        }
        $res .=
           '<a href="'.$_SERVER['PHP_SELF'].
           "?action=view-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey&amp;part=".$this->part.'" title="click save as ..." class="small">'.
           'save</a>';
      }
    }
    else if($this->if_attachment()){
      $res  = '<table class="top center" cellpadding="2">';
      //if($this->structure->description)
      //  $res .= 'Description :'.$this->structure->description."<br/>\n";

      $res .= '<tr><th class="top center">';

      if(eregi('image/',$this->mime_type)){
        $tmpname = TempFileManager::getTempFile('img');
        file_put_contents($tmpname,$this->body);
        $size = @getimagesize($tmpname);
        unlink($tmpname);
        if($size[0] > MAX_IMG_WIDTH){
          $w = MAX_IMG_WIDTH;
          $h = intval((MAX_IMG_WIDTH*$size[1])/$size[0]);
        }
        else{
          $w = $size[0];
          $h = $size[1];
        }
        // Link for javascript little window
        $res .=
          '<a href="'.$_SERVER['PHP_SELF']."?action=view-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey&amp;part=".$this->part.'&'.sid().'">'.
          //'<a onclick="rs('."'".$_SERVER['PHP_SELF']."?action=view-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey".
          //"&amp;part=".$this->part.'&'.sid()."',".($w+40).','.($h+40).');">'.
          
          '<img class="enlarge" src="'.$_SERVER['PHP_SELF']."?action=get-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey".
          "&amp;part=".$this->part.'&thumbnail=ok&'.sid().'" '.
          'title="'.strtolower($this->mime_type).'" alt="'.h($this->filename).'" name="'.$this->filename.'"/>'.
          '</a>';
      }
      else{
        $res .= '<img src="images/mime-type/'.(get_mime_icon($this->mime_type)).'" title="'.strtolower($this->mime_type).'" alt="'.strtolower($this->mime_type).'"/>';
      }
      
      $res .= '</th><td class="middle">';

      // signature info
      if($this->if_pgp_signature() && isset($this->signature_info)){
        if(isset($this->signature_info['error']))
          $res .= '<div class="small red">'.nl2br(h($this->signature_info['error'])).'</div>';
        else
          $res .= '<div class="small">'.nl2br(h($this->signature_info['info'])).'</div>';
      }
      else{
        $res .= '<b>'.($this->filename?$this->filename:"Untitled part").'</b><br/>';
        $res .= bytes2string($this->size).' ';
      }

      // we show images/html in browser
      if(eregi('text/',$this->mime_type) || eregi('image/',$this->mime_type)){
        $res .= ' '.
          '<a href="'.$_SERVER['PHP_SELF']."?action=view-part&amp;mailbox=$mailbox&amp;mailkey=$mailkey".
          "&amp;part=".$this->part.'&'.sid().'" target="_blank">view</a>';
      }
      
      // can be converted to html
      if($converted_to = ToHtmlConverter::is_supported($this->mime_type)){
        $res .= 
          '<a href="'.$_SERVER['PHP_SELF'].'?action=view-part&'.
          "mailbox=$mailbox&mailkey=$mailkey&part=".$this->part.'&'.sid().'" '.
          'title="view as HTML">view as '.$converted_to.'</a>';
      }

      if($this->size > 0){
        
        $res .= ' '.
          '<a href="'.$_SERVER['PHP_SELF'].'?action=get-part&'.
          "mailbox=$mailbox&mailkey=$mailkey&part=".$this->part.'&'.sid().'" '.
          'title="click to save">download</a>';
        
        $res .=
          ' <a onclick="rs('."'".$_SERVER['PHP_SELF']."?action=scan-virus-part&mailbox=$mailbox&mailkey=$mailkey".
          "&part=".$this->part."',".'350,50);">'.
          'scan for viruses'.
          '</a>';
      }
     
      $res .= '</td></tr>';
      $res .= '</table>';
    }
    // if error
    if($this->error)
      $res = '<div class="red small" style="float:right">'.h($this->error).'</div>'.$res;
    // if decrypted
    if($this->decrypted)
      $res = '<img src="./images/encrypted.gif" title="decrypted" alt="decrypted" style="float:right"/>'.$res;
    // gpg passphrase form
    if($this->need_gpg_passphrase){
      $res .= '<form action="'.$_SERVER['PHP_SELF'].'" method="post">';
      $res .= '<input type="hidden" name="mailbox" value="'.$mailbox.'"/>';
      $res .= '<input type="hidden" name="mailkey" value="'.$mailkey.'"/>';
      $res .= '<input type="hidden" name="action" value="gnupg-verify-passphrase"/>';
      $res .= '<table class="notice">';
      $res .= '<tr><td class="right">';
      $res .= 'Enter private key passphrase<br/>in order to decrypt:';
      $res .= '</td><td class="middle">';
      $res .= '<input type="password" name="password"/>';
      $res .= '&nbsp;';
      $res .= '<input value="ok" type="submit"/>';
      $res .= '</td></tr></table>';
      $res .= '</form>';
    }
    
    
    return $res;
  }
}
// previous part
function previous_part($part){
  $arr = explode('.',$part);
  $arr[count($arr)-1]--;
  return implode('.',$arr);
}
///////////////////////////
// Getting single part
///////////////////////////
function get_part($mailbox,$mailkey,$part){
  $mp = getIMAP();
  $mail = $mp->get_mail($mailbox,$mailkey);
  $parts = explode(".",$part);
  foreach($parts as $p){
    if(!$mail)
     trigger_error("$mailbox:$mailkey".'->'."$part is null.<br/>\n",
                   E_USER_ERROR);
    if(array_not_empty($mail['parts']))
      $mail = $mail['parts'][$p];
  }
  $mail_part = new MailPart($part,$mail);
  return $mail_part;
}
function print_parts(&$mail,$key=false){
  print "<b>$key</b> ".$mail['header']['content-type']['mime-type'];
  if(is_array($mail['parts'])){
    print '<ul>';
    foreach($mail['parts'] as $k=>$p){
      print '<li>';
      print_parts($p,$key?"$key.$k":$k);
      print '</li>';
    }
    print '</ul>';
  }
}
// getting all parts of message (recursive helper)
function get_parts(&$mail,$key=false){
  $arr = array();
  if(is_array($mail['parts'])){
    foreach($mail['parts'] as $k=>$p){
      $ret_arr = &get_parts($p,$key?"$key.$k":$k);
      
      foreach($ret_arr as $kk=>$pp){
        if(!isset($pp->parent_mime_type) &&
           (strpos("$pp->part","$key") === 0 ||
            ($key===false && strpos($pp->part,'.') === false))){
          $ret_arr[$kk]->parent_mime_type = $mail['header']['content-type']['mime-type'];
        }
      }
      
      $arr = array_merge($arr,$ret_arr);
    }
  }
  else
    $arr[] = new MailPart($key?$key:1,$mail);
 
  return $arr;
}
/////////////////////
// Reading of mail
/////////////////////
class ReadMail{
  var $_mailbox;
  var $mailbox_name;
  var $mailbox_name_print;
  var $ifnntp;
  var $header;
  var $key;
  var $parts_count;
  var $parts;
  var $iffirst;
  var $iflast;
  var $mailboxes_list;
  var $charset;
  function ReadMail(&$mailbox,$key){
    if($mailbox == false)
      throw new Exception('Mailbox is null');
    if(eregi('^NNTPMBox$',get_class($mailbox)))
      $this->ifnntp = true;
    
    $this->_mailbox = $mailbox;
    $this->mailbox_name = $mailbox->name;
    $this->mailbox_name_print = $mailbox->name_print;
    
    $this->key = $key;
    
    $mp = $mailbox->getMP();
    // get parsed mail
    $mail = $mp->get_mail($this->mailbox_name,$key);
    // if(is_test_user()) print_parts($mail);
    
    $this->header = new MailHeader($this->mailbox_name,$mail['header']);
    // NNTP has no threads
    if(!$this->ifnntp && $_SESSION['preferences']->getDefaultView() == 'thread'){
      $this->thread = new MailHeadersThread($mp,$this->mailbox_name,$this->key);
    }
    // get parts
    $this->parts = get_parts($mail);


    // GnuPG support: decrypt parts if its encrypted and verify signature
    if($_SESSION['preferences']->getUseGnuPG()){
      require_once('simple_gpg.php');
      $gpg = new SimpleGPG();
      
      $new_parts = array();
      $was_encrypted = false;
      $changed = false;
      foreach($this->parts as $part_key=>$part){
        if($part->if_pgp_encrypted()){
          $was_encrypted = true;
        }
        // if was pgp-encrypted part befor or inline PGP message
        else if($was_encrypted || $gpg->isInlinePGPMessage($part->body)){
          
          $ret = $gpg->decrypt($part->body);
          
          if($ret['returnval'] === 0){
            $parser = new MailParser();
            $mail = $parser->parse_mail($ret['plaintext']);
            // just body
            if($mail === false){
              list($before,,$after) = $gpg->separatePGPMessage($part->body);
              
              if($before != ''){
                $dummy_part = new MailPart(count($new_parts)+1,$dummy_mail=array());
                $dummy_part->mime_type = $part->mime_type;
                $dummy_part->body = $before;
                $new_parts[] = $dummy_part;
              }
              
              $part->part = count($new_parts)+1;
              $part->body = $ret['plaintext'];
              $part->decrypted = true;
              $new_parts[] = $part;
              
              if($after != ''){
                $dummy_part = new MailPart(count($new_parts)+1,$dummy_mail=array());
                $dummy_part->mime_type = $part->mime_type;
                $dummy_part->body = $after;
                $new_parts[] = $dummy_part;
              }
            }
            else{
              // get parts
              $decrypted_parts = get_parts($mail);
              foreach($decrypted_parts as $k=>$p){
                $decrypted_parts[$k]->decrypted = true;
              }
              // add parts
              $new_parts = array_merge($new_parts,$decrypted_parts);
            }
            // if encryption signid
            if(isset($ret['GnuPGSignature']) && is_object($ret['GnuPGSignature'])){
              // dummy signature part
              $sig_part = new MailPart(count($new_parts)+1,$sig_mail=array());
              $sig_part->ifattach = true;
              $sig_part->mime_type = 'application/pgp-signature';
              
              $sig_part->signature_info = array('info'=>$ret['signature'][0]."\n".$ret['signature'][1]);
            
              $new_parts[] = $sig_part;
            }
            
            // trigger
            $changed = true;
            $was_encrypted = false;
          }
          else{
            if(Cache::haveCachedGPGPassphrase())
              $part->error = 'Can\'t decrypt, probably not your private key.';
            else
              $part->need_gpg_passphrase = true;
          }
        }
        else{
          // signature
          if($part->if_pgp_signature() || $gpg->isInlinePGPSignature($part->body)){

            // hack for inline
            if(!$part->if_pgp_signature() && $gpg->isInlinePGPSignature($part->body)){
              $new_parts[] = $part;
              list($before,$signed,$after) = $gpg->separatePGPSignature($part->body);
              $ret = $gpg->verifyInline($signed);

              // part is new "dummy" signature part
              $part = new MailPart(count($new_parts)+1,$sig_mail=array());
              $part->ifattach = true;
              $part->mime_type = 'application/pgp-signature';
            }
            else{
              // take previous for signature part
              $for_verify = $mail['parts'][$part->part-1]['source']; 
              $signature = $part->body; 
              
              $ret = $gpg->verify($for_verify,$signature);
            }

            if($ret['returnval'] === 0){
              $part->signature_info = array('info'=>$ret['signature'][0]."\n".$ret['signature'][1]);
            }
            else{
              if(is_object($ret['GnuPGSignature']))
                $part->signature_info = array('error'=>$ret['signature'][0]."\n".$ret['signature'][1]);
              else
                $part->signature_info = array('error'=>'Signature verification error.');
            }

            $changed = true;
            $new_parts[] = $part;
          }
          else
            $new_parts[] = $part;
        }
      }
      if($changed)
        $this->parts = $new_parts;
    }

    // set $this for some of mails
    foreach($this->parts as $k=>$part){
      if($part->if_printable() && eregi('/html',$part->mime_type)){
        $this->parts[$k]->read_mail =& $this;
      }
    }
    
    if(is_object($_SESSION['preferences']))
      $this->charset = $_SESSION['preferences']->getCharset();
    else
      $this->charset = $GLOBALS['DEFAULT_CHARSET'];

    if($mail['header']['content-type']['charset'] &&
       !eregi('us-ascii',$mail['header']['content-type']['charset'])){
      $this->charset = $mail['header']['content-type']['charset'];
    }
    else{
      foreach($this->parts as $p){
        if($p->if_printable()){
          $this->charset = $p->get_charset();
          break;
        }
      }
    }
    if($mail['header']['subject-charset'] != 'default' && $this->charset !== $mail['header']['subject-charset']){
      $this->charset = $mail['header']['subject-charset'];
    }

    $this->parts_count = count($this->parts);
    reset($this->parts);
    $this->iffirst = ($this->key == 1);
    $status = $mp->status($this->mailbox_name);
    $this->iflast  = ($this->key == $status['messages']);
    $this->mailboxes_list = get_mailboxes_names($this->mailbox_name);
  }
  function get_part($part){
    foreach($this->parts as $p){
      if($p->part == $part) return $p;
    }
    return false;
  }
  function get_charset(){
    return $this->charset;
  }
  function get_full_mail_header(){
    return $this->header->_header['all'];
  }
  function print_presentation(){
    include(TMPLPATH.'ReadMail_presentation.php');
  }
  function print_preview_presentation(){
    include(TMPLPATH.'ReadMail_preview_presentation.php');
  }
  function print_printable_presentation(){
    include(TMPLPATH.'ReadMail_printable_presentation.php');
  }
  function print_controls_table(){
    include(TMPLPATH.'ReadMail_controls.php');
  }
}

?>
Return current item: CsWebmail