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