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