diff options
-rw-r--r-- | program/include/rcube_imap.php | 23 | ||||
-rw-r--r-- | program/include/rcube_mime_struct.php | 209 | ||||
-rw-r--r-- | program/lib/mime.inc | 330 |
3 files changed, 220 insertions, 342 deletions
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 7dc70df32..22f497927 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -21,10 +21,6 @@ */ -require_once('lib/mime.inc'); -require_once('lib/tnef_decoder.inc'); - - /** * Interface class for accessing an IMAP server * @@ -1614,9 +1610,10 @@ class rcube_imap return $headers->structure; } - if (!$structure_str) + if (!$structure_str) { $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); - $structure = iml_GetRawStructureArray($structure_str); + } + $structure = rcube_mime_struct::parseStructure($structure_str); $struct = false; // parse structure and add headers @@ -1966,16 +1963,16 @@ class rcube_imap // get part encoding if not provided if (!is_object($o_part)) { $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); - $structure = iml_GetRawStructureArray($structure_str); + $structure = new rcube_mime_struct(); // error or message not found - if (empty($structure)) + if (!$structure->loadStructure($structure_str)) { return false; + } - $part_type = iml_GetPartTypeCode($structure, $part); $o_part = new rcube_message_part; - $o_part->ctype_primary = $part_type==0 ? 'text' : ($part_type==2 ? 'message' : 'other'); - $o_part->encoding = strtolower(iml_GetPartEncodingString($structure, $part)); - $o_part->charset = iml_GetPartCharset($structure, $part); + $o_part->ctype_primary = strtolower($structure->getPartType($part)); + $o_part->encoding = strtolower($structure->getPartEncoding($part)); + $o_part->charset = $structure->getPartCharset($part); } // TODO: Add caching for message parts @@ -3331,6 +3328,8 @@ class rcube_imap if (!isset($part->body)) $part->body = $this->get_message_part($uid, $part->mime_id, $part); + require_once('lib/tnef_decoder.inc'); + $pid = 0; $tnef_parts = array(); $tnef_arr = tnef_decode($part->body); diff --git a/program/include/rcube_mime_struct.php b/program/include/rcube_mime_struct.php new file mode 100644 index 000000000..bc00da50a --- /dev/null +++ b/program/include/rcube_mime_struct.php @@ -0,0 +1,209 @@ +<?php + + +/* + +-----------------------------------------------------------------------+ + | program/include/rcube_mime_struct.php | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland | + | Licensed under the GNU GPL | + | | + | PURPOSE: | + | Provide functions for handling mime messages structure | + | | + | Based on Iloha MIME Library. See http://ilohamail.org/ for details | + | | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + | Author: Ryo Chijiiwa <Ryo@IlohaMail.org> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +class rcube_mime_struct +{ + private $structure; + + + function __construct($str=null) + { + if ($str) + $this->structure = $this->parseStructure($str); + } + + /* + * Parses IMAP's BODYSTRUCTURE string into array + */ + function parseStructure($str) + { + $line = substr($str, 1, strlen($str) - 2); + $line = str_replace(')(', ') (', $line); + + $struct = self::parseBSString($line); + if (!is_array($struct[0]) && (strcasecmp($struct[0], 'message') == 0) + && (strcasecmp($struct[1], 'rfc822') == 0)) { + $struct = array($struct); + } + + return $struct; + } + + /* + * Parses IMAP's BODYSTRUCTURE string into array and loads it into class internal variable + */ + function loadStructure($str) + { + if (empty($str)) + return true; + + $this->structure = $this->parseStructure($str); + return (!empty($this->structure)); + } + + function getPartType($part) + { + $part_a = $this->getPartArray($this->structure, $part); + if (!empty($part_a)) { + if (is_array($part_a[0])) + return 'multipart'; + else if ($part_a[0]) + return $part_a[0]; + } + + return 'other'; + } + + function getPartEncoding($part) + { + $part_a = $this->getPartArray($this->structure, $part); + if ($part_a) { + if (!is_array($part_a[0])) + return $part_a[5]; + } + + return ''; + } + + function getPartCharset($part) + { + $part_a = $this->getPartArray($this->structure, $part); + if ($part_a) { + if (is_array($part_a[0])) + return ''; + else { + if (is_array($part_a[2])) { + $name = ''; + while (list($key, $val) = each($part_a[2])) + if (strcasecmp($val, 'charset') == 0) + return $part_a[2][$key+1]; + } + } + } + + return ''; + } + + function getPartArray($a, $part) + { + if (!is_array($a)) { + return false; + } + if (strpos($part, '.') > 0) { + $original_part = $part; + $pos = strpos($part, '.'); + $rest = substr($original_part, $pos+1); + $part = substr($original_part, 0, $pos); + if ((strcasecmp($a[0], 'message') == 0) && (strcasecmp($a[1], 'rfc822') == 0)) { + $a = $a[8]; + } + return self::getPartArray($a[$part-1], $rest); + } + else if ($part>0) { + if (!is_array($a[0]) && (strcasecmp($a[0], 'message') == 0) + && (strcasecmp($a[1], 'rfc822') == 0)) { + $a = $a[8]; + } + if (is_array($a[$part-1])) + return $a[$part-1]; + else + return $a; + } + else if (($part==0) || (empty($part))) { + return $a; + } + } + + private function closingParenPos($str, $start) + { + $level = 0; + $len = strlen($str); + $in_quote = 0; + + for ($i=$start; $i<$len; $i++) { + if ($str[$i] == '"' && $str[$i-1] != "\\") { + $in_quote = ($in_quote + 1) % 2; + } + if (!$in_quote) { + if ($str[$i] == '(') + $level++; + else if (($level > 0) && ($str[$i] == ')')) + $level--; + else if (($level == 0) && ($str[$i] == ')')) + return $i; + } + } + } + + /* + * Parses IMAP's BODYSTRUCTURE string into array + */ + private function parseBSString($str) + { + $id = 0; + $a = array(); + $len = strlen($str); + $in_quote = 0; + + for ($i=0; $i<$len; $i++) { + if ($str[$i] == '"') { + $in_quote = ($in_quote + 1) % 2; + } else if (!$in_quote) { + // space means new element + if ($str[$i] == ' ') { + $id++; + // skip additional spaces + while ($str[$i+1] == ' ') + $i++; + // new part + } else if ($str[$i] == '(') { + $i++; + $endPos = self::closingParenPos($str, $i); + $partLen = $endPos - $i; + if ($partLen < 0) + break; + $part = substr($str, $i, $partLen); + $a[$id] = self::parseBSString($part); // send part string + $i = $endPos; + } else + $a[$id] .= $str[$i]; //add to current element in array + } else if ($in_quote) { + if ($str[$i] == "\\") { + $i++; // escape backslashes + if ($str[$i] == '"' || $str[$i] == "\\") + $a[$id] .= $str[$i]; + } + else + $a[$id] .= $str[$i]; //add to current element in array + } + } + + reset($a); + return $a; + } + + +} diff --git a/program/lib/mime.inc b/program/lib/mime.inc deleted file mode 100644 index cb4f7285d..000000000 --- a/program/lib/mime.inc +++ /dev/null @@ -1,330 +0,0 @@ -<?php -///////////////////////////////////////////////////////// -// -// Iloha MIME Library (IML) -// -// (C)Copyright 2002 Ryo Chijiiwa <Ryo@IlohaMail.org> -// -// This file is part of IlohaMail. IlohaMail is free software released -// under the GPL license. See enclosed file COPYING for details, or -// see http://www.fsf.org/copyleft/gpl.html -// -///////////////////////////////////////////////////////// - -/******************************************************** - - FILE: include/mime.inc - PURPOSE: - Provide functions for handling mime messages. - USAGE: - Use iil_C_FetchStructureString to get IMAP structure stirng, then pass that through - iml_GetRawStructureArray() to get root node to a nested data structure. - Pass root node to the iml_GetPart*() functions to retreive individual bits of info. - -********************************************************/ -$MIME_INVALID = -1; -$MIME_TEXT = 0; -$MIME_MULTIPART = 1; -$MIME_MESSAGE = 2; -$MIME_APPLICATION = 3; -$MIME_AUDIO = 4; -$MIME_IMAGE = 5; -$MIME_VIDEO = 6; -$MIME_OTHER = 7; - -function iml_ClosingParenPos($str, $start) { - $level=0; - $len = strlen($str); - $in_quote = 0; - - for ($i=$start; $i<$len; $i++) { - if ($str[$i] == '"' && $str[$i-1] != "\\") - $in_quote = ($in_quote + 1) % 2; - if (!$in_quote) { - if ($str[$i]=="(") $level++; - else if (($level > 0) && ($str[$i]==")")) $level--; - else if (($level == 0) && ($str[$i]==")")) return $i; - } - } -} - -function iml_ParseBSString($str){ - - $id = 0; - $a = array(); - $len = strlen($str); - $in_quote = 0; - - for ($i=0; $i<$len; $i++) { - if ($str[$i] == '"') { - $in_quote = ($in_quote + 1) % 2; - } else if (!$in_quote) { - if ($str[$i] == " ") { //space means new element - $id++; - while ($str[$i+1] == " ") $i++; // skip additional spaces - } else if ($str[$i]=="(") { //new part - $i++; - $endPos = iml_ClosingParenPos($str, $i); - $partLen = $endPos - $i; - if ($partLen < 0) break; - $part = substr($str, $i, $partLen); - $a[$id] = iml_ParseBSString($part); //send part string - $i = $endPos; - } else - $a[$id].=$str[$i]; //add to current element in array - } else if ($in_quote) { - if ($str[$i]=="\\") { - $i++; //escape backslashes - if ($str[$i] == '"' || $str[$i] == "\\") - $a[$id] .= $str[$i]; - } else - $a[$id] .= $str[$i]; //add to current element in array - } - } - - reset($a); - return $a; -} - -function iml_GetRawStructureArray($str){ - $line=substr($str, 1, strlen($str) - 2); - $line = str_replace(")(", ") (", $line); - - $struct = iml_ParseBSString($line); - if (!is_array($struct[0]) && (strcasecmp($struct[0], "message")==0) - && (strcasecmp($struct[1], "rfc822")==0)) { - $struct = array($struct); - } - return $struct; -} - -function iml_GetPartArray($a, $part){ - if (!is_array($a)) return false; - if (strpos($part, ".") > 0){ - $original_part = $part; - $pos = strpos($part, "."); - $rest = substr($original_part, $pos+1); - $part = substr($original_part, 0, $pos); - if ((strcasecmp($a[0], "message")==0) && (strcasecmp($a[1], "rfc822")==0)){ - $a = $a[8]; - } - //echo "m - part: $original_part current: $part rest: $rest array: ".implode(" ", $a)."<br>\n"; - return iml_GetPartArray($a[$part-1], $rest); - }else if ($part>0){ - if (!is_array($a[0]) && (strcasecmp($a[0], "message")==0) && (strcasecmp($a[1], "rfc822")==0)){ - $a = $a[8]; - } - //echo "s - part: $part rest: $rest array: ".implode(" ", $a)."<br>\n"; - if (is_array($a[$part-1])) return $a[$part-1]; - else return $a; - }else if (($part==0) || (empty($part))){ - return $a; - } -} - -function iml_GetNumParts($a, $part){ - if (is_array($a)){ - $parent=iml_GetPartArray($a, $part); - - if ((strcasecmp($parent[0], "message")==0) && (strcasecmp($parent[1], "rfc822")==0)){ - $parent = $parent[8]; - } - - $is_array=true; - $c=0; - while (( list ($key, $val) = each ($parent) )&&($is_array)){ - $is_array=is_array($parent[$key]); - if ($is_array) $c++; - } - return $c; - } - - return false; -} - -function iml_GetPartTypeString($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])){ - $type_str = "MULTIPART/"; - reset($part_a); - while(list($n,$element)=each($part_a)){ - if (!is_array($part_a[$n])){ - $type_str.=$part_a[$n]; - break; - } - } - return $type_str; - }else return $part_a[0]."/".$part_a[1]; - }else return false; -} - -function iml_GetFirstTextPart($structure,$part){ - if ($part==0) $part=""; - $typeCode = -1; - while ($typeCode!=0){ - $typeCode = iml_GetPartTypeCode($structure, $part); - if ($typeCode == 1){ - $part .= (empty($part)?"":".")."1"; - }else if ($typeCode > 0){ - $parts_a = explode(".", $part); - $lastPart = count($parts_a) - 1; - $parts_a[$lastPart] = (int)$parts_a[$lastPart] + 1; - $part = implode(".", $parts_a); - }else if ($typeCode == -1){ - return ""; - } - } - - return $part; -} - -function iml_GetPartTypeCode($a, $part){ - $types=array(0=>"text",1=>"multipart",2=>"message",3=>"application",4=>"audio",5=>"image",6=>"video",7=>"other"); - - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) $str="multipart"; - else $str=$part_a[0]; - - $code=7; - while ( list($key, $val) = each($types)) if (strcasecmp($val, $str)==0) $code=$key; - return $code; - }else return -1; -} - -function iml_GetPartEncodingCode($a, $part){ - $encodings=array("7BIT", "8BIT", "BINARY", "BASE64", "QUOTED-PRINTABLE", "OTHER"); - - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else $str=$part_a[5]; - - $code=5; - while ( list($key, $val) = each($encodings)) if (strcasecmp($val, $str)==0) $code=$key; - - return $code; - - }else return -1; -} - -function iml_GetPartEncodingString($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else return $part_a[5]; - }else return -1; -} - -function iml_GetPartSize($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else return $part_a[6]; - }else return -1; -} - -function iml_GetPartID($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else return $part_a[3]; - }else return -1; -} - -function iml_GetPartDisposition($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else{ - $id = count($part_a) - 2; - if (is_array($part_a[$id])) return $part_a[$id][0]; - else return ""; - } - }else return ""; -} - -function iml_GetPartName($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else{ - $name = ""; - if (is_array($part_a[2])){ - //first look in content type - $name=""; - while ( list($key, $val) = each ($part_a[2])){ - if ((strcasecmp($val, "NAME")==0)||(strcasecmp($val, "FILENAME")==0)) - $name=$part_a[2][$key+1]; - } - } - if (empty($name)){ - //check in content disposition - $id = count($part_a) - 2; - if ((is_array($part_a[$id])) && (is_array($part_a[$id][1]))){ - $array = $part_a[$id][1]; - while ( list($key, $val) = each($array)){ - if ((strcasecmp($val, "NAME")==0)||(strcasecmp($val, "FILENAME")==0)) - $name=$array[$key+1]; - } - } - } - return $name; - } - }else return ""; -} - - -function iml_GetPartCharset($a, $part){ - $part_a=iml_GetPartArray($a, $part); - if ($part_a){ - if (is_array($part_a[0])) return -1; - else{ - if (is_array($part_a[2])){ - $name=""; - while ( list($key, $val) = each ($part_a[2])) if (strcasecmp($val, "charset")==0) $name=$part_a[2][$key+1]; - return $name; - } - else return ""; - } - }else return ""; -} - -function iml_GetPartList($a, $part){ - //echo "MOO?"; flush(); - $data = array(); - $num_parts = iml_GetNumParts($a, $part); - //echo "($num_parts)"; flush(); - if ($num_parts !== false){ - //echo "<!-- ($num_parts parts)//-->\n"; - for ($i = 0; $i<$num_parts; $i++){ - $part_code = $part.(empty($part)?"":".").($i+1); - $part_type = iml_GetPartTypeCode($a, $part_code); - $part_disposition = iml_GetPartDisposition($a, $part_code); - //echo "<!-- part: $part_code type: $part_type //-->\n"; - if (strcasecmp($part_disposition, "attachment")!=0 && - (($part_type == 1) || ($part_type==2))){ - $data = array_merge($data, iml_GetPartList($a, $part_code)); - }else{ - $data[$part_code]["typestring"] = iml_GetPartTypeString($a, $part_code); - $data[$part_code]["disposition"] = $part_disposition; - $data[$part_code]["size"] = iml_GetPartSize($a, $part_code); - $data[$part_code]["name"] = iml_GetPartName($a, $part_code); - $data[$part_code]["id"] = iml_GetPartID($a, $part_code); - } - } - } - return $data; -} - -function iml_GetNextPart($part){ - if (strpos($part, ".")===false) return $part++; - else{ - $parts_a = explode(".", $part); - $num_levels = count($parts_a); - $parts_a[$num_levels-1]++; - return implode(".", $parts_a); - } -} -?>
\ No newline at end of file |