dolibarr 19.0.3
emailcollector.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
24// Put here all includes required by your class file
25include_once DOL_DOCUMENT_ROOT .'/emailcollector/lib/emailcollector.lib.php';
26
27require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
28require_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
29
30require_once DOL_DOCUMENT_ROOT .'/comm/propal/class/propal.class.php'; // Customer Proposal
31require_once DOL_DOCUMENT_ROOT .'/commande/class/commande.class.php'; // Sale Order
32require_once DOL_DOCUMENT_ROOT .'/compta/facture/class/facture.class.php'; // Customer Invoice
33require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php'; // Contact / Address
34require_once DOL_DOCUMENT_ROOT .'/expedition/class/expedition.class.php'; // Shipping / Delivery
35require_once DOL_DOCUMENT_ROOT .'/fourn/class/fournisseur.commande.class.php'; // Purchase Order
36require_once DOL_DOCUMENT_ROOT .'/fourn/class/fournisseur.facture.class.php'; // Purchase Invoice
37require_once DOL_DOCUMENT_ROOT .'/projet/class/project.class.php'; // Project
38require_once DOL_DOCUMENT_ROOT .'/reception/class/reception.class.php'; // Reception
39require_once DOL_DOCUMENT_ROOT .'/recruitment/class/recruitmentcandidature.class.php'; // Recruiting
40require_once DOL_DOCUMENT_ROOT .'/societe/class/societe.class.php'; // Third-Party
41require_once DOL_DOCUMENT_ROOT .'/supplier_proposal/class/supplier_proposal.class.php'; // Supplier Proposal
42require_once DOL_DOCUMENT_ROOT .'/ticket/class/ticket.class.php'; // Ticket
43//require_once DOL_DOCUMENT_ROOT .'/expensereport/class/expensereport.class.php'; // Expense Report
44//require_once DOL_DOCUMENT_ROOT .'/holiday/class/holiday.class.php'; // Holidays (leave request)
45
46
47use Webklex\PHPIMAP\ClientManager;
48use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
49use Webklex\PHPIMAP\Exceptions\InvalidWhereQueryCriteriaException;
50use Webklex\PHPIMAP\Exceptions\GetMessagesFailedException;
51
52use OAuth\Common\Storage\DoliStorage;
53use OAuth\Common\Consumer\Credentials;
54
59{
63 public $element = 'emailcollector';
64
68 public $table_element = 'emailcollector_emailcollector';
69
73 public $ismultientitymanaged = 1;
74
78 public $isextrafieldmanaged = 0;
79
83 public $picto = 'email';
84
88 public $fk_element = 'fk_emailcollector';
89
93 protected $childtables = array();
94
98 protected $childtablesoncascade = array('emailcollector_emailcollectorfilter', 'emailcollector_emailcollectoraction');
99
100
120 // BEGIN MODULEBUILDER PROPERTIES
124 public $fields = array(
125 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1),
126 'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>20),
127 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1, 'help'=>'Example: MyCollector1', 'csslist'=>'tdoverflowmax200'),
128 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'notnull'=>-1, 'searchall'=>1, 'help'=>'Example: My Email collector', 'csslist'=>'tdoverflowmax150'),
129 'description' => array('type'=>'text', 'label'=>'Description', 'visible'=>-1, 'enabled'=>1, 'position'=>60, 'notnull'=>-1, 'cssview'=>'small', 'csslist'=>'small tdoverflowmax200'),
130 'host' => array('type'=>'varchar(255)', 'label'=>'EMailHost', 'visible'=>1, 'enabled'=>1, 'position'=>90, 'notnull'=>1, 'searchall'=>1, 'comment'=>"IMAP server", 'help'=>'Example: imap.gmail.com', 'csslist'=>'tdoverflowmax125'),
131 'port' => array('type'=>'varchar(10)', 'label'=>'EMailHostPort', 'visible'=>1, 'enabled'=>1, 'position'=>91, 'notnull'=>1, 'searchall'=>0, 'comment'=>"IMAP server port", 'help'=>'Example: 993', 'csslist'=>'tdoverflowmax50', 'default'=>'993'),
132 'hostcharset' => array('type'=>'varchar(16)', 'label'=>'HostCharset', 'visible'=>-1, 'enabled'=>1, 'position'=>92, 'notnull'=>0, 'searchall'=>0, 'comment'=>"IMAP server charset", 'help'=>'Example: "UTF-8" (May be "US-ASCII" with some Office365)', 'default'=>'UTF-8'),
133 'imap_encryption' => array('type'=>'varchar(16)', 'label'=>'ImapEncryption', 'visible'=>-1, 'enabled'=>1, 'position'=>93, 'searchall'=>0, 'comment'=>"IMAP encryption", 'help'=>'ImapEncryptionHelp', 'arrayofkeyval'=> array('ssl'=>'SSL', 'tls' => 'TLS', 'notls' => 'NOTLS'), 'default'=>'ssl'),
134 'norsh' => array('type'=>'integer', 'label'=>'NoRSH', 'visible'=>-1, 'enabled'=>"!getDolGlobalInt('MAIN_IMAP_USE_PHPIMAP')", 'position'=>94, 'searchall'=>0, 'help'=>'NoRSHHelp', 'arrayofkeyval'=> array(0 =>'No', 1 => 'Yes'), 'default'=> 0),
135 'acces_type' => array('type'=>'integer', 'label'=>'accessType', 'visible'=>-1, 'enabled'=>"getDolGlobalInt('MAIN_IMAP_USE_PHPIMAP')", 'position'=>101, 'notnull'=>1, 'index'=>1, 'comment'=>"IMAP login type", 'arrayofkeyval'=>array('0'=>'loginPassword', '1'=>'oauthToken'), 'default'=>'0', 'help'=>''),
136 'login' => array('type'=>'varchar(128)', 'label'=>'Login', 'visible'=>-1, 'enabled'=>1, 'position'=>102, 'notnull'=>-1, 'index'=>1, 'comment'=>"IMAP login", 'help'=>'Example: myaccount@gmail.com'),
137 'password' => array('type'=>'password', 'label'=>'Password', 'visible'=>-1, 'enabled'=>"1", 'position'=>103, 'notnull'=>-1, 'comment'=>"IMAP password", 'help'=>'WithGMailYouCanCreateADedicatedPassword'),
138 'oauth_service' => array('type'=>'varchar(128)', 'label'=>'oauthService', 'visible'=>-1, 'enabled'=>"getDolGlobalInt('MAIN_IMAP_USE_PHPIMAP')", 'position'=>104, 'notnull'=>0, 'index'=>1, 'comment'=>"IMAP login oauthService", 'arrayofkeyval'=>array(), 'help'=>'TokenMustHaveBeenCreated'),
139 'source_directory' => array('type'=>'varchar(255)', 'label'=>'MailboxSourceDirectory', 'visible'=>-1, 'enabled'=>1, 'position'=>109, 'notnull'=>1, 'default' => 'Inbox', 'help'=>'Example: INBOX, [Gmail]/Spam, [Gmail]/Draft, [Gmail]/Brouillons, [Gmail]/Sent Mail, [Gmail]/Messages envoyés, ...'),
140 'target_directory' => array('type'=>'varchar(255)', 'label'=>'MailboxTargetDirectory', 'visible'=>1, 'enabled'=>1, 'position'=>110, 'notnull'=>0, 'help'=>"EmailCollectorTargetDir"),
141 'maxemailpercollect' => array('type'=>'integer', 'label'=>'MaxEmailCollectPerCollect', 'visible'=>-1, 'enabled'=>1, 'position'=>111, 'default'=>50),
142 'datelastresult' => array('type'=>'datetime', 'label'=>'DateLastCollectResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>121, 'notnull'=>-1, 'csslist'=>'nowraponall'),
143 'codelastresult' => array('type'=>'varchar(16)', 'label'=>'CodeLastResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>122, 'notnull'=>-1,),
144 'lastresult' => array('type'=>'varchar(255)', 'label'=>'LastResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>123, 'notnull'=>-1, 'cssview'=>'small', 'csslist'=>'small tdoverflowmax200'),
145 'datelastok' => array('type'=>'datetime', 'label'=>'DateLastcollectResultOk', 'visible'=>1, 'enabled'=>'$action != "create"', 'position'=>125, 'notnull'=>-1, 'csslist'=>'nowraponall'),
146 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'visible'=>0, 'enabled'=>1, 'position'=>61, 'notnull'=>-1,),
147 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'visible'=>0, 'enabled'=>1, 'position'=>62, 'notnull'=>-1,),
148 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>-2, 'enabled'=>1, 'position'=>500, 'notnull'=>1,),
149 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-2, 'enabled'=>1, 'position'=>501, 'notnull'=>1,),
150 //'date_validation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>502),
151 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'visible'=>-2, 'enabled'=>1, 'position'=>510, 'notnull'=>1,),
152 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'visible'=>-2, 'enabled'=>1, 'position'=>511, 'notnull'=>-1,),
153 //'fk_user_valid' =>array('type'=>'integer', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>512),
154 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'visible'=>-2, 'enabled'=>1, 'position'=>1000, 'notnull'=>-1,),
155 'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'default'=>'0', 'index'=>1, 'arrayofkeyval'=>array('0'=>'Inactive', '1'=>'Active'))
156 );
157
158
162 public $rowid;
163
167 public $ref;
168
172 public $entity;
173
177 public $label;
178
179
183 public $status;
184
188 public $date_creation;
189
193 public $tms;
194
198 public $fk_user_creat;
199
203 public $fk_user_modif;
204
208 public $import_key;
209
210 public $host;
211 public $port;
212 public $hostcharset;
213 public $login;
214 public $password;
215 public $acces_type;
216 public $oauth_service;
217 public $imap_encryption;
218 public $norsh;
219 public $source_directory;
220 public $target_directory;
221 public $maxemailpercollect;
222
226 public $datelastresult;
227
228 public $codelastresult;
229 public $lastresult;
230 public $datelastok;
231 // END MODULEBUILDER PROPERTIES
232
233 public $filters;
234 public $actions;
235
236 public $debuginfo;
237
238 const STATUS_DISABLED = 0;
239 const STATUS_ENABLED = 1;
240
241
247 public function __construct(DoliDB $db)
248 {
249 global $conf, $langs;
250
251 $this->db = $db;
252
253 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
254 $this->fields['rowid']['visible'] = 0;
255 }
256 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
257 $this->fields['entity']['enabled'] = 0;
258 }
259
260 // List of oauth services
261 $oauthservices = array();
262
263 foreach ($conf->global as $key => $val) {
264 if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) {
265 $key = preg_replace('/^OAUTH_/', '', $key);
266 $key = preg_replace('/_ID$/', '', $key);
267 if (preg_match('/^.*-/', $key)) {
268 $name = preg_replace('/^.*-/', '', $key);
269 } else {
270 $name = $langs->trans("NoName");
271 }
272 $provider = preg_replace('/-.*$/', '', $key);
273 $provider = ucfirst(strtolower($provider));
274
275 $oauthservices[$key] = $name." (".$provider.")";
276 }
277 }
278
279 $this->fields['oauth_service']['arrayofkeyval'] = $oauthservices;
280
281 // Unset fields that are disabled
282 foreach ($this->fields as $key => $val) {
283 if (isset($val['enabled']) && empty($val['enabled'])) {
284 unset($this->fields[$key]);
285 }
286 }
287
288 // Translate some data of arrayofkeyval
289 foreach ($this->fields as $key => $val) {
290 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
291 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
292 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
293 }
294 }
295 }
296 }
297
305 public function create(User $user, $notrigger = false)
306 {
307 global $langs;
308
309 // Check parameters
310 if ($this->host && preg_match('/^http:/i', trim($this->host))) {
311 $langs->load("errors");
312 $this->error = $langs->trans("ErrorHostMustNotStartWithHttp", $this->host);
313 return -1;
314 }
315
316 include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
317 $this->password = dolEncrypt($this->password);
318
319 $id = $this->createCommon($user, $notrigger);
320
321 $this->password = dolDecrypt($this->password);
322
323 if (is_array($this->filters) && count($this->filters)) {
324 $emailcollectorfilter = new EmailCollectorFilter($this->db);
325
326 foreach ($this->filters as $filter) {
327 $emailcollectorfilter->type = $filter['type'];
328 $emailcollectorfilter->rulevalue = $filter['rulevalue'];
329 $emailcollectorfilter->fk_emailcollector = $this->id;
330 $emailcollectorfilter->status = $filter['status'];
331
332 $emailcollectorfilter->create($user);
333 }
334 }
335
336 if (is_array($this->actions) && count($this->actions)) {
337 $emailcollectoroperation = new EmailCollectorAction($this->db);
338
339 foreach ($this->actions as $operation) {
340 $emailcollectoroperation->type = $operation['type'];
341 $emailcollectoroperation->actionparam = $operation['actionparam'];
342 $emailcollectoroperation->fk_emailcollector = $this->id;
343 $emailcollectoroperation->status = $operation['status'];
344 $emailcollectoroperation->position = $operation['position'];
345
346 $emailcollectoroperation->create($user);
347 }
348 }
349
350 return $id;
351 }
352
360 public function createFromClone(User $user, $fromid)
361 {
362 global $langs, $extrafields;
363 $error = 0;
364
365 dol_syslog(__METHOD__, LOG_DEBUG);
366
367 $object = new self($this->db);
368
369 $this->db->begin();
370
371 // Load source object
372 $object->fetchCommon($fromid);
373
374 $object->fetchFilters(); // Rules
375 $object->fetchActions(); // Operations
376
377 // Reset some properties
378 unset($object->id);
379 unset($object->fk_user_creat);
380 unset($object->import_key);
381 unset($object->password);
382 unset($object->lastresult);
383 unset($object->codelastresult);
384 unset($object->datelastresult);
385 unset($object->datelastok);
386 unset($object->debuginfo);
387
388 // Clear fields
389 $object->ref = "copy_of_".$object->ref;
390 $object->label = $langs->trans("CopyOf")." ".$object->label;
391 if (empty($object->host)) {
392 $object->host = 'imap.example.com';
393 }
394 // Clear extrafields that are unique
395 if (is_array($object->array_options) && count($object->array_options) > 0) {
396 $extrafields->fetch_name_optionals_label($this->table_element);
397 foreach ($object->array_options as $key => $option) {
398 $shortkey = preg_replace('/options_/', '', $key);
399 if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
400 //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
401 unset($object->array_options[$key]);
402 }
403 }
404 }
405
406 // Create clone
407 $object->context['createfromclone'] = 'createfromclone';
408 $result = $object->create($user);
409 if ($result < 0) {
410 $error++;
411 $this->error = $object->error;
412 $this->errors = $object->errors;
413 }
414
415 unset($object->context['createfromclone']);
416
417 // End
418 if (!$error) {
419 $this->db->commit();
420 return $object;
421 } else {
422 $this->db->rollback();
423 return -1;
424 }
425 }
426
434 public function fetch($id, $ref = null)
435 {
436 $result = $this->fetchCommon($id, $ref);
437
438 include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
439 $this->password = dolDecrypt($this->password);
440
441 //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
442 return $result;
443 }
444
450 /*
451 public function fetchLines()
452 {
453 $this->lines=array();
454
455 // Load lines with object EmailCollectorLine
456
457 return count($this->lines)?1:0;
458 }
459 */
460
472 public function fetchAll(User $user, $activeOnly = 0, $sortfield = 's.rowid', $sortorder = 'ASC', $limit = 100, $page = 0)
473 {
474 global $langs;
475
476 $obj_ret = array();
477
478 $sql = "SELECT s.rowid";
479 $sql .= " FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector as s";
480 $sql .= ' WHERE s.entity IN ('.getEntity('emailcollector').')';
481 if ($activeOnly) {
482 $sql .= " AND s.status = 1";
483 }
484 $sql .= $this->db->order($sortfield, $sortorder);
485 if ($limit) {
486 if ($page < 0) {
487 $page = 0;
488 }
489 $offset = $limit * $page;
490
491 $sql .= $this->db->plimit($limit + 1, $offset);
492 }
493
494 $result = $this->db->query($sql);
495 if ($result) {
496 $num = $this->db->num_rows($result);
497 $i = 0;
498 while ($i < $num) {
499 $obj = $this->db->fetch_object($result);
500 $emailcollector_static = new EmailCollector($this->db);
501 if ($emailcollector_static->fetch($obj->rowid)) {
502 $obj_ret[] = $emailcollector_static;
503 }
504 $i++;
505 }
506 } else {
507 $this->errors[] = 'EmailCollector::fetchAll Error when retrieve emailcollector list';
508 dol_syslog('EmailCollector::fetchAll Error when retrieve emailcollector list', LOG_ERR);
509 $ret = -1;
510 }
511 if (!count($obj_ret)) {
512 dol_syslog('EmailCollector::fetchAll No emailcollector found', LOG_DEBUG);
513 }
514
515 return $obj_ret;
516 }
517
525 public function update(User $user, $notrigger = false)
526 {
527 global $langs;
528
529 // Check parameters
530 if ($this->host && preg_match('/^http:/i', trim($this->host))) {
531 $langs->load("errors");
532 $this->error = $langs->trans("ErrorHostMustNotStartWithHttp", $this->host);
533 return -1;
534 }
535
536 include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
537 $this->password = dolEncrypt($this->password);
538
539 $result = $this->updateCommon($user, $notrigger);
540
541 $this->password = dolDecrypt($this->password);
542
543 return $result;
544 }
545
553 public function delete(User $user, $notrigger = false)
554 {
555 return $this->deleteCommon($user, $notrigger, 1);
556 }
557
568 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
569 {
570 global $conf, $langs, $action, $hookmanager;
571
572 if (!empty($conf->dol_no_mouse_hover)) {
573 $notooltip = 1; // Force disable tooltips
574 }
575
576 $result = '';
577
578 $label = '<u>'.$langs->trans("EmailCollector").'</u>';
579 $label .= '<br>';
580 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
581
582 $url = DOL_URL_ROOT.'/admin/emailcollector_card.php?id='.$this->id;
583
584 if ($option != 'nolink') {
585 // Add param to save lastsearch_values or not
586 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
587 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
588 $add_save_lastsearch_values = 1;
589 }
590 if ($add_save_lastsearch_values) {
591 $url .= '&save_lastsearch_values=1';
592 }
593 }
594
595 $linkclose = '';
596 if (empty($notooltip)) {
597 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
598 $label = $langs->trans("ShowEmailCollector");
599 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
600 }
601 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
602 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
603 } else {
604 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
605 }
606
607 $linkstart = '<a href="'.$url.'"';
608 $linkstart .= $linkclose.'>';
609 $linkend = '</a>';
610
611 $result .= $linkstart;
612 if ($withpicto) {
613 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
614 }
615 if ($withpicto != 2) {
616 $result .= $this->ref;
617 }
618 $result .= $linkend;
619 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
620
621 $hookmanager->initHooks(array('emailcollectordao'));
622 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
623 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
624 if ($reshook > 0) {
625 $result = $hookmanager->resPrint;
626 } else {
627 $result .= $hookmanager->resPrint;
628 }
629
630 return $result;
631 }
632
639 public function getLibStatut($mode = 0)
640 {
641 return $this->LibStatut($this->status, $mode);
642 }
643
644 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
652 public function LibStatut($status, $mode = 0)
653 {
654 // phpcs:enable
655 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
656 global $langs;
657 //$langs->load("mymodule");
658 $this->labelStatus[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
659 $this->labelStatus[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
660 $this->labelStatusShort[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
661 $this->labelStatusShort[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
662 }
663
664 $statusType = 'status5';
665 if ($status == self::STATUS_ENABLED) {
666 $statusType = 'status4';
667 }
668
669 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
670 }
671
678 public function info($id)
679 {
680 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
681 $sql .= ' fk_user_creat, fk_user_modif';
682 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
683 $sql .= ' WHERE t.rowid = '.((int) $id);
684 $result = $this->db->query($sql);
685 if ($result) {
686 if ($this->db->num_rows($result)) {
687 $obj = $this->db->fetch_object($result);
688
689 $this->id = $obj->rowid;
690
691 $this->user_creation_id = $obj->fk_user_creat;
692 $this->user_modification_id = $obj->fk_user_modif;
693 $this->date_creation = $this->db->jdate($obj->datec);
694 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
695 }
696
697 $this->db->free($result);
698 } else {
699 dol_print_error($this->db);
700 }
701 }
702
709 public function initAsSpecimen()
710 {
711 $this->host = 'localhost';
712 $this->login = 'alogin';
713
714 $this->initAsSpecimenCommon();
715 }
716
723 public function fetchFilters()
724 {
725 $this->filters = array();
726
727 $sql = 'SELECT rowid, type, rulevalue, status';
728 $sql .= ' FROM '.MAIN_DB_PREFIX.'emailcollector_emailcollectorfilter';
729 $sql .= ' WHERE fk_emailcollector = '.((int) $this->id);
730 //$sql.= ' ORDER BY position';
731
732 $resql = $this->db->query($sql);
733 if ($resql) {
734 $num = $this->db->num_rows($resql);
735 $i = 0;
736 while ($i < $num) {
737 $obj = $this->db->fetch_object($resql);
738 $this->filters[$obj->rowid] = array('id'=>$obj->rowid, 'type'=>$obj->type, 'rulevalue'=>$obj->rulevalue, 'status'=>$obj->status);
739 $i++;
740 }
741 $this->db->free($resql);
742 } else {
743 dol_print_error($this->db);
744 }
745
746 return 1;
747 }
748
755 public function fetchActions()
756 {
757 $this->actions = array();
758
759 $sql = 'SELECT rowid, type, actionparam, status';
760 $sql .= ' FROM '.MAIN_DB_PREFIX.'emailcollector_emailcollectoraction';
761 $sql .= ' WHERE fk_emailcollector = '.((int) $this->id);
762 $sql .= ' ORDER BY position';
763
764 $resql = $this->db->query($sql);
765 if ($resql) {
766 $num = $this->db->num_rows($resql);
767 $i = 0;
768 while ($i < $num) {
769 $obj = $this->db->fetch_object($resql);
770 $this->actions[$obj->rowid] = array('id'=>$obj->rowid, 'type'=>$obj->type, 'actionparam'=>$obj->actionparam, 'status'=>$obj->status);
771 $i++;
772 }
773 $this->db->free($resql);
774
775 return 1;
776 } else {
777 dol_print_error($this->db);
778
779 return -1;
780 }
781 }
782
783
789 public function getConnectStringIMAP()
790 {
791 global $conf;
792
793 // Connect to IMAP
794 $flags = '/service=imap'; // IMAP
795 if (getDolGlobalString('IMAP_FORCE_TLS')) {
796 $flags .= '/tls';
797 } elseif (empty($this->imap_encryption) || ($this->imap_encryption == 'ssl' && getDolGlobalString('IMAP_FORCE_NOSSL'))) {
798 $flags .= '';
799 } else {
800 $flags .= '/' . $this->imap_encryption;
801 }
802
803 $flags .= '/novalidate-cert';
804 //$flags.='/readonly';
805 //$flags.='/debug';
806 if (!empty($this->norsh) || getDolGlobalString('IMAP_FORCE_NORSH')) {
807 $flags .= '/norsh';
808 }
809 //Used in shared mailbox from Office365
810 if (strpos($this->login, '/') != false) {
811 $partofauth = explode('/', $this->login);
812 $flags .= '/authuser='.$partofauth[0].'/user='.$partofauth[1];
813 }
814
815 $connectstringserver = '{'.$this->host.':'.$this->port.$flags.'}';
816
817 return $connectstringserver;
818 }
819
826 public function getEncodedUtf7($str)
827 {
828 if (function_exists('mb_convert_encoding')) {
829 // change spaces by entropy because mb_convert fail with spaces
830 $str = preg_replace("/ /", "xxxSPACExxx", $str); // the replacement string must be valid in utf7 so _ can't be used
831 $str = preg_replace("/\[Gmail\]/", "xxxGMAILxxx", $str); // the replacement string must be valid in utf7 so _ can't be used
832 // if mb_convert work
833 if ($str = mb_convert_encoding($str, "UTF-7")) {
834 // change characters
835 $str = preg_replace("/\+A/", "&A", $str);
836 // change to spaces again
837 $str = preg_replace("/xxxSPACExxx/", " ", $str);
838 // change to [Gmail] again
839 $str = preg_replace("/xxxGMAILxxx/", "[Gmail]", $str);
840 return $str;
841 } else {
842 // print error and return false
843 $this->error = "error: is not possible to encode this string '".$str."'";
844 return false;
845 }
846 } else {
847 return $str;
848 }
849 }
850
857 public function doCollect()
858 {
859 global $user;
860
861 $nberror = 0;
862
863 $arrayofcollectors = $this->fetchAll($user, 1);
864
865 // Loop on each collector
866 foreach ($arrayofcollectors as $emailcollector) {
867 $result = $emailcollector->doCollectOneCollector(0);
868 dol_syslog("doCollect result = ".$result." for emailcollector->id = ".$emailcollector->id);
869
870 $this->error .= 'EmailCollector ID '.$emailcollector->id.':'.$emailcollector->error.'<br>';
871 if (!empty($emailcollector->errors)) {
872 $this->error .= join('<br>', $emailcollector->errors);
873 }
874 $this->output .= 'EmailCollector ID '.$emailcollector->id.': '.$emailcollector->lastresult.'<br>';
875 }
876
877 return $nberror;
878 }
879
891 private function overwritePropertiesOfObject(&$object, $actionparam, $messagetext, $subject, $header, &$operationslog)
892 {
893 global $conf, $langs;
894
895 $errorforthisaction = 0;
896
897 // set output lang
898 $outputlangs = $langs;
899 $newlang = '';
900 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
901 $newlang = GETPOST('lang_id', 'aZ09');
902 }
903 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
904 $newlang = $object->thirdparty->default_lang;
905 }
906 if (!empty($newlang)) {
907 $outputlangs = new Translate('', $conf);
908 $outputlangs->setDefaultLang($newlang);
909 }
910
911 // Overwrite values with values extracted from source email
912 // $this->actionparam = 'opportunity_status=123;abc=EXTRACT:BODY:....'
913 $arrayvaluetouse = dolExplodeIntoArray($actionparam, '(\n\r|\r|\n|;)', '=');
914
915 $tmp = array();
916
917 // Loop on each property set into actionparam
918 foreach ($arrayvaluetouse as $propertytooverwrite => $valueforproperty) {
919 $tmpclass = '';
920 $tmpproperty = '';
921 $tmparray = explode('.', $propertytooverwrite);
922 if (count($tmparray) == 2) {
923 $tmpclass = $tmparray[0];
924 $tmpproperty = $tmparray[1];
925 } else {
926 $tmpproperty = $tmparray[0];
927 }
928 if ($tmpclass && ($tmpclass != $object->element)) {
929 continue; // Property is for another type of object
930 }
931
932 //if (property_exists($object, $tmpproperty) || preg_match('/^options_/', $tmpproperty))
933 if ($tmpproperty) {
934 $sourcestring = '';
935 $sourcefield = '';
936 $regexstring = '';
937 //$transformationstring='';
938 $regforregex = array();
939 if (preg_match('/^EXTRACT:([a-zA-Z0-9_]+):(.*):([^:])$/', $valueforproperty, $regforregex)) {
940 $sourcefield = $regforregex[1];
941 $regexstring = $regforregex[2];
942 //$transofrmationstring=$regforregex[3];
943 } elseif (preg_match('/^EXTRACT:([a-zA-Z0-9_]+):(.*)$/', $valueforproperty, $regforregex)) {
944 $sourcefield = $regforregex[1];
945 $regexstring = $regforregex[2];
946 }
947
948 if (!empty($sourcefield) && !empty($regexstring)) {
949 if (strtolower($sourcefield) == 'body') {
950 $sourcestring = $messagetext;
951 } elseif (strtolower($sourcefield) == 'subject') {
952 $sourcestring = $subject;
953 } elseif (strtolower($sourcefield) == 'header') {
954 $sourcestring = $header;
955 }
956
957 if ($sourcestring) {
958 $regforval = array();
959 $regexoptions = '';
960 if (strtolower($sourcefield) == 'body') {
961 $regexoptions = 'ms'; // The m means ^ and $ char is valid at each new line. The s means the char '.' is valid for new lines char too
962 }
963 if (strtolower($sourcefield) == 'header') {
964 $regexoptions = 'm'; // The m means ^ and $ char is valid at each new line.
965 }
966
967 //var_dump($tmpproperty.' - '.$regexstring.' - '.$regexoptions.' - '.$sourcestring);
968 if (preg_match('/'.$regexstring.'/'.$regexoptions, $sourcestring, $regforval)) {
969 // Overwrite param $tmpproperty
970 $valueextracted = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
971 if (strtolower($sourcefield) == 'header') { // extract from HEADER
972 if (preg_match('/^options_/', $tmpproperty)) {
973 $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $this->decodeSMTPSubject($valueextracted);
974 } else {
975 if (property_exists($object, $tmpproperty)) {
976 $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted);
977 } else {
978 $tmp[$tmpproperty] = $this->decodeSMTPSubject($valueextracted);
979 }
980 }
981 } else { // extract from BODY
982 if (preg_match('/^options_/', $tmpproperty)) {
983 $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $this->decodeSMTPSubject($valueextracted);
984 } else {
985 if (property_exists($object, $tmpproperty)) {
986 $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted);
987 } else {
988 $tmp[$tmpproperty] = $this->decodeSMTPSubject($valueextracted);
989 }
990 }
991 }
992 if (preg_match('/^options_/', $tmpproperty)) {
993 $operationslog .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($object->array_options[preg_replace('/^options_/', '', $tmpproperty)], 128));
994 } else {
995 if (property_exists($object, $tmpproperty)) {
996 $operationslog .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($object->$tmpproperty, 128));
997 } else {
998 $operationslog .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($tmp[$tmpproperty], 128));
999 }
1000 }
1001 } else {
1002 // Regex not found
1003 if (property_exists($object, $tmpproperty)) {
1004 $object->$tmpproperty = null;
1005 } else {
1006 $tmp[$tmpproperty] = null;
1007 }
1008
1009 $operationslog .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> not found, so property '.dol_escape_htmltag($tmpproperty).' is set to null.';
1010 }
1011 } else {
1012 // Nothing can be done for this param
1013 $errorforthisaction++;
1014 $this->error = 'The extract rule to use to overwrite properties has on an unknown source (must be HEADER, SUBJECT or BODY)';
1015 $this->errors[] = $this->error;
1016
1017 $operationslog .= '<br>'.$this->error;
1018 }
1019 } elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $regforregex)) {
1020 $valuecurrent = '';
1021 if (preg_match('/^options_/', $tmpproperty)) {
1022 $valuecurrent = $object->array_options[preg_replace('/^options_/', '', $tmpproperty)];
1023 } else {
1024 if (property_exists($object, $tmpproperty)) {
1025 $valuecurrent = $object->$tmpproperty;
1026 } else {
1027 $valuecurrent = $tmp[$tmpproperty];
1028 }
1029 }
1030
1031 if ($regforregex[1] == 'SET' || empty($valuecurrent)) {
1032 $valuetouse = $regforregex[2];
1033 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
1034 complete_substitutions_array($substitutionarray, $outputlangs, $object);
1035 $matcharray = array();
1036 preg_match_all('/__([a-z0-9]+(?:_[a-z0-9]+)?)__/i', $valuetouse, $matcharray);
1037 //var_dump($tmpproperty.' - '.$object->$tmpproperty.' - '.$valuetouse); var_dump($matcharray);
1038 if (is_array($matcharray[1])) { // $matcharray[1] is an array with the list of substitution key found without the __X__ syntax into the SET entry
1039 foreach ($matcharray[1] as $keytoreplace) {
1040 if ($keytoreplace) {
1041 if (preg_match('/^options_/', $keytoreplace)) {
1042 $substitutionarray['__'.$keytoreplace.'__'] = $object->array_options[preg_replace('/^options_/', '', $keytoreplace)];
1043 } else {
1044 if (property_exists($object, $keytoreplace)) {
1045 $substitutionarray['__'.$keytoreplace.'__'] = $object->$keytoreplace;
1046 } else {
1047 $substitutionarray['__'.$keytoreplace.'__'] = $tmp[$keytoreplace];
1048 }
1049 }
1050 }
1051 }
1052 }
1053 //var_dump($substitutionarray);
1054 //dol_syslog('substitutionarray='.var_export($substitutionarray, true));
1055
1056 $valuetouse = make_substitutions($valuetouse, $substitutionarray);
1057 if (preg_match('/^options_/', $tmpproperty)) {
1058 $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $valuetouse;
1059
1060 $operationslog .= '<br>Set value '.dol_escape_htmltag($valuetouse).' into object->array_options['.dol_escape_htmltag(preg_replace('/^options_/', '', $tmpproperty)).']';
1061 } else {
1062 if (property_exists($object, $tmpproperty)) {
1063 $object->$tmpproperty = $valuetouse;
1064 } else {
1065 $tmp[$tmpproperty] = $valuetouse;
1066 }
1067
1068 $operationslog .= '<br>Set value '.dol_escape_htmltag($valuetouse).' into object->'.dol_escape_htmltag($tmpproperty);
1069 }
1070 }
1071 } else {
1072 $errorforthisaction++;
1073 $this->error = 'Bad syntax for description of action parameters: '.$actionparam;
1074 $this->errors[] = $this->error;
1075 }
1076 }
1077 }
1078
1079 return $errorforthisaction;
1080 }
1081
1088 public function doCollectOneCollector($mode = 0)
1089 {
1090 global $db, $conf, $langs, $user;
1091 global $hookmanager;
1092
1093 //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1094
1095 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1096 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1097 require_once DOL_DOCUMENT_ROOT.'/includes/webklex/php-imap/vendor/autoload.php';
1098 }
1099
1100 dol_syslog("EmailCollector::doCollectOneCollector start for id=".$this->id." - ".$this->ref, LOG_INFO);
1101
1102 $langs->loadLangs(array("project", "companies", "mails", "errors", "ticket", "agenda", "commercial"));
1103
1104 $error = 0;
1105 $this->output = '';
1106 $this->error = '';
1107 $this->debuginfo = '';
1108
1109 $search = '';
1110 $searchhead = '';
1111 $searchfilterdoltrackid = 0;
1112 $searchfilternodoltrackid = 0;
1113 $searchfilterisanswer = 0;
1114 $searchfilterisnotanswer = 0;
1115 $searchfilterreplyto = 0;
1116 $searchfilterexcludebodyarray = array();
1117 $searchfilterexcludesubjectarray = array();
1118 $operationslog = '';
1119
1120 $now = dol_now();
1121
1122 if (empty($this->host)) {
1123 $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('EMailHost'));
1124 return -1;
1125 }
1126 if (empty($this->login)) {
1127 $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Login'));
1128 return -1;
1129 }
1130 if (empty($this->source_directory)) {
1131 $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('MailboxSourceDirectory'));
1132 return -1;
1133 }
1134
1135 $sourcedir = $this->source_directory;
1136 $targetdir = ($this->target_directory ? $this->target_directory : ''); // Can be '[Gmail]/Trash' or 'mytag'
1137
1138 $this->fetchFilters();
1139 $this->fetchActions();
1140
1141 $sourcedir = $this->source_directory;
1142 $targetdir = ($this->target_directory ? $this->target_directory : ''); // Can be '[Gmail]/Trash' or 'mytag'
1143
1144 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1145 if ($this->acces_type == 1) {
1146 // Mode OAUth2 (access_type == 1) with PHP-IMAP
1147 $this->debuginfo .= 'doCollectOneCollector is using method MAIN_IMAP_USE_PHPIMAP=1, access_type=1 (OAUTH2)<br>';
1148
1149 require_once DOL_DOCUMENT_ROOT.'/core/lib/oauth.lib.php';
1150
1151 $supportedoauth2array = getSupportedOauth2Array();
1152
1153 $keyforsupportedoauth2array = $this->oauth_service;
1154 if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
1155 $keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
1156 } else {
1157 $keyforprovider = '';
1158 }
1159 $keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
1160 $keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
1161
1162 $OAUTH_SERVICENAME = 'Unknown';
1163 if (array_key_exists($keyforsupportedoauth2array, $supportedoauth2array)
1164 && array_key_exists('name', $supportedoauth2array[$keyforsupportedoauth2array])
1165 && !empty($supportedoauth2array[$keyforsupportedoauth2array]['name'])) {
1166 $OAUTH_SERVICENAME = $supportedoauth2array[$keyforsupportedoauth2array]['name'].(!empty($keyforprovider) ? '-'.$keyforprovider : '');
1167 }
1168
1169 require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
1170 //$debugtext = "Host: ".$this->host."<br>Port: ".$this->port."<br>Login: ".$this->login."<br>Password: ".$this->password."<br>access type: ".$this->acces_type."<br>oauth service: ".$this->oauth_service."<br>Max email per collect: ".$this->maxemailpercollect;
1171 //dol_syslog($debugtext);
1172
1173 $token = '';
1174
1175 $storage = new DoliStorage($db, $conf, $keyforprovider);
1176
1177 try {
1178 $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
1179
1180 $expire = true;
1181 // Is token expired or will token expire in the next 30 seconds
1182 // if (is_object($tokenobj)) {
1183 // $expire = ($tokenobj->getEndOfLife() !== -9002 && $tokenobj->getEndOfLife() !== -9001 && time() > ($tokenobj->getEndOfLife() - 30));
1184 // }
1185 // Token expired so we refresh it
1186 if (is_object($tokenobj) && $expire) {
1187 $credentials = new Credentials(
1188 getDolGlobalString('OAUTH_'.$this->oauth_service.'_ID'),
1189 getDolGlobalString('OAUTH_'.$this->oauth_service.'_SECRET'),
1190 getDolGlobalString('OAUTH_'.$this->oauth_service.'_URLAUTHORIZE')
1191 );
1192 $serviceFactory = new \OAuth\ServiceFactory();
1193 $oauthname = explode('-', $OAUTH_SERVICENAME);
1194 // ex service is Google-Emails we need only the first part Google
1195 $apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, array());
1196 // We have to save the token because Google give it only once
1197 $refreshtoken = $tokenobj->getRefreshToken();
1198 $tokenobj = $apiService->refreshAccessToken($tokenobj);
1199 $tokenobj->setRefreshToken($refreshtoken);
1200 $storage->storeAccessToken($OAUTH_SERVICENAME, $tokenobj);
1201 }
1202 $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
1203 if (is_object($tokenobj)) {
1204 $token = $tokenobj->getAccessToken();
1205 } else {
1206 $this->error = "Token not found";
1207 return -1;
1208 }
1209 } catch (Exception $e) {
1210 // Return an error if token not found
1211 $this->error = $e->getMessage();
1212 dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR);
1213 return -1;
1214 }
1215
1216 $cm = new ClientManager();
1217 $client = $cm->make([
1218 'host' => $this->host,
1219 'port' => $this->port,
1220 'encryption' => !empty($this->imap_encryption) ? $this->imap_encryption : false,
1221 'validate_cert' => true,
1222 'protocol' => 'imap',
1223 'username' => $this->login,
1224 'password' => $token,
1225 'authentication' => "oauth",
1226 ]);
1227 } else {
1228 // Mode LOGIN (login/pass) with PHP-IMAP
1229 $this->debuginfo .= 'doCollectOneCollector is using method MAIN_IMAP_USE_PHPIMAP=1, access_type=0 (LOGIN)<br>';
1230
1231 $cm = new ClientManager();
1232 $client = $cm->make([
1233 'host' => $this->host,
1234 'port' => $this->port,
1235 'encryption' => !empty($this->imap_encryption) ? $this->imap_encryption : false,
1236 'validate_cert' => true,
1237 'protocol' => 'imap',
1238 'username' => $this->login,
1239 'password' => $this->password,
1240 'authentication' => "login",
1241 ]);
1242 }
1243
1244 try {
1245 $client->connect();
1246 } catch (ConnectionFailedException $e) {
1247 $this->error = $e->getMessage();
1248 $this->errors[] = $this->error;
1249 dol_syslog("EmailCollector::doCollectOneCollector ".$this->error, LOG_ERR);
1250 return -1;
1251 }
1252
1253 $host = dol_getprefix('email');
1254 } else {
1255 // Use native IMAP functions
1256 $this->debuginfo .= 'doCollectOneCollector is using method MAIN_IMAP_USE_PHPIMAP=0 (native PHP imap, LOGIN)<br>';
1257
1258 if (!function_exists('imap_open')) {
1259 $this->error = 'IMAP function not enabled on your PHP';
1260 return -2;
1261 }
1262
1263 $connectstringserver = $this->getConnectStringIMAP();
1264 $connectstringsource = $connectstringserver.$this->getEncodedUtf7($sourcedir);
1265 $connectstringtarget = $connectstringserver.$this->getEncodedUtf7($targetdir);
1266
1267 $this->debuginfo .= 'connectstringsource = '.$connectstringsource.', $connectstringtarget='.$connectstringtarget.'<br>';
1268
1269 $connection = imap_open($connectstringsource, $this->login, $this->password);
1270 if (!$connection) {
1271 $this->error = 'Failed to open IMAP connection '.$connectstringsource.' '.imap_last_error();
1272 return -3;
1273 }
1274 imap_errors(); // Clear stack of errors.
1275
1276 $host = dol_getprefix('email');
1277 //$host = '123456';
1278
1279 // Define the IMAP search string
1280 // See https://tools.ietf.org/html/rfc3501#section-6.4.4 for IMAPv4 (PHP not yet compatible)
1281 // See https://tools.ietf.org/html/rfc1064 page 13 for IMAPv2
1282 //$search='ALL';
1283 }
1284
1285 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1286 // Use PHPIMAP external library
1287 $criteria = array(array('UNDELETED')); // Seems not supported by some servers
1288 foreach ($this->filters as $rule) {
1289 if (empty($rule['status'])) {
1290 continue;
1291 }
1292
1293 $not = '';
1294 if (strpos($rule['rulevalue'], '!') === 0) {
1295 // The value start with !, so we exclude the criteria
1296 $not = 'NOT ';
1297 // Then remove the ! from the string for next filters
1298 $rule['rulevalue'] = substr($rule['rulevalue'], 1);
1299 }
1300
1301 if ($rule['type'] == 'from') {
1302 $tmprulevaluearray = explode('*', $rule['rulevalue']);
1303 if (count($tmprulevaluearray) >= 2) {
1304 foreach ($tmprulevaluearray as $tmprulevalue) {
1305 array_push($criteria, array($not."FROM" => $tmprulevalue));
1306 }
1307 } else {
1308 array_push($criteria, array($not."FROM" => $rule['rulevalue']));
1309 }
1310 }
1311 if ($rule['type'] == 'to') {
1312 $tmprulevaluearray = explode('*', $rule['rulevalue']);
1313 if (count($tmprulevaluearray) >= 2) {
1314 foreach ($tmprulevaluearray as $tmprulevalue) {
1315 array_push($criteria, array($not."TO" => $tmprulevalue));
1316 }
1317 } else {
1318 array_push($criteria, array($not."TO" => $rule['rulevalue']));
1319 }
1320 }
1321 if ($rule['type'] == 'bcc') {
1322 array_push($criteria, array($not."BCC" => $rule['rulevalue']));
1323 }
1324 if ($rule['type'] == 'cc') {
1325 array_push($criteria, array($not."CC" => $rule['rulevalue']));
1326 }
1327 if ($rule['type'] == 'subject') {
1328 if (strpos($rule['rulevalue'], '!') === 0) {
1329 //array_push($criteria, array("NOT SUBJECT" => $rule['rulevalue']));
1330 $searchfilterexcludesubjectarray[] = preg_replace('/^!/', '', $rule['rulevalue']);
1331 } else {
1332 array_push($criteria, array("SUBJECT" => $rule['rulevalue']));
1333 }
1334 }
1335 if ($rule['type'] == 'body') {
1336 if (strpos($rule['rulevalue'], '!') === 0) {
1337 //array_push($criteria, array("NOT BODY" => $rule['rulevalue']));
1338 $searchfilterexcludebodyarray[] = preg_replace('/^!/', '', $rule['rulevalue']);
1339 } else {
1340 array_push($criteria, array("BODY" => $rule['rulevalue']));
1341 }
1342 }
1343 if ($rule['type'] == 'header') {
1344 array_push($criteria, array($not."HEADER" => $rule['rulevalue']));
1345 }
1346
1347 /* seems not used */
1348 /*
1349 if ($rule['type'] == 'notinsubject') {
1350 array_push($criteria, array($not."SUBJECT NOT" => $rule['rulevalue']));
1351 }
1352 if ($rule['type'] == 'notinbody') {
1353 array_push($criteria, array($not."BODY NOT" => $rule['rulevalue']));
1354 }*/
1355
1356 if ($rule['type'] == 'seen') {
1357 array_push($criteria, array($not."SEEN"));
1358 }
1359 if ($rule['type'] == 'unseen') {
1360 array_push($criteria, array($not."UNSEEN"));
1361 }
1362 if ($rule['type'] == 'unanswered') {
1363 array_push($criteria, array($not."UNANSWERED"));
1364 }
1365 if ($rule['type'] == 'answered') {
1366 array_push($criteria, array($not."ANSWERED"));
1367 }
1368 if ($rule['type'] == 'smaller') {
1369 array_push($criteria, array($not."SMALLER"));
1370 }
1371 if ($rule['type'] == 'larger') {
1372 array_push($criteria, array($not."LARGER"));
1373 }
1374
1375 // Rules to filter after the search imap
1376 if ($rule['type'] == 'withtrackingidinmsgid') {
1377 $searchfilterdoltrackid++;
1378 $searchhead .= '/Message-ID.*@'.preg_quote($host, '/').'/';
1379 }
1380 if ($rule['type'] == 'withouttrackingidinmsgid') {
1381 $searchfilterdoltrackid++;
1382 $searchhead .= '/Message-ID.*@'.preg_quote($host, '/').'/';
1383 }
1384 if ($rule['type'] == 'withtrackingid') {
1385 $searchfilterdoltrackid++;
1386 $searchhead .= '/References.*@'.preg_quote($host, '/').'/';
1387 }
1388 if ($rule['type'] == 'withouttrackingid') {
1389 $searchfilternodoltrackid++;
1390 $searchhead .= '! /References.*@'.preg_quote($host, '/').'/';
1391 }
1392
1393 if ($rule['type'] == 'isanswer') {
1394 $searchfilterisanswer++;
1395 $searchhead .= '/References.*@.*/';
1396 }
1397 if ($rule['type'] == 'isnotanswer') {
1398 $searchfilterisnotanswer++;
1399 $searchhead .= '! /References.*@.*/';
1400 }
1401
1402 if ($rule['type'] == 'replyto') {
1403 $searchfilterreplyto++;
1404 $searchhead .= '/Reply-To.*'.preg_quote($rule['rulevalue'], '/').'/';
1405 }
1406 }
1407
1408 if (empty($targetdir)) { // Use last date as filter if there is no targetdir defined.
1409 $fromdate = 0;
1410 if ($this->datelastok) {
1411 $fromdate = $this->datelastok;
1412 }
1413 if ($fromdate > 0) {
1414 // $search .= ($search ? ' ' : '').'SINCE '.date('j-M-Y', $fromdate - 1); // SENTSINCE not supported. Date must be X-Abc-9999 (X on 1 digit if < 10)
1415 array_push($criteria, array("SINCE" => date('j-M-Y', $fromdate - 1)));
1416 }
1417 //$search.=($search?' ':'').'SINCE 8-Apr-2022';
1418 }
1419
1420 dol_syslog("IMAP search string = ".var_export($criteria, true));
1421 $search = var_export($criteria, true);
1422 } else {
1423 // Use native IMAP functions
1424 $search = 'UNDELETED'; // Seems not supported by some servers
1425 foreach ($this->filters as $rule) {
1426 if (empty($rule['status'])) {
1427 continue;
1428 }
1429
1430 // Forge the IMAP search string.
1431 // See https://www.rfc-editor.org/rfc/rfc3501
1432
1433 $not = '';
1434 if (strpos($rule['rulevalue'], '!') === 0) {
1435 // The value start with !, so we exclude the criteria
1436 $not = 'NOT ';
1437 // Then remove the ! from the string for next filters
1438 $rule['rulevalue'] = substr($rule['rulevalue'], 1);
1439 }
1440
1441 if ($rule['type'] == 'from') {
1442 $tmprulevaluearray = explode('*', $rule['rulevalue']); // Search on abc*def means searching on 'abc' and on 'def'
1443 if (count($tmprulevaluearray) >= 2) {
1444 foreach ($tmprulevaluearray as $tmprulevalue) {
1445 $search .= ($search ? ' ' : '').$not.'FROM "'.str_replace('"', '', $tmprulevalue).'"';
1446 }
1447 } else {
1448 $search .= ($search ? ' ' : '').$not.'FROM "'.str_replace('"', '', $rule['rulevalue']).'"';
1449 }
1450 }
1451 if ($rule['type'] == 'to') {
1452 $tmprulevaluearray = explode('*', $rule['rulevalue']); // Search on abc*def means searching on 'abc' and on 'def'
1453 if (count($tmprulevaluearray) >= 2) {
1454 foreach ($tmprulevaluearray as $tmprulevalue) {
1455 $search .= ($search ? ' ' : '').$not.'TO "'.str_replace('"', '', $tmprulevalue).'"';
1456 }
1457 } else {
1458 $search .= ($search ? ' ' : '').$not.'TO "'.str_replace('"', '', $rule['rulevalue']).'"';
1459 }
1460 }
1461 if ($rule['type'] == 'bcc') {
1462 $search .= ($search ? ' ' : '').$not.'BCC';
1463 }
1464 if ($rule['type'] == 'cc') {
1465 $search .= ($search ? ' ' : '').$not.'CC';
1466 }
1467 if ($rule['type'] == 'subject') {
1468 if ($not) {
1469 //$search .= ($search ? ' ' : '').'NOT BODY "'.str_replace('"', '', $rule['rulevalue']).'"';
1470 $searchfilterexcludesubjectarray[] = $rule['rulevalue'];
1471 } else {
1472 $search .= ($search ? ' ' : '').'SUBJECT "'.str_replace('"', '', $rule['rulevalue']).'"';
1473 }
1474 }
1475 if ($rule['type'] == 'body') {
1476 if ($not) {
1477 //$search .= ($search ? ' ' : '').'NOT BODY "'.str_replace('"', '', $rule['rulevalue']).'"';
1478 $searchfilterexcludebodyarray[] = $rule['rulevalue'];
1479 } else {
1480 // Warning: Google doesn't implement IMAP properly, and only matches whole words,
1481 $search .= ($search ? ' ' : '').'BODY "'.str_replace('"', '', $rule['rulevalue']).'"';
1482 }
1483 }
1484 if ($rule['type'] == 'header') {
1485 $search .= ($search ? ' ' : '').$not.'HEADER '.$rule['rulevalue'];
1486 }
1487
1488 /* seems not used */
1489 /*
1490 if ($rule['type'] == 'notinsubject') {
1491 $search .= ($search ? ' ' : '').'NOT SUBJECT "'.str_replace('"', '', $rule['rulevalue']).'"';
1492 }
1493 if ($rule['type'] == 'notinbody') {
1494 $search .= ($search ? ' ' : '').'NOT BODY "'.str_replace('"', '', $rule['rulevalue']).'"';
1495 }*/
1496
1497 if ($rule['type'] == 'seen') {
1498 $search .= ($search ? ' ' : '').$not.'SEEN';
1499 }
1500 if ($rule['type'] == 'unseen') {
1501 $search .= ($search ? ' ' : '').$not.'UNSEEN';
1502 }
1503 if ($rule['type'] == 'unanswered') {
1504 $search .= ($search ? ' ' : '').$not.'UNANSWERED';
1505 }
1506 if ($rule['type'] == 'answered') {
1507 $search .= ($search ? ' ' : '').$not.'ANSWERED';
1508 }
1509 if ($rule['type'] == 'smaller') {
1510 $search .= ($search ? ' ' : '').$not.'SMALLER "'.str_replace('"', '', $rule['rulevalue']).'"';
1511 }
1512 if ($rule['type'] == 'larger') {
1513 $search .= ($search ? ' ' : '').$not.'LARGER "'.str_replace('"', '', $rule['rulevalue']).'"';
1514 }
1515
1516 // Rules to filter after the search imap
1517 if ($rule['type'] == 'withtrackingidinmsgid') {
1518 $searchfilterdoltrackid++;
1519 $searchhead .= '/Message-ID.*@'.preg_quote($host, '/').'/';
1520 }
1521 if ($rule['type'] == 'withouttrackingidinmsgid') {
1522 $searchfilterdoltrackid++;
1523 $searchhead .= '/Message-ID.*@'.preg_quote($host, '/').'/';
1524 }
1525 if ($rule['type'] == 'withtrackingid') {
1526 $searchfilterdoltrackid++;
1527 $searchhead .= '/References.*@'.preg_quote($host, '/').'/';
1528 }
1529 if ($rule['type'] == 'withouttrackingid') {
1530 $searchfilternodoltrackid++;
1531 $searchhead .= '! /References.*@'.preg_quote($host, '/').'/';
1532 }
1533
1534 if ($rule['type'] == 'isanswer') {
1535 $searchfilterisanswer++;
1536 $searchhead .= '/References.*@.*/';
1537 }
1538 if ($rule['type'] == 'isnotanswer') {
1539 $searchfilterisnotanswer++;
1540 $searchhead .= '! /References.*@.*/';
1541 }
1542
1543 if ($rule['type'] == 'replyto') {
1544 $searchfilterreplyto++;
1545 $searchhead .= '/Reply-To.*'.preg_quote($rule['rulevalue'], '/').'/';
1546 }
1547 }
1548
1549 if (empty($targetdir)) { // Use last date as filter if there is no targetdir defined.
1550 $fromdate = 0;
1551 if ($this->datelastok) {
1552 $fromdate = $this->datelastok;
1553 }
1554 if ($fromdate > 0) {
1555 $search .= ($search ? ' ' : '').'SINCE '.date('j-M-Y', $fromdate - 1); // SENTSINCE not supported. Date must be X-Abc-9999 (X on 1 digit if < 10)
1556 }
1557 //$search.=($search?' ':'').'SINCE 8-Apr-2018';
1558 }
1559
1560 dol_syslog("IMAP search string = ".$search);
1561 //var_dump($search);
1562 }
1563
1564 $nbemailprocessed = 0;
1565 $nbemailok = 0;
1566 $nbactiondone = 0;
1567 $charset = ($this->hostcharset ? $this->hostcharset : "UTF-8");
1568
1569 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1570 try {
1571 //$criteria = [['ALL']];
1572 //$Query = $client->getFolders()[0]->messages()->where($criteria);
1573 $f = $client->getFolders(false, $sourcedir);
1574 $Query = $f[0]->messages()->where($criteria);
1575 } catch (InvalidWhereQueryCriteriaException $e) {
1576 $this->error = $e->getMessage();
1577 $this->errors[] = $this->error;
1578 dol_syslog("EmailCollector::doCollectOneCollector ".$this->error, LOG_ERR);
1579 return -1;
1580 } catch (Exception $e) {
1581 $this->error = $e->getMessage();
1582 $this->errors[] = $this->error;
1583 dol_syslog("EmailCollector::doCollectOneCollector ".$this->error, LOG_ERR);
1584 return -1;
1585 }
1586
1587 try {
1588 //var_dump($Query->count());
1589 if ($mode > 0) {
1590 $Query->leaveUnread();
1591 }
1592 $arrayofemail = $Query->limit($this->maxemailpercollect)->setFetchOrder("asc")->get();
1593 //var_dump($arrayofemail);
1594 } catch (Exception $e) {
1595 $this->error = $e->getMessage();
1596 $this->errors[] = $this->error;
1597 dol_syslog("EmailCollector::doCollectOneCollector ".$this->error, LOG_ERR);
1598 return -1;
1599 }
1600 } else {
1601 // Scan IMAP inbox (for native IMAP, the source dir is inside the $connection variable)
1602 $arrayofemail = imap_search($connection, $search, SE_UID, $charset);
1603
1604 if ($arrayofemail === false) {
1605 // Nothing found or search string not understood
1606 $mapoferrrors = imap_errors();
1607 if ($mapoferrrors !== false) {
1608 $error++;
1609 $this->error = "Search string not understood - ".join(',', $mapoferrrors);
1610 $this->errors[] = $this->error;
1611 }
1612 }
1613 }
1614
1615 $arrayofemailtodelete = array(); // Track email to delete to make the deletion at end.
1616
1617 // Loop on each email found
1618 if (!$error && !empty($arrayofemail) && count($arrayofemail) > 0) {
1619 // Loop to get part html and plain
1620 /*
1621 0 multipart/mixed
1622 1 multipart/alternative
1623 1.1 text/plain
1624 1.2 text/html
1625 2 message/rfc822
1626 2 multipart/mixed
1627 2.1 multipart/alternative
1628 2.1.1 text/plain
1629 2.1.2 text/html
1630 2.2 message/rfc822
1631 2.2 multipart/alternative
1632 2.2.1 text/plain
1633 2.2.2 text/html
1634 */
1635 dol_syslog("Start of loop on email", LOG_INFO, 1);
1636
1637 $iforemailloop = 0;
1638 foreach ($arrayofemail as $imapemail) {
1639 if ($nbemailprocessed > 1000) {
1640 break; // Do not process more than 1000 email per launch (this is a different protection than maxnbcollectedpercollect)
1641 }
1642 $iforemailloop++;
1643
1644
1645 // GET header and overview datas
1646 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1647 $header = $imapemail->getHeader()->raw;
1648 $overview = $imapemail->getAttributes();
1649 } else {
1650 $header = imap_fetchheader($connection, $imapemail, FT_UID);
1651 $overview = imap_fetch_overview($connection, $imapemail, FT_UID);
1652 }
1653
1654 $header = preg_replace('/\r\n\s+/m', ' ', $header); // When a header line is on several lines, merge lines
1655
1656 $matches = array();
1657 preg_match_all('/([^: ]+): (.+?(?:\r\n\s(?:.+?))*)\r\n/m', $header, $matches);
1658 $headers = array_combine($matches[1], $matches[2]);
1659 //var_dump($headers);exit;
1660
1661 if (!empty($headers['in-reply-to']) && empty($headers['In-Reply-To'])) {
1662 $headers['In-Reply-To'] = $headers['in-reply-to'];
1663 }
1664 if (!empty($headers['references']) && empty($headers['References'])) {
1665 $headers['References'] = $headers['references'];
1666 }
1667 if (!empty($headers['message-id']) && empty($headers['Message-ID'])) {
1668 $headers['Message-ID'] = $headers['message-id'];
1669 }
1670 if (!empty($headers['subject']) && empty($headers['Subject'])) {
1671 $headers['Subject'] = $headers['subject'];
1672 }
1673
1674 $headers['Subject'] = $this->decodeSMTPSubject($headers['Subject']);
1675
1676 $emailto = $this->decodeSMTPSubject($overview[0]->to);
1677
1678 $operationslog .= '<br>** Process email #'.dol_escape_htmltag($iforemailloop);
1679 if (getDolGlobalInt('MAIN_IMAP_USE_PHPIMAP')) {
1681 // $operationslog .= " - ".dol_escape_htmltag((string) $imapemail);
1682 } else {
1683 $operationslog .= " - ".dol_escape_htmltag((string) $imapemail);
1684 }
1685 $operationslog .= " - References: ".dol_escape_htmltag($headers['References']??'')." - Subject: ".dol_escape_htmltag($headers['Subject']);
1686
1687 dol_syslog("** Process email ".$iforemailloop." References: ".($headers['References']??'')." Subject: ".$headers['Subject']);
1688
1689
1690 $trackidfoundintorecipienttype = '';
1691 $trackidfoundintorecipientid = 0;
1692 $reg = array();
1693 // See also later list of all supported tags...
1694 if (preg_match('/\+(thi|ctc|use|mem|sub|proj|tas|con|tic|pro|ord|inv|spro|sor|sin|leav|stockinv|job|surv|salary)([0-9]+)@/', $emailto, $reg)) {
1695 $trackidfoundintorecipienttype = $reg[1];
1696 $trackidfoundintorecipientid = $reg[2];
1697 } elseif (preg_match('/\+emailing-(\w+)@/', $emailto, $reg)) { // Can be 'emailing-test' or 'emailing-IdMailing-IdRecipient'
1698 $trackidfoundintorecipienttype = 'emailing';
1699 $trackidfoundintorecipientid = $reg[1];
1700 }
1701
1702 // If there is a filter on trackid
1703 if ($searchfilterdoltrackid > 0) {
1704 if (empty($trackidfoundintorecipienttype)) {
1705 if (empty($headers['References']) || !preg_match('/@'.preg_quote($host, '/').'/', $headers['References'])) {
1706 $nbemailprocessed++;
1707 dol_syslog(" Discarded - No suffix in email recipient and no Header References found matching the signature of the application, so with a trackid coming from the application");
1708 continue; // Exclude email
1709 }
1710 }
1711 }
1712 if ($searchfilternodoltrackid > 0) {
1713 if (!empty($trackidfoundintorecipienttype) || (!empty($headers['References']) && preg_match('/@'.preg_quote($host, '/').'/', $headers['References']))) {
1714 $nbemailprocessed++;
1715 dol_syslog(" Discarded - Suffix found into email or Header References found and matching signature of application so with a trackid");
1716 continue; // Exclude email
1717 }
1718 }
1719
1720 if ($searchfilterisanswer > 0) {
1721 if (empty($headers['In-Reply-To'])) {
1722 $nbemailprocessed++;
1723 dol_syslog(" Discarded - Email is not an answer (no In-Reply-To header)");
1724 continue; // Exclude email
1725 }
1726 $isanswer = 0;
1727 if (preg_match('/^(Re|AW)\s*:\s+/i', $headers['Subject'])) {
1728 $isanswer = 1;
1729 }
1730 if (getDolglobalString('EMAILCOLLECTOR_USE_IN_REPLY_TO_TO_DETECT_ANSWERS')) {
1731 // Note: "In-Reply-To" to detect if mail is an answer of another mail is not reliable because we can have:
1732 // Message-ID=A, In-Reply-To=B, References=B and message can BE an answer but may be NOT (for example a transfer of an email rewriten)
1733 if (!empty($headers['In-Reply-To'])) {
1734 $isanswer = 1;
1735 }
1736 }
1737 //if ($headers['In-Reply-To'] != $headers['Message-ID'] && empty($headers['References'])) $isanswer = 1; // If in-reply-to differs of message-id, this is a reply
1738 //if ($headers['In-Reply-To'] != $headers['Message-ID'] && !empty($headers['References']) && strpos($headers['References'], $headers['Message-ID']) !== false) $isanswer = 1;
1739
1740 if (!$isanswer) {
1741 $nbemailprocessed++;
1742 dol_syslog(" Discarded - Email is not an answer (no RE prefix in subject)");
1743 continue; // Exclude email
1744 }
1745 }
1746 if ($searchfilterisnotanswer > 0) {
1747 if (!empty($headers['In-Reply-To'])) {
1748 // Note: we can have
1749 // Message-ID=A, In-Reply-To=B, References=B and message can BE an answer or NOT (a transfer rewriten)
1750 $isanswer = 0;
1751 if (preg_match('/Re\s*:\s+/i', $headers['Subject'])) {
1752 $isanswer = 1;
1753 }
1754 //if ($headers['In-Reply-To'] != $headers['Message-ID'] && empty($headers['References'])) $isanswer = 1; // If in-reply-to differs of message-id, this is a reply
1755 //if ($headers['In-Reply-To'] != $headers['Message-ID'] && !empty($headers['References']) && strpos($headers['References'], $headers['Message-ID']) !== false) $isanswer = 1;
1756 if ($isanswer) {
1757 $nbemailprocessed++;
1758 dol_syslog(" Discarded - Email is an answer");
1759 continue; // Exclude email
1760 }
1761 }
1762 }
1763
1764 //print "Process mail ".$iforemailloop." Subject: ".dol_escape_htmltag($headers['Subject'])." selected<br>\n";
1765
1766 $thirdpartystatic = new Societe($this->db);
1767 $contactstatic = new Contact($this->db);
1768 $projectstatic = new Project($this->db);
1769
1770 $nbactiondoneforemail = 0;
1771 $errorforemail = 0;
1772 $errorforactions = 0;
1773 $thirdpartyfoundby = '';
1774 $contactfoundby = '';
1775 $projectfoundby = '';
1776 $ticketfoundby = '';
1777 $candidaturefoundby = '';
1778
1779
1780 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1781 dol_syslog("msgid=".$overview['message_id']." date=".dol_print_date($overview['date'], 'dayrfc', 'gmt')." from=".$overview['from']." to=".$overview['to']." subject=".$overview['subject']);
1782
1783 // Removed emojis
1784 $overview['subject'] = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $overview['subject']);
1785 } else {
1786 dol_syslog("msgid=".$overview[0]->message_id." date=".dol_print_date($overview[0]->udate, 'dayrfc', 'gmt')." from=".$overview[0]->from." to=".$overview[0]->to." subject=".$overview[0]->subject);
1787
1788 $overview[0]->subject = $this->decodeSMTPSubject($overview[0]->subject);
1789
1790 $overview[0]->from = $this->decodeSMTPSubject($overview[0]->from);
1791
1792 // Removed emojis
1793 $overview[0]->subject = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $overview[0]->subject);
1794 }
1795 // GET IMAP email structure/content
1796 global $htmlmsg, $plainmsg, $charset, $attachments;
1797
1798 if (getDolGlobalInt('MAIN_IMAP_USE_PHPIMAP')) {
1800 if ($imapemail->hasHTMLBody()) {
1801 $htmlmsg = $imapemail->getHTMLBody();
1802 }
1803 if ($imapemail->hasTextBody()) {
1804 $plainmsg = $imapemail->getTextBody();
1805 }
1806 if ($imapemail->hasAttachments()) {
1807 $attachments = $imapemail->getAttachments()->all();
1808 } else {
1809 $attachments = [];
1810 }
1811 } else {
1812 $this->getmsg($connection, $imapemail); // This set global var $charset, $htmlmsg, $plainmsg, $attachments
1813 }
1814 //print $plainmsg;
1815 //var_dump($plainmsg); exit;
1816
1817 //$htmlmsg,$plainmsg,$charset,$attachments
1818 $messagetext = $plainmsg ? $plainmsg : dol_string_nohtmltag($htmlmsg, 0);
1819 // Removed emojis
1820
1821 if (utf8_valid($messagetext)) {
1822 //$messagetext = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $messagetext);
1823 $messagetext = $this->removeEmoji($messagetext);
1824 } else {
1825 $operationslog .= '<br>Discarded - Email body is not valid utf8';
1826 dol_syslog(" Discarded - Email body is not valid utf8");
1827 continue; // Exclude email
1828 }
1829
1830 if (!empty($searchfilterexcludebodyarray)) {
1831 foreach ($searchfilterexcludebodyarray as $searchfilterexcludebody) {
1832 if (preg_match('/'.preg_quote($searchfilterexcludebody, '/').'/ms', $messagetext)) {
1833 $nbemailprocessed++;
1834 $operationslog .= '<br>Discarded - Email body contains string '.$searchfilterexcludebody;
1835 dol_syslog(" Discarded - Email body contains string ".$searchfilterexcludebody);
1836 continue 2; // Exclude email
1837 }
1838 }
1839 }
1840
1841 //var_dump($plainmsg);
1842 //var_dump($htmlmsg);
1843 //var_dump($messagetext);
1844 //var_dump($charset);
1845 //var_dump($attachments);
1846 //exit;
1847
1848 // Parse IMAP email structure
1849 /*
1850 $structure = imap_fetchstructure($connection, $imapemail, FT_UID);
1851
1852 $partplain = $parthtml = -1;
1853 $encodingplain = $encodinghtml = '';
1854
1855 $result = createPartArray($structure, '');
1856
1857 foreach($result as $part)
1858 {
1859 // $part['part_object']->type seems 0 for content
1860 // $part['part_object']->type seems 5 for attachment
1861 if (empty($part['part_object'])) continue;
1862 if ($part['part_object']->subtype == 'HTML')
1863 {
1864 $parthtml=$part['part_number'];
1865 if ($part['part_object']->encoding == 4)
1866 {
1867 $encodinghtml = 'aaa';
1868 }
1869 }
1870 if ($part['part_object']->subtype == 'PLAIN')
1871 {
1872 $partplain=$part['part_number'];
1873 if ($part['part_object']->encoding == 4)
1874 {
1875 $encodingplain = 'rr';
1876 }
1877 }
1878 }
1879 //var_dump($result);
1880 //var_dump($partplain);
1881 //var_dump($parthtml);
1882
1883 //var_dump($structure);
1884 //var_dump($parthtml);
1885 //var_dump($partplain);
1886
1887 $messagetext = imap_fetchbody($connection, $imapemail, ($parthtml != '-1' ? $parthtml : ($partplain != '-1' ? $partplain : 1)), FT_PEEK|FTP_UID);
1888 */
1889
1890 //var_dump($messagetext);
1891 //var_dump($structure->parts[0]->parts);
1892 //print $header;
1893 //print $messagetext;
1894 //exit;
1895
1896 $fromstring = '';
1897 $replytostring = '';
1898
1899 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
1900 $fromstring = $overview['from'];
1901 //$replytostring = empty($overview['reply-to']) ? '' : $overview['reply-to'];
1902
1903 $sender = $overview['sender'];
1904 $to = $overview['to'];
1905 $sendtocc = empty($overview['cc']) ? '' : $overview['cc'];
1906 $sendtobcc = empty($overview['bcc']) ? '' : $overview['bcc'];
1907 $date = $overview['date'];
1908 $msgid = str_replace(array('<', '>'), '', $overview['message_id']);
1909 $subject = $overview['subject'];
1910 } else {
1911 $fromstring = $overview[0]->from;
1912 //$replytostring = empty($overview[0]->replyto) ? '' : $overview[0]->replyto;
1913
1914 $sender = $overview[0]->sender;
1915 $to = $overview[0]->to;
1916 $sendtocc = $overview[0]->cc;
1917 $sendtobcc = $overview[0]->bcc;
1918 $date = $overview[0]->udate;
1919 $msgid = str_replace(array('<', '>'), '', $overview[0]->message_id);
1920 $subject = $overview[0]->subject;
1921 //var_dump($msgid);exit;
1922 }
1923
1924 if (!empty($searchfilterexcludesubjectarray)) {
1925 foreach ($searchfilterexcludesubjectarray as $searchfilterexcludesubject) {
1926 if (preg_match('/'.preg_quote($searchfilterexcludesubject, '/').'/ms', $subject)) {
1927 $nbemailprocessed++;
1928 $operationslog .= '<br>Discarded - Email subject contains string '.$searchfilterexcludesubject;
1929 dol_syslog(" Discarded - Email subject contains string ".$searchfilterexcludesubject);
1930 continue 2; // Exclude email
1931 }
1932 }
1933 }
1934
1935 $reg = array();
1936 if (preg_match('/^(.*)<(.*)>$/', $fromstring, $reg)) {
1937 $from = $reg[2];
1938 $fromtext = $reg[1];
1939 } else {
1940 $from = $fromstring;
1941 $fromtext = '';
1942 }
1943 if (preg_match('/^(.*)<(.*)>$/', $replytostring, $reg)) {
1944 $replyto = $reg[2];
1945 $replytotext = $reg[1];
1946 } else {
1947 $replyto = $replytostring;
1948 $replytotext = '';
1949 }
1950 $fk_element_id = 0;
1951 $fk_element_type = '';
1952
1953 $this->db->begin();
1954
1955 $contactid = 0;
1956 $thirdpartyid = 0;
1957 $projectid = 0;
1958 $ticketid = 0;
1959
1960 // Analyze TrackId in field References. For example:
1961 // References: <1542377954.SMTPs-dolibarr-thi649@8f6014fde11ec6cdec9a822234fc557e>
1962 // References: <1542377954.SMTPs-dolibarr-tic649@8f6014fde11ec6cdec9a822234fc557e>
1963 // References: <1542377954.SMTPs-dolibarr-abc649@8f6014fde11ec6cdec9a822234fc557e>
1964 $trackid = '';
1965 $objectid = 0;
1966 $objectemail = null;
1967
1968 $reg = array();
1969 if (!empty($headers['References'])) {
1970 $arrayofreferences = preg_split('/(,|\s+)/', $headers['References']);
1971 // var_dump($headers['References']);
1972 // var_dump($arrayofreferences);
1973
1974 foreach ($arrayofreferences as $reference) {
1975 //print "Process mail ".$iforemailloop." email_msgid ".$msgid.", date ".dol_print_date($date, 'dayhour').", subject ".$subject.", reference ".dol_escape_htmltag($reference)."<br>\n";
1976 if (!empty($trackidfoundintorecipienttype)) {
1977 $resultsearchtrackid = -1;
1978 $reg[1] = $trackidfoundintorecipienttype;
1979 $reg[2] = $trackidfoundintorecipientid;
1980 } else {
1981 $resultsearchtrackid = preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote($host, '/').'/', $reference, $reg);
1982 if (empty($resultsearchtrackid) && getDolGlobalString('EMAIL_ALTERNATIVE_HOST_SIGNATURE')) {
1983 $resultsearchtrackid = preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote(getDolGlobalString('EMAIL_ALTERNATIVE_HOST_SIGNATURE'), '/').'/', $reference, $reg);
1984 }
1985 }
1986
1987 if (!empty($resultsearchtrackid)) {
1988 // We found a tracker (in recipient email or into a Reference matching the Dolibarr server)
1989 $trackid = $reg[1].$reg[2];
1990
1991 $objectid = $reg[2];
1992 // See also list into interface_50_modAgenda_ActionsAuto
1993 if ($reg[1] == 'thi') { // Third-party
1994 $objectemail = new Societe($this->db);
1995 }
1996 if ($reg[1] == 'ctc') { // Contact
1997 $objectemail = new Contact($this->db);
1998 }
1999 if ($reg[1] == 'inv') { // Customer Invoice
2000 $objectemail = new Facture($this->db);
2001 }
2002 if ($reg[1] == 'sinv') { // Supplier Invoice
2003 $objectemail = new FactureFournisseur($this->db);
2004 }
2005 if ($reg[1] == 'pro') { // Customer Proposal
2006 $objectemail = new Propal($this->db);
2007 }
2008 if ($reg[1] == 'ord') { // Sale Order
2009 $objectemail = new Commande($this->db);
2010 }
2011 if ($reg[1] == 'shi') { // Shipment
2012 $objectemail = new Expedition($this->db);
2013 }
2014 if ($reg[1] == 'spro') { // Supplier Proposal
2015 $objectemail = new SupplierProposal($this->db);
2016 }
2017 if ($reg[1] == 'sord') { // Supplier Order
2018 $objectemail = new CommandeFournisseur($this->db);
2019 }
2020 if ($reg[1] == 'rec') { // Reception
2021 $objectemail = new Reception($this->db);
2022 }
2023 if ($reg[1] == 'proj') { // Project
2024 $objectemail = new Project($this->db);
2025 }
2026 if ($reg[1] == 'tas') { // Task
2027 $objectemail = new Task($this->db);
2028 }
2029 if ($reg[1] == 'con') { // Contact
2030 $objectemail = new Contact($this->db);
2031 }
2032 if ($reg[1] == 'use') { // User
2033 $objectemail = new User($this->db);
2034 }
2035 if ($reg[1] == 'tic') { // Ticket
2036 $objectemail = new Ticket($this->db);
2037 }
2038 if ($reg[1] == 'recruitmentcandidature') { // Recruiting Candidate
2039 $objectemail = new RecruitmentCandidature($this->db);
2040 }
2041 if ($reg[1] == 'mem') { // Member
2042 $objectemail = new Adherent($this->db);
2043 }
2044 /*if ($reg[1] == 'leav') { // Leave / Holiday
2045 $objectemail = new Holiday($db);
2046 }
2047 if ($reg[1] == 'exp') { // ExpenseReport
2048 $objectemail = new ExpenseReport($db);
2049 }*/
2050 } elseif (preg_match('/<(.*@.*)>/', $reference, $reg)) {
2051 // This is an external reference, we check if we have it in our database
2052 if (!is_object($objectemail) && isModEnabled('ticket')) {
2053 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."ticket where email_msgid = '".$this->db->escape($reg[1])."'";
2054 $resql = $this->db->query($sql);
2055 if ($resql) {
2056 $obj = $this->db->fetch_object($resql);
2057 if ($obj) {
2058 $objectid = $obj->rowid;
2059 $objectemail = new Ticket($this->db);
2060 $ticketfoundby = $langs->transnoentitiesnoconv("EmailMsgID").' ('.$reg[1].')';
2061 }
2062 } else {
2063 $errorforemail++;
2064 }
2065 }
2066
2067 if (!is_object($objectemail) && isModEnabled('project')) {
2068 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."projet where email_msgid = '".$this->db->escape($reg[1])."'";
2069 $resql = $this->db->query($sql);
2070 if ($resql) {
2071 $obj = $this->db->fetch_object($resql);
2072 if ($obj) {
2073 $objectid = $obj->rowid;
2074 $objectemail = new Project($this->db);
2075 $projectfoundby = $langs->transnoentitiesnoconv("EmailMsgID").' ('.$reg[1].')';
2076 }
2077 } else {
2078 $errorforemail++;
2079 }
2080 }
2081
2082 if (!is_object($objectemail) && isModEnabled('recruitment')) {
2083 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."recruitment_recruitmentcandidature where email_msgid = '".$this->db->escape($reg[1])."'";
2084 $resql = $this->db->query($sql);
2085 if ($resql) {
2086 $obj = $this->db->fetch_object($resql);
2087 if ($obj) {
2088 $objectid = $obj->rowid;
2089 $objectemail = new RecruitmentCandidature($this->db);
2090 $candidaturefoundby = $langs->transnoentitiesnoconv("EmailMsgID").' ('.$reg[1].')';
2091 }
2092 } else {
2093 $errorforemail++;
2094 }
2095 }
2096 }
2097
2098 // Load object linked to email
2099 if (is_object($objectemail)) {
2100 $result = $objectemail->fetch($objectid);
2101 if ($result > 0) {
2102 $fk_element_id = $objectemail->id;
2103 $fk_element_type = $objectemail->element;
2104 // Fix fk_element_type
2105 if ($fk_element_type == 'facture') {
2106 $fk_element_type = 'invoice';
2107 }
2108
2109 if (get_class($objectemail) != 'Societe') {
2110 $thirdpartyid = $objectemail->fk_soc ?? $objectemail->socid;
2111 } else {
2112 $thirdpartyid = $objectemail->id;
2113 }
2114
2115 if (get_class($objectemail) != 'Contact') {
2116 $contactid = $objectemail->fk_socpeople;
2117 } else {
2118 $contactid = $objectemail->id;
2119 }
2120
2121 if (get_class($objectemail) != 'Project') {
2122 $projectid = isset($objectemail->fk_project) ? $objectemail->fk_project : $objectemail->fk_projet;
2123 } else {
2124 $projectid = $objectemail->id;
2125 }
2126 }
2127 }
2128
2129 // Project
2130 if ($projectid > 0) {
2131 $result = $projectstatic->fetch($projectid);
2132 if ($result <= 0) {
2133 $projectstatic->id = 0;
2134 } else {
2135 $projectid = $projectstatic->id;
2136 if ($trackid) {
2137 $projectfoundby = 'trackid ('.$trackid.')';
2138 }
2139 if (empty($contactid)) {
2140 $contactid = $projectstatic->fk_contact;
2141 }
2142 if (empty($thirdpartyid)) {
2143 $thirdpartyid = $projectstatic->fk_soc;
2144 }
2145 }
2146 }
2147 // Contact
2148 if ($contactid > 0) {
2149 $result = $contactstatic->fetch($contactid);
2150 if ($result <= 0) {
2151 $contactstatic->id = 0;
2152 } else {
2153 $contactid = $contactstatic->id;
2154 if ($trackid) {
2155 $contactfoundby = 'trackid ('.$trackid.')';
2156 }
2157 if (empty($thirdpartyid)) {
2158 $thirdpartyid = $contactstatic->fk_soc;
2159 }
2160 }
2161 }
2162 // Thirdparty
2163 if ($thirdpartyid > 0) {
2164 $result = $thirdpartystatic->fetch($thirdpartyid);
2165 if ($result <= 0) {
2166 $thirdpartystatic->id = 0;
2167 } else {
2168 $thirdpartyid = $thirdpartystatic->id;
2169 if ($trackid) {
2170 $thirdpartyfoundby = 'trackid ('.$trackid.')';
2171 }
2172 }
2173 }
2174
2175 if (is_object($objectemail)) {
2176 break; // Exit loop of references. We already found an accurate reference
2177 }
2178 }
2179 }
2180
2181 if (empty($contactid)) { // Try to find contact using email
2182 $result = $contactstatic->fetch(0, null, '', $from);
2183
2184 if ($result > 0) {
2185 dol_syslog("We found a contact with the email ".$from);
2186 $contactid = $contactstatic->id;
2187 $contactfoundby = 'email of contact ('.$from.')';
2188 if (empty($thirdpartyid) && $contactstatic->socid > 0) {
2189 $result = $thirdpartystatic->fetch($contactstatic->socid);
2190 if ($result > 0) {
2191 $thirdpartyid = $thirdpartystatic->id;
2192 $thirdpartyfoundby = 'email of contact ('.$from.')';
2193 }
2194 }
2195 }
2196 }
2197
2198 if (empty($thirdpartyid)) { // Try to find thirdparty using email
2199 $result = $thirdpartystatic->fetch(0, '', '', '', '', '', '', '', '', '', $from);
2200 if ($result > 0) {
2201 dol_syslog("We found a thirdparty with the email ".$from);
2202 $thirdpartyid = $thirdpartystatic->id;
2203 $thirdpartyfoundby = 'email ('.$from.')';
2204 }
2205 }
2206
2207 /*
2208 if ($replyto) {
2209 if (empty($contactid)) { // Try to find contact using email
2210 $result = $contactstatic->fetch(0, null, '', $replyto);
2211
2212 if ($result > 0) {
2213 dol_syslog("We found a contact with the email ".$replyto);
2214 $contactid = $contactstatic->id;
2215 $contactfoundby = 'email of contact ('.$replyto.')';
2216 if (empty($thirdpartyid) && $contactstatic->socid > 0) {
2217 $result = $thirdpartystatic->fetch($contactstatic->socid);
2218 if ($result > 0) {
2219 $thirdpartyid = $thirdpartystatic->id;
2220 $thirdpartyfoundby = 'email of contact ('.$replyto.')';
2221 }
2222 }
2223 }
2224 }
2225
2226 if (empty($thirdpartyid)) { // Try to find thirdparty using email
2227 $result = $thirdpartystatic->fetch(0, '', '', '', '', '', '', '', '', '', $replyto);
2228 if ($result > 0) {
2229 dol_syslog("We found a thirdparty with the email ".$replyto);
2230 $thirdpartyid = $thirdpartystatic->id;
2231 $thirdpartyfoundby = 'email ('.$replyto.')';
2232 }
2233 }
2234 }
2235 */
2236
2237 // Do operations (extract variables and creating data)
2238 if ($mode < 2) { // 0=Mode production, 1=Mode test (read IMAP and try SQL update then rollback), 2=Mode test with no SQL updates
2239 foreach ($this->actions as $operation) {
2240 $errorforthisaction = 0;
2241
2242 if ($errorforactions) {
2243 break;
2244 }
2245 if (empty($operation['status'])) {
2246 continue;
2247 }
2248
2249 $operationslog .= '<br>* Process operation '.$operation['type'];
2250
2251 // Make Operation
2252 dol_syslog("Execute action ".$operation['type']." actionparam=".$operation['actionparam'].' thirdpartystatic->id='.$thirdpartystatic->id.' contactstatic->id='.$contactstatic->id.' projectstatic->id='.$projectstatic->id);
2253 dol_syslog("Execute action fk_element_id=".$fk_element_id." fk_element_type=".$fk_element_type); // If a Dolibarr tracker id is found, we should now the id of object
2254
2255 $actioncode = 'EMAIL_IN';
2256 // If we scan the Sent box, we use the code for out email
2257 if (preg_match('/Sent$/', $sourcedir)) {
2258 $actioncode = 'EMAIL_OUT';
2259 }
2260
2261 $description = $descriptiontitle = $descriptionmeta = $descriptionfull = '';
2262
2263 $descriptiontitle = $langs->trans("RecordCreatedByEmailCollector", $this->ref, $msgid);
2264
2265 $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailTopic").' : '.dol_escape_htmltag($subject));
2266 $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailFrom").($langs->trans("MailFrom") != 'From' ? ' (From)' : '').' : '.dol_escape_htmltag($fromstring));
2267 if ($sender) {
2268 $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Sender").($langs->trans("Sender") != 'Sender' ? ' (Sender)' : '').' : '.dol_escape_htmltag($sender));
2269 }
2270 $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailTo").($langs->trans("MailTo") != 'To' ? ' (To)' : '').' : '.dol_escape_htmltag($to));
2271 if ($sendtocc) {
2272 $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailCC").($langs->trans("MailCC") != 'CC' ? ' (CC)' : '').' : '.dol_escape_htmltag($sendtocc));
2273 }
2274
2275 // Search and create thirdparty
2276 if ($operation['type'] == 'loadthirdparty' || $operation['type'] == 'loadandcreatethirdparty') {
2277 if (empty($operation['actionparam'])) {
2278 $errorforactions++;
2279 $this->error = "Action loadthirdparty or loadandcreatethirdparty has empty parameter. Must be a rule like 'name=HEADER:^From:(.*);' or 'name=SET:xxx' or 'name=EXTRACT:(body|subject):regex where 'name' can be replaced with 'id' or 'email' to define how to set or extract data. More properties can also be set, for example client=SET:2;";
2280 $this->errors[] = $this->error;
2281 } else {
2282 $actionparam = $operation['actionparam'];
2283 $idtouseforthirdparty = '';
2284 $nametouseforthirdparty = '';
2285 $emailtouseforthirdparty = '';
2286 $namealiastouseforthirdparty = '';
2287
2288 $operationslog .= '<br>Loop on each property to set into actionparam';
2289
2290 // $actionparam = 'param=SET:aaa' or 'param=EXTRACT:BODY:....'
2291 $arrayvaluetouse = dolExplodeIntoArray($actionparam, '(\n\r|\r|\n|;)', '=');
2292 foreach ($arrayvaluetouse as $propertytooverwrite => $valueforproperty) {
2293 $sourcestring = '';
2294 $sourcefield = '';
2295 $regexstring = '';
2296 $regforregex = array();
2297
2298 if (preg_match('/^EXTRACT:([a-zA-Z0-9_]+):(.*)$/', $valueforproperty, $regforregex)) {
2299 $sourcefield = $regforregex[1];
2300 $regexstring = $regforregex[2];
2301 }
2302
2303 if (!empty($sourcefield) && !empty($regexstring)) {
2304 if (strtolower($sourcefield) == 'body') {
2305 $sourcestring = $messagetext;
2306 } elseif (strtolower($sourcefield) == 'subject') {
2307 $sourcestring = $subject;
2308 } elseif (strtolower($sourcefield) == 'header') {
2309 $sourcestring = $header;
2310 }
2311
2312 if ($sourcestring) {
2313 $regforval = array();
2314 //var_dump($regexstring);var_dump($sourcestring);
2315 if (preg_match('/'.$regexstring.'/ms', $sourcestring, $regforval)) {
2316 //var_dump($regforval[count($regforval)-1]);exit;
2317 // Overwrite param $tmpproperty
2318 if ($propertytooverwrite == 'id') {
2319 $idtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
2320
2321 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty);
2322 } elseif ($propertytooverwrite == 'email') {
2323 $emailtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
2324
2325 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found emailtouseforthirdparty='.dol_escape_htmltag($emailtouseforthirdparty);
2326 } elseif ($propertytooverwrite == 'name') {
2327 $nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
2328
2329 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
2330 } elseif ($propertytooverwrite == 'name_alias') {
2331 $namealiastouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
2332
2333 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty);
2334 } else {
2335 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> We discard this, not a field used to search an existing thirdparty';
2336 }
2337 } else {
2338 // Regex not found
2339 if (in_array($propertytooverwrite, array('id', 'email', 'name', 'name_alias'))) {
2340 $idtouseforthirdparty = null;
2341 $nametouseforthirdparty = null;
2342 $emailtouseforthirdparty = null;
2343 $namealiastouseforthirdparty = null;
2344
2345 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Not found. Property searched is critical so we cancel the search.';
2346 } else {
2347 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Not found';
2348 }
2349 }
2350 //var_dump($object->$tmpproperty);exit;
2351 } else {
2352 // Nothing can be done for this param
2353 $errorforactions++;
2354 $this->error = 'The extract rule to use to load thirdparty for email '.$msgid.' has an unknown source (must be HEADER, SUBJECT or BODY)';
2355 $this->errors[] = $this->error;
2356
2357 $operationslog .= '<br>'.$this->error;
2358 }
2359 } elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $reg)) {
2360 //if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $reg[1];
2361 //else $object->$tmpproperty = $reg[1];
2362 // Example: id=SETIFEMPTY:123
2363 if ($propertytooverwrite == 'id') {
2364 $idtouseforthirdparty = $reg[2];
2365
2366 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' We set property idtouseforthrdparty='.dol_escape_htmltag($idtouseforthirdparty);
2367 } elseif ($propertytooverwrite == 'email') {
2368 $emailtouseforthirdparty = $reg[2];
2369
2370 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty);
2371 } elseif ($propertytooverwrite == 'name') {
2372 $nametouseforthirdparty = $reg[2];
2373
2374 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
2375 } elseif ($propertytooverwrite == 'name_alias') {
2376 $namealiastouseforthirdparty = $reg[2];
2377
2378 $operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' We set property namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty);
2379 }
2380 } else {
2381 $errorforactions++;
2382 $this->error = 'Bad syntax for description of action parameters: '.$actionparam;
2383 $this->errors[] = $this->error;
2384 break;
2385 }
2386 }
2387
2388 if (!$errorforactions && ($idtouseforthirdparty || $emailtouseforthirdparty || $nametouseforthirdparty || $namealiastouseforthirdparty)) {
2389 // We make another search on thirdparty
2390 $operationslog .= '<br>We have this data to search thirdparty: id='.$idtouseforthirdparty.', email='.$emailtouseforthirdparty.', name='.$nametouseforthirdparty.', name_alias='.$namealiastouseforthirdparty;
2391
2392 $tmpobject = new stdClass();
2393 $tmpobject->element == 'generic';
2394 $tmpobject->id = $idtouseforthirdparty;
2395 $tmpobject->name = $nametouseforthirdparty;
2396 $tmpobject->name_alias = $namealiastouseforthirdparty;
2397 $tmpobject->email = $emailtouseforthirdparty;
2398
2399 $this->overwritePropertiesOfObject($tmpobject, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
2400
2401 $idtouseforthirdparty = $tmpobject->id;
2402 $nametouseforthirdparty = $tmpobject->name;
2403 $namealiastouseforthirdparty = $tmpobject->name_alias;
2404 $emailtouseforthirdparty = $tmpobject->email;
2405
2406 $operationslog .= '<br>We try to search existing thirdparty with '.$idtouseforthirdparty.' '.$emailtouseforthirdparty.' '.$nametouseforthirdparty.' '.$namealiastouseforthirdparty;
2407
2408 $result = $thirdpartystatic->fetch($idtouseforthirdparty, $nametouseforthirdparty, '', '', '', '', '', '', '', '', $emailtouseforthirdparty, $namealiastouseforthirdparty);
2409 if ($result < 0) {
2410 $errorforactions++;
2411 $this->error = 'Error when getting thirdparty with name '.$nametouseforthirdparty.' (may be 2 record exists with same name ?)';
2412 $this->errors[] = $this->error;
2413 break;
2414 } elseif ($result == 0) {
2415 if ($operation['type'] == 'loadthirdparty') {
2416 dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." name_alias=".$namealiastouseforthirdparty." was not found");
2417
2418 //search into contacts of thirdparty
2419 $resultContact = $contactstatic->fetch('', '', '', $emailtouseforthirdparty);
2420 if ($resultContact > 0) {
2421 $idtouseforthirdparty = $contactstatic->socid;
2422 $result = $thirdpartystatic->fetch($idtouseforthirdparty);
2423 if ($result > 0) {
2424 dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." name_alias=".$namealiastouseforthirdparty." was found thanks to linked contact search");
2425 } else {
2426 $errorforactions++;
2427 $langs->load("errors");
2428 $this->error = $langs->trans('ErrorFailedToLoadThirdParty', $idtouseforthirdparty, $emailtouseforthirdparty, $nametouseforthirdparty, $namealiastouseforthirdparty);
2429 $this->errors[] = $this->error;
2430 }
2431 } else {
2432 $errorforactions++;
2433 $langs->load("errors");
2434 $this->error = $langs->trans('ErrorFailedToLoadThirdParty', $idtouseforthirdparty, $emailtouseforthirdparty, $nametouseforthirdparty, $namealiastouseforthirdparty);
2435 $this->errors[] = $this->error;
2436 }
2437 } elseif ($operation['type'] == 'loadandcreatethirdparty') {
2438 dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." name_alias=".$namealiastouseforthirdparty." was not found. We try to create it.");
2439
2440 // Create thirdparty
2441 $thirdpartystatic = new Societe($db);
2442 $thirdpartystatic->name = $nametouseforthirdparty;
2443 if (!empty($namealiastouseforthirdparty)) {
2444 if ($namealiastouseforthirdparty != $nametouseforthirdparty) {
2445 $thirdpartystatic->name_alias = $namealiastouseforthirdparty;
2446 }
2447 } else {
2448 $thirdpartystatic->name_alias = (empty($replytostring) ? (empty($fromtext) ? '' : $fromtext) : $replytostring);
2449 }
2450 $thirdpartystatic->email = (empty($emailtouseforthirdparty) ? (empty($replyto) ? (empty($from) ? '' : $from) : $replyto) : $emailtouseforthirdparty);
2451
2452 // Overwrite values with values extracted from source email
2453 $errorforthisaction = $this->overwritePropertiesOfObject($thirdpartystatic, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
2454
2455 if ($thirdpartystatic->client && empty($thirdpartystatic->code_client)) {
2456 $thirdpartystatic->code_client = 'auto';
2457 }
2458 if ($thirdpartystatic->fournisseur && empty($thirdpartystatic->code_fournisseur)) {
2459 $thirdpartystatic->code_fournisseur = 'auto';
2460 }
2461
2462 if ($errorforthisaction) {
2463 $errorforactions++;
2464 } else {
2465 $result = $thirdpartystatic->create($user);
2466 if ($result <= 0) {
2467 $errorforactions++;
2468 $this->error = $thirdpartystatic->error;
2469 $this->errors = $thirdpartystatic->errors;
2470 } else {
2471 $operationslog .= '<br>Thirdparty created -> id = '.dol_escape_htmltag($thirdpartystatic->id);
2472 }
2473 }
2474 }
2475 } else {
2476 dol_syslog("One and only one existing third party has been found");
2477
2478 $operationslog .= '<br>Thirdparty already exists with id = '.dol_escape_htmltag($thirdpartystatic->id);
2479 }
2480 }
2481 }
2482 } elseif ($operation['type'] == 'loadandcreatecontact') { // Search and create contact
2483 if (empty($operation['actionparam'])) {
2484 $errorforactions++;
2485 $this->error = "Action loadandcreatecontact has empty parameter. Must be 'SET:xxx' or 'EXTRACT:(body|subject):regex' to define how to extract data";
2486 $this->errors[] = $this->error;
2487 } else {
2488 $contact_static = new Contact($this->db);
2489 // Overwrite values with values extracted from source email
2490 $errorforthisaction = $this->overwritePropertiesOfObject($contact_static, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
2491 if ($errorforthisaction) {
2492 $errorforactions++;
2493 } else {
2494 if (!empty($contact_static->email) && $contact_static->email != $from) {
2495 $from = $contact_static->email;
2496 }
2497
2498 $result = $contactstatic->fetch(0, null, '', $from);
2499 if ($result < 0) {
2500 $errorforactions++;
2501 $this->error = 'Error when getting contact with email ' . $from;
2502 $this->errors[] = $this->error;
2503 break;
2504 } elseif ($result == 0) {
2505 dol_syslog("Contact with email " . $from . " was not found. We try to create it.");
2506 $contactstatic = new Contact($this->db);
2507
2508 // Create contact
2509 $contactstatic->email = $from;
2510 $operationslog .= '<br>We set property email='.dol_escape_htmltag($from);
2511
2512 // Overwrite values with values extracted from source email
2513 $errorforthisaction = $this->overwritePropertiesOfObject($contactstatic, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
2514
2515 if ($errorforthisaction) {
2516 $errorforactions++;
2517 } else {
2518 // Search country by name or code
2519 if (!empty($contactstatic->country)) {
2520 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
2521 $result = getCountry('', 3, $this->db, '', 1, $contactstatic->country);
2522 if ($result == 'NotDefined') {
2523 $errorforactions++;
2524 $this->error = "Error country not found by this name '" . $contactstatic->country . "'";
2525 } elseif (!($result > 0)) {
2526 $errorforactions++;
2527 $this->error = "Error when search country by this name '" . $contactstatic->country . "'";
2528 $this->errors[] = $this->db->lasterror();
2529 } else {
2530 $contactstatic->country_id = $result;
2531 $operationslog .= '<br>We set property country_id='.dol_escape_htmltag($result);
2532 }
2533 } elseif (!empty($contactstatic->country_code)) {
2534 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
2535 $result = getCountry($contactstatic->country_code, 3, $this->db);
2536 if ($result == 'NotDefined') {
2537 $errorforactions++;
2538 $this->error = "Error country not found by this code '" . $contactstatic->country_code . "'";
2539 } elseif (!($result > 0)) {
2540 $errorforactions++;
2541 $this->error = "Error when search country by this code '" . $contactstatic->country_code . "'";
2542 $this->errors[] = $this->db->lasterror();
2543 } else {
2544 $contactstatic->country_id = $result;
2545 $operationslog .= '<br>We set property country_id='.dol_escape_htmltag($result);
2546 }
2547 }
2548
2549 if (!$errorforactions) {
2550 // Search state by name or code (for country if defined)
2551 if (!empty($contactstatic->state)) {
2552 require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php';
2553 $result = dol_getIdFromCode($this->db, $contactstatic->state, 'c_departements', 'nom', 'rowid');
2554 if (empty($result)) {
2555 $errorforactions++;
2556 $this->error = "Error state not found by this name '" . $contactstatic->state . "'";
2557 } elseif (!($result > 0)) {
2558 $errorforactions++;
2559 $this->error = "Error when search state by this name '" . $contactstatic->state . "'";
2560 $this->errors[] = $this->db->lasterror();
2561 } else {
2562 $contactstatic->state_id = $result;
2563 $operationslog .= '<br>We set property state_id='.dol_escape_htmltag($result);
2564 }
2565 } elseif (!empty($contactstatic->state_code)) {
2566 require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php';
2567 $result = dol_getIdFromCode($this->db, $contactstatic->state_code, 'c_departements', 'code_departement', 'rowid');
2568 if (empty($result)) {
2569 $errorforactions++;
2570 $this->error = "Error state not found by this code '" . $contactstatic->state_code . "'";
2571 } elseif (!($result > 0)) {
2572 $errorforactions++;
2573 $this->error = "Error when search state by this code '" . $contactstatic->state_code . "'";
2574 $this->errors[] = $this->db->lasterror();
2575 } else {
2576 $contactstatic->state_id = $result;
2577 $operationslog .= '<br>We set property state_id='.dol_escape_htmltag($result);
2578 }
2579 }
2580 }
2581
2582 if (!$errorforactions) {
2583 $result = $contactstatic->create($user);
2584 if ($result <= 0) {
2585 $errorforactions++;
2586 $this->error = $contactstatic->error;
2587 $this->errors = $contactstatic->errors;
2588 } else {
2589 $operationslog .= '<br>Contact created -> id = '.dol_escape_htmltag($contactstatic->id);
2590 }
2591 }
2592 }
2593 }
2594 }
2595 }
2596 } elseif ($operation['type'] == 'recordevent') {
2597 // Create event
2598 $actioncomm = new ActionComm($this->db);
2599
2600 $alreadycreated = $actioncomm->fetch(0, '', '', $msgid);
2601 if ($alreadycreated == 0) {
2602 if ($projectstatic->id > 0) {
2603 if ($projectfoundby) {
2604 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Project found from '.$projectfoundby);
2605 }
2606 }
2607 if ($thirdpartystatic->id > 0) {
2608 if ($thirdpartyfoundby) {
2609 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Third party found from '.$thirdpartyfoundby);
2610 }
2611 }
2612 if ($contactstatic->id > 0) {
2613 if ($contactfoundby) {
2614 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Contact/address found from '.$contactfoundby);
2615 }
2616 }
2617
2618 $description = $descriptiontitle;
2619 $description = dol_concatdesc($description, "-----");
2620 $description = dol_concatdesc($description, $descriptionmeta);
2621 $description = dol_concatdesc($description, "-----");
2622 $description = dol_concatdesc($description, $messagetext);
2623
2624 $descriptionfull = $description;
2625 if (!getDolGlobalString('MAIN_EMAILCOLLECTOR_MAIL_WITHOUT_HEADER')) {
2626 $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
2627 $descriptionfull = dol_concatdesc($descriptionfull, $header);
2628 }
2629
2630 // Insert record of emails sent
2631 $actioncomm->type_code = 'AC_OTH_AUTO'; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
2632 $actioncomm->code = 'AC_'.$actioncode;
2633 $actioncomm->label = $langs->trans("ActionAC_".$actioncode).' - '.$langs->trans("MailFrom").' '.$from;
2634 $actioncomm->note_private = $descriptionfull;
2635 $actioncomm->fk_project = $projectstatic->id;
2636 $actioncomm->datep = $date; // date of email
2637 $actioncomm->datef = $date; // date of email
2638 $actioncomm->percentage = -1; // Not applicable
2639 $actioncomm->socid = $thirdpartystatic->id;
2640 $actioncomm->contact_id = $contactstatic->id;
2641 $actioncomm->socpeopleassigned = (!empty($contactstatic->id) ? array($contactstatic->id => '') : array());
2642 $actioncomm->authorid = $user->id; // User saving action
2643 $actioncomm->userownerid = $user->id; // Owner of action
2644 // Fields when action is an email (content should be added into note)
2645 $actioncomm->email_msgid = $msgid;
2646 $actioncomm->email_from = $fromstring;
2647 $actioncomm->email_sender = $sender;
2648 $actioncomm->email_to = $to;
2649 $actioncomm->email_tocc = $sendtocc;
2650 $actioncomm->email_tobcc = $sendtobcc;
2651 $actioncomm->email_subject = $subject;
2652 $actioncomm->errors_to = '';
2653
2654 if (!in_array($fk_element_type, array('societe', 'contact', 'project', 'user'))) {
2655 $actioncomm->fk_element = $fk_element_id;
2656 $actioncomm->elementid = $fk_element_id;
2657 $actioncomm->elementtype = $fk_element_type;
2658 if (is_object($objectemail) && $objectemail->module) {
2659 $actioncomm->elementtype .= '@'.$objectemail->module;
2660 }
2661 }
2662
2663 //$actioncomm->extraparams = $extraparams;
2664
2665 // Overwrite values with values extracted from source email
2666 $errorforthisaction = $this->overwritePropertiesOfObject($actioncomm, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
2667
2668 //var_dump($fk_element_id);
2669 //var_dump($fk_element_type);
2670 //var_dump($alreadycreated);
2671 //var_dump($operation['type']);
2672 //var_dump($actioncomm);
2673 //exit;
2674
2675 if ($errorforthisaction) {
2676 $errorforactions++;
2677 } else {
2678 $result = $actioncomm->create($user);
2679 if ($result <= 0) {
2680 $errorforactions++;
2681 $this->errors = $actioncomm->errors;
2682 } else {
2683 $operationslog .= '<br>Event created -> id='.dol_escape_htmltag($actioncomm->id);
2684 }
2685 }
2686 }
2687 } elseif ($operation['type'] == 'recordjoinpiece') {
2688 $data = [];
2689 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
2690 foreach ($attachments as $attachment) {
2691 if ($attachment->getName() === 'undefined') {
2692 continue;
2693 }
2694 $data[$attachment->getName()] = $attachment->getContent();
2695 }
2696 } else {
2697 $pj = getAttachments($imapemail, $connection);
2698 foreach ($pj as $key => $val) {
2699 $data[$val['filename']] = getFileData($imapemail, $val['pos'], $val['type'], $connection);
2700 }
2701 }
2702 if (count($data) > 0) {
2703 $sql = "SELECT rowid as id FROM ".MAIN_DB_PREFIX."user WHERE email LIKE '%".$this->db->escape($from)."%'";
2704 $resql = $this->db->query($sql);
2705 if ($this->db->num_rows($resql) == 0) {
2706 $this->errors[] = "User Not allowed to add documents ({$from})";
2707 }
2708 $arrayobject = array(
2709 'propale' => array('table' => 'propal',
2710 'fields' => array('ref'),
2711 'class' => 'comm/propal/class/propal.class.php',
2712 'object' => 'Propal'),
2713 'holiday' => array('table' => 'holiday',
2714 'fields' => array('ref'),
2715 'class' => 'holiday/class/holiday.class.php',
2716 'object' => 'Holiday'),
2717 'expensereport' => array('table' => 'expensereport',
2718 'fields' => array('ref'),
2719 'class' => 'expensereport/class/expensereport.class.php',
2720 'object' => 'ExpenseReport'),
2721 'recruitment/recruitmentjobposition' => array('table' => 'recruitment_recruitmentjobposition',
2722 'fields' => array('ref'),
2723 'class' => 'recruitment/class/recruitmentjobposition.class.php',
2724 'object' => 'RecruitmentJobPosition'),
2725 'recruitment/recruitmentcandidature' => array('table' => 'recruitment_recruitmentcandidature',
2726 'fields' => array('ref'),
2727 'class' => 'recruitment/class/recruitmentcandidature.class.php',
2728 'object' => ' RecruitmentCandidature'),
2729 'societe' => array('table' => 'societe',
2730 'fields' => array('code_client', 'code_fournisseur'),
2731 'class' => 'societe/class/societe.class.php',
2732 'object' => 'Societe'),
2733 'commande' => array('table' => 'commande',
2734 'fields' => array('ref'),
2735 'class' => 'commande/class/commande.class.php',
2736 'object' => 'Commande'),
2737 'expedition' => array('table' => 'expedition',
2738 'fields' => array('ref'),
2739 'class' => 'expedition/class/expedition.class.php',
2740 'object' => 'Expedition'),
2741 'contract' => array('table' => 'contrat',
2742 'fields' => array('ref'),
2743 'class' => 'contrat/class/contrat.class.php',
2744 'object' => 'Contrat'),
2745 'fichinter' => array('table' => 'fichinter',
2746 'fields' => array('ref'),
2747 'class' => 'fichinter/class/fichinter.class.php',
2748 'object' => 'Fichinter'),
2749 'ticket' => array('table' => 'ticket',
2750 'fields' => array('ref'),
2751 'class' => 'ticket/class/ticket.class.php',
2752 'object' => 'Ticket'),
2753 'knowledgemanagement' => array('table' => 'knowledgemanagement_knowledgerecord',
2754 'fields' => array('ref'),
2755 'class' => 'knowledgemanagement/class/knowledgemanagement.class.php',
2756 'object' => 'KnowledgeRecord'),
2757 'supplier_proposal' => array('table' => 'supplier_proposal',
2758 'fields' => array('ref'),
2759 'class' => 'supplier_proposal/class/supplier_proposal.class.php',
2760 'object' => 'SupplierProposal'),
2761 'fournisseur/commande' => array('table' => 'commande_fournisseur',
2762 'fields' => array('ref', 'ref_supplier'),
2763 'class' => 'fourn/class/fournisseur.commande.class.php',
2764 'object' => 'SupplierProposal'),
2765 'facture' => array('table' => 'facture',
2766 'fields' => array('ref'),
2767 'class' => 'compta/facture/class/facture.class.php',
2768 'object' => 'Facture'),
2769 'fournisseur/facture' => array('table' => 'facture_fourn',
2770 'fields' => array('ref', 'ref_client'),
2771 'class' => 'fourn/class/fournisseur.facture.class.php',
2772 'object' => 'FactureFournisseur'),
2773 'produit' => array('table' => 'product',
2774 'fields' => array('ref'),
2775 'class' => 'product/class/product.class.php',
2776 'object' => 'Product'),
2777 'productlot' => array('table' => 'product_lot',
2778 'fields' => array('batch'),
2779 'class' => 'product/stock/class/productlot.class.php',
2780 'object' => 'Productlot'),
2781 'projet' => array('table' => 'projet',
2782 'fields' => array('ref'),
2783 'class' => 'projet/class/projet.class.php',
2784 'object' => 'Project'),
2785 'projet_task' => array('table' => 'projet_task',
2786 'fields' => array('ref'),
2787 'class' => 'projet/class/task.class.php',
2788 'object' => 'Task'),
2789 'ressource' => array('table' => 'resource',
2790 'fields' => array('ref'),
2791 'class' => 'ressource/class/dolressource.class.php',
2792 'object' => 'Dolresource'),
2793 'bom' => array('table' => 'bom_bom',
2794 'fields' => array('ref'),
2795 'class' => 'bom/class/bom.class.php',
2796 'object' => 'BOM'),
2797 'mrp' => array('table' => 'mrp_mo',
2798 'fields' => array('ref'),
2799 'class' => 'mrp/class/mo.class.php',
2800 'object' => 'Mo'),
2801 );
2802
2803 if (!is_object($hookmanager)) {
2804 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
2805 $hookmanager = new HookManager($this->db);
2806 }
2807 $hookmanager->initHooks(array('emailcolector'));
2808 $parameters = array('arrayobject' => $arrayobject);
2809 $reshook = $hookmanager->executeHooks('addmoduletoeamailcollectorjoinpiece', $parameters); // Note that $action and $object may have been modified by some hooks
2810 if ($reshook > 0) {
2811 $arrayobject = $hookmanager->resArray;
2812 }
2813
2814 $resultobj = array();
2815
2816 foreach ($arrayobject as $key => $objectdesc) {
2817 $sql = 'SELECT DISTINCT t.rowid ';
2818 $sql .= ' FROM ' . MAIN_DB_PREFIX . $objectdesc['table'] . ' AS t';
2819 $sql .= ' WHERE ';
2820 foreach ($objectdesc['fields'] as $field) {
2821 $sql .= "('" .$this->db->escape($subject) . "' LIKE CONCAT('%', t." . $field . ", '%') AND t." . $field . "<>'') OR ";
2822 }
2823 $sql = substr($sql, 0, -4);
2824
2825 $ressqlobj = $this->db->query($sql);
2826 if ($ressqlobj) {
2827 while ($obj = $this->db->fetch_object($ressqlobj)) {
2828 $resultobj[$key][] = $obj->rowid;
2829 }
2830 }
2831 }
2832 $dirs = array();
2833 foreach ($resultobj as $mod => $ids) {
2834 $moddesc = $arrayobject[$mod];
2835 $elementpath = $mod;
2836 dol_include_once($moddesc['class']);
2837 $objectmanaged = new $moddesc['object']($this->db);
2838 foreach ($ids as $val) {
2839 $res = $objectmanaged->fetch($val);
2840 if ($res) {
2841 $path = ($objectmanaged->entity > 1 ? "/" . $objectmanaged->entity : '');
2842 $dirs[] = DOL_DATA_ROOT . $path . "/" . $elementpath . '/' . dol_sanitizeFileName($objectmanaged->ref) . '/';
2843 } else {
2844 $this->errors[] = 'object not found';
2845 }
2846 }
2847 }
2848 foreach ($dirs as $target) {
2849 $prefix = $this->actions[$this->id]['actionparam'];
2850 foreach ($data as $filename => $content) {
2851 $resr = saveAttachment($target, $prefix . '_' . $filename, $content);
2852 if ($resr == -1) {
2853 $this->errors[] = 'Doc not saved';
2854 }
2855 }
2856 }
2857
2858 $operationslog .= '<br>Save attachment files on disk';
2859 } else {
2860 $this->errors[] = 'no joined piece';
2861
2862 $operationslog .= '<br>No joinded files';
2863 }
2864 } elseif ($operation['type'] == 'project') {
2865 // Create project / lead
2866 $projecttocreate = new Project($this->db);
2867 $alreadycreated = $projecttocreate->fetch(0, '', '', $msgid);
2868 if ($alreadycreated == 0) {
2869 if ($thirdpartystatic->id > 0) {
2870 $projecttocreate->socid = $thirdpartystatic->id;
2871 if ($thirdpartyfoundby) {
2872 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Third party found from '.$thirdpartyfoundby);
2873 }
2874 }
2875 if ($contactstatic->id > 0) {
2876 $projecttocreate->contact_id = $contactstatic->id;
2877 if ($contactfoundby) {
2878 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Contact/address found from '.$contactfoundby);
2879 }
2880 }
2881
2882 $description = $descriptiontitle;
2883 $description = dol_concatdesc($description, "-----");
2884 $description = dol_concatdesc($description, $descriptionmeta);
2885 $description = dol_concatdesc($description, "-----");
2886 $description = dol_concatdesc($description, $messagetext);
2887
2888 $descriptionfull = $description;
2889 if (!getDolGlobalString('MAIN_EMAILCOLLECTOR_MAIL_WITHOUT_HEADER')) {
2890 $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
2891 $descriptionfull = dol_concatdesc($descriptionfull, $header);
2892 }
2893
2894 $id_opp_status = dol_getIdFromCode($this->db, 'PROSP', 'c_lead_status', 'code', 'rowid');
2895 $percent_opp_status = dol_getIdFromCode($this->db, 'PROSP', 'c_lead_status', 'code', 'percent');
2896
2897 $projecttocreate->title = $subject;
2898 $projecttocreate->date_start = $date; // date of email
2899 $projecttocreate->date_end = '';
2900 $projecttocreate->opp_status = $id_opp_status;
2901 $projecttocreate->opp_percent = $percent_opp_status;
2902 $projecttocreate->description = dol_concatdesc(dolGetFirstLineOfText(dol_string_nohtmltag($description, 2), 10), '...'.$langs->transnoentities("SeePrivateNote").'...');
2903 $projecttocreate->note_private = $descriptionfull;
2904 $projecttocreate->entity = $conf->entity;
2905 $projecttocreate->email_msgid = $msgid;
2906
2907 $savesocid = $projecttocreate->socid;
2908
2909 // Overwrite values with values extracted from source email.
2910 // This may overwrite any $projecttocreate->xxx properties.
2911 $errorforthisaction = $this->overwritePropertiesOfObject($projecttocreate, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
2912
2913 // Set project ref if not yet defined
2914 if (empty($projecttocreate->ref)) {
2915 // Get next Ref
2916 $defaultref = '';
2917 $modele = !getDolGlobalString('PROJECT_ADDON') ? 'mod_project_simple' : $conf->global->PROJECT_ADDON;
2918
2919 // Search template files
2920 $file = '';
2921 $classname = '';
2922 $filefound = 0;
2923 $reldir = '';
2924 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2925 foreach ($dirmodels as $reldir) {
2926 $file = dol_buildpath($reldir."core/modules/project/".$modele.'.php', 0);
2927 if (file_exists($file)) {
2928 $filefound = 1;
2929 $classname = $modele;
2930 break;
2931 }
2932 }
2933
2934 if ($filefound) {
2935 if ($savesocid > 0) {
2936 if ($savesocid != $projecttocreate->socid) {
2937 $errorforactions++;
2938 setEventMessages('You loaded a thirdparty (id='.$savesocid.') and you force another thirdparty id (id='.$projecttocreate->socid.') by setting socid in operation with a different value', null, 'errors');
2939 }
2940 } else {
2941 if ($projecttocreate->socid > 0) {
2942 $thirdpartystatic->fetch($projecttocreate->socid);
2943 }
2944 }
2945
2946 $result = dol_include_once($reldir."core/modules/project/".$modele.'.php');
2947 $modModuleToUseForNextValue = new $classname();
2948 $defaultref = $modModuleToUseForNextValue->getNextValue(($thirdpartystatic->id > 0 ? $thirdpartystatic : null), $projecttocreate);
2949 }
2950 $projecttocreate->ref = $defaultref;
2951 }
2952
2953
2954 if ($errorforthisaction) {
2955 $errorforactions++;
2956 } else {
2957 if (empty($projecttocreate->ref) || (is_numeric($projecttocreate->ref) && $projecttocreate->ref <= 0)) {
2958 $errorforactions++;
2959 $this->error = 'Failed to create project: Can\'t get a valid value for the field ref with numbering template = '.$modele.', thirdparty id = '.$thirdpartystatic->id;
2960
2961 $operationslog .= '<br>'.$this->error;
2962 } else {
2963 // Create project
2964 $result = $projecttocreate->create($user);
2965 if ($result <= 0) {
2966 $errorforactions++;
2967 $this->error = 'Failed to create project: '.$langs->trans($projecttocreate->error);
2968 $this->errors = $projecttocreate->errors;
2969
2970 $operationslog .= '<br>'.$this->error;
2971 } else {
2972 if ($attachments) {
2973 $destdir = $conf->project->dir_output.'/'.$projecttocreate->ref;
2974 if (!dol_is_dir($destdir)) {
2975 dol_mkdir($destdir);
2976 }
2977 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
2978 foreach ($attachments as $attachment) {
2979 // $attachment->save($destdir.'/');
2980 $typeattachment = (string) $attachment->getDisposition();
2981 $filename = $attachment->getFilename();
2982 $content = $attachment->getContent();
2983 $this->saveAttachment($destdir, $filename, $content);
2984 }
2985 } else {
2986 $this->getmsg($connection, $imapemail, $destdir);
2987 }
2988
2989 $operationslog .= '<br>Project created with attachments -> id='.dol_escape_htmltag($projecttocreate->id);
2990 } else {
2991 $operationslog .= '<br>Project created without attachments -> id='.dol_escape_htmltag($projecttocreate->id);
2992 }
2993 }
2994 }
2995 }
2996 } else {
2997 dol_syslog("Project already exists for msgid = ".dol_escape_htmltag($msgid).", so we do not recreate it.");
2998
2999 $operationslog .= '<br>Project already exists for msgid ='.dol_escape_htmltag($msgid);
3000 }
3001 } elseif ($operation['type'] == 'ticket') {
3002 // Create ticket
3003 $tickettocreate = new Ticket($this->db);
3004
3005 $alreadycreated = $tickettocreate->fetch(0, '', '', $msgid);
3006 if ($alreadycreated == 0) {
3007 if ($thirdpartystatic->id > 0) {
3008 $tickettocreate->socid = $thirdpartystatic->id;
3009 $tickettocreate->fk_soc = $thirdpartystatic->id;
3010 if ($thirdpartyfoundby) {
3011 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Third party found from '.$thirdpartyfoundby);
3012 }
3013 }
3014 if ($contactstatic->id > 0) {
3015 $tickettocreate->contact_id = $contactstatic->id;
3016 if ($contactfoundby) {
3017 $descriptionmeta = dol_concatdesc($descriptionmeta, 'Contact/address found from '.$contactfoundby);
3018 }
3019 }
3020
3021 $description = $descriptiontitle;
3022 $description = dol_concatdesc($description, "-----");
3023 $description = dol_concatdesc($description, $descriptionmeta);
3024 $description = dol_concatdesc($description, "-----");
3025 $description = dol_concatdesc($description, $messagetext);
3026
3027 $descriptionfull = $description;
3028 if (!getDolGlobalString('MAIN_EMAILCOLLECTOR_MAIL_WITHOUT_HEADER')) {
3029 $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
3030 $descriptionfull = dol_concatdesc($descriptionfull, $header);
3031 }
3032
3033 $tickettocreate->subject = $subject;
3034 $tickettocreate->message = $description;
3035 $tickettocreate->type_code = (getDolGlobalString('MAIN_EMAILCOLLECTOR_TICKET_TYPE_CODE') ? $conf->global->MAIN_EMAILCOLLECTOR_TICKET_TYPE_CODE : dol_getIdFromCode($this->db, 1, 'c_ticket_type', 'use_default', 'code', 1));
3036 $tickettocreate->category_code = (getDolGlobalString('MAIN_EMAILCOLLECTOR_TICKET_CATEGORY_CODE') ? $conf->global->MAIN_EMAILCOLLECTOR_TICKET_CATEGORY_CODE : dol_getIdFromCode($this->db, 1, 'c_ticket_category', 'use_default', 'code', 1));
3037 $tickettocreate->severity_code = (getDolGlobalString('MAIN_EMAILCOLLECTOR_TICKET_SEVERITY_CODE') ? $conf->global->MAIN_EMAILCOLLECTOR_TICKET_SEVERITY_CODE : dol_getIdFromCode($this->db, 1, 'c_ticket_severity', 'use_default', 'code', 1));
3038 $tickettocreate->origin_email = $from;
3039 $tickettocreate->fk_user_create = $user->id;
3040 $tickettocreate->datec = dol_now();
3041 $tickettocreate->fk_project = $projectstatic->id;
3042 $tickettocreate->notify_tiers_at_create = getDolGlobalInt('TICKET_CHECK_NOTIFY_THIRDPARTY_AT_CREATION');
3043 $tickettocreate->note_private = $descriptionfull;
3044 $tickettocreate->entity = $conf->entity;
3045 $tickettocreate->email_msgid = $msgid;
3046 $tickettocreate->email_date = $date;
3047 //$tickettocreate->fk_contact = $contactstatic->id;
3048
3049 $savesocid = $tickettocreate->socid;
3050
3051 // Overwrite values with values extracted from source email.
3052 // This may overwrite any $projecttocreate->xxx properties.
3053 $errorforthisaction = $this->overwritePropertiesOfObject($tickettocreate, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
3054
3055 // Set ticket ref if not yet defined
3056 if (empty($tickettocreate->ref)) {
3057 // Get next Ref
3058 $defaultref = '';
3059 $modele = !getDolGlobalString('TICKET_ADDON') ? 'mod_ticket_simple' : $conf->global->TICKET_ADDON;
3060
3061 // Search template files
3062 $file = '';
3063 $classname = '';
3064 $filefound = 0;
3065 $reldir = '';
3066 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
3067 foreach ($dirmodels as $reldir) {
3068 $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
3069 if (file_exists($file)) {
3070 $filefound = 1;
3071 $classname = $modele;
3072 break;
3073 }
3074 }
3075
3076 if ($filefound) {
3077 if ($savesocid > 0) {
3078 if ($savesocid != $tickettocreate->socid) {
3079 $errorforactions++;
3080 setEventMessages('You loaded a thirdparty (id='.$savesocid.') and you force another thirdparty id (id='.$tickettocreate->socid.') by setting socid in operation with a different value', null, 'errors');
3081 }
3082 } else {
3083 if ($tickettocreate->socid > 0) {
3084 $thirdpartystatic->fetch($tickettocreate->socid);
3085 }
3086 }
3087
3088 $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
3089 $modModuleToUseForNextValue = new $classname();
3090 $defaultref = $modModuleToUseForNextValue->getNextValue(($thirdpartystatic->id > 0 ? $thirdpartystatic : null), $tickettocreate);
3091 }
3092 $tickettocreate->ref = $defaultref;
3093 }
3094
3095 if ($errorforthisaction) {
3096 $errorforactions++;
3097 } else {
3098 if (is_numeric($tickettocreate->ref) && $tickettocreate->ref <= 0) {
3099 $errorforactions++;
3100 $this->error = 'Failed to create ticket: Can\'t get a valid value for the field ref with numbering template = '.$modele.', thirdparty id = '.$thirdpartystatic->id;
3101 } else {
3102 // Create project
3103 $result = $tickettocreate->create($user);
3104 if ($result <= 0) {
3105 $errorforactions++;
3106 $this->error = 'Failed to create ticket: '.$langs->trans($tickettocreate->error);
3107 $this->errors = $tickettocreate->errors;
3108 } else {
3109 if ($attachments) {
3110 $destdir = $conf->ticket->dir_output.'/'.$tickettocreate->ref;
3111 if (!dol_is_dir($destdir)) {
3112 dol_mkdir($destdir);
3113 }
3114 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
3115 foreach ($attachments as $attachment) {
3116 // $attachment->save($destdir.'/');
3117 $typeattachment = (string) $attachment->getDisposition();
3118 $filename = $attachment->getFilename();
3119 $content = $attachment->getContent();
3120 $this->saveAttachment($destdir, $filename, $content);
3121 }
3122 } else {
3123 $this->getmsg($connection, $imapemail, $destdir);
3124 }
3125
3126 $operationslog .= '<br>Ticket created with attachments -> id='.dol_escape_htmltag($tickettocreate->id);
3127 } else {
3128 $operationslog .= '<br>Ticket created without attachments -> id='.dol_escape_htmltag($tickettocreate->id);
3129 }
3130 }
3131 }
3132 }
3133 }
3134 } elseif ($operation['type'] == 'candidature') {
3135 // Create candidature
3136 $candidaturetocreate = new RecruitmentCandidature($this->db);
3137
3138 $alreadycreated = $candidaturetocreate->fetch(0, '', $msgid);
3139 if ($alreadycreated == 0) {
3140 $description = $descriptiontitle;
3141 $description = dol_concatdesc($description, "-----");
3142 $description = dol_concatdesc($description, $descriptionmeta);
3143 $description = dol_concatdesc($description, "-----");
3144 $description = dol_concatdesc($description, $messagetext);
3145
3146 $descriptionfull = $description;
3147 $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
3148 $descriptionfull = dol_concatdesc($descriptionfull, $header);
3149
3150 $candidaturetocreate->subject = $subject;
3151 $candidaturetocreate->message = $description;
3152 $candidaturetocreate->type_code = 0;
3153 $candidaturetocreate->category_code = null;
3154 $candidaturetocreate->severity_code = null;
3155 $candidaturetocreate->email = $from;
3156 //$candidaturetocreate->lastname = $langs->trans("Anonymous").' - '.$from;
3157 $candidaturetocreate->fk_user_creat = $user->id;
3158 $candidaturetocreate->date_creation = dol_now();
3159 $candidaturetocreate->fk_project = $projectstatic->id;
3160 $candidaturetocreate->description = $description;
3161 $candidaturetocreate->note_private = $descriptionfull;
3162 $candidaturetocreate->entity = $conf->entity;
3163 $candidaturetocreate->email_msgid = $msgid;
3164 $candidaturetocreate->email_date = $date; // date of email
3165 $candidaturetocreate->status = $candidaturetocreate::STATUS_DRAFT;
3166 //$candidaturetocreate->fk_contact = $contactstatic->id;
3167
3168 // Overwrite values with values extracted from source email.
3169 // This may overwrite any $projecttocreate->xxx properties.
3170 $errorforthisaction = $this->overwritePropertiesOfObject($candidaturetocreate, $operation['actionparam'], $messagetext, $subject, $header, $operationslog);
3171
3172 // Set candidature ref if not yet defined
3173 /*if (empty($candidaturetocreate->ref)) We do not need this because we create object in draft status
3174 {
3175 // Get next Ref
3176 $defaultref = '';
3177 $modele = empty($conf->global->CANDIDATURE_ADDON) ? 'mod_candidature_simple' : $conf->global->CANDIDATURE_ADDON;
3178
3179 // Search template files
3180 $file = ''; $classname = ''; $filefound = 0; $reldir = '';
3181 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
3182 foreach ($dirmodels as $reldir)
3183 {
3184 $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
3185 if (file_exists($file)) {
3186 $filefound = 1;
3187 $classname = $modele;
3188 break;
3189 }
3190 }
3191
3192 if ($filefound) {
3193 if ($savesocid > 0) {
3194 if ($savesocid != $candidaturetocreate->socid) {
3195 $errorforactions++;
3196 setEventMessages('You loaded a thirdparty (id='.$savesocid.') and you force another thirdparty id (id='.$candidaturetocreate->socid.') by setting socid in operation with a different value', null, 'errors');
3197 }
3198 } else {
3199 if ($candidaturetocreate->socid > 0)
3200 {
3201 $thirdpartystatic->fetch($candidaturetocreate->socid);
3202 }
3203 }
3204
3205 $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
3206 $modModuleToUseForNextValue = new $classname;
3207 $defaultref = $modModuleToUseForNextValue->getNextValue(($thirdpartystatic->id > 0 ? $thirdpartystatic : null), $tickettocreate);
3208 }
3209 $candidaturetocreate->ref = $defaultref;
3210 }*/
3211
3212 if ($errorforthisaction) {
3213 $errorforactions++;
3214 } else {
3215 // Create project
3216 $result = $candidaturetocreate->create($user);
3217 if ($result <= 0) {
3218 $errorforactions++;
3219 $this->error = 'Failed to create candidature: '.join(', ', $candidaturetocreate->errors);
3220 $this->errors = $candidaturetocreate->errors;
3221 }
3222
3223 $operationslog .= '<br>Candidature created without attachments -> id='.dol_escape_htmltag($candidaturetocreate->id);
3224 }
3225 }
3226 } elseif (substr($operation['type'], 0, 4) == 'hook') {
3227 // Create event specific on hook
3228 // this code action is hook..... for support this call
3229 if (!is_object($hookmanager)) {
3230 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
3231 $hookmanager = new HookManager($this->db);
3232 $hookmanager->initHooks(['emailcolector']);
3233 }
3234
3235 $parameters = array(
3236 'connection'=> $connection,
3237 'imapemail'=>$imapemail,
3238 'overview'=>$overview,
3239
3240 'from' => $from,
3241 'fromtext' => $fromtext,
3242
3243 'actionparam'=> $operation['actionparam'],
3244
3245 'thirdpartyid' => $thirdpartyid,
3246 'objectid'=> $objectid,
3247 'objectemail'=> $objectemail,
3248
3249 'messagetext'=>$messagetext,
3250 'subject'=>$subject,
3251 'header'=>$header,
3252 'attachments'=>$attachments,
3253 );
3254 $reshook = $hookmanager->executeHooks('doCollectImapOneCollector', $parameters, $this, $operation['type']);
3255
3256 if ($reshook < 0) {
3257 $errorforthisaction++;
3258 $this->error = $hookmanager->resPrint;
3259 }
3260 if ($errorforthisaction) {
3261 $errorforactions++;
3262 $operationslog .= '<br>Hook doCollectImapOneCollector executed with error';
3263 } else {
3264 $operationslog .= '<br>Hook doCollectImapOneCollector executed without error';
3265 }
3266 }
3267
3268 if (!$errorforactions) {
3269 $nbactiondoneforemail++;
3270 }
3271 }
3272 }
3273
3274 // Error for email or not ?
3275 if (!$errorforactions) {
3276 if (!empty($targetdir)) {
3277 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
3278 // Move mail using PHP-IMAP
3279 dol_syslog("EmailCollector::doCollectOneCollector move message ".($imapemail->getHeader()->get('subject'))." to ".$targetdir, LOG_DEBUG);
3280 if (empty($mode)) { // $mode > 0 is test
3281 $imapemail->move($targetdir);
3282 }
3283 } else {
3284 dol_syslog("EmailCollector::doCollectOneCollector move message ".($this->uidAsString($imapemail))." to ".$connectstringtarget, LOG_DEBUG);
3285 $operationslog .= '<br>Move mail '.($this->uidAsString($imapemail)).' - '.$msgid;
3286
3287 $arrayofemailtodelete[$imapemail] = $msgid;
3288 // Note: Real move is done later using $arrayofemailtodelete
3289 }
3290 } else {
3291 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
3292 dol_syslog("EmailCollector::doCollectOneCollector message '".($imapemail->getHeader()->get('subject'))."' using this->host=".$this->host.", this->access_type=".$this->acces_type." was set to read", LOG_DEBUG);
3293 } else {
3294 dol_syslog("EmailCollector::doCollectOneCollector message ".($this->uidAsString($imapemail))." to ".$connectstringtarget." was set to read", LOG_DEBUG);
3295 }
3296 }
3297 } else {
3298 $errorforemail++;
3299 }
3300
3301
3302 unset($objectemail);
3303 unset($projectstatic);
3304 unset($thirdpartystatic);
3305 unset($contactstatic);
3306
3307 $nbemailprocessed++;
3308
3309 if (!$errorforemail) {
3310 $nbactiondone += $nbactiondoneforemail;
3311 $nbemailok++;
3312
3313 if (empty($mode)) {
3314 $this->db->commit();
3315 } else {
3316 $this->db->rollback();
3317 }
3318
3319 // Stop the loop to process email if we reach maximum collected per collect
3320 if ($this->maxemailpercollect > 0 && $nbemailok >= $this->maxemailpercollect) {
3321 dol_syslog("EmailCollect::doCollectOneCollector We reach maximum of ".$nbemailok." collected with success, so we stop this collector now.");
3322 break;
3323 }
3324 } else {
3325 $error++;
3326
3327 $this->db->rollback();
3328 }
3329 }
3330
3331 $output = $langs->trans('XEmailsDoneYActionsDone', $nbemailprocessed, $nbemailok, $nbactiondone);
3332
3333 dol_syslog("End of loop on emails", LOG_INFO, -1);
3334 } else {
3335 $langs->load("admin");
3336 $output = $langs->trans('NoNewEmailToProcess');
3337 $output .= ' (defaultlang='.$langs->defaultlang.')';
3338 }
3339
3340 // Disconnect
3341 if (getDolGlobalString('MAIN_IMAP_USE_PHPIMAP')) {
3342 $client->disconnect();
3343 } else {
3344 foreach ($arrayofemailtodelete as $imapemail => $msgid) {
3345 dol_syslog("EmailCollect::doCollectOneCollector delete email ".$imapemail." ".$msgid);
3346
3347 $operationslog .= "<br> delete email ".$imapemail." ".$msgid;
3348
3349 if (empty($mode) && empty($error)) {
3350 $res = imap_mail_move($connection, $imapemail, $targetdir, CP_UID);
3351 if ($res == false) {
3352 $errorforemail++;
3353 $this->error = imap_last_error();
3354 $this->errors[] = $this->error;
3355
3356 $operationslog .= '<br>Error in move '.$this->error;
3357
3358 dol_syslog(imap_last_error());
3359 }
3360 }
3361 }
3362
3363 if (empty($mode) && empty($error)) {
3364 dol_syslog("Expunge", LOG_DEBUG);
3365 $operationslog .= "<br>Expunge";
3366
3367 imap_expunge($connection); // To validate all moves
3368 }
3369 imap_close($connection);
3370 }
3371
3372 $this->datelastresult = $now;
3373 $this->lastresult = $output;
3374 $this->debuginfo .= 'IMAP search string used : '.$search;
3375 if ($searchhead) {
3376 $this->debuginfo .= '<br>Then search string into email header : '.dol_escape_htmltag($searchhead);
3377 }
3378 if ($operationslog) {
3379 $this->debuginfo .= $operationslog;
3380 }
3381
3382 if (empty($error) && empty($mode)) {
3383 $this->datelastok = $now;
3384 }
3385
3386 if (!empty($this->errors)) {
3387 $this->lastresult .= "<br>".join("<br>", $this->errors);
3388 }
3389 $this->codelastresult = ($error ? 'KO' : 'OK');
3390
3391 if (empty($mode)) {
3392 $this->update($user);
3393 }
3394
3395 dol_syslog("EmailCollector::doCollectOneCollector end", LOG_INFO);
3396
3397 return $error ? -1 : 1;
3398 }
3399
3400
3401
3402 // Loop to get part html and plain. Code found on PHP imap_fetchstructure documentation
3403
3412 private function getmsg($mbox, $mid, $destdir = '')
3413 {
3414 // input $mbox = IMAP stream, $mid = message id
3415 // output all the following:
3416 global $charset, $htmlmsg, $plainmsg, $attachments;
3417 $htmlmsg = $plainmsg = $charset = '';
3418 $attachments = array();
3419
3420 // HEADER
3421 //$h = imap_header($mbox,$mid);
3422 // add code here to get date, from, to, cc, subject...
3423
3424 // BODY
3425 $s = imap_fetchstructure($mbox, $mid, FT_UID);
3426
3427
3428 if (!$s->parts) {
3429 // simple
3430 $this->getpart($mbox, $mid, $s, 0); // pass 0 as part-number
3431 } else {
3432 // multipart: cycle through each part
3433 foreach ($s->parts as $partno0 => $p) {
3434 $this->getpart($mbox, $mid, $p, $partno0 + 1, $destdir);
3435 }
3436 }
3437 }
3438
3439 /* partno string
3440 0 multipart/mixed
3441 1 multipart/alternative
3442 1.1 text/plain
3443 1.2 text/html
3444 2 message/rfc822
3445 2 multipart/mixed
3446 2.1 multipart/alternative
3447 2.1.1 text/plain
3448 2.1.2 text/html
3449 2.2 message/rfc822
3450 2.2 multipart/alternative
3451 2.2.1 text/plain
3452 2.2.2 text/html
3453 */
3454
3465 private function getpart($mbox, $mid, $p, $partno, $destdir = '')
3466 {
3467 // $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
3468 global $htmlmsg, $plainmsg, $charset, $attachments;
3469
3470 // DECODE DATA
3471 $data = ($partno) ?
3472 imap_fetchbody($mbox, $mid, $partno, FT_UID) : // multipart
3473 imap_body($mbox, $mid, FT_UID); // simple
3474 // Any part may be encoded, even plain text messages, so check everything.
3475 if ($p->encoding == 4) {
3476 $data = quoted_printable_decode($data);
3477 } elseif ($p->encoding == 3) {
3478 $data = base64_decode($data);
3479 }
3480
3481 // PARAMETERS
3482 // get all parameters, like charset, filenames of attachments, etc.
3483 $params = array();
3484 if ($p->parameters) {
3485 foreach ($p->parameters as $x) {
3486 $params[strtolower($x->attribute)] = $x->value;
3487 }
3488 }
3489 if (!empty($p->dparameters)) {
3490 foreach ($p->dparameters as $x) {
3491 $params[strtolower($x->attribute)] = $x->value;
3492 }
3493 }
3494
3495 // ATTACHMENT
3496 // Any part with a filename is an attachment,
3497 // so an attached text file (type 0) is not mistaken as the message.
3498 if (!empty($params['filename']) || !empty($params['name'])) {
3499 // filename may be given as 'Filename' or 'Name' or both
3500 $filename = $params['filename'] ?? $params['name'];
3501 // filename may be encoded, so see imap_mime_header_decode()
3502 $attachments[$filename] = $data; // this is a problem if two files have same name
3503
3504 if (strlen($destdir)) {
3505 if (substr($destdir, -1) != '/') {
3506 $destdir .= '/';
3507 }
3508
3509 // Get file name (with extension)
3510 $file_name_complete = $params['filename'];
3511 $destination = $destdir.$file_name_complete;
3512
3513 // Extract file extension
3514 $extension = pathinfo($file_name_complete, PATHINFO_EXTENSION);
3515
3516 // Extract file name without extension
3517 $file_name = pathinfo($file_name_complete, PATHINFO_FILENAME);
3518
3519 // Save an original file name variable to track while renaming if file already exists
3520 $file_name_original = $file_name;
3521
3522 // Increment file name by 1
3523 $num = 1;
3524
3529 while (file_exists($destdir.$file_name.".".$extension)) {
3530 $file_name = $file_name_original . ' (' . $num . ')';
3531 $file_name_complete = $file_name . "." . $extension;
3532 $destination = $destdir.$file_name_complete;
3533 $num++;
3534 }
3535
3536 $destination = dol_sanitizePathName($destination);
3537
3538 file_put_contents($destination, $data);
3539 }
3540 }
3541
3542 // TEXT
3543 if ($p->type == 0 && $data) {
3544 if (!empty($params['charset'])) {
3545 $data = $this->convertStringEncoding($data, $params['charset']);
3546 }
3547 // Messages may be split in different parts because of inline attachments,
3548 // so append parts together with blank row.
3549 if (strtolower($p->subtype) == 'plain') {
3550 $plainmsg .= trim($data)."\n\n";
3551 } else {
3552 $htmlmsg .= $data."<br><br>";
3553 }
3554 $charset = $params['charset']; // assume all parts are same charset
3555 } elseif ($p->type == 2 && $data) {
3556 // EMBEDDED MESSAGE
3557 // Many bounce notifications embed the original message as type 2,
3558 // but AOL uses type 1 (multipart), which is not handled here.
3559 // There are no PHP functions to parse embedded messages,
3560 // so this just appends the raw source to the main message.
3561 if (!empty($params['charset'])) {
3562 $data = $this->convertStringEncoding($data, $params['charset']);
3563 }
3564 $plainmsg .= $data."\n\n";
3565 }
3566
3567 // SUBPART RECURSION
3568 if (!empty($p->parts)) {
3569 foreach ($p->parts as $partno0 => $p2) {
3570 $this->getpart($mbox, $mid, $p2, $partno.'.'.($partno0 + 1), $destdir); // 1.2, 1.2.1, etc.
3571 }
3572 }
3573 }
3574
3584 protected function convertStringEncoding($string, $fromEncoding, $toEncoding = 'UTF-8')
3585 {
3586 if (!$string || $fromEncoding == $toEncoding) {
3587 return $string;
3588 }
3589 $convertedString = function_exists('iconv') ? @iconv($fromEncoding, $toEncoding.'//IGNORE', $string) : null;
3590 if (!$convertedString && extension_loaded('mbstring')) {
3591 $convertedString = @mb_convert_encoding($string, $toEncoding, $fromEncoding);
3592 }
3593 if (!$convertedString) {
3594 throw new Exception('Mime string encoding conversion failed');
3595 }
3596 return $convertedString;
3597 }
3598
3609 protected function decodeSMTPSubject($subject)
3610 {
3611 // Decode $overview[0]->subject according to RFC2047
3612 // Can use also imap_mime_header_decode($str)
3613 // Can use also mb_decode_mimeheader($str)
3614 // Can use also iconv_mime_decode($str, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8')
3615 if (function_exists('imap_mime_header_decode') && function_exists('iconv_mime_decode')) {
3616 $elements = imap_mime_header_decode($subject);
3617 $newstring = '';
3618 if (!empty($elements)) {
3619 $num = count($elements);
3620 for ($i = 0; $i < $num; $i++) {
3621 $stringinutf8 = (in_array(strtoupper($elements[$i]->charset), array('DEFAULT', 'UTF-8')) ? $elements[$i]->text : iconv_mime_decode($elements[$i]->text, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, $elements[$i]->charset));
3622 $newstring .= $stringinutf8;
3623 }
3624 $subject = $newstring;
3625 }
3626 } elseif (!function_exists('mb_decode_mimeheader')) {
3627 $subject = mb_decode_mimeheader($subject);
3628 } elseif (function_exists('iconv_mime_decode')) {
3629 $subject = iconv_mime_decode($subject, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8');
3630 }
3631
3632 return $subject;
3633 }
3634
3641 protected function removeEmoji($text)
3642 {
3643 // Supprimer les caractères emoji en utilisant une expression régulière
3644 $text = preg_replace('/[\x{1F600}-\x{1F64F}]/u', '', $text);
3645 $text = preg_replace('/[\x{1F300}-\x{1F5FF}]/u', '', $text);
3646 $text = preg_replace('/[\x{1F680}-\x{1F6FF}]/u', '', $text);
3647 $text = preg_replace('/[\x{2600}-\x{26FF}]/u', '', $text);
3648 $text = preg_replace('/[\x{2700}-\x{27BF}]/u', '', $text);
3649 $text = preg_replace('/[\x{1F900}-\x{1F9FF}]/u', '', $text);
3650 $text = preg_replace('/[\x{1F1E0}-\x{1F1FF}]/u', '', $text);
3651
3652 return $text;
3653 }
3654
3663 private function saveAttachment($destdir, $filename, $content)
3664 {
3665 require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
3666
3667 $tmparraysize = getDefaultImageSizes();
3668 $maxwidthsmall = $tmparraysize['maxwidthsmall'];
3669 $maxheightsmall = $tmparraysize['maxheightsmall'];
3670 $maxwidthmini = $tmparraysize['maxwidthmini'];
3671 $maxheightmini = $tmparraysize['maxheightmini'];
3672 $quality = $tmparraysize['quality'];
3673
3674 file_put_contents($destdir.'/'.$filename, $content);
3675 if (image_format_supported($filename) == 1) {
3676 // Create thumbs
3677 vignette($destdir.'/'.$filename, $maxwidthsmall, $maxheightsmall, '_small', $quality, "thumbs");
3678 // Create mini thumbs for image (Ratio is near 16/9)
3679 vignette($destdir.'/'.$filename, $maxwidthmini, $maxheightmini, '_mini', $quality, "thumbs");
3680 }
3681 addFileIntoDatabaseIndex($destdir, $filename);
3682 }
3683
3690 protected function uidAsString($imapemail)
3691 {
3692 if (is_object($imapemail)) {
3693 return $imapemail->getAttributes()["uid"];
3694 } else {
3695 return (string) $imapemail;
3696 }
3697 }
3698}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$object ref
Definition info.php:79
Class to manage agenda events (actions)
Class to manage members of a foundation.
Class to manage predefined suppliers products.
Class to manage customers orders.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
createCommon(User $user, $notrigger=false)
Create object into database.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
updateCommon(User $user, $notrigger=false)
Update object into database.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
Class to manage Dolibarr database access.
Class for EmailCollectorAction.
Class for EmailCollectorFilter.
Class for EmailCollector.
fetch($id, $ref=null)
Load object in memory from the database.
createFromClone(User $user, $fromid)
Clone and object into another one.
create(User $user, $notrigger=false)
Create object into database.
update(User $user, $notrigger=false)
Update object into database.
convertStringEncoding($string, $fromEncoding, $toEncoding='UTF-8')
Converts a string from one encoding to another.
overwritePropertiesOfObject(&$object, $actionparam, $messagetext, $subject, $header, &$operationslog)
overwitePropertiesOfObject
__construct(DoliDB $db)
Constructor.
getpart($mbox, $mid, $p, $partno, $destdir='')
Sub function for getpart().
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
removeEmoji($text)
Remove EMoji from email content.
getEncodedUtf7($str)
Convert str to UTF-7 imap.
getConnectStringIMAP()
Return the connectstring to use with IMAP connection function.
decodeSMTPSubject($subject)
Decode a subject string according to RFC2047 Example: '=?Windows-1252?Q?RE=A0:_ABC?...
fetchFilters()
Fetch filters.
uidAsString($imapemail)
Get UID of message as a string.
LibStatut($status, $mode=0)
Return the status.
fetchActions()
Fetch actions.
saveAttachment($destdir, $filename, $content)
saveAttachment
fetchAll(User $user, $activeOnly=0, $sortfield='s.rowid', $sortorder='ASC', $limit=100, $page=0)
Load object lines in memory from the database.
info($id)
Charge les informations d'ordre info dans l'objet commande.
getmsg($mbox, $mid, $destdir='')
getmsg
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
doCollect()
Action executed by scheduler CAN BE A CRON TASK.
getLibStatut($mode=0)
Return label of the status.
Class to manage shipments.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage hooks.
Class to manage projects.
Class to manage proposals.
Class to manage receptions.
Class for RecruitmentCandidature.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage price ask supplier.
Class to manage tasks.
Class to manage translations.
Class to manage Dolibarr users.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
getFileData($jk, $fpos, $type, $mbox)
Get content of a joined file from its position into a given email.
getAttachments($jk, $mbox)
Get attachments of a given mail.
addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0, $object=null)
Add a file into database index.
dol_is_dir($folder)
Test if filename is a directory.
dolExplodeIntoArray($string, $delimiter=';', $kv='=')
Split a string with 2 keys into key array.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
if(!defined( 'IMAGETYPE_WEBP')) getDefaultImageSizes()
Return default values for image sizes.
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Class to generate the form for creating a new ticket.
getSupportedOauth2Array()
Return array of tabs to used on pages to setup cron module.
dolEncrypt($chain, $key='', $ciphering='AES-256-CTR', $forceseed='')
Encode a string with a symetric encryption.
dolDecrypt($chain, $key='')
Decode a string with a symetric encryption.
Contact()
Old copy.
Definition index.php:572