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