dolibarr  17.0.4
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 ?? $objectemail->socid;
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 }
$object ref
Definition: info.php:78
Class to manage agenda events (actions)
Class to manage members of a foundation.
Class to manage predefined suppliers products.
Class to manage customers orders.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
createCommon(User $user, $notrigger=false)
Create object into database.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
updateCommon(User $user, $notrigger=false)
Update object into database.
Class to manage contact/addresses.
Class to manage Dolibarr database access.
Class for EmailCollectorAction.
Class for EmailCollectorFilter.
Class for EmailCollector.
fetch($id, $ref=null)
Load object in memory from the database.
createFromClone(User $user, $fromid)
Clone and object into another one.
create(User $user, $notrigger=false)
Create object into database.
update(User $user, $notrigger=false)
Update object into database.
convertStringEncoding($string, $fromEncoding, $toEncoding='UTF-8')
Converts a string from one encoding to another.
overwritePropertiesOfObject(&$object, $actionparam, $messagetext, $subject, $header, &$operationslog)
overwitePropertiesOfObject
__construct(DoliDB $db)
Constructor.
getpart($mbox, $mid, $p, $partno, $destdir='')
Sub function for getpart().
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
removeEmoji($text)
Remove EMoji from email content.
getEncodedUtf7($str)
Convert str to UTF-7 imap default mailbox names.
decodeSMTPSubject($subject)
Decode a subject string according to RFC2047 Example: '=?Windows-1252?Q?RE=A0:_ABC?...
fetchFilters()
Fetch filters.
LibStatut($status, $mode=0)
Return the status.
fetchActions()
Fetch actions.
fetchAll(User $user, $activeOnly=0, $sortfield='s.rowid', $sortorder='ASC', $limit=100, $page=0)
Load object lines in memory from the database.
getConnectStringIMAP($ssl=1, $norsh=0)
Return the connectstring to use with IMAP connection function.
info($id)
Charge les informations d'ordre info dans l'objet commande.
getmsg($mbox, $mid, $destdir='')
getmsg
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
doCollectOneCollector($mode=0)
Execute collect for current collector loaded previously with fetch.
doCollect()
Action executed by scheduler CAN BE A CRON TASK.
getLibStatut($mode=0)
Return label of the status.
Class to manage shipments.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage hooks.
Class to manage projects.
Class to manage proposals.
Class to manage receptions.
Class for RecruitmentCandidature.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage price ask supplier.
Class to manage tasks.
Definition: task.class.php:38
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:47
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
saveAttachment($path, $filename, $data)
Save joined file into a directory with a given name.
getFileData($jk, $fpos, $type, $mbox)
Get content of a joined file from its position into a given email.
getAttachments($jk, $mbox)
Get attachments of a given mail.
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:451
dolExplodeIntoArray($string, $delimiter=';', $kv='=')
Split a string with 2 keys into key array.
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.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null)
Return array of possible common substitutions.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Class to generate the form for creating a new ticket.
dolEncrypt($chain, $key='', $ciphering='AES-256-CTR', $forceseed='')
Encode a string with a symetric encryption.
dolDecrypt($chain, $key='')
Decode a string with a symetric encryption.
$conf db
API class for accounts.
Definition: inc.php:41