1 Catch error from address parsing.
3 --- eventum-20060717/include/class.mail.php~ 2006-07-18 01:21:08.631017731 +0300
4 +++ eventum-20060717/include/class.mail.php 2006-07-18 01:22:01.102190536 +0300
6 $address = Mime_Helper::encodeValue($address);
7 include_once(APP_PEAR_PATH . "Mail/RFC822.php");
8 $t = Mail_RFC822::parseAddressList($address, null, null, false);
9 + if (PEAR::isError($t)) {
10 + Error_Handler::logError(array($t->getMessage(), $t->getDebugInfo()), __FILE__, __LINE__);
14 for ($i = 0; $i < count($t); $i++) {
15 -------------------------------------------------------------------------------------------------------
16 Detect and log possibly corrupted MIME emails.
18 --- eventum-1.7.1/include/class.mime_helper.php 2006-04-12 00:48:18.579879862 +0300
19 +++ /home/glen/class.mime_helper.php 2006-04-12 00:52:33.225568723 +0300
23 include_once(APP_PEAR_PATH . "Mail/mimeDecode.php");
24 +include_once(APP_INC_PATH . "class.error_handler.php");
27 * Class to handle the business logic related to the MIME email
31 Mime_Helper::parse_output($output, $parts);
32 + if (empty($parts)) {
33 + Error_Handler::logError(array("Mime_Helper::parse_output failed. Corrupted MIME in email?", $output), __FILE__, __LINE__);
34 + // we continue as if nothing happened until it's clear it's right check to do.
38 if (isset($parts["text"])) {
40 -------------------------------------------------------------------------------------------------------
41 Rewrite routing part to have consistent API for matching issue_ids from mail headers.
42 Add new method Routing::getMatchingIssueIDs().
43 --- eventum-1.7.1/include/class.routing.php 2006-04-12 00:48:18.189871149 +0300
44 +++ /home/glen/class.routing.php 2006-04-12 00:52:33.295570287 +0300
46 if ($setup['email_routing']['status'] != 'enabled') {
47 return array(78, "Error: The email routing interface is disabled.\n");
49 - $prefix = $setup['email_routing']['address_prefix'];
50 - // escape plus signs so 'issue+1@example.com' becomes a valid routing address
51 - $prefix = str_replace('+', '\+', $prefix);
52 - $mail_domain = quotemeta($setup['email_routing']['address_host']);
53 - $mail_domain_alias = quotemeta(@$setup['email_routing']['host_alias']);
54 - if (!empty($mail_domain_alias)) {
55 - $mail_domain = "(?:" . $mail_domain . "|" . $mail_domain_alias . ")";
57 - if (empty($prefix)) {
58 + if (empty($setup['email_routing']['address_prefix'])) {
59 return array(78, gettext("Error: Please configure the email address prefix.") . "\n");
61 - if (empty($mail_domain)) {
62 + if (empty($setup['email_routing']['address_host'])) {
63 return array(78, gettext("Error: Please configure the email address domain.") . "\n");
66 $structure = Mime_Helper::decode($full_message, true, true);
68 // find which issue ID this email refers to
69 - @preg_match("/$prefix(\d*)@$mail_domain/i", $structure->headers['to'], $matches);
70 - @$issue_id = $matches[1];
71 + if (isset($structure->headers['to'])) {
72 + $issue_id = Routing::getMatchingIssueIDs($structure->headers['to'], 'email');
74 // validation is always a good idea
75 - if (empty($issue_id)) {
76 + if (empty($issue_id) and isset($structure->headers['cc'])) {
77 // we need to try the Cc header as well
78 - @preg_match("/$prefix(\d*)@$mail_domain/i", $structure->headers['cc'], $matches);
79 - if (!empty($matches[1])) {
80 - $issue_id = $matches[1];
82 - return array(65, gettext("Error: The routed email had no associated Eventum issue ID or had an invalid recipient address.") . "\n");
84 + $issue_id = Routing::getMatchingIssueIDs($structure->headers['cc'], 'email');
87 + if (empty($issue_id)) {
88 + return array(65, gettext("Error: The routed email had no associated Eventum issue ID or had an invalid recipient address.") . "\n");
91 if (empty($email_account_id)) {
92 $issue_prj_id = Issue::getProjectID($issue_id);
93 if (empty($issue_prj_id)) {
95 if (@$setup['note_routing']['status'] != 'enabled') {
96 return array(78, gettext("Error: The internal note routing interface is disabled.") . "\n");
98 - $prefix = $setup['note_routing']['address_prefix'];
99 - // escape plus signs so 'note+1@example.com' becomes a valid routing address
100 - $prefix = str_replace('+', '\+', $prefix);
101 - $mail_domain = quotemeta($setup['note_routing']['address_host']);
102 - if (empty($prefix)) {
103 + if (empty($setup['note_routing']['address_prefix'])) {
104 return array(78, gettext("Error: Please configure the email address prefix.") . "\n");
106 - if (empty($mail_domain)) {
107 + if (empty($setup['note_routing']['address_host'])) {
108 return array(78, gettext("Error: Please configure the email address domain.") . "\n");
110 $structure = Mime_Helper::decode($full_message, true, true);
112 // find which issue ID this email refers to
113 - @preg_match("/$prefix(\d*)@$mail_domain/i", $structure->headers['to'], $matches);
114 - @$issue_id = $matches[1];
115 + if (isset($structure->headers['to'])) {
116 + $issue_id = Routing::getMatchingIssueIDs($structure->headers['to'], 'note');
118 // validation is always a good idea
119 - if (empty($issue_id)) {
120 + if (empty($issue_id) and isset($structure->headers['cc'])) {
121 // we need to try the Cc header as well
122 - @preg_match("/$prefix(\d*)@$mail_domain/i", $structure->headers['cc'], $matches);
123 - if (!empty($matches[1])) {
124 - $issue_id = $matches[1];
126 - return array(65, gettext("Error: The routed note had no associated Eventum issue ID or had an invalid recipient address.") . "\n");
128 + $issue_id = Routing::getMatchingIssueIDs($structure->headers['cc'], 'note');
131 + if (empty($issue_id)) {
132 + return array(65, gettext("Error: The routed note had no associated Eventum issue ID or had an invalid recipient address.")" . "\n");
135 $prj_id = Issue::getProjectID($issue_id);
138 Support::extractAttachments($issue_id, $full_message, true, $res);
140 + // FIXME! $res == -2 is not handled
141 History::add($issue_id, Auth::getUserID(), History::getTypeID('note_routed'), ev_gettext('Note routed from %1$s', $structure->headers['from']));
144 @@ -433,30 +424,27 @@
145 if (@$setup['draft_routing']['status'] != 'enabled') {
146 return array(78, gettext("Error: The email draft interface is disabled.") . "\n");
148 - $prefix = $setup['draft_routing']['address_prefix'];
149 - // escape plus signs so 'draft+1@example.com' becomes a valid address
150 - $prefix = str_replace('+', '\+', $prefix);
151 - $mail_domain = quotemeta($setup['draft_routing']['address_host']);
152 - if (empty($prefix)) {
153 + if (empty($setup['draft_routing']['address_prefix'])) {
154 return array(78, gettext("Error: Please configure the email address prefix.") . "\n");
156 - if (empty($mail_domain)) {
157 + if (empty($setup['draft_routing']['address_host'])) {
158 return array(78, gettext("Error: Please configure the email address domain.") . "\n");
161 $structure = Mime_Helper::decode($full_message, true, false);
163 // find which issue ID this email refers to
164 - @preg_match("/$prefix(\d*)@$mail_domain/i", $structure->headers['to'], $matches);
165 - @$issue_id = $matches[1];
166 + if (isset($structure->headers['to'])) {
167 + $issue_id = Routing::getMatchingIssueIDs($structure->headers['to'], 'draft');
169 // validation is always a good idea
170 - if (empty($issue_id)) {
171 + if (empty($issue_id) and isset($structure->headers['cc'])) {
172 // we need to try the Cc header as well
173 - @preg_match("/$prefix(\d*)@$mail_domain/i", $structure->headers['cc'], $matches);
174 - if (!empty($matches[1])) {
175 - $issue_id = $matches[1];
177 - return array(65, gettext("Error: The routed draft had no associated Eventum issue ID or had an invalid recipient address.") . "\n");
179 + $issue_id = Routing::getMatchingIssueIDs($structure->headers['cc'], 'draft');
182 + if (empty($issue_id)) {
183 + return array(65, gettext("Error: The routed email had no associated Eventum issue ID or had an invalid recipient address.") . "\n");
186 $prj_id = Issue::getProjectID($issue_id);
188 History::add($issue_id, Auth::getUserID(), History::getTypeID('draft_routed'), "Draft routed from " . $structure->headers['from']);
193 + * Check for $adresses for matches
195 + * @param mixed $addresses to check
196 + * @param string Type of address match to find (email, note, draft)
197 + * @return mixed $issue_id in case of match otherwise false
199 + function getMatchingIssueIDs($addresses, $type)
201 + $setup = Setup::load();
202 + $settings = $setup["${type}_routing"];
203 + if (!is_array($settings)) {
207 + if (empty($settings['address_prefix'])) {
210 + // escape plus signs so 'issue+1@example.com' becomes a valid routing address
211 + $prefix = quotemeta($settings['address_prefix']);
213 + if (empty($settings['address_host'])) {
216 + $mail_domain = quotemeta($settings['address_host']);
218 + // it is not checked for type when host alias is asked. this leaves
219 + // room foradding host_alias for other than email routing.
220 + if (isset($settings['host_alias'])) {
221 + // TODO: can't quotemeta() host alias as it can contain multiple hosts separated with pipe
222 + $mail_domain = '(?:' . $mail_domain . '|' . $settings['host_alias'] . ')';
225 + // if there are multiple CC or To headers Mail_Mime creates array.
226 + // handle both cases (strings and arrays).
227 + if (!is_array($addresses)) {
228 + $addresses = array($addresses);
231 + // everything safely escaped and checked, try matching address
232 + foreach ($addresses as $address) {
233 + if (preg_match("/$prefix(\d*)@$mail_domain/i", $address, $matches)) {
234 + return $matches[1];
242 --- eventum-1.7.1/include/class.support.php 2006-04-12 00:48:18.619880756 +0300
243 +++ /home/glen/class.support.php 2006-04-12 00:52:33.395572521 +0300
244 @@ -504,22 +504,22 @@
245 if ($info['ema_use_routing'] == 1) {
246 $setup = Setup::load();
248 - if (@$setup['email_routing']['status'] == 'enabled') {
249 - $prefix = $setup['email_routing']['address_prefix'];
250 - // escape plus signs so 'issue+1@example.com' becomes a valid routing address
251 - $prefix = str_replace('+', '\+', $prefix);
252 - $mail_domain = $setup['email_routing']['address_host'];
253 - $mail_domain_alias = @$setup['email_routing']['host_alias'];
254 - if (!empty($mail_domain_alias)) {
255 - $mail_domain = "[" . $mail_domain . "|" . $mail_domain_alias . "]";
257 - if (empty($prefix)) {
259 + // we create addresses array so it can be reused
260 + $addresses = array();
261 + if (isset($email->to)) {
262 + foreach ($email->to as $address) {
263 + $addresses[] = $address->mailbox . '@' . $address->host;
265 - if (empty($mail_domain)) {
268 + if (isset($email->cc)) {
269 + foreach ($email->cc as $address) {
270 + $addresses[] = $address->mailbox . '@' . $address->host;
272 - if ((isset($email->toaddress)) && (preg_match("/$prefix(\d*)@$mail_domain/i", $email->toaddress, $matches))) {
275 + if (@$setup['email_routing']['status'] == 'enabled') {
276 + $res = Routing::getMatchingIssueIDs($addresses, 'email');
277 + if ($res != false) {
278 $return = Routing::route_emails($message);
279 if ($return == true) {
280 Support::deleteMessage($info, $mbox, $num);
284 if (@$setup['note_routing']['status'] == 'enabled') {
285 - $prefix = $setup['note_routing']['address_prefix'];
286 - // escape plus signs so 'note+1@example.com' becomes a valid routing address
287 - $prefix = str_replace('+', '\+', $prefix);
288 - $mail_domain = $setup['note_routing']['address_host'];
289 - if (empty($prefix)) {
292 - if (empty($mail_domain)) {
296 - if (preg_match("/$prefix(\d*)@$mail_domain/i", $email->toaddress, $matches)) {
297 + $res = Routing::getMatchingIssueIDs($addresses, 'note');
298 + if ($res != false) {
299 $return = Routing::route_notes($message);
300 if ($return == true) {
301 Support::deleteMessage($info, $mbox, $num);
305 if (@$setup['draft_routing']['status'] == 'enabled') {
306 - $prefix = $setup['draft_routing']['address_prefix'];
307 - // escape plus signs so 'draft+1@example.com' becomes a valid routing address
308 - $prefix = str_replace('+', '\+', $prefix);
309 - $mail_domain = $setup['draft_routing']['address_host'];
310 - if (empty($prefix)) {
313 - if (empty($mail_domain)) {
317 - if (preg_match("/$prefix(\d*)@$mail_domain/i", $email->toaddress, $matches)) {
318 + $res = Routing::getMatchingIssueIDs($addresses, 'draft');
319 + if ($res != false) {
320 $return = Routing::route_drafts($message);
321 if ($return == true) {
322 Support::deleteMessage($info, $mbox, $num);
324 -------------------------------------------------------------------------------------------------------
325 Fix possible Cc: headers composition of routed Notes where Eventum user email and email from headers differ with case.
326 --- eventum-1.7.1/include/class.routing.php 2006-04-12 00:48:18.189871149 +0300
327 +++ /home/glen/class.routing.php 2006-04-12 00:52:33.295570287 +0300
328 @@ -356,12 +346,11 @@
330 foreach ($addresses as $email) {
331 if (in_array(strtolower($email), $user_emails)) {
332 - $cc_users[] = $users[$email];
333 + $cc_users[] = $users[strtolower($email)];
337 $body = Mime_Helper::getMessageBody($structure);
339 $reference_msg_id = Mail_API::getReferenceMessageID($headers);
340 if (!empty($reference_msg_id)) {
341 $parent_id = Note::getIDByMessageID($reference_msg_id);
342 -------------------------------------------------------------------------------------------------------
343 API cleanup: drop unneccessary $email_account_id in route_emails to be consistent with download_emails based routing.
344 --- eventum-1.7.1/misc/route_emails.php 2006-04-12 00:54:57.398789518 +0300
345 +++ /home/glen/route_emails.php 2006-04-12 01:03:52.300737408 +0300
347 include_once(APP_INC_PATH . "db_access.php");
348 include_once(APP_INC_PATH . "class.routing.php");
350 -$email_account_id = $HTTP_SERVER_VARS['argv'][1];
351 $full_message = Misc::getInput();
353 -$return = Routing::route_emails($full_message, $email_account_id);
354 +$return = Routing::route_emails($full_message);
355 if (is_array($return)) {
358 --- eventum-1.7.1/include/class.routing.php 2006-04-12 00:54:57.278786838 +0300
359 +++ /home/glen/class.routing.php 2006-04-12 01:03:45.370582745 +0300
361 * Routes an email to the correct issue.
363 * @param string $full_message The full email message, including headers
364 - * @param integer $email_account_id The ID of the email account this email should be routed too. If empty this method will try to figure it out
366 - function route_emails($full_message, $email_account_id = 0)
367 + function route_emails($full_message)
369 GLOBAL $HTTP_POST_VARS;