chimera-mark2-core-release/core/fox/mailClient.php

258 lines
9.1 KiB
PHP

<?php
namespace fox;
/**
* Class fox\mailClient
**/
class mailClient {
protected ?mailAccount $acct;
protected $conn;
protected $stat;
protected $list;
public array $messages=[];
public function __construct(?mailAccount $a) {
$this->acct = $a;
}
public function getList($folder=null, $criteria="UNSEEN", $range=null) {
if (strtolower($this->acct->rxProto) != 'imap') { throw new \Exception("Protocol '".$this->acct->rxProto."' not implemented yet");}
if (empty($folder)) {
$folder=$this->acct->rxFolder;
if (empty($folder)) {$folder = 'INBOX';}
}
$this->conn = (\imap_open("{".$this->acct->rxServer.":".$this->acct->rxPort."/".strtolower($this->acct->rxProto).(($this->acct->rxSSL==false)?"/novalidate-cert":"/ssl")."}$folder",$this->acct->rxLogin,$this->acct->rxPassword));
if (!$this->conn)
{
throw new \Exception("Connection to '".$this->acct->rxServer."' failed");
}
$this->stat = (array)imap_mailboxmsginfo($this->conn);
$this->list = imap_search($this->conn, $criteria, SE_UID);
$this->messages=[];
}
public function getMessages() {
$this->messages = [];
if (empty($this->list)) { return; }
foreach ($this->list as $idx) {
array_push($this->messages, $this->getMessage($idx));
}
}
public function getMessage($uid) {
$message = new mailMessage();
$num = imap_msgno ( $this->conn , $uid );
$msg = imap_fetch_overview ( $this->conn , $num)[0];
if (property_exists($msg, "in_reply_to")) {
try {
$message->addRecipient(self::decodeHeader($msg->to));
} catch (\Exception $e) {}
}
$message->account = $this->acct;
$message->addSender(self::decodeHeader($msg->from));
$message->messageId = $msg->message_id;
$message->udate = $msg->udate;
$message->subject = self::decodeHeader(imap_utf8($msg->subject));
$message->refNum=$num;
$message->conn=$this->conn;
$message->direction='RX';
if (property_exists($msg, "in_reply_to")) { $message->inReplyTo=$msg->in_reply_to;};
if (property_exists($msg, "references")) { $message->references =$msg->references;}
$pheaders = imap_rfc822_parse_headers(imap_fetchheader($this->conn, $num));
$struct = imap_fetchstructure ($this->conn, $num);
$parts_found = null;
$this->search_parts($struct,null,$parts_found);
try {
if (property_exists($pheaders, "fromaddress")) { foreach (explode(",", $pheaders->fromaddress) as $item) { $message->addSender(self::decodeHeader($item)); }; }
} catch(\Exception $e) {}
try {
if (property_exists($pheaders, "toaddress")) { foreach (explode(",", $pheaders->toaddress) as $item) { $message->addRecipient(self::decodeHeader($item)); }; }
} catch(\Exception $e) {}
try {
if (property_exists($pheaders, "ccaddress")) { foreach (explode(",", $pheaders->ccaddress) as $item) { $message->addCC(self::decodeHeader($item)); }; }
} catch(\Exception $e) {}
if (isset($parts_found["type"]["PLAIN"]))
{
$text = imap_fetchbody ($this->conn, $num, $parts_found["type"]["PLAIN"],FT_PEEK );
$encoding = $parts_found[$parts_found["type"]["PLAIN"]]["encoding"];
$text_encoding = $parts_found[$parts_found["type"]["PLAIN"]]["text-encoding"];
if ($encoding == 3)
{
$text = base64_decode($text);
} elseif ($encoding == 4) {
$text=quoted_printable_decode($text);
}
if ($text_encoding == 'default')
{
$msg_plain_text = $text;
} else {
$msg_plain_text = iconv($text_encoding, "utf-8", $text);
}
$message->bodyPlain = $msg_plain_text;
}
if (isset($parts_found["type"]["HTML"]))
{
$encoding = $parts_found[$parts_found["type"]["HTML"]]["encoding"];
$html_text=imap_fetchbody ($this->conn, $num, $parts_found["type"]["HTML"],FT_PEEK );
if ($encoding == 3)
{
$html_text = base64_decode($html_text);
} elseif ($encoding == 4) {
$html_text=quoted_printable_decode($html_text);
}
$message->bodyHTML = $html_text;
}
foreach ($parts_found as $pkey=>$part)
{
if ($pkey != 'type') {
if (isset($part["disposition"]) && (($part["disposition"] == 'attachment') || (($part["dparameters"]["0"]->value != ''))))
{
$att = mailAttachment::createFromPart($part, $pkey, $message);
$message->addAttachment($att);
}
}
}
//imap_setflag_full($this->conn, $message->refNum, "\Seen");
return $message;
}
protected function search_parts($struct, $path=null, &$parts_found=null)
{
if (!isset($path))
{
$path='';
$parts_found = null;
$parts_found["type"]["HTML"] = null;
$parts_found["type"]["PLAIN"] = null;
}
$retval = $this->parce_struct($struct);
$path_rv = $path;
if ($path_rv == '') { $path_rv = 1;}
$parts_found[$path_rv] = $retval;
if (($retval["type"] == 0) && ($retval["subtype"] == "PLAIN"))
{
$parts_found["type"]["PLAIN"] = $path_rv;
} elseif (($retval["type"] == 0) && ($retval["subtype"] == "HTML"))
{
$parts_found["type"]["HTML"] = $path_rv;
}
if ($retval["parts_count"] > 0)
{
foreach ($struct->parts as $pkey=>$part)
{
$path_t = $path;
if ($path_t != '') {$path_t .= '.';};
// $path_t=$path.".".($pkey+1);
$path_t.=($pkey+1);
$this->search_parts($part, $path_t, $parts_found);
}
}
return $retval;
}
protected function parce_struct($struct, $path="")
{
$retval["type"] = $struct->type;
$retval["encoding"] = $struct->encoding;
$retval["subtype"] = ($struct->ifsubtype==1)?$struct->subtype:"-1";
$retval["disposition"] = ($struct->ifdisposition==1)?$struct->disposition:null;
$retval["dparameters"] = ($struct->ifdparameters==1)?$struct->dparameters:null;
$retval["parts_count"] = ($retval["type"] == TYPEMULTIPART)?count($struct->parts):0;
$retval["text-encoding"] = "default";
if (isset($struct->parameters))
{
foreach ($struct->parameters as $p_stk)
{
if ($p_stk->attribute=="charset")
{
$retval["text-encoding"] = $p_stk->value;
}
}
}
// $retval["parts"] = $struct->parts;
return $retval;
}
/* workaround to make most of headers to parse properly */
protected static function decodeHeader($hdr, $cset = 'UTF8')
{
// Copied nearly intact from PEAR's Mail_mimeDecode.
$hdr = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $hdr);
$m = array();
if(is_array($hdr))
$hdr = $hdr[0];
while(preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $hdr, $m))
{
$encoded = $m[1];
$charset = strtoupper($m[2]);
$encoding = strtolower($m[3]);
$text = $m[4];
switch($encoding)
{
case 'b':
$text = base64_decode($text);
break;
case 'q':
$text = str_replace('_', ' ', $text);
preg_match_all('/=([a-f0-9]{2})/i', $text, $m);
foreach($m[1] as $value)
$text = str_replace('=' . $value, chr(hexdec($value)), $text);
break;
}
if($charset !== $cset)
$text = self::charconv($charset, $cset, $text);
$hdr = str_replace($encoded, $text, $hdr);
}
return $hdr;
}
/* workaround to make most of headers to parse properly */
protected function charconv($enc_from, $enc_to, $text)
{
if(function_exists('iconv'))
return iconv($enc_from, $enc_to, $text);
elseif(function_exists('recode_string'))
return recode_string("$enc_from..$enc_to", $text);
elseif(function_exists('mb_convert_encoding'))
return mb_convert_encoding($text, $enc_to, $enc_from);
return $text;
}
}
?>