MailZu 0.8RC3
[bMailZu.git] / lib / MailMime.class.php
blob3a981e17aa4a9cbc53e9dd2c50da22b9a9ee720d
1 <?php
2 /**
3 * MailEngine class
4 * @author Brian Wong <bwsource@users.sourceforge.net>
5 * @version 04-12-05
6 * @package MailEngine
8 * Copyright (C) 2003 - 2007 MailZu
9 * License: GPL, see LICENSE
11 /**
12 * Base directory of application
14 @define('BASE_DIR', dirname(__FILE__) . '/..');
15 /**
16 * CmnFns class
18 include_once('CmnFns.class.php');
19 /**
20 * Pear::DB
22 if ($GLOBALS['conf']['app']['safeMode']) {
23 ini_set('include_path', ( dirname(__FILE__) . '/pear/' . PATH_SEPARATOR . ini_get('include_path') ));
24 include_once('pear/Mail/mimeDecode.php');
26 else {
27 include_once('Mail/mimeDecode.php');
30 /**
31 * Include htmlfilter class
33 include_once('lib/htmlfilter.php');
36 /**
37 * Provide all MIME functionality
40 /**
41 * Get full MIME type
42 * $param The mime structure object
44 function GetCtype($struct) {
45 $ctype_p = strtolower(trim($struct->ctype_primary));
46 $ctype_s = strtolower(trim($struct->ctype_secondary));
47 $type = $ctype_p . '/' . $ctype_s;
48 return $type;
51 /**
52 * Recursively parse MIME structure
53 * $param The mime structure object
55 $filelist = array ();
56 $errors = array ();
58 function MsgParseBody($struct) {
60 global $filelist;
61 global $errors;
62 $ctype_p = strtolower(trim($struct->ctype_primary));
63 $ctype_s = strtolower(trim($struct->ctype_secondary));
65 switch ($ctype_p) {
66 case "multipart":
67 switch ($ctype_s) {
68 case "alternative":
69 // Handle multipart/alternative parts
70 $alt_entity = FindMultiAlt($struct->parts);
71 // Ignore if we return false NEEDS WORK
72 if ($alt_entity) MsgParseBody($alt_entity);
73 break;
74 case "related":
75 // Handle multipart/related parts
76 $rel_entities = FindMultiRel($struct);
77 foreach ($rel_entities as $ent) {
78 MsgParseBody($ent);
80 break;
81 default:
82 // Probably multipart/mixed here
83 // Recursively process nested mime entities
84 if ( is_array($struct->parts) || is_object($struct->parts) ) {
85 foreach ($struct->parts as $cur_part) {
86 MsgParseBody($cur_part);
88 } else {
89 $errors['Invalid or Corrupt MIME Detected.'] = true;
91 break;
93 break;
95 case "text":
96 // Do not display attached text types
97 if ($attachment = $struct->d_parameters['filename'] or
98 $attachment = $struct->d_parameters['name']) {
99 array_push($filelist, $attachment);
100 break;
102 switch ($ctype_s) {
103 // Plain text
104 case "plain":
105 MsgBodyPlainText($struct->body);
106 break;
107 // HTML text
108 case "html":
109 MsgBodyHtmlText($struct->body);
110 break;
111 // Text type we do not support
112 default:
113 $errors['Portions of text could not be displayed'] = true;
115 break;
117 default:
118 // Save the listed filename or notify the
119 // reader that this mail is not displayed completely
120 $attachment = $struct->d_parameters['filename'];
121 $attachment ? array_push($filelist, $attachment) : $errors['Unsupported MIME objects present'] = true;
127 * Get the best MIME entity for multipart/alternative
128 * Adapted from SqurrelMail
129 * $param Array of MIME entities
130 * $return Single MIME entity
132 function FindMultiAlt($parts) {
133 $alt_pref = array ('text/plain', 'text/html');
134 $best_view = 0;
135 // Bad Headers sometimes have invalid MIME....
136 if ( is_array($parts) || is_object($parts) ) {
137 foreach ($parts as $cur_part) {
138 $type = GetCtype($cur_part);
139 if ($type == 'multipart/related') {
140 $type = $cur_part->d_parameters['type'];
141 // Mozilla bug. Mozilla does not provide the parameter type.
142 if (!$type) $type = 'text/html';
144 $altCount = count($alt_pref);
145 for ($j = $best_view; $j < $altCount; ++$j) {
146 if (($alt_pref[$j] == $type) && ($j >= $best_view)) {
147 $best_view = $j;
148 $struct = $cur_part;
152 return $struct;
153 } else {
154 $errors['Invalid or Corrupt MIME Detected.'] = true;
159 * Get the list of related entities for multipart/related
160 * Adapted from SqurrelMail
161 * $param multipart/alternative structure
162 * @return List of MIME entities
164 function FindMultiRel($struct) {
165 $entities = array();
166 $type = $struct->d_parameters['type'];
167 // Mozilla bug. Mozilla does not provide the parameter type.
168 if (!$type) $type = 'text/html';
169 // Bad Headers sometimes have invalid MIME....
170 if ( is_array($struct->parts) || is_object($struct->parts) ) {
171 foreach ($struct->parts as $part) {
172 if (GetCtype($part) == $type || GetCtype($part) == "multipart/alternative") {
173 array_push($entities,$part);
176 } else {
177 $errors['Invalid or Corrupt MIME Detected.'] = true;
179 return $entities;
182 // Wrapper script for htmlfilter. Settings taken
183 // from SquirrelMail
184 function sanitizeHTML($body) {
185 if (isset($_COOKIE['lang']) &&
186 file_exists("img/".substr($_COOKIE['lang'],0,2).".blocked_img.png")) {
187 $secremoveimg = "img/".substr($_COOKIE['lang'],0,2).".blocked_img.png";
188 } else {
189 $secremoveimg = "img/blocked_img.png";
191 $tag_list = Array(
192 false,
193 "object",
194 "meta",
195 "html",
196 "head",
197 "base",
198 "link",
199 "frame",
200 "iframe",
201 "plaintext",
202 "marquee"
205 $rm_tags_with_content = Array(
206 "script",
207 "applet",
208 "embed",
209 "title",
210 "frameset",
211 "xml",
212 "style"
215 $self_closing_tags = Array(
216 "img",
217 "br",
218 "hr",
219 "input"
222 $force_tag_closing = true;
224 $rm_attnames = Array(
225 "/.*/" =>
226 Array(
227 "/target/i",
228 "/^on.*/i",
229 "/^dynsrc/i",
230 "/^data.*/i",
231 "/^lowsrc.*/i"
235 $bad_attvals = Array(
236 "/.*/" =>
237 Array(
238 "/^src|background/i" =>
239 Array(
240 Array(
241 "/^([\'\"])\s*\S+script\s*:.*([\'\"])/si",
242 "/^([\'\"])\s*mocha\s*:*.*([\'\"])/si",
243 "/^([\'\"])\s*about\s*:.*([\'\"])/si",
244 "/^([\'\"])\s*https*:.*([\'\"])/si",
245 "/^([\'\"])\s*cid*:.*([\'\"])/si"
247 Array(
248 "\\1$secremoveimg\\2",
249 "\\1$secremoveimg\\2",
250 "\\1$secremoveimg\\2",
251 "\\1$secremoveimg\\2",
252 "\\1$secremoveimg\\2"
255 "/^href|action/i" =>
256 Array(
257 Array(
258 "/^([\'\"])\s*\S+script\s*:.*([\'\"])/si",
259 "/^([\'\"])\s*mocha\s*:*.*([\'\"])/si",
260 "/^([\'\"])\s*about\s*:.*([\'\"])/si"
262 Array(
263 "\\1#\\1",
264 "\\1#\\1",
265 "\\1#\\1",
266 "\\1#\\1"
269 "/^style/i" =>
270 Array(
271 Array(
272 "/expression/i",
273 "/binding/i",
274 "/behaviou*r/i",
275 "/include-source/i",
276 "/url\s*\(\s*([\'\"])\s*\S+script\s*:.*([\'\"])\s*\)/si",
277 "/url\s*\(\s*([\'\"])\s*mocha\s*:.*([\'\"])\s*\)/si",
278 "/url\s*\(\s*([\'\"])\s*about\s*:.*([\'\"])\s*\)/si",
279 "/(.*)\s*:\s*url\s*\(\s*([\'\"]*)\s*\S+script\s*:.*([\'\"]*)\s*\)/si",
280 "/url\(([\'\"])\s*https*:.*([\'\"])\)/si"
282 Array(
283 "idiocy",
284 "idiocy",
285 "idiocy",
286 "idiocy",
287 "url(\\1#\\1)",
288 "url(\\1#\\1)",
289 "url(\\1#\\1)",
290 "url(\\1#\\1)",
291 "url(\\1#\\1)",
292 "\\1:url(\\2#\\3)",
293 "url(\\1$secremoveimg\\1)"
299 $add_attr_to_tag = Array(
300 "/^a$/i" =>
301 Array('target'=>'"_new"'
305 $trusted_html = sanitize($body,
306 $tag_list,
307 $rm_tags_with_content,
308 $self_closing_tags,
309 $force_tag_closing,
310 $rm_attnames,
311 $bad_attvals,
312 $add_attr_to_tag
315 return $trusted_html;