Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | ||
18 | // we should consider moving these to the settings table | |
19 | // before the 4.1 release | |
20 | define('EMAIL_ACTIVITY_TYPE_ID', NULL); | |
21 | define('MAIL_BATCH_SIZE', 50); | |
5bc392e6 EM |
22 | |
23 | /** | |
b8c71ffa | 24 | * Class CRM_Utils_Mail_EmailProcessor. |
5bc392e6 | 25 | */ |
6a488035 TO |
26 | class CRM_Utils_Mail_EmailProcessor { |
27 | ||
01467aec EE |
28 | const MIME_MAX_RECURSION = 10; |
29 | ||
6a488035 TO |
30 | /** |
31 | * Process the default mailbox (ie. that is used by civiMail for the bounce) | |
32 | * | |
3ff238ae | 33 | * @param bool $is_create_activities |
34 | * Should activities be created | |
6a488035 | 35 | */ |
3ff238ae | 36 | public static function processBounces($is_create_activities) { |
ae5ffbb7 | 37 | $dao = new CRM_Core_DAO_MailSettings(); |
353ffa53 | 38 | $dao->domain_id = CRM_Core_Config::domainID(); |
6a488035 TO |
39 | $dao->is_default = TRUE; |
40 | $dao->find(); | |
41 | ||
42 | while ($dao->fetch()) { | |
3ff238ae | 43 | self::_process(TRUE, $dao, $is_create_activities); |
6a488035 | 44 | } |
6a488035 TO |
45 | } |
46 | ||
6a488035 | 47 | /** |
b8c71ffa | 48 | * Process the mailboxes that aren't default (ie. that aren't used by civiMail for the bounce). |
ee3db087 SL |
49 | * |
50 | * @return bool | |
51 | * | |
52 | * @throws CRM_Core_Exception. | |
6a488035 | 53 | */ |
00be9182 | 54 | public static function processActivities() { |
ae5ffbb7 | 55 | $dao = new CRM_Core_DAO_MailSettings(); |
353ffa53 | 56 | $dao->domain_id = CRM_Core_Config::domainID(); |
6a488035 TO |
57 | $dao->is_default = FALSE; |
58 | $dao->find(); | |
59 | $found = FALSE; | |
60 | while ($dao->fetch()) { | |
61 | $found = TRUE; | |
2c2409c3 | 62 | self::_process(FALSE, $dao, TRUE); |
6a488035 TO |
63 | } |
64 | if (!$found) { | |
ee3db087 | 65 | throw new CRM_Core_Exception(ts('No mailboxes have been configured for Email to Activity Processing')); |
6a488035 TO |
66 | } |
67 | return $found; | |
68 | } | |
69 | ||
70 | /** | |
fe482240 | 71 | * Process the mailbox for all the settings from civicrm_mail_settings. |
6a488035 | 72 | * |
fd31fa4c | 73 | * @param bool|string $civiMail if true, processing is done in CiviMail context, or Activities otherwise. |
6a488035 | 74 | */ |
00be9182 | 75 | public static function process($civiMail = TRUE) { |
ae5ffbb7 | 76 | $dao = new CRM_Core_DAO_MailSettings(); |
6a488035 TO |
77 | $dao->domain_id = CRM_Core_Config::domainID(); |
78 | $dao->find(); | |
79 | ||
80 | while ($dao->fetch()) { | |
81 | self::_process($civiMail, $dao); | |
82 | } | |
83 | } | |
84 | ||
5bc392e6 EM |
85 | /** |
86 | * @param $civiMail | |
040073c9 | 87 | * @param CRM_Core_DAO_MailSettings $dao |
3ff238ae | 88 | * @param bool $is_create_activities |
89 | * Create activities. | |
5bc392e6 EM |
90 | * |
91 | * @throws Exception | |
ee3db087 | 92 | * @throws CRM_Core_Exception |
5bc392e6 | 93 | */ |
3ff238ae | 94 | public static function _process($civiMail, $dao, $is_create_activities) { |
6a488035 TO |
95 | // 0 = activities; 1 = bounce; |
96 | $usedfor = $dao->is_default; | |
97 | ||
ae5ffbb7 | 98 | $emailActivityTypeId |
d15a97f4 | 99 | = (defined('EMAIL_ACTIVITY_TYPE_ID') && EMAIL_ACTIVITY_TYPE_ID) |
100 | ? EMAIL_ACTIVITY_TYPE_ID | |
70a32eb8 | 101 | : CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email'); |
6a488035 TO |
102 | |
103 | if (!$emailActivityTypeId) { | |
ee3db087 | 104 | throw new CRM_Core_Exception(ts('Could not find a valid Activity Type ID for Inbound Email')); |
6a488035 TO |
105 | } |
106 | ||
353ffa53 | 107 | $config = CRM_Core_Config::singleton(); |
f0fed404 JF |
108 | $verpSeparator = preg_quote($config->verpSeparator); |
109 | $twoDigitStringMin = $verpSeparator . '(\d+)' . $verpSeparator . '(\d+)'; | |
110 | $twoDigitString = $twoDigitStringMin . $verpSeparator; | |
111 | $threeDigitString = $twoDigitString . '(\d+)' . $verpSeparator; | |
6a488035 TO |
112 | |
113 | // FIXME: legacy regexen to handle CiviCRM 2.1 address patterns, with domain id and possible VERP part | |
114 | $commonRegex = '/^' . preg_quote($dao->localpart) . '(b|bounce|c|confirm|o|optOut|r|reply|re|e|resubscribe|u|unsubscribe)' . $threeDigitString . '([0-9a-f]{16})(-.*)?@' . preg_quote($dao->domain) . '$/'; | |
115 | $subscrRegex = '/^' . preg_quote($dao->localpart) . '(s|subscribe)' . $twoDigitStringMin . '@' . preg_quote($dao->domain) . '$/'; | |
116 | ||
117 | // a common-for-all-actions regex to handle CiviCRM 2.2 address patterns | |
118 | $regex = '/^' . preg_quote($dao->localpart) . '(b|c|e|o|r|u)' . $twoDigitString . '([0-9a-f]{16})@' . preg_quote($dao->domain) . '$/'; | |
119 | ||
120 | // a tighter regex for finding bounce info in soft bounces’ mail bodies | |
619526f6 | 121 | $rpRegex = '/Return-Path:\s*' . preg_quote($dao->localpart) . '(b)' . $twoDigitString . '([0-9a-f]{16})@' . preg_quote($dao->domain) . '/'; |
6a488035 | 122 | |
1a4d92b6 | 123 | // a regex for finding bound info X-Header |
08523e94 O |
124 | $rpXheaderRegex = '/X-CiviMail-Bounce: ' . preg_quote($dao->localpart) . '(b)' . $twoDigitString . '([0-9a-f]{16})@' . preg_quote($dao->domain) . '/i'; |
125 | // CiviMail in regex and Civimail in header !!! | |
1a4d92b6 | 126 | |
6a488035 TO |
127 | // retrieve the emails |
128 | try { | |
129 | $store = CRM_Mailing_MailStore::getStore($dao->name); | |
130 | } | |
993a642c | 131 | catch (Exception $e) { |
86bfa4f6 | 132 | $message = ts('Could not connect to MailStore for ') . $dao->username . '@' . $dao->server . '<p>'; |
6a488035 TO |
133 | $message .= ts('Error message: '); |
134 | $message .= '<pre>' . $e->getMessage() . '</pre><p>'; | |
ee3db087 | 135 | throw new CRM_Core_Exception($message); |
6a488035 TO |
136 | } |
137 | ||
6a488035 TO |
138 | // process fifty at a time, CRM-4002 |
139 | while ($mails = $store->fetchNext(MAIL_BATCH_SIZE)) { | |
140 | foreach ($mails as $key => $mail) { | |
141 | ||
142 | // for every addressee: match address elements if it's to CiviMail | |
be2fb01f | 143 | $matches = []; |
6a488035 TO |
144 | $action = NULL; |
145 | ||
146 | if ($usedfor == 1) { | |
147 | foreach ($mail->to as $address) { | |
148 | if (preg_match($regex, $address->email, $matches)) { | |
149 | list($match, $action, $job, $queue, $hash) = $matches; | |
150 | break; | |
151 | // FIXME: the below elseifs should be dropped when we drop legacy support | |
152 | } | |
153 | elseif (preg_match($commonRegex, $address->email, $matches)) { | |
154 | list($match, $action, $_, $job, $queue, $hash) = $matches; | |
155 | break; | |
156 | } | |
157 | elseif (preg_match($subscrRegex, $address->email, $matches)) { | |
158 | list($match, $action, $_, $job) = $matches; | |
159 | break; | |
160 | } | |
161 | } | |
162 | ||
163 | // CRM-5471: if $matches is empty, it still might be a soft bounce sent | |
164 | // to another address, so scan the body for ‘Return-Path: …bounce-pattern…’ | |
165 | if (!$matches and preg_match($rpRegex, $mail->generateBody(), $matches)) { | |
166 | list($match, $action, $job, $queue, $hash) = $matches; | |
167 | } | |
168 | ||
1a4d92b6 DL |
169 | // if $matches is still empty, look for the X-CiviMail-Bounce header |
170 | // CRM-9855 | |
171 | if (!$matches and preg_match($rpXheaderRegex, $mail->generateBody(), $matches)) { | |
172 | list($match, $action, $job, $queue, $hash) = $matches; | |
173 | } | |
08523e94 O |
174 | // With Mandrilla, the X-CiviMail-Bounce header is produced by generateBody |
175 | // is base64 encoded | |
176 | // Check all parts | |
177 | if (!$matches) { | |
6ac3485f | 178 | $all_parts = $mail->fetchParts(); |
08523e94 O |
179 | foreach ($all_parts as $k_part => $v_part) { |
180 | if ($v_part instanceof ezcMailFile) { | |
181 | $p_file = $v_part->__get('fileName'); | |
6ac3485f | 182 | $c_file = file_get_contents($p_file); |
08523e94 | 183 | if (preg_match($rpXheaderRegex, $c_file, $matches)) { |
08523e94 O |
184 | list($match, $action, $job, $queue, $hash) = $matches; |
185 | } | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
6a488035 TO |
190 | // if all else fails, check Delivered-To for possible pattern |
191 | if (!$matches and preg_match($regex, $mail->getHeader('Delivered-To'), $matches)) { | |
192 | list($match, $action, $job, $queue, $hash) = $matches; | |
193 | } | |
194 | } | |
195 | ||
196 | // preseve backward compatibility | |
3ff238ae | 197 | if ($usedfor == 0 || $is_create_activities) { |
f945f0c4 I |
198 | // Mail account may have 'Skip emails which do not have a Case ID |
199 | // or Case hash' option, if its enabled and email is not related | |
200 | // to cases - then we need to put email to ignored folder. | |
201 | $caseMailUtils = new CRM_Utils_Mail_CaseMail(); | |
202 | if (!empty($dao->is_non_case_email_skipped) && !$caseMailUtils->isCaseEmail($mail->subject)) { | |
203 | $store->markIgnored($key); | |
204 | continue; | |
205 | } | |
206 | ||
6a488035 | 207 | // if its the activities that needs to be processed .. |
5fdd5f80 | 208 | try { |
993a642c I |
209 | $createContact = !($dao->is_contact_creation_disabled_if_no_match ?? FALSE); |
210 | $mailParams = CRM_Utils_Mail_Incoming::parseMailingObject($mail, $createContact, FALSE); | |
fad9031a | 211 | } |
83cd2236 DH |
212 | catch (Exception $e) { |
213 | echo $e->getMessage(); | |
214 | $store->markIgnored($key); | |
215 | continue; | |
216 | } | |
6a488035 | 217 | |
360ebaac | 218 | $params = self::deprecated_activity_buildmailparams($mailParams, $emailActivityTypeId); |
6a488035 TO |
219 | |
220 | $params['version'] = 3; | |
040073c9 CW |
221 | if (!empty($dao->activity_status)) { |
222 | $params['status_id'] = $dao->activity_status; | |
223 | } | |
993a642c | 224 | |
6a488035 TO |
225 | $result = civicrm_api('activity', 'create', $params); |
226 | ||
227 | if ($result['is_error']) { | |
228 | $matches = FALSE; | |
229 | echo "Failed Processing: {$mail->subject}. Reason: {$result['error_message']}\n"; | |
230 | } | |
231 | else { | |
232 | $matches = TRUE; | |
7349cf08 | 233 | CRM_Utils_Hook::emailProcessor('activity', $params, $mail, $result); |
6a488035 TO |
234 | echo "Processed as Activity: {$mail->subject}\n"; |
235 | } | |
6a488035 TO |
236 | } |
237 | ||
238 | // if $matches is empty, this email is not CiviMail-bound | |
239 | if (!$matches) { | |
240 | $store->markIgnored($key); | |
241 | continue; | |
242 | } | |
243 | ||
244 | // get $replyTo from either the Reply-To header or from From | |
245 | // FIXME: make sure it works with Reply-Tos containing non-email stuff | |
246 | $replyTo = $mail->getHeader('Reply-To') ? $mail->getHeader('Reply-To') : $mail->from->email; | |
247 | ||
248 | // handle the action by passing it to the proper API call | |
249 | // FIXME: leave only one-letter cases when dropping legacy support | |
250 | if (!empty($action)) { | |
251 | $result = NULL; | |
252 | ||
253 | switch ($action) { | |
254 | case 'b': | |
255 | case 'bounce': | |
256 | $text = ''; | |
257 | if ($mail->body instanceof ezcMailText) { | |
258 | $text = $mail->body->text; | |
259 | } | |
260 | elseif ($mail->body instanceof ezcMailMultipart) { | |
01467aec | 261 | $text = self::getTextFromMultipart($mail->body); |
6a488035 | 262 | } |
9dcd46ef | 263 | elseif ($mail->body instanceof ezcMailFile) { |
264 | $text = file_get_contents($mail->body->__get('fileName')); | |
265 | } | |
6a488035 TO |
266 | |
267 | if ( | |
9b9a8713 | 268 | empty($text) && |
6a488035 TO |
269 | $mail->subject == "Delivery Status Notification (Failure)" |
270 | ) { | |
271 | // Exchange error - CRM-9361 | |
272 | foreach ($mail->body->getParts() as $part) { | |
273 | if ($part instanceof ezcMailDeliveryStatus) { | |
274 | foreach ($part->recipients as $rec) { | |
275 | if ($rec["Status"] == "5.1.1") { | |
9b9a8713 SL |
276 | if (isset($rec["Description"])) { |
277 | $text = $rec["Description"]; | |
278 | } | |
279 | else { | |
0addad12 | 280 | $text = $rec["Status"] . " Delivery to the following recipients failed"; |
9b9a8713 | 281 | } |
6a488035 TO |
282 | break; |
283 | } | |
284 | } | |
285 | } | |
286 | } | |
287 | } | |
288 | ||
289 | if (empty($text)) { | |
290 | // If bounce processing fails, just take the raw body. Cf. CRM-11046 | |
291 | $text = $mail->generateBody(); | |
292 | ||
293 | // if text is still empty, lets fudge a blank text so the api call below will succeed | |
6ac9d864 DL |
294 | if (empty($text)) { |
295 | $text = ts('We could not extract the mail body from this bounce message.'); | |
296 | } | |
6a488035 TO |
297 | } |
298 | ||
be2fb01f | 299 | $params = [ |
6a488035 TO |
300 | 'job_id' => $job, |
301 | 'event_queue_id' => $queue, | |
302 | 'hash' => $hash, | |
303 | 'body' => $text, | |
304 | 'version' => 3, | |
cdc5c450 | 305 | // Setting is_transactional means it will rollback if |
306 | // it crashes part way through creating the bounce. | |
307 | // If the api were standard & had a create this would be the | |
308 | // default. Adding the standard api & deprecating this one | |
309 | // would probably be the | |
310 | // most consistent way to address this - but this is | |
311 | // a quick hack. | |
312 | 'is_transactional' => 1, | |
be2fb01f | 313 | ]; |
6a488035 TO |
314 | $result = civicrm_api('Mailing', 'event_bounce', $params); |
315 | break; | |
316 | ||
317 | case 'c': | |
318 | case 'confirm': | |
319 | // CRM-7921 | |
be2fb01f | 320 | $params = [ |
6a488035 TO |
321 | 'contact_id' => $job, |
322 | 'subscribe_id' => $queue, | |
323 | 'hash' => $hash, | |
324 | 'version' => 3, | |
be2fb01f | 325 | ]; |
6a488035 TO |
326 | $result = civicrm_api('Mailing', 'event_confirm', $params); |
327 | break; | |
328 | ||
329 | case 'o': | |
330 | case 'optOut': | |
be2fb01f | 331 | $params = [ |
6a488035 TO |
332 | 'job_id' => $job, |
333 | 'event_queue_id' => $queue, | |
334 | 'hash' => $hash, | |
335 | 'version' => 3, | |
be2fb01f | 336 | ]; |
6a488035 TO |
337 | $result = civicrm_api('MailingGroup', 'event_domain_unsubscribe', $params); |
338 | break; | |
339 | ||
340 | case 'r': | |
341 | case 'reply': | |
342 | // instead of text and HTML parts (4th and 6th params) send the whole email as the last param | |
be2fb01f | 343 | $params = [ |
6a488035 TO |
344 | 'job_id' => $job, |
345 | 'event_queue_id' => $queue, | |
346 | 'hash' => $hash, | |
347 | 'bodyTxt' => NULL, | |
348 | 'replyTo' => $replyTo, | |
349 | 'bodyHTML' => NULL, | |
350 | 'fullEmail' => $mail->generate(), | |
351 | 'version' => 3, | |
be2fb01f | 352 | ]; |
6a488035 TO |
353 | $result = civicrm_api('Mailing', 'event_reply', $params); |
354 | break; | |
355 | ||
356 | case 'e': | |
357 | case 're': | |
358 | case 'resubscribe': | |
be2fb01f | 359 | $params = [ |
6a488035 TO |
360 | 'job_id' => $job, |
361 | 'event_queue_id' => $queue, | |
362 | 'hash' => $hash, | |
363 | 'version' => 3, | |
be2fb01f | 364 | ]; |
6a488035 TO |
365 | $result = civicrm_api('MailingGroup', 'event_resubscribe', $params); |
366 | break; | |
367 | ||
368 | case 's': | |
369 | case 'subscribe': | |
be2fb01f | 370 | $params = [ |
6a488035 TO |
371 | 'email' => $mail->from->email, |
372 | 'group_id' => $job, | |
373 | 'version' => 3, | |
be2fb01f | 374 | ]; |
6a488035 TO |
375 | $result = civicrm_api('MailingGroup', 'event_subscribe', $params); |
376 | break; | |
377 | ||
378 | case 'u': | |
379 | case 'unsubscribe': | |
be2fb01f | 380 | $params = [ |
6a488035 TO |
381 | 'job_id' => $job, |
382 | 'event_queue_id' => $queue, | |
383 | 'hash' => $hash, | |
384 | 'version' => 3, | |
be2fb01f | 385 | ]; |
6a488035 TO |
386 | $result = civicrm_api('MailingGroup', 'event_unsubscribe', $params); |
387 | break; | |
388 | } | |
389 | ||
390 | if ($result['is_error']) { | |
391 | echo "Failed Processing: {$mail->subject}, Action: $action, Job ID: $job, Queue ID: $queue, Hash: $hash. Reason: {$result['error_message']}\n"; | |
392 | } | |
393 | else { | |
394 | CRM_Utils_Hook::emailProcessor('mailing', $params, $mail, $result, $action); | |
395 | } | |
396 | } | |
397 | ||
398 | $store->markProcessed($key); | |
399 | } | |
400 | // CRM-7356 – used by IMAP only | |
401 | $store->expunge(); | |
402 | } | |
403 | } | |
96025800 | 404 | |
01467aec EE |
405 | /** |
406 | * @param \ezcMailMultipart $multipart | |
407 | * @param int $recursionLevel | |
408 | * | |
409 | * @return array | |
410 | */ | |
411 | protected static function getTextFromMultipart($multipart, $recursionLevel = 0) { | |
412 | if ($recursionLevel >= self::MIME_MAX_RECURSION) { | |
413 | return NULL; | |
414 | } | |
415 | $recursionLevel += 1; | |
416 | $text = NULL; | |
417 | if ($multipart instanceof ezcMailMultipartReport) { | |
418 | $text = self::getTextFromMulipartReport($multipart, $recursionLevel); | |
419 | } | |
420 | elseif ($multipart instanceof ezcMailMultipartRelated) { | |
421 | $text = self::getTextFromMultipartRelated($multipart, $recursionLevel); | |
422 | } | |
423 | else { | |
424 | foreach ($multipart->getParts() as $part) { | |
425 | if (isset($part->subType) and $part->subType === 'plain') { | |
426 | $text = $part->text; | |
427 | } | |
428 | elseif ($part instanceof ezcMailMultipart) { | |
429 | $text = self::getTextFromMultipart($part, $recursionLevel); | |
430 | } | |
431 | if ($text) { | |
432 | break; | |
433 | } | |
434 | } | |
435 | } | |
436 | return $text; | |
437 | } | |
438 | ||
439 | /** | |
440 | * @param \ezcMailMultipartRelated $related | |
441 | * @param int $recursionLevel | |
442 | * | |
443 | * @return array | |
444 | */ | |
445 | protected static function getTextFromMultipartRelated($related, $recursionLevel) { | |
446 | $text = NULL; | |
447 | foreach ($related->getRelatedParts() as $part) { | |
448 | if (isset($part->subType) and $part->subType === 'plain') { | |
449 | $text = $part->text; | |
450 | } | |
451 | elseif ($part instanceof ezcMailMultipart) { | |
452 | $text = self::getTextFromMultipart($part, $recursionLevel); | |
453 | } | |
454 | if ($text) { | |
455 | break; | |
456 | } | |
457 | } | |
458 | return $text; | |
459 | } | |
460 | ||
461 | /** | |
462 | * @param \ezcMailMultipartReport $multipart | |
463 | * @param $recursionLevel | |
464 | * | |
465 | * @return array | |
466 | */ | |
467 | protected static function getTextFromMulipartReport($multipart, $recursionLevel) { | |
468 | $text = NULL; | |
469 | $part = $multipart->getMachinePart(); | |
470 | if ($part instanceof ezcMailDeliveryStatus) { | |
471 | foreach ($part->recipients as $rec) { | |
472 | if (isset($rec["Diagnostic-Code"])) { | |
473 | $text = $rec["Diagnostic-Code"]; | |
474 | break; | |
475 | } | |
476 | elseif (isset($rec["Description"])) { | |
477 | $text = $rec["Description"]; | |
478 | break; | |
479 | } | |
480 | // no diagnostic info present - try getting the human readable part | |
481 | elseif (isset($rec["Status"])) { | |
482 | $text = $rec["Status"]; | |
483 | $textpart = $multipart->getReadablePart(); | |
484 | if ($textpart !== NULL and isset($textpart->text)) { | |
485 | $text .= " " . $textpart->text; | |
486 | } | |
487 | else { | |
488 | $text .= " Delivery failed but no diagnostic code or description."; | |
489 | } | |
490 | break; | |
491 | } | |
492 | } | |
493 | } | |
494 | elseif ($part !== NULL and isset($part->text)) { | |
495 | $text = $part->text; | |
496 | } | |
497 | elseif (($part = $multipart->getReadablePart()) !== NULL) { | |
498 | if (isset($part->text)) { | |
499 | $text = $part->text; | |
500 | } | |
501 | elseif ($part instanceof ezcMailMultipart) { | |
502 | $text = self::getTextFromMultipart($part, $recursionLevel); | |
503 | } | |
504 | } | |
505 | return $text; | |
506 | } | |
507 | ||
360ebaac | 508 | /** |
509 | * @param array $result | |
510 | * @param int $activityTypeID | |
511 | * | |
512 | * @return array | |
513 | * <type> $params | |
514 | */ | |
515 | protected static function deprecated_activity_buildmailparams($result, $activityTypeID) { | |
516 | // get ready for collecting data about activity to be created | |
517 | $params = []; | |
518 | ||
519 | $params['activity_type_id'] = $activityTypeID; | |
520 | ||
521 | $params['status_id'] = 'Completed'; | |
522 | if (!empty($result['from']['id'])) { | |
523 | $params['source_contact_id'] = $params['assignee_contact_id'] = $result['from']['id']; | |
524 | } | |
525 | $params['target_contact_id'] = []; | |
526 | $keys = ['to', 'cc', 'bcc']; | |
527 | foreach ($keys as $key) { | |
528 | if (is_array($result[$key])) { | |
529 | foreach ($result[$key] as $key => $keyValue) { | |
530 | if (!empty($keyValue['id'])) { | |
531 | $params['target_contact_id'][] = $keyValue['id']; | |
532 | } | |
533 | } | |
534 | } | |
535 | } | |
536 | $params['subject'] = $result['subject']; | |
537 | $params['activity_date_time'] = $result['date']; | |
538 | $params['details'] = $result['body']; | |
539 | ||
540 | $numAttachments = Civi::settings()->get('max_attachments_backend') ?? CRM_Core_BAO_File::DEFAULT_MAX_ATTACHMENTS_BACKEND; | |
541 | for ($i = 1; $i <= $numAttachments; $i++) { | |
542 | if (isset($result["attachFile_$i"])) { | |
543 | $params["attachFile_$i"] = $result["attachFile_$i"]; | |
544 | } | |
545 | else { | |
546 | // No point looping 100 times if there's only one attachment | |
547 | break; | |
548 | } | |
549 | } | |
550 | ||
551 | return $params; | |
552 | } | |
553 | ||
6a488035 | 554 | } |