]> git.donarmstrong.com Git - roundcube.git/blob - program/include/rcube_mime_struct.php
Imported Upstream version 0.5
[roundcube.git] / program / include / rcube_mime_struct.php
1 <?php
2
3
4 /*
5  +-----------------------------------------------------------------------+
6  | program/include/rcube_mime_struct.php                                 |
7  |                                                                       |
8  | This file is part of the Roundcube Webmail client                     |
9  | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland                 |
10  | Licensed under the GNU GPL                                            |
11  |                                                                       |
12  | PURPOSE:                                                              |
13  |   Provide functions for handling mime messages structure              |
14  |                                                                       |
15  |   Based on Iloha MIME Library. See http://ilohamail.org/ for details  |
16  |                                                                       |
17  +-----------------------------------------------------------------------+
18  | Author: Aleksander Machniak <alec@alec.pl>                            |
19  | Author: Ryo Chijiiwa <Ryo@IlohaMail.org>                              |
20  +-----------------------------------------------------------------------+
21
22  $Id$
23
24 */
25
26 /**
27  * Helper class to process IMAP's BODYSTRUCTURE string
28  *
29  * @package    Mail
30  * @author     Aleksander Machniak <alec@alec.pl>
31  */
32 class rcube_mime_struct
33 {
34     private $structure;
35
36
37     function __construct($str=null)
38     {
39         if ($str)
40             $this->structure = $this->parseStructure($str);
41     }
42
43     /*
44      * Parses IMAP's BODYSTRUCTURE string into array
45     */
46     function parseStructure($str)
47     {
48         $line = substr($str, 1, strlen($str) - 2);
49         $line = str_replace(')(', ') (', $line);
50
51             $struct = self::parseBSString($line);
52         if (!is_array($struct[0]) && (strcasecmp($struct[0], 'message') == 0)
53                     && (strcasecmp($struct[1], 'rfc822') == 0)) {
54                     $struct = array($struct);
55             }
56
57         return $struct;
58     }
59
60     /*
61      * Parses IMAP's BODYSTRUCTURE string into array and loads it into class internal variable
62     */
63     function loadStructure($str)
64     {
65         if (empty($str))
66             return true;
67
68         $this->structure = $this->parseStructure($str);
69         return (!empty($this->structure));
70     }
71
72     function getPartType($part)
73     {
74             $part_a = $this->getPartArray($this->structure, $part);
75             if (!empty($part_a)) {
76                     if (is_array($part_a[0]))
77                 return 'multipart';
78                     else if ($part_a[0])
79                 return $part_a[0];
80             }
81         
82         return 'other';
83     }
84
85     function getPartEncoding($part)
86     {
87             $part_a = $this->getPartArray($this->structure, $part);
88             if ($part_a) {
89                     if (!is_array($part_a[0]))
90                 return $part_a[5];
91             }
92         
93         return '';
94     }
95
96     function getPartCharset($part)
97     {
98             $part_a = $this->getPartArray($this->structure, $part);
99             if ($part_a) {
100                     if (is_array($part_a[0]))
101                 return '';
102                     else {
103                             if (is_array($part_a[2])) {
104                                     $name = '';
105                                     while (list($key, $val) = each($part_a[2]))
106                         if (strcasecmp($val, 'charset') == 0)
107                             return $part_a[2][$key+1];
108                             }
109                     }
110             }
111         
112         return '';
113     }
114
115     function getPartArray($a, $part)
116     {
117             if (!is_array($a)) {
118             return false;
119         }
120             if (strpos($part, '.') > 0) {
121                     $original_part = $part;
122                     $pos = strpos($part, '.');
123                     $rest = substr($original_part, $pos+1);
124                     $part = substr($original_part, 0, $pos);
125                     if ((strcasecmp($a[0], 'message') == 0) && (strcasecmp($a[1], 'rfc822') == 0)) {
126                             $a = $a[8];
127                     }
128                     return self::getPartArray($a[$part-1], $rest);
129             }
130         else if ($part>0) {
131                     if (!is_array($a[0]) && (strcasecmp($a[0], 'message') == 0)
132                 && (strcasecmp($a[1], 'rfc822') == 0)) {
133                             $a = $a[8];
134                     }
135                     if (is_array($a[$part-1]))
136                 return $a[$part-1];
137                     else
138                 return $a;
139             }
140         else if (($part==0) || (empty($part))) {
141                     return $a;
142             }
143     }
144
145     private function closingParenPos($str, $start)
146     {
147         $level = 0;
148         $len = strlen($str);
149         $in_quote = 0;
150
151         for ($i=$start; $i<$len; $i++) {
152             if ($str[$i] == '"' && $str[$i-1] != "\\") {
153                         $in_quote = ($in_quote + 1) % 2;
154             }
155             if (!$in_quote) {
156                     if ($str[$i] == '(')
157                     $level++;
158                     else if (($level > 0) && ($str[$i] == ')'))
159                     $level--;
160                     else if (($level == 0) && ($str[$i] == ')'))
161                     return $i;
162             }
163         }
164     }
165
166     /*
167      * Parses IMAP's BODYSTRUCTURE string into array
168     */
169     private function parseBSString($str)
170     {   
171         $id = 0;
172         $a = array();
173         $len = strlen($str);
174         $in_quote = 0;
175
176         for ($i=0; $i<$len; $i++) {
177             if ($str[$i] == '"') {
178                     $in_quote = ($in_quote + 1) % 2;
179             } else if (!$in_quote) {
180                 // space means new element
181                 if ($str[$i] == ' ') {
182                     $id++;
183                     // skip additional spaces
184                     while ($str[$i+1] == ' ')
185                         $i++;
186                 // new part
187                 } else if ($str[$i] == '(') {
188                     $i++;
189                     $endPos = self::closingParenPos($str, $i);
190                     $partLen = $endPos - $i;
191                     if ($partLen < 0)
192                         break;
193                     $part = substr($str, $i, $partLen);
194                     $a[$id] = self::parseBSString($part); // send part string
195                     $i = $endPos;
196                 } else
197                             $a[$id] .= $str[$i]; //add to current element in array
198             } else if ($in_quote) {
199                 if ($str[$i] == "\\") {
200                             $i++; // escape backslashes
201                             if ($str[$i] == '"' || $str[$i] == "\\")
202                                 $a[$id] .= $str[$i];
203                 }
204                 else
205                             $a[$id] .= $str[$i]; //add to current element in array
206             }
207         }
208         
209         reset($a);
210         return $a;
211     }
212
213
214 }