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