Passed
Branch develop (5cbde9)
by
unknown
26:38
created

EmailCollector   F

Complexity

Total Complexity 318

Size/Duplication

Total Lines 1959
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Importance

Changes 0
Metric Value
dl 0
loc 1959
rs 0.8
c 0
b 0
f 0
wmc 318
lcom 2
cbo 9

20 Methods

Rating   Name   Duplication   Size   Complexity  
A delete() 0 3 1
F doCollectOneCollector() 0 1002 183
A doCollect() 0 20 3
B __construct() 0 26 11
F getNomUrl() 0 64 20
A getConnectStringIMAP() 0 12 1
B fetchAll() 0 45 8
D LibStatut() 0 43 19
A fetch() 0 5 1
A getLibStatut() 0 3 1
A create() 0 3 1
A getmsg() 0 21 3
B createFromClone() 0 55 7
F overwritePropertiesOfObject() 0 116 27
F getpart() 0 68 18
B info() 0 44 6
A initAsSpecimen() 0 3 1
A fetchFilters() 0 25 3
A update() 0 3 1
A fetchActions() 0 23 3

How to fix   Complexity   

Complex Class

Complex classes like EmailCollector often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EmailCollector, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* Copyright (C) 2017  Laurent Destailleur <[email protected]>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
/**
19
 * \file        emailcollector/class/emailcollector.class.php
20
 * \ingroup     emailcollector
21
 * \brief       This file is a CRUD class file for EmailCollector (Create/Read/Update/Delete)
22
 */
23
24
// Put here all includes required by your class file
25
require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php';
26
require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
27
require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
28
require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
29
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
30
require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
31
32
33
/**
34
 * Class for EmailCollector
35
 */
36
class EmailCollector extends CommonObject
37
{
38
    /**
39
     * @var string ID to identify managed object
40
     */
41
    public $element = 'emailcollector';
42
    /**
43
     * @var string Name of table without prefix where object is stored
44
     */
45
    public $table_element = 'emailcollector_emailcollector';
46
    /**
47
     * @var int  Does emailcollector support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
48
     */
49
    public $ismultientitymanaged = 1;
50
    /**
51
     * @var int  Does emailcollector support extrafields ? 0=No, 1=Yes
52
     */
53
    public $isextrafieldmanaged = 0;
54
    /**
55
     * @var string String with name of icon for emailcollector. Must be the part after the 'object_' into object_emailcollector.png
56
     */
57
    public $picto = 'generic';
58
59
    /**
60
     * @var int    Field with ID of parent key if this field has a parent
61
     */
62
    public $fk_element = 'fk_emailcollector';
63
64
    /**
65
	 * @var array	List of child tables. To test if we can delete object.
66
     */
67
    protected $childtables=array();
68
    /**
69
     * @var array	List of child tables. To know object to delete on cascade.
70
     */
71
    protected $childtablesoncascade=array('emailcollector_emailcollectorfilter','emailcollector_emailcollectoraction');
72
73
74
    /**
75
     *  'type' if the field format.
76
     *  'label' the translation key.
77
     *  'enabled' is a condition when the field must be managed.
78
     *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only. Using a negative value means field is not shown by default on list but can be selected for viewing)
79
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
80
     *  'default' is a default value for creation (can still be replaced by the global setup of default values)
81
     *  'index' if we want an index in database.
82
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
83
     *  'position' is the sort order of field.
84
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
85
     *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
86
     *  'css' is the CSS style to use on field. For example: 'maxwidth200'
87
     *  'help' is a string visible as a tooltip on field
88
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
89
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
90
     *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
91
     */
92
93
    // BEGIN MODULEBUILDER PROPERTIES
94
    /**
95
     * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
96
     */
97
    public $fields=array(
98
        'rowid'         => array('type'=>'integer', 'label'=>'TechnicalID','visible'=>2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1),
99
        'entity'        => array('type'=>'integer',      'label'=>'Entity',           'enabled'=>1, 'visible'=>0,  'default'=>1, 'notnull'=>1,  'index'=>1, 'position'=>20),
100
        'ref'           => array('type'=>'varchar(128)', 'label'=>'Ref',              'enabled'=>1, 'visible'=>1,  'notnull'=>1,  'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1, 'help'=>'Example: MyCollector1'),
101
        'label'         => array('type'=>'varchar(255)', 'label'=>'Label', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'notnull'=>-1, 'searchall'=>1, 'help'=>'Example: My Email collector'),
102
        'description'   => array('type'=>'text', 'label'=>'Description', 'visible'=>-1, 'enabled'=>1, 'position'=>60, 'notnull'=>-1),
103
        'host'          => array('type'=>'varchar(255)', 'label'=>'EMailHost', 'visible'=>1, 'enabled'=>1, 'position'=>100, 'notnull'=>1, 'searchall'=>1, 'comment'=>"IMAP server", 'help'=>'Example: imap.gmail.com'),
104
        'login'         => array('type'=>'varchar(128)', 'label'=>'Login', 'visible'=>1, 'enabled'=>1, 'position'=>101, 'notnull'=>-1, 'index'=>1, 'comment'=>"IMAP login", 'help'=>'Example: [email protected]'),
105
        'password'      => array('type'=>'password', 'label'=>'Password', 'visible'=>-1, 'enabled'=>1, 'position'=>102, 'notnull'=>-1, 'comment'=>"IMAP password", 'help'=>'WithGMailYouCanCreateADedicatedPassword'),
106
        'source_directory' => array('type'=>'varchar(255)', 'label'=>'MailboxSourceDirectory', 'visible'=>-1, 'enabled'=>1, 'position'=>103, 'notnull'=>1, 'default' => 'Inbox', 'help'=>'Example: INBOX'),
107
        //'filter' => array('type'=>'text', 'label'=>'Filter', 'visible'=>1, 'enabled'=>1, 'position'=>105),
108
        //'actiontodo' => array('type'=>'varchar(255)', 'label'=>'ActionToDo', 'visible'=>1, 'enabled'=>1, 'position'=>106),
109
        'target_directory' => array('type'=>'varchar(255)', 'label'=>'MailboxTargetDirectory', 'visible'=>1, 'enabled'=>1, 'position'=>110, 'notnull'=>0, 'comment'=>"Where to store messages once processed"),
110
        'maxemailpercollect' => array('type'=>'integer', 'label'=>'MaxEmailCollectPerCollect','visible'=>-1, 'enabled'=>1, 'position'=>111, 'default'=>100),
111
        'datelastresult' => array('type'=>'datetime', 'label'=>'DateLastCollectResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>121, 'notnull'=>-1,),
112
        'codelastresult' => array('type'=>'varchar(16)', 'label'=>'CodeLastResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>122, 'notnull'=>-1,),
113
        'lastresult' => array('type'=>'varchar(255)', 'label'=>'LastResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>123, 'notnull'=>-1,),
114
        'datelastok' => array('type'=>'datetime', 'label'=>'DateLastcollectResultOk', 'visible'=>1, 'enabled'=>'$action != "create"', 'position'=>125, 'notnull'=>-1,),
115
        'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'visible'=>0, 'enabled'=>1, 'position'=>61, 'notnull'=>-1,),
116
        'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'visible'=>0, 'enabled'=>1, 'position'=>62, 'notnull'=>-1,),
117
        'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>-2, 'enabled'=>1, 'position'=>500, 'notnull'=>1,),
118
        'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-2, 'enabled'=>1, 'position'=>501, 'notnull'=>1,),
119
        //'date_validation' => array('type'=>'datetime',     'label'=>'DateCreation',     'enabled'=>1, 'visible'=>-2, 'position'=>502),
120
        'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'visible'=>-2, 'enabled'=>1, 'position'=>510, 'notnull'=>1,),
121
        'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'visible'=>-2, 'enabled'=>1, 'position'=>511, 'notnull'=>-1,),
122
        //'fk_user_valid' =>array('type'=>'integer',      'label'=>'UserValidation',        'enabled'=>1, 'visible'=>-1, 'position'=>512),
123
        'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'visible'=>-2, 'enabled'=>1, 'position'=>1000, 'notnull'=>-1,),
124
        'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Inactive', '1'=>'Active'))
125
    );
126
127
128
    /**
129
     * @var int ID
130
     */
131
    public $rowid;
132
133
    /**
134
     * @var string Ref
135
     */
136
    public $ref;
137
138
    /**
139
     * @var int Entity
140
     */
141
    public $entity;
142
143
    /**
144
     * @var string label
145
     */
146
    public $label;
147
148
149
    /**
150
     * @var int Status
151
     */
152
    public $status;
153
154
    public $date_creation;
155
    public $tms;
156
157
    /**
158
     * @var int ID
159
     */
160
    public $fk_user_creat;
161
162
    /**
163
     * @var int ID
164
     */
165
    public $fk_user_modif;
166
167
    public $import_key;
168
169
170
    public $host;
171
    public $login;
172
    public $password;
173
    public $source_directory;
174
    public $target_directory;
175
    public $maxemailpercollect;
176
    public $datelastresult;
177
    public $lastresult;
178
    // END MODULEBUILDER PROPERTIES
179
180
    public $filters;
181
    public $actions;
182
183
    public $debuginfo;
184
185
186
    /**
187
     * Constructor
188
     *
189
     * @param DoliDb $db Database handler
190
     */
191
    public function __construct(DoliDB $db)
192
    {
193
        global $conf, $langs;
194
195
        $this->db = $db;
196
197
        if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) $this->fields['rowid']['visible']=0;
198
        if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) $this->fields['entity']['enabled']=0;
199
200
        // Unset fields that are disabled
201
        foreach($this->fields as $key => $val)
202
        {
203
            if (isset($val['enabled']) && empty($val['enabled']))
204
            {
205
                unset($this->fields[$key]);
206
            }
207
        }
208
209
        // Translate some data of arrayofkeyval
210
        foreach($this->fields as $key => $val)
211
        {
212
        	if (is_array($val['arrayofkeyval']))
213
            {
214
            	foreach($val['arrayofkeyval'] as $key2 => $val2)
215
                {
216
                	$this->fields[$key]['arrayofkeyval'][$key2]=$langs->trans($val2);
217
                }
218
            }
219
        }
220
    }
221
222
    /**
223
     * Create object into database
224
     *
225
     * @param  User $user      User that creates
226
     * @param  bool $notrigger false=launch triggers after, true=disable triggers
227
     * @return int             <0 if KO, Id of created object if OK
228
     */
229
    public function create(User $user, $notrigger = false)
230
    {
231
        return $this->createCommon($user, $notrigger);
232
    }
233
234
    /**
235
     * Clone and object into another one
236
     *
237
     * @param  	User 	$user      	User that creates
238
     * @param  	int 	$fromid     Id of object to clone
239
     * @return 	mixed 				New object created, <0 if KO
240
     */
241
    public function createFromClone(User $user, $fromid)
242
    {
243
        global $langs, $extrafields;
244
        $error = 0;
245
246
        dol_syslog(__METHOD__, LOG_DEBUG);
247
248
        $object = new self($this->db);
249
250
        $this->db->begin();
251
252
        // Load source object
253
        $object->fetchCommon($fromid);
254
        // Reset some properties
255
        unset($object->id);
256
        unset($object->fk_user_creat);
257
        unset($object->import_key);
258
259
        // Clear fields
260
        $object->ref = "copy_of_".$object->ref;
261
        $object->title = $langs->trans("CopyOf")." ".$object->title;
262
        // ...
263
        // Clear extrafields that are unique
264
        if (is_array($object->array_options) && count($object->array_options) > 0)
265
        {
266
            $extrafields->fetch_name_optionals_label($this->element);
267
            foreach($object->array_options as $key => $option)
268
            {
269
                $shortkey = preg_replace('/options_/', '', $key);
270
                if (! empty($extrafields->attributes[$this->element]['unique'][$shortkey]))
271
                {
272
                    //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
273
                    unset($object->array_options[$key]);
274
                }
275
            }
276
        }
277
278
        // Create clone
279
        $object->context['createfromclone'] = 'createfromclone';
280
        $result = $object->createCommon($user);
281
        if ($result < 0) {
282
            $error++;
283
            $this->error = $object->error;
284
            $this->errors = $object->errors;
285
        }
286
287
        unset($object->context['createfromclone']);
288
289
        // End
290
        if (!$error) {
291
            $this->db->commit();
292
            return $object;
293
        } else {
294
            $this->db->rollback();
295
            return -1;
296
        }
297
    }
298
299
    /**
300
     * Load object in memory from the database
301
     *
302
     * @param int    $id   Id object
303
     * @param string $ref  Ref
304
     * @return int         <0 if KO, 0 if not found, >0 if OK
305
     */
306
    public function fetch($id, $ref = null)
307
    {
308
        $result = $this->fetchCommon($id, $ref);
309
        //if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines();
310
        return $result;
311
    }
312
313
    /**
314
     * Load object lines in memory from the database
315
     *
316
     * @return int         <0 if KO, 0 if not found, >0 if OK
317
     */
318
    /*
319
    public function fetchLines()
320
    {
321
        $this->lines=array();
322
323
        // Load lines with object EmailCollectorLine
324
325
        return count($this->lines)?1:0;
326
    }
327
    */
328
329
    /**
330
     * Fetch all account and load objects into an array
331
     *
332
     * @param   User    $user           User
333
     * @param   int     $activeOnly     filter if active
334
     * @param   string  $sortfield      field for sorting
335
     * @param   string  $sortorder      sorting order
336
     * @param   int     $limit          sort limit
337
     * @param   int     $page           page to start on
338
     * @return  array   Array with key => EmailCollector object
339
     */
340
    public function fetchAll(User $user, $activeOnly = 0, $sortfield = 's.rowid', $sortorder = 'ASC', $limit = 100, $page = 0)
341
    {
342
        global $langs;
343
344
        $obj_ret = array();
345
346
        $sql = "SELECT s.rowid";
347
        $sql.= " FROM ".MAIN_DB_PREFIX."emailcollector_emailcollector as s";
348
        $sql.= ' WHERE s.entity IN ('.getEntity('emailcollector').')';
349
        if ($activeOnly) {
350
            $sql.= " AND s.status = 1";
351
        }
352
        $sql.= $this->db->order($sortfield, $sortorder);
353
        if ($limit) {
354
            if ($page < 0) {
355
                $page = 0;
356
            }
357
            $offset = $limit * $page;
358
359
            $sql.= $this->db->plimit($limit + 1, $offset);
360
        }
361
362
        $result = $this->db->query($sql);
363
        if ($result) {
364
            $num = $this->db->num_rows($result);
365
            $i = 0;
366
            while ($i < $num)
367
            {
368
                $obj = $this->db->fetch_object($result);
369
                $emailcollector_static = new EmailCollector($this->db);
370
                if ($emailcollector_static->fetch($obj->rowid)) {
371
                    $obj_ret[] = $emailcollector_static;
372
                }
373
                $i++;
374
            }
375
        } else {
376
            $this->errors[] = 'EmailCollector::fetchAll Error when retrieve emailcollector list';
377
            dol_syslog('EmailCollector::fetchAll Error when retrieve emailcollector list', LOG_ERR);
378
            $ret = -1;
379
        }
380
        if (! count($obj_ret)) {
381
            dol_syslog('EmailCollector::fetchAll No emailcollector found', LOG_DEBUG);
382
        }
383
384
        return $obj_ret;
385
    }
386
387
    /**
388
     * Update object into database
389
     *
390
     * @param  User $user      User that modifies
391
     * @param  bool $notrigger false=launch triggers after, true=disable triggers
392
     * @return int             <0 if KO, >0 if OK
393
     */
394
    public function update(User $user, $notrigger = false)
395
    {
396
        return $this->updateCommon($user, $notrigger);
397
    }
398
399
    /**
400
     * Delete object in database
401
     *
402
     * @param User $user       User that deletes
403
     * @param bool $notrigger  false=launch triggers after, true=disable triggers
404
     * @return int             <0 if KO, >0 if OK
405
     */
406
    public function delete(User $user, $notrigger = false)
407
    {
408
        return $this->deleteCommon($user, $notrigger, 1);
409
    }
410
411
    /**
412
     *  Return a link to the object card (with optionaly the picto)
413
     *
414
     *	@param	int		$withpicto					Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
415
     *	@param	string	$option						On what the link point to ('nolink', ...)
416
     *  @param	int  	$notooltip					1=Disable tooltip
417
     *  @param  string  $morecss            		Add more css on link
418
     *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
419
     *	@return	string								String with URL
420
     */
421
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
422
    {
423
        global $conf, $langs, $hookmanager;
424
425
        if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
426
427
        $result = '';
428
429
        $label = '<u>' . $langs->trans("EmailCollector") . '</u>';
430
        $label.= '<br>';
431
        $label.= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
432
433
        $url = dol_buildpath('/admin/emailcollector_card.php', 1).'?id='.$this->id;
434
435
        if ($option != 'nolink')
436
        {
437
            // Add param to save lastsearch_values or not
438
            $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
439
            if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
440
                $add_save_lastsearch_values=1;
441
            }
442
            if ($add_save_lastsearch_values) {
443
                $url.='&save_lastsearch_values=1';
444
            }
445
        }
446
447
        $linkclose='';
448
        if (empty($notooltip))
449
        {
450
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
451
            {
452
                $label=$langs->trans("ShowEmailCollector");
453
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
454
            }
455
            $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"';
456
            $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"';
457
458
            /*
459
             $hookmanager->initHooks(array('myobjectdao'));
460
             $parameters=array('id'=>$this->id);
461
             $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
462
             if ($reshook > 0) $linkclose = $hookmanager->resPrint;
463
             */
464
        }
465
        else $linkclose = ($morecss?' class="'.$morecss.'"':'');
466
467
        $linkstart = '<a href="'.$url.'"';
468
        $linkstart.=$linkclose.'>';
469
        $linkend='</a>';
470
471
        $result .= $linkstart;
472
        if ($withpicto) $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);
473
        if ($withpicto != 2) $result.= $this->ref;
474
        $result .= $linkend;
475
        //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
476
477
        global $action,$hookmanager;
478
        $hookmanager->initHooks(array('emailcollectordao'));
479
        $parameters=array('id'=>$this->id, 'getnomurl'=>$result);
480
        $reshook=$hookmanager->executeHooks('getNomUrl', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
481
        if ($reshook > 0) $result = $hookmanager->resPrint;
482
        else $result .= $hookmanager->resPrint;
483
484
        return $result;
485
    }
486
487
    /**
488
     *  Return label of the status
489
     *
490
     *  @param  int		$mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
491
     *  @return	string 			       Label of status
492
     */
493
    public function getLibStatut($mode = 0)
494
    {
495
        return $this->LibStatut($this->status, $mode);
496
    }
497
498
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
499
    /**
500
     *  Return the status
501
     *
502
     *  @param	int		$status        Id status
503
     *  @param  int		$mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
504
     *  @return string 			       Label of status
505
     */
506
    public function LibStatut($status, $mode = 0)
507
    {
508
        // phpcs:enable
509
        if (empty($this->labelstatus))
510
        {
511
            global $langs;
512
            //$langs->load("mymodule");
513
            $this->labelstatus[1] = $langs->trans('Enabled');
514
            $this->labelstatus[0] = $langs->trans('Disabled');
515
        }
516
517
        if ($mode == 0)
518
        {
519
            return $this->labelstatus[$status];
520
        }
521
        elseif ($mode == 1)
522
        {
523
            return $this->labelstatus[$status];
524
        }
525
        elseif ($mode == 2)
526
        {
527
            if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
528
            elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
529
        }
530
        elseif ($mode == 3)
531
        {
532
            if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle');
533
            elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle');
534
        }
535
        elseif ($mode == 4)
536
        {
537
            if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
538
            elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
539
        }
540
        elseif ($mode == 5)
541
        {
542
            if ($status == 1) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle');
543
            elseif ($status == 0) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle');
544
        }
545
        elseif ($mode == 6)
546
        {
547
            if ($status == 1) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle');
548
            elseif ($status == 0) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle');
549
        }
550
    }
551
552
    /**
553
     *	Charge les informations d'ordre info dans l'objet commande
554
     *
555
     *	@param  int		$id       Id of order
556
     *	@return	void
557
     */
558
    public function info($id)
559
    {
560
        $sql = 'SELECT rowid, date_creation as 	datec, tms as datem,';
561
        $sql.= ' fk_user_creat, fk_user_modif';
562
        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
563
        $sql.= ' WHERE t.rowid = '.$id;
564
        $result=$this->db->query($sql);
565
        if ($result)
566
        {
567
            if ($this->db->num_rows($result))
568
            {
569
                $obj = $this->db->fetch_object($result);
570
                $this->id = $obj->rowid;
571
                if ($obj->fk_user_author)
572
                {
573
                    $cuser = new User($this->db);
574
                    $cuser->fetch($obj->fk_user_author);
575
                    $this->user_creation   = $cuser;
576
                }
577
578
                if ($obj->fk_user_valid)
579
                {
580
                    $vuser = new User($this->db);
581
                    $vuser->fetch($obj->fk_user_valid);
582
                    $this->user_validation = $vuser;
583
                }
584
585
                if ($obj->fk_user_cloture)
586
                {
587
                    $cluser = new User($this->db);
588
                    $cluser->fetch($obj->fk_user_cloture);
589
                    $this->user_cloture   = $cluser;
590
                }
591
592
                $this->date_creation     = $this->db->jdate($obj->datec);
593
                $this->date_modification = $this->db->jdate($obj->datem);
594
                $this->date_validation   = $this->db->jdate($obj->datev);
595
            }
596
597
            $this->db->free($result);
598
        }
599
        else
600
        {
601
            dol_print_error($this->db);
602
        }
603
    }
604
605
    /**
606
     * Initialise object with example values
607
     * Id must be 0 if object instance is a specimen
608
     *
609
     * @return void
610
     */
611
    public function initAsSpecimen()
612
    {
613
        $this->initAsSpecimenCommon();
614
    }
615
616
    /**
617
     * Fetch filters
618
     *
619
     * @return 	int		<0 if KO, >0 if OK
620
     */
621
    public function fetchFilters()
622
    {
623
        $this->filters = array();
624
625
        $sql = 'SELECT rowid, type, rulevalue, status';
626
        $sql.= ' FROM '.MAIN_DB_PREFIX.'emailcollector_emailcollectorfilter';
627
        $sql.= ' WHERE fk_emailcollector = '.$this->id;
628
        //$sql.= ' ORDER BY position';
629
630
        $resql = $this->db->query($sql);
631
        if ($resql)
632
        {
633
            $num=$this->db->num_rows($resql);
634
            $i = 0;
635
            while($i < $num)
636
            {
637
                $obj=$this->db->fetch_object($resql);
638
                $this->filters[$obj->rowid]=array('id'=>$obj->rowid, 'type'=>$obj->type, 'rulevalue'=>$obj->rulevalue, 'status'=>$obj->status);
639
                $i++;
640
            }
641
            $this->db->free($resql);
642
        }
643
        else dol_print_error($this->db);
644
645
        return 1;
646
    }
647
648
    /**
649
     * Fetch actions
650
     *
651
     * @return 	int		<0 if KO, >0 if OK
652
     */
653
    public function fetchActions()
654
    {
655
        $this->actions = array();
656
657
        $sql = 'SELECT rowid, type, actionparam, status';
658
        $sql.= ' FROM '.MAIN_DB_PREFIX.'emailcollector_emailcollectoraction';
659
        $sql.= ' WHERE fk_emailcollector = '.$this->id;
660
        $sql.= ' ORDER BY position';
661
662
        $resql = $this->db->query($sql);
663
        if ($resql)
664
        {
665
            $num=$this->db->num_rows($resql);
666
            $i = 0;
667
            while($i < $num)
668
            {
669
                $obj=$this->db->fetch_object($resql);
670
                $this->actions[$obj->rowid]=array('id'=>$obj->rowid, 'type'=>$obj->type, 'actionparam'=>$obj->actionparam, 'status'=>$obj->status);
671
                $i++;
672
            }
673
            $this->db->free($resql);
674
        }
675
        else dol_print_error($this->db);
676
    }
677
678
679
    /**
680
     * Return the connectstring to use with IMAP connection function
681
     *
682
     * @return string
683
     */
684
    public function getConnectStringIMAP()
685
    {
686
        // Connect to IMAP
687
        $flags ='/service=imap';		// IMAP
688
        $flags.='/ssl';					// '/tls'
689
        $flags.='/novalidate-cert';
690
        //$flags.='/readonly';
691
        //$flags.='/debug';
692
693
        $connectstringserver = '{'.$this->host.':993'.$flags.'}';
694
695
        return $connectstringserver;
696
    }
697
698
    /**
699
     * Action executed by scheduler
700
     * CAN BE A CRON TASK. In such a case, paramerts come from the schedule job setup field 'Parameters'
701
     *
702
     * @return	int			0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
703
     */
704
    public function doCollect()
705
    {
706
        global $user;
707
708
        $nberror = 0;
709
710
        $arrayofcollectors = $this->fetchAll($user, 1);
711
712
        // Loop on each collector
713
        foreach($arrayofcollectors as $emailcollector)
714
        {
715
            $result = $emailcollector->doCollectOneCollector();
716
            dol_syslog("doCollect result = ".$result." for emailcollector->id = ".$emailcollector->id);
717
718
            $this->error.='EmailCollector ID '.$emailcollector->id.':'.$emailcollector->error.'<br>';
719
            if (! empty($emailcollector->errors)) $this->error.=join('<br>', $emailcollector->errors);
720
            $this->output.='EmailCollector ID '.$emailcollector->id.': '.$emailcollector->lastresult.'<br>';
721
        }
722
723
        return $nberror;
724
    }
725
726
    /**
727
     * overwitePropertiesOfObject
728
     *
729
     * @param	object	$object			Current object
730
     * @param	string	$actionparam	Action parameters
731
     * @param	string	$messagetext	Body
732
     * @param	string	$subject		Subject
733
     * @param   string  $header         Header
734
     * @return	int						0=OK, Nb of error if error
735
     */
736
    private function overwritePropertiesOfObject(&$object, $actionparam, $messagetext, $subject, $header)
737
    {
738
        $errorforthisaction = 0;
739
740
        // Overwrite values with values extracted from source email
741
        // $this->actionparam = 'opportunity_status=123;abc=EXTRACT:BODY:....'
742
        $arrayvaluetouse = dolExplodeIntoArray($actionparam, ';', '=');
743
        foreach($arrayvaluetouse as $propertytooverwrite => $valueforproperty)
744
        {
745
            $tmpclass=''; $tmpproperty='';
746
            $tmparray=explode('.', $propertytooverwrite);
747
            if (count($tmparray) == 2)
748
            {
749
                $tmpclass=$tmparray[0];
750
                $tmpproperty=$tmparray[1];
751
            }
752
            else
753
            {
754
                $tmpproperty=$tmparray[0];
755
            }
756
            if ($tmpclass && ($tmpclass != $object->element)) continue;	// Property is for another type of object
757
758
            //if (property_exists($object, $tmpproperty) || preg_match('/^options_/', $tmpproperty))
759
            if ($tmpproperty)
760
            {
761
                $sourcestring='';
762
                $sourcefield='';
763
                $regexstring='';
764
                //$transformationstring='';
765
                $regforregex=array();
766
                if (preg_match('/^EXTRACT:([a-zA-Z0-9]+):(.*):([^:])$/', $valueforproperty, $regforregex))
767
                {
768
                    $sourcefield=$regforregex[1];
769
                    $regexstring=$regforregex[2];
770
                    //$transofrmationstring=$regforregex[3];
771
                }
772
                elseif (preg_match('/^EXTRACT:([a-zA-Z0-9]+):(.*)$/', $valueforproperty, $regforregex))
773
                {
774
                    $sourcefield=$regforregex[1];
775
                    $regexstring=$regforregex[2];
776
                }
777
                if (! empty($sourcefield) && ! empty($regexstring))
778
                {
779
                    if (strtolower($sourcefield) == 'body') $sourcestring=$messagetext;
780
                    elseif (strtolower($sourcefield) == 'subject') $sourcestring=$subject;
781
                    elseif (strtolower($sourcefield) == 'header') $sourcestring=$header;
782
783
                    if ($sourcestring)
784
                    {
785
                        $regforval=array();
786
                        $regexoptions='';
787
                        if (strtolower($sourcefield) == 'body') $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
788
                        if (strtolower($sourcefield) == 'header') $regexoptions='m';    // The m means ^ and $ char is valid at each new line.
789
790
                        //var_dump($tmpproperty.' - '.$regexstring.' - '.$regexoptions.' - '.$sourcestring);
791
                        if (preg_match('/'.$regexstring.'/'.$regexoptions, $sourcestring, $regforval))
792
                        {
793
                            //var_dump($regforval[1]);exit;
794
                            // Overwrite param $tmpproperty
795
                            $object->$tmpproperty = isset($regforval[1])?trim($regforval[1]):null;
796
                        }
797
                        else
798
                        {
799
                            // Regex not found
800
                            $object->$tmpproperty = null;
801
                        }
802
                    }
803
                    else
804
                    {
805
                        // Nothing can be done for this param
806
                        $errorforthisaction++;
807
                        $this->error = 'The extract rule to use has on an unknown source (must be HEADER, SUBJECT or BODY)';
808
                        $this->errors[] = $this->error;
809
                    }
810
                }
811
                elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $regforregex))
812
                {
813
                    $valuecurrent='';
814
                    if (preg_match('/^options_/', $tmpproperty)) $valuecurrent = $object->array_options[preg_replace('/^options_/', '', $tmpproperty)];
815
                    else $valuecurrent = $object->$tmpproperty;
816
817
                    if ($regforregex[1] == 'SET' || empty($valuecurrent))
818
                    {
819
                        $valuetouse = $regforregex[2];
820
                        $substitutionarray=array();
821
                        $matcharray=array();
822
                        preg_match_all('/__([a-z0-9]+(?:_[a-z0-9]+)?)__/i', $valuetouse, $matcharray);
823
                        //var_dump($tmpproperty.' - '.$object->$tmpproperty.' - '.$valuetouse); var_dump($matcharray);
824
                        if (is_array($matcharray[1]))    // $matcharray[1] is array with list of substitution key found without the __
825
                        {
826
                            foreach($matcharray[1] as $keytoreplace)
827
                            {
828
                                if ($keytoreplace && isset($object->$keytoreplace))
829
                                {
830
                                    $substitutionarray['__'.$keytoreplace.'__']=$object->$keytoreplace;
831
                                }
832
                            }
833
                        }
834
                        //var_dump($substitutionarray);
835
                        dol_syslog(var_export($substitutionarray, true));
836
                        //var_dump($substitutionarray);
837
                        $valuetouse = make_substitutions($valuetouse, $substitutionarray);
838
                        if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $valuetouse;
839
                        else $object->$tmpproperty = $valuetouse;
840
                    }
841
                }
842
                else
843
                {
844
                    $errorforthisaction++;
845
                    $this->error = 'Bad syntax for description of action parameters: '.$actionparam;
846
                    $this->errors[] = $this->error;
847
                }
848
            }
849
        }
850
851
        return $errorforthisaction;
852
    }
853
854
    /**
855
     * Execute collect for current collector loaded previously with fetch.
856
     *
857
     * @return	int			<0 if KO, >0 if OK
858
     */
859
    public function doCollectOneCollector()
860
    {
861
        global $conf, $langs, $user;
862
863
        //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
864
865
        require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
866
867
        dol_syslog("EmailCollector::doCollectOneCollector start", LOG_DEBUG);
868
869
        $langs->loadLangs(array("project", "companies", "mails", "errors", "ticket"));
870
871
        $error = 0;
872
        $this->output = '';
873
        $this->error='';
874
875
        $now = dol_now();
876
877
        if (empty($this->host))
878
        {
879
            $this->error=$langs->trans('ErrorFieldRequired', 'EMailHost');
880
            return -1;
881
        }
882
        if (empty($this->login))
883
        {
884
            $this->error=$langs->trans('ErrorFieldRequired', 'Login');
885
            return -1;
886
        }
887
        if (empty($this->source_directory))
888
        {
889
            $this->error=$langs->trans('ErrorFieldRequired', 'MailboxSourceDirectory');
890
            return -1;
891
        }
892
        if (! function_exists('imap_open'))
893
        {
894
            $this->error='IMAP function not enabled on your PHP';
895
            return -2;
896
        }
897
898
        $this->fetchFilters();
899
        $this->fetchActions();
900
901
        $sourcedir = $this->source_directory;
902
        $targetdir = ($this->target_directory ? $this->target_directory : '');			// Can be '[Gmail]/Trash' or 'mytag'
903
904
        $connectstringserver = $this->getConnectStringIMAP();
905
        $connectstringsource = $connectstringserver.imap_utf7_encode($sourcedir);
906
        $connectstringtarget = $connectstringserver.imap_utf7_encode($targetdir);
907
908
        $connection = imap_open($connectstringsource, $this->login, $this->password);
909
        if (! $connection)
910
        {
911
            $this->error = 'Failed to open IMAP connection '.$connectstringsource;
912
            return -3;
913
        }
914
        imap_errors();  // Clear stack of errors.
915
916
        // $conf->global->MAIL_PREFIX_FOR_EMAIL_ID must be defined
917
        $host=dol_getprefix('email');
918
919
        // Define the IMAP search string
920
        // See https://tools.ietf.org/html/rfc3501#section-6.4.4 for IMAPv4 (PHP not yet compatible)
921
        // See https://tools.ietf.org/html/rfc1064 page 13 for IMAPv2
922
        //$search='ALL';
923
        $search='UNDELETED';  // Seems not supported by some servers
924
        $searchhead='';
925
        $searchfilterdoltrackid=0;
926
        $searchfilternodoltrackid=0;
927
        foreach($this->filters as $rule)
928
        {
929
            if (empty($rule['status'])) continue;
930
931
            if ($rule['type'] == 'to')      $search.=($search?' ':'').'TO "'.str_replace('"', '', $rule['rulevalue']).'"';
932
            if ($rule['type'] == 'bcc')     $search.=($search?' ':'').'BCC';
933
            if ($rule['type'] == 'cc')      $search.=($search?' ':'').'CC';
934
            if ($rule['type'] == 'from')    $search.=($search?' ':'').'FROM "'.str_replace('"', '', $rule['rulevalue']).'"';
935
            if ($rule['type'] == 'subject') $search.=($search?' ':'').'SUBJECT "'.str_replace('"', '', $rule['rulevalue']).'"';
936
            if ($rule['type'] == 'body')    $search.=($search?' ':'').'BODY "'.str_replace('"', '', $rule['rulevalue']).'"';
937
            if ($rule['type'] == 'header')  $search.=($search?' ':'').'HEADER '.$rule['rulevalue'];
938
939
            if ($rule['type'] == 'notinsubject') $search.=($search?' ':'').'SUBJECT NOT "'.str_replace('"', '', $rule['rulevalue']).'"';
940
            if ($rule['type'] == 'notinbody') $search.=($search?' ':'').'BODY NOT "'.str_replace('"', '', $rule['rulevalue']).'"';
941
942
            if ($rule['type'] == 'seen')    $search.=($search?' ':'').'SEEN';
943
            if ($rule['type'] == 'unseen')  $search.=($search?' ':'').'UNSEEN';
944
            if ($rule['type'] == 'unanswered') $search.=($search?' ':'').'UNANSWERED';
945
            if ($rule['type'] == 'answered')   $search.=($search?' ':'').'ANSWERED';
946
            if ($rule['type'] == 'smaller') $search.=($search?' ':'').'SMALLER "'.str_replace('"', '', $rule['rulevalue']).'"';
947
            if ($rule['type'] == 'larger')  $search.=($search?' ':'').'LARGER "'.str_replace('"', '', $rule['rulevalue']).'"';
948
949
            if ($rule['type'] == 'withtrackingid')    { $searchfilterdoltrackid++; $searchhead.='/References.*@'.preg_quote($host, '/').'/'; }
950
            if ($rule['type'] == 'withouttrackingid') { $searchfilternodoltrackid++; $searchhead.='! /References.*@'.preg_quote($host, '/').'/';}
951
        }
952
953
        if (empty($targetdir))	// Use last date as filter if there is no targetdir defined.
954
        {
955
            $fromdate=0;
956
            if ($this->datelastok) $fromdate = $this->datelastok;
957
            if ($fromdate > 0) $search.=($search?' ':'').'SINCE '.date('j-M-Y', $fromdate - 1); // SENTSINCE not supported. Date must be X-Abc-9999 (X on 1 digit if < 10)
958
            //$search.=($search?' ':'').'SINCE 8-Apr-2018';
959
        }
960
        dol_syslog("IMAP search string = ".$search);
961
        //var_dump($search);
962
963
        $nbemailprocessed=0;
964
        $nbemailok=0;
965
        $nbactiondone=0;
966
967
        // Scan IMAP inbox
968
        $arrayofemail= imap_search($connection, $search, null, "UTF-8");
969
        if ($arrayofemail === false)
970
        {
971
            // Nothing found or search string not understood
972
            $mapoferrrors = imap_errors();
973
            if ($mapoferrrors !== false)
974
            {
975
                $error++;
976
                $this->error = "Search string not understood - ".join(',', $mapoferrrors);
977
                $this->errors[] = $this->error;
978
            }
979
        }
980
981
        // Loop on each email found
982
        if (! $error && ! empty($arrayofemail) && count($arrayofemail) > 0)
983
        {
984
            // Loop to get part html and plain
985
            /*
986
             0 multipart/mixed
987
             1 multipart/alternative
988
             1.1 text/plain
989
             1.2 text/html
990
             2 message/rfc822
991
             2 multipart/mixed
992
             2.1 multipart/alternative
993
             2.1.1 text/plain
994
             2.1.2 text/html
995
             2.2 message/rfc822
996
             2.2 multipart/alternative
997
             2.2.1 text/plain
998
             2.2.2 text/html
999
             */
1000
            /**
1001
             * create_part_array
1002
             *
1003
             * @param 	Object $structure	Structure
1004
             * @param 	string $prefix		prefix
1005
             * @return 	array				Array with number and object
1006
             */
1007
            /*function createPartArray($structure, $prefix = "")
1008
            {
1009
                //print_r($structure);
1010
                $part_array=array();
1011
                if (count($structure->parts) > 0) {    // There some sub parts
1012
                    foreach ($structure->parts as $count => $part) {
1013
                        addPartToArray($part, $prefix.($count+1), $part_array);
1014
                    }
1015
                }else{    // Email does not have a seperate mime attachment for text
1016
                    $part_array[] = array('part_number' => $prefix.'1', 'part_object' => $structure);
1017
                }
1018
                return $part_array;
1019
            }*/
1020
1021
            /**
1022
             * Sub function for createPartArray(). Only called by createPartArray() and itself.
1023
             *
1024
             * @param 	Object		$obj			Structure
1025
             * @param 	string		$partno			Part no
1026
             * @param 	array		$part_array		array
1027
             * @return	void
1028
             */
1029
            /*function addPartToArray($obj, $partno, &$part_array)
1030
            {
1031
                $part_array[] = array('part_number' => $partno, 'part_object' => $obj);
1032
                if ($obj->type == 2) { // Check to see if the part is an attached email message, as in the RFC-822 type
1033
                    //print_r($obj);
1034
                    if (array_key_exists('parts', $obj)) {    // Check to see if the email has parts
1035
                        foreach ($obj->parts as $count => $part) {
1036
                            // Iterate here again to compensate for the broken way that imap_fetchbody() handles attachments
1037
                            if (count($part->parts) > 0) {
1038
                                foreach ($part->parts as $count2 => $part2) {
1039
                                    addPartToArray($part2, $partno.".".($count2+1), $part_array);
1040
                                }
1041
                            }else{    // Attached email does not have a seperate mime attachment for text
1042
                                $part_array[] = array('part_number' => $partno.'.'.($count+1), 'part_object' => $obj);
1043
                            }
1044
                        }
1045
                    }else{    // Not sure if this is possible
1046
                        $part_array[] = array('part_number' => $partno.'.1', 'part_object' => $obj);
1047
                    }
1048
                }else{    // If there are more sub-parts, expand them out.
1049
                    if (array_key_exists('parts', $obj)) {
1050
                        foreach ($obj->parts as $count => $p) {
1051
                            addPartToArray($p, $partno.".".($count+1), $part_array);
1052
                        }
1053
                    }
1054
                }
1055
            }*/
1056
1057
            dol_syslog("Start of loop on email", LOG_INFO, 1);
1058
1059
            foreach($arrayofemail as $imapemail)
1060
            {
1061
                if ($nbemailprocessed > 1000)
1062
                {
1063
                    break;			// Do not process more than 1000 email per launch (this is a different protection than maxnbcollectedpercollect
1064
                }
1065
1066
                $header = imap_fetchheader($connection, $imapemail, 0);
1067
                $matches=array();
1068
                preg_match_all('/([^: ]+): (.+?(?:\r\n\s(?:.+?))*)\r\n/m', $header, $matches);
1069
                $headers = array_combine($matches[1], $matches[2]);
1070
                //var_dump($headers);
1071
1072
                // If there is a filter on trackid
1073
                if ($searchfilterdoltrackid > 0)
1074
                {
1075
                    //if (empty($headers['X-Dolibarr-TRACKID'])) continue;
1076
                    if (empty($headers['References']) || ! preg_match('/@'.preg_quote($host, '/').'/', $headers['References']))
1077
                    {
1078
                        $nbemailprocessed++;
1079
                        continue;
1080
                    }
1081
                }
1082
                if ($searchfilternodoltrackid > 0)
1083
                {
1084
                    if (! empty($headers['References']) && preg_match('/@'.preg_quote($host, '/').'/', $headers['References']))
1085
                    {
1086
                        $nbemailprocessed++;
1087
                        continue;
1088
                    }
1089
                    //if (! empty($headers['X-Dolibarr-TRACKID']) continue;
1090
                }
1091
1092
                $thirdpartystatic=new Societe($this->db);
1093
                $contactstatic=new Contact($this->db);
1094
                $projectstatic=new Project($this->db);
1095
1096
                $nbactiondoneforemail = 0;
1097
                $errorforemail = 0;
1098
                $errorforactions = 0;
1099
                $thirdpartyfoundby = '';
1100
                $contactfoundby = '';
1101
                $projectfoundby = '';
1102
1103
                $this->db->begin();
1104
1105
                // GET Email meta datas
1106
                $overview = imap_fetch_overview($connection, $imapemail, 0);
1107
1108
                dol_syslog("** Process email - msgid=".$overview[0]->message_id." date=".dol_print_date($overview[0]->udate, 'dayrfc', 'gmt')." subject=".$overview[0]->subject);
1109
1110
                // Parse IMAP email structure
1111
                global $htmlmsg, $plainmsg, $charset, $attachments;
1112
                $this->getmsg($connection, $imapemail);
1113
1114
                //$htmlmsg,$plainmsg,$charset,$attachments
1115
                $messagetext = $plainmsg ? $plainmsg : dol_string_nohtmltag($htmlmsg, 0);
1116
                /*var_dump($plainmsg);
1117
                var_dump($htmlmsg);
1118
                var_dump($messagetext);*/
1119
                /*var_dump($charset);
1120
                var_dump($attachments);
1121
                exit;*/
1122
1123
                // Parse IMAP email structure
1124
                /*
1125
                $structure = imap_fetchstructure($connection, $imapemail, 0);
1126
1127
                $partplain = $parthtml = -1;
1128
                $encodingplain = $encodinghtml = '';
1129
1130
                $result = createPartArray($structure, '');
1131
1132
                foreach($result as $part)
1133
                {
1134
                    // $part['part_object']->type seems 0 for content
1135
                    // $part['part_object']->type seems 5 for attachment
1136
                    if (empty($part['part_object'])) continue;
1137
                    if ($part['part_object']->subtype == 'HTML')
1138
                    {
1139
                        $parthtml=$part['part_number'];
1140
                        if ($part['part_object']->encoding == 4)
1141
                        {
1142
                            $encodinghtml = 'aaa';
1143
                        }
1144
                    }
1145
                    if ($part['part_object']->subtype == 'PLAIN')
1146
                    {
1147
                        $partplain=$part['part_number'];
1148
                        if ($part['part_object']->encoding == 4)
1149
                        {
1150
                            $encodingplain = 'rr';
1151
                        }
1152
                    }
1153
                }
1154
                //var_dump($result); var_dump($partplain); var_dump($parthtml);
1155
1156
                var_dump($structure);
1157
                var_dump($parthtml);
1158
                var_dump($partplain);
1159
1160
                $messagetext = imap_fetchbody($connection, $imapemail, ($parthtml != '-1' ? $parthtml : ($partplain != '-1' ? $partplain : 1)), FT_PEEK);
1161
                */
1162
1163
                //var_dump($messagetext);
1164
                //var_dump($structure->parts[0]->parts);
1165
                //print $header;
1166
                //print $messagetext;
1167
                //exit;
1168
1169
                $fromstring=$overview[0]->from;
1170
                $sender=$overview[0]->sender;
1171
                $to=$overview[0]->to;
1172
                $sendtocc=$overview[0]->cc;
1173
                $sendtobcc=$overview[0]->bcc;
1174
                $date=$overview[0]->udate;
1175
                $msgid=str_replace(array('<','>'), '', $overview[0]->message_id);
1176
                $subject=$overview[0]->subject;
1177
                //var_dump($msgid);exit;
1178
1179
                $reg=array();
1180
                if (preg_match('/^(.*)<(.*)>$/', $fromstring, $reg))
1181
                {
1182
                    $from=$reg[2];
1183
                    $fromtext=$reg[1];
1184
                }
1185
                else
1186
                {
1187
                    $from = $fromstring;
1188
                    $fromtext='';
1189
                }
1190
                $fk_element_id = 0; $fk_element_type = '';
1191
1192
                $contactid = 0; $thirdpartyid = 0; $projectid = 0;
1193
1194
                // Analyze TrackId in field References. For example:
1195
                // References: <1542377954.SMTPs-dolibarr-thi649@8f6014fde11ec6cdec9a822234fc557e>
1196
                // References: <1542377954.SMTPs-dolibarr-tic649@8f6014fde11ec6cdec9a822234fc557e>
1197
                // References: <1542377954.SMTPs-dolibarr-abc649@8f6014fde11ec6cdec9a822234fc557e>
1198
                $trackid = '';
1199
                $reg=array();
1200
                if (! empty($headers['References']) && preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote($host, '/').'/', $headers['References'], $reg))
1201
                {
1202
                    $trackid = $reg[1].$reg[2];
1203
1204
                    $objectid = 0;
1205
                    $objectemail = null;
1206
                    if ($reg[0] == 'inv')
1207
                    {
1208
                        $objectid = $reg[1];
1209
                        $objectemail = new Facture($this->db);
1210
                    }
1211
                    if ($reg[0] == 'proj')
1212
                    {
1213
                        $objectid = $reg[1];
1214
                        $objectemail = new Project($this->db);
1215
                    }
1216
                    if ($reg[0] == 'con')
1217
                    {
1218
                        $objectid = $reg[1];
1219
                        $objectemail = new Contact($this->db);
1220
                    }
1221
                    if ($reg[0] == 'thi')
1222
                    {
1223
                        $objectid = $reg[1];
1224
                        $objectemail = new Societe($this->db);
1225
                    }
1226
                    if ($reg[0] == 'use')
1227
                    {
1228
                        $objectid = $reg[1];
1229
                        $objectemail = new User($this->db);
1230
                    }
1231
                    if ($reg[0] == 'tic')
1232
                    {
1233
                        $objectid = $reg[1];
1234
                        $objectemail = new Ticket($this->db);
1235
                    }
1236
1237
                    if (is_object($objectemail))
1238
                    {
1239
                        $result = $objectemail->fetch($objectid);
1240
                        if ($result > 0)
1241
                        {
1242
                            $fk_element_id = $objectemail->id;
1243
                            $fk_element_type = $objectemail->element;
1244
                            // Fix fk_element_type
1245
                            if ($fk_element_type == 'facture') $fk_element_type = 'invoice';
1246
1247
                            $thirdpartyid = $objectemail->fk_soc;
1248
                            $contactid = $objectemail->fk_socpeople;
1249
                            $projectid = isset($objectemail->fk_project)?$objectemail->fk_project:$objectemail->fk_projet;
1250
                        }
1251
                    }
1252
1253
                    // Project
1254
                    if ($projectid > 0)
1255
                    {
1256
                        $result = $projectstatic->fetch($projectid);
1257
                        if ($result <= 0) $projectstatic->id = 0;
1258
                        else
1259
                        {
1260
                            $projectid = $projectstatic->id;
1261
                            $projectfoundby = 'trackid ('.$trackid.')';
1262
                            if (empty($contactid)) $contactid = $projectstatic->fk_contact;
1263
                            if (empty($thirdpartyid)) $thirdpartyid = $projectstatic->fk_soc;
1264
                        }
1265
                    }
1266
                    // Contact
1267
                    if ($contactid > 0)
1268
                    {
1269
                        $result = $contactstatic->fetch($contactid);
1270
                        if ($result <= 0) $contactstatic->id = 0;
1271
                        else
1272
                        {
1273
                            $contactid = $contactstatic->id;
1274
                            $contactfoundby = 'trackid ('.$trackid.')';
1275
                            if (empty($thirdpartyid)) $thirdpartyid = $contactstatic->fk_soc;
1276
                        }
1277
                    }
1278
                    // Thirdparty
1279
                    if ($thirdpartyid > 0)
1280
                    {
1281
                        $result = $thirdpartystatic->fetch($thirdpartyid);
1282
                        if ($result <= 0) $thirdpartystatic->id = 0;
1283
                        else
1284
                        {
1285
                            $thirdpartyid = $thirdpartystatic->id;
1286
                            $thirdpartyfoundby = 'trackid ('.$trackid.')';
1287
                        }
1288
                    }
1289
                }
1290
1291
                if (empty($contactid))		// Try to find contact using email
1292
                {
1293
                    $result = $contactstatic->fetch(0, null, '', $from);
1294
1295
                    if ($result > 0)
1296
                    {
1297
                        $contactid = $contactstatic->id;
1298
                        $contactfoundby = 'email of contact ('.$from.')';
1299
	                    if ($contactstatic->socid > 0)
1300
                        {
1301
	                        $result = $thirdpartystatic->fetch($contactstatic->socid);
1302
                            if ($result > 0)
1303
                            {
1304
                                $thirdpartyid = $thirdpartystatic->id;
1305
                                $thirdpartyfoundby = 'email of contact ('.$from.')';
1306
                            }
1307
                        }
1308
                    }
1309
                }
1310
1311
                if (empty($thirdpartyid))		// Try to find thirdparty using email
1312
                {
1313
                    $result = $thirdpartystatic->fetch(0, '', '', '', '', '', '', '', '', '', $from);
1314
                    if ($result > 0) $thirdpartyfoundby = 'email ('.$from.')';
1315
                }
1316
1317
                // Do operations
1318
                foreach($this->actions as $operation)
1319
                {
1320
                    if ($errorforactions) break;
1321
                    if (empty($operation['status'])) continue;
1322
1323
                    // Make Operation
1324
                    dol_syslog("Execute action ".$operation['type']." actionparam=".$operation['actionparam'].' thirdpartystatic->id='.$thirdpartystatic->id.' contactstatic->id='.$contactstatic->id.' projectstatic->id='.$projectstatic->id);
1325
1326
                    $actioncode = 'EMAIL_IN';
1327
                    // If we scan the Sent box, we use the code for out email
1328
                    if ($this->source_directory == 'Sent') $actioncode = 'EMAIL_OUT';
1329
1330
                    $description = $descriptiontitle = $descriptionmeta = $descriptionfull = '';
1331
                    if (in_array($operation['type'], array('recordevent', 'project', 'ticket')))
1332
                    {
1333
                        if ($operation['type'] == 'project') $descriptiontitle = $langs->trans("ProjectCreatedByEmailCollector", $msgid);
1334
                        elseif ($operation['type'] == 'ticket') $descriptiontitle = $langs->trans("TicketCreatedByEmailCollector", $msgid);
1335
                        else $descriptiontitle = $langs->trans("ActionAC_".$actioncode).' - '.$langs->trans("MailFrom").' '.$from;
1336
1337
                        $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailTopic").' : '.dol_escape_htmltag($subject));
1338
                        $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailFrom").($langs->trans("MailFrom") != 'From' ? ' (From)':'').' : '.dol_escape_htmltag($fromstring));
1339
                        if ($sender) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Sender").($langs->trans("Sender") != 'Sender' ? ' (Sender)':'').' : '.dol_escape_htmltag($sender));
1340
                        $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailTo").($langs->trans("MailTo") != 'To' ? ' (To)':'').' : '.dol_escape_htmltag($to));
1341
                        if ($sendtocc) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailCC").($langs->trans("MailCC") != 'CC' ? ' (CC)':'').' : '.dol_escape_htmltag($sendtocc));
1342
                        //if ($bcc) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Bcc").' : '.dol_escape_htmltag($bcc));
1343
                    }
1344
1345
                    // Search and create thirdparty
1346
                    if ($operation['type'] == 'loadthirdparty' || $operation['type'] == 'loadandcreatethirdparty')
1347
                    {
1348
                        if (empty($operation['actionparam']))
1349
                        {
1350
                            $errorforactions++;
1351
                            $this->error = "Action loadthirdparty or loadandcreatethirdparty has empty parameter. Must be 'SET:xxx' or 'EXTRACT:(body|subject):regex' to define how to extract data";
1352
                            $this->errors[] = $this->error;
1353
                        }
1354
                        else
1355
                        {
1356
                            $actionparam = $operation['actionparam'];
1357
                            $nametouseforthirdparty='';
1358
1359
                            // $this->actionparam = 'SET:aaa' or 'EXTRACT:BODY:....'
1360
                            $arrayvaluetouse = dolExplodeIntoArray($actionparam, ';', '=');
1361
                            foreach($arrayvaluetouse as $propertytooverwrite => $valueforproperty)
1362
                            {
1363
                                $sourcestring='';
1364
                                $sourcefield='';
1365
                                $regexstring='';
1366
                                $regforregex=array();
1367
1368
                                if (preg_match('/^EXTRACT:([a-zA-Z0-9]+):(.*)$/', $valueforproperty, $regforregex))
1369
                                {
1370
                                    $sourcefield=$regforregex[1];
1371
                                    $regexstring=$regforregex[2];
1372
                                }
1373
1374
                                if (! empty($sourcefield) && ! empty($regexstring))
1375
                                {
1376
                                    if (strtolower($sourcefield) == 'body') $sourcestring=$messagetext;
1377
                                    elseif (strtolower($sourcefield) == 'subject') $sourcestring=$subject;
1378
                                    elseif (strtolower($sourcefield) == 'header') $sourcestring=$header;
1379
1380
                                    if ($sourcestring)
1381
                                    {
1382
                                        $regforval=array();
1383
                                        //var_dump($regexstring);var_dump($sourcestring);
1384
                                        if (preg_match('/'.$regexstring.'/ms', $sourcestring, $regforval))
1385
                                        {
1386
                                            //var_dump($regforval[1]);exit;
1387
                                            // Overwrite param $tmpproperty
1388
                                            $nametouseforthirdparty = isset($regforval[1])?trim($regforval[1]):null;
1389
                                        }
1390
                                        else
1391
                                        {
1392
                                            // Regex not found
1393
                                            $nametouseforthirdparty = null;
1394
                                        }
1395
                                        //var_dump($object->$tmpproperty);exit;
1396
                                    }
1397
                                    else
1398
                                    {
1399
                                        // Nothing can be done for this param
1400
                                        $errorforactions++;
1401
                                        $this->error = 'The extract rule to use to load thirdparty has on an unknown source (must be HEADER, SUBJECT or BODY)';
1402
                                        $this->errors[] = $this->error;
1403
                                    }
1404
                                }
1405
                                elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $reg))
1406
                                {
1407
                                    //if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $reg[1];
1408
                                    //else $object->$tmpproperty = $reg[1];
1409
                                    $nametouseforthirdparty = $reg[2];
1410
                                }
1411
                                else
1412
                                {
1413
                                    $errorforactions++;
1414
                                    $this->error = 'Bad syntax for description of action parameters: '.$actionparam;
1415
                                    $this->errors[] = $this->error;
1416
                                    break;
1417
                                }
1418
                            }
1419
1420
                            if (! $errorforactions && $nametouseforthirdparty)
1421
                            {
1422
                                $result = $thirdpartystatic->fetch(0, $nametouseforthirdparty);
1423
                                if ($result < 0)
1424
                                {
1425
                                    $errorforactions++;
1426
                                    $this->error = 'Error when getting thirdparty with name '.$nametouseforthirdparty.' (may be 2 record exists with same name ?)';
1427
                                    $this->errors[] = $this->error;
1428
                                    break;
1429
                                }
1430
                                elseif ($result == 0)
1431
                                {
1432
                                    if ($operation['type'] == 'loadthirdparty')
1433
                                    {
1434
                                        dol_syslog("Third party with name ".$nametouseforthirdparty." was not found");
1435
1436
                                        $errorforactions++;
1437
                                        $this->error = 'ErrorFailedToLoadThirdParty';
1438
                                        $this->errors[] = 'ErrorFailedToLoadThirdParty';
1439
                                    }
1440
                                    elseif ($operation['type'] == 'loadandcreatethirdparty')
1441
                                    {
1442
                                        dol_syslog("Third party with name ".$nametouseforthirdparty." was not found. We try to create it.");
1443
1444
                                        // Create thirdparty
1445
                                        $thirdpartystatic->name = $nametouseforthirdparty;
1446
                                        if ($fromtext != $nametouseforthirdparty) $thirdpartystatic->name_alias = $fromtext;
1447
                                        $thirdpartystatic->email = $from;
1448
1449
                                        // Overwrite values with values extracted from source email
1450
                                        $errorforthisaction = $this->overwritePropertiesOfObject($thirdpartystatic, $operation['actionparam'], $messagetext, $subject, $header);
1451
1452
                                        if ($errorforthisaction)
1453
                                        {
1454
                                            $errorforactions++;
1455
                                        }
1456
                                        else
1457
                                        {
1458
                                            $result = $thirdpartystatic->create($user);
1459
                                            if ($result <= 0)
1460
                                            {
1461
                                                $errorforactions++;
1462
                                                $this->error = $thirdpartystatic->error;
1463
                                                $this->errors = $thirdpartystatic->errors;
1464
                                            }
1465
                                        }
1466
                                    }
1467
                                }
1468
                            }
1469
                        }
1470
                    }
1471
                    // Create event
1472
                    elseif ($operation['type'] == 'recordevent')
1473
                    {
1474
                        if ($projectstatic->id > 0)
1475
                        {
1476
                            if ($projectfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Project found from '.$projectfoundby);
1477
                        }
1478
                        if ($thirdpartystatic->id > 0)
1479
                        {
1480
                            if ($thirdpartyfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Third party found from '.$thirdpartyfoundby);
1481
                        }
1482
                        if ($contactstatic->id > 0)
1483
                        {
1484
                            if ($contactfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Contact/address found from '.$contactfoundby);
1485
                        }
1486
1487
                        $description = $descriptiontitle;
1488
                        $description = dol_concatdesc($description, "-----");
1489
                        $description = dol_concatdesc($description, $descriptionmeta);
1490
                        $description = dol_concatdesc($description, "-----");
1491
                        $description = dol_concatdesc($description, $messagetext);
1492
1493
                        $descriptionfull = $description;
1494
                        $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
1495
                        $descriptionfull = dol_concatdesc($descriptionfull, $header);
1496
1497
                        // Insert record of emails sent
1498
                        $actioncomm = new ActionComm($this->db);
1499
                        $actioncomm->type_code   = 'AC_OTH_AUTO';		// Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
1500
                        $actioncomm->code        = 'AC_'.$actioncode;
1501
                        $actioncomm->label       = $langs->trans("ActionAC_".$actioncode).' - '.$langs->trans("MailFrom").' '.$from;
1502
                        $actioncomm->note        = $descriptionfull;
1503
                        $actioncomm->fk_project  = $projectstatic->id;
1504
                        $actioncomm->datep       = $date;
1505
                        $actioncomm->datef       = $date;
1506
                        $actioncomm->percentage  = -1;   // Not applicable
1507
                        $actioncomm->socid       = $thirdpartystatic->id;
1508
                        $actioncomm->contactid   = $contactstatic->id;
1509
	                    $actioncomm->socpeopleassigned = (!empty($contactstatic->id) ? array($contactstatic->id => '') : array());
1510
                        $actioncomm->authorid    = $user->id;   // User saving action
1511
                        $actioncomm->userownerid = $user->id;	// Owner of action
1512
                        // Fields when action is an email (content should be added into note)
1513
                        $actioncomm->email_msgid = $msgid;
1514
                        $actioncomm->email_from  = $fromstring;
1515
                        $actioncomm->email_sender= $sender;
1516
                        $actioncomm->email_to    = $to;
1517
                        $actioncomm->email_tocc  = $sendtocc;
1518
                        $actioncomm->email_tobcc = $sendtobcc;
1519
                        $actioncomm->email_subject = $subject;
1520
                        $actioncomm->errors_to   = '';
1521
1522
                        if (! in_array($fk_element_type, array('societe','contact','project','user')))
1523
                        {
1524
                            $actioncomm->fk_element  = $fk_element_id;
1525
                            $actioncomm->elementtype = $fk_element_type;
1526
                        }
1527
1528
                        //$actioncomm->extraparams = $extraparams;
1529
1530
                        // Overwrite values with values extracted from source email
1531
                        $errorforthisaction = $this->overwritePropertiesOfObject($actioncomm, $operation['actionparam'], $messagetext, $subject, $header);
1532
1533
                        if ($errorforthisaction)
1534
                        {
1535
                            $errorforactions++;
1536
                        }
1537
                        else
1538
                        {
1539
                            $result = $actioncomm->create($user);
1540
                            if ($result <= 0)
1541
                            {
1542
                                $errorforactions++;
1543
                                $this->errors = $actioncomm->errors;
1544
                            }
1545
                        }
1546
                    }
1547
                    // Create event
1548
                    elseif ($operation['type'] == 'project')
1549
                    {
1550
                        $projecttocreate = new Project($this->db);
1551
                        if ($thirdpartystatic->id > 0)
1552
                        {
1553
                            $projecttocreate->socid = $thirdpartystatic->id;
1554
                            if ($thirdpartyfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Third party found from '.$thirdpartyfoundby);
1555
                        }
1556
                        if ($contactstatic->id > 0)
1557
                        {
1558
                            $projecttocreate->contact_id = $contactstatic->id;
1559
                            if ($contactfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Contact/address found from '.$contactfoundby);
1560
                        }
1561
1562
                        $description = $descriptiontitle;
1563
                        $description = dol_concatdesc($description, "-----");
1564
                        $description = dol_concatdesc($description, $descriptionmeta);
1565
                        $description = dol_concatdesc($description, "-----");
1566
                        $description = dol_concatdesc($description, $messagetext);
1567
1568
                        $descriptionfull = $description;
1569
                        $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
1570
                        $descriptionfull = dol_concatdesc($descriptionfull, $header);
1571
1572
                        $id_opp_status = dol_getIdFromCode($this->db, 'PROSP', 'c_lead_status', 'code', 'rowid');
1573
                        $percent_opp_status = dol_getIdFromCode($this->db, 'PROSP', 'c_lead_status', 'code', 'percent');
1574
1575
                        $projecttocreate->title = $subject;
1576
                        $projecttocreate->date_start = $date;
1577
                        $projecttocreate->date_end = '';
1578
                        $projecttocreate->opp_status = $id_opp_status;
1579
                        $projecttocreate->opp_percent = $percent_opp_status;
1580
                        $projecttocreate->description = dol_concatdesc(dolGetFirstLineOfText(dol_string_nohtmltag($description, 2), 10), '...'.$langs->transnoentities("SeePrivateNote").'...');
1581
                        $projecttocreate->note_private = $descriptionfull;
1582
                        $projecttocreate->entity = $conf->entity;
1583
1584
                        // Overwrite values with values extracted from source email.
1585
                        // This may overwrite any $projecttocreate->xxx properties.
1586
                        $savesocid = $projecttocreate->socid;
1587
                        $errorforthisaction = $this->overwritePropertiesOfObject($projecttocreate, $operation['actionparam'], $messagetext, $subject, $header);
1588
1589
                        // Set project ref if not yet defined
1590
                        if (empty($projecttocreate->ref))
1591
                        {
1592
                            // Get next project Ref
1593
                            $defaultref='';
1594
                            $modele = empty($conf->global->PROJECT_ADDON)?'mod_project_simple':$conf->global->PROJECT_ADDON;
1595
1596
                            // Search template files
1597
                            $file=''; $classname=''; $filefound=0; $reldir='';
1598
                            $dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
1599
                            foreach($dirmodels as $reldir)
1600
                            {
1601
                                $file=dol_buildpath($reldir."core/modules/project/".$modele.'.php', 0);
1602
                                if (file_exists($file))
1603
                                {
1604
                                    $filefound=1;
1605
                                    $classname = $modele;
1606
                                    break;
1607
                                }
1608
                            }
1609
1610
                            if ($filefound)
1611
                            {
1612
                                $result=dol_include_once($reldir."core/modules/project/".$modele.'.php');
1613
                                $modProject = new $classname;
1614
1615
                                if ($savesocid > 0)
1616
                                {
1617
                                    if ($savesocid != $projecttocreate->socid)
1618
                                    {
1619
                                        $errorforactions++;
1620
                                        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');
1621
                                    }
1622
                                }
1623
                                else {
1624
                                    if ($projecttocreate->socid > 0)
1625
                                    {
1626
                                        $thirdpartystatic->fetch($projecttocreate->socid);
1627
                                    }
1628
                                }
1629
1630
                                $defaultref = $modProject->getNextValue(($thirdpartystatic->id > 0 ? $thirdpartystatic : null), $projecttocreate);
1631
                            }
1632
                            $projecttocreate->ref = $defaultref;
1633
                        }
1634
1635
                        if ($errorforthisaction)
1636
                        {
1637
                            $errorforactions++;
1638
                        }
1639
                        else
1640
                        {
1641
                            if (empty($projecttocreate->ref) || (is_numeric($projecttocreate->ref) && $projecttocreate->ref <= 0))
1642
                            {
1643
                                $errorforactions++;
1644
                                $this->error = 'Failed to create project: Can\'t get a valid value for the field ref with numbering template = '.$modele.', thirdparty id = '.$thirdpartystatic->id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $modele does not seem to be defined for all execution paths leading up to this point.
Loading history...
1645
                            }
1646
                            else
1647
                            {
1648
                                // Create project
1649
                                $result = $projecttocreate->create($user);
1650
                                if ($result <= 0)
1651
                                {
1652
                                    $errorforactions++;
1653
                                    $this->error = 'Failed to create project: '.$langs->trans($projecttocreate->error);
1654
                                    $this->errors = $projecttocreate->errors;
1655
                                }
1656
                            }
1657
                        }
1658
                    }
1659
                    // Create event
1660
                    elseif ($operation['type'] == 'ticket')
1661
                    {
1662
                        $tickettocreate = new Ticket($this->db);
1663
                        if ($thirdpartystatic->id > 0)
1664
                        {
1665
                            $tickettocreate->socid = $thirdpartystatic->id;
1666
                            if ($thirdpartyfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Third party found from '.$thirdpartyfoundby);
1667
                        }
1668
                        if ($contactstatic->id > 0)
1669
                        {
1670
                            $tickettocreate->contact_id = $contactstatic->id;
1671
                            if ($contactfoundby) $descriptionmeta = dol_concatdesc($descriptionmeta, 'Contact/address found from '.$contactfoundby);
1672
                        }
1673
1674
                        $description = $descriptiontitle;
1675
                        $description = dol_concatdesc($description, "-----");
1676
                        $description = dol_concatdesc($description, $descriptionmeta);
1677
                        $description = dol_concatdesc($description, "-----");
1678
                        $description = dol_concatdesc($description, $messagetext);
1679
1680
                        $descriptionfull = $description;
1681
                        $descriptionfull = dol_concatdesc($descriptionfull, "----- Header");
1682
                        $descriptionfull = dol_concatdesc($descriptionfull, $header);
1683
1684
                        $tickettocreate->subject = $subject;
1685
                        $tickettocreate->message = $description;
1686
                        $tickettocreate->type_code = 0;
1687
                        $tickettocreate->category_code = 0;
1688
                        $tickettocreate->severity_code = 0;
1689
                        $tickettocreate->origin_email = $from;
1690
                        $tickettocreate->fk_user_create = $user->id;
1691
                        $tickettocreate->datec = $date;
1692
                        $tickettocreate->fk_project = $projectstatic->id;
1693
                        $tickettocreate->fk_soc = $thirdpartystatic->id;
1694
                        $tickettocreate->notify_tiers_at_create = 0;
1695
                        $tickettocreate->note_private = $descriptionfull;
1696
                        $tickettocreate->entity = $conf->entity;
1697
                        //$tickettocreate->fk_contact = $contactstatic->id;
1698
1699
                        // Overwrite values with values extracted from source email.
1700
                        // This may overwrite any $projecttocreate->xxx properties.
1701
                        $savesocid = $tickettocreate->socid;
1702
                        $errorforthisaction = $this->overwritePropertiesOfObject($tickettocreate, $operation['actionparam'], $messagetext, $subject, $header);
1703
1704
                        // Set ticket ref if not yet defined
1705
                        if (empty($tickettocreate->ref))
1706
                        {
1707
                            // Get next project Ref
1708
                            $defaultref='';
1709
                            $modele = empty($conf->global->TICKET_ADDON)?'mod_ticket_simple':$conf->global->TICKET_ADDON;
1710
1711
                            // Search template files
1712
                            $file=''; $classname=''; $filefound=0; $reldir='';
1713
                            $dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
1714
                            foreach($dirmodels as $reldir)
1715
                            {
1716
                                $file=dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
1717
                                if (file_exists($file))
1718
                                {
1719
                                    $filefound=1;
1720
                                    $classname = $modele;
1721
                                    break;
1722
                                }
1723
                            }
1724
1725
                            if ($filefound)
1726
                            {
1727
                                $result=dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
1728
                                $modTicket = new $classname;
1729
1730
                                if ($savesocid > 0)
1731
                                {
1732
                                    if ($savesocid != $tickettocreate->socid)
1733
                                    {
1734
                                        $errorforactions++;
1735
                                        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');
1736
                                    }
1737
                                }
1738
                                else {
1739
                                    if ($tickettocreate->socid > 0)
1740
                                    {
1741
                                        $thirdpartystatic->fetch($tickettocreate->socid);
1742
                                    }
1743
                                }
1744
1745
                                $defaultref = $modTicket->getNextValue(($thirdpartystatic->id > 0 ? $thirdpartystatic : null), $tickettocreate);
1746
                            }
1747
                            $tickettocreate->ref = $defaultref;
1748
                        }
1749
1750
                        if ($errorforthisaction)
1751
                        {
1752
                            $errorforactions++;
1753
                        }
1754
                        else
1755
                        {
1756
                            if (is_numeric($tickettocreate->ref) && $tickettocreate->ref <= 0)
1757
                            {
1758
                                $errorforactions++;
1759
                                $this->error = 'Failed to create ticket: Can\'t get a valid value for the field ref with numbering template = '.$modele.', thirdparty id = '.$thirdpartystatic->id;
1760
                            }
1761
                            else
1762
                            {
1763
                                // Create project
1764
                                $result = $tickettocreate->create($user);
1765
                                if ($result <= 0)
1766
                                {
1767
                                    $errorforactions++;
1768
                                    $this->error = 'Failed to create ticket: '.$langs->trans($tickettocreate->error);
1769
                                    $this->errors = $tickettocreate->errors;
1770
                                }
1771
                            }
1772
                        }
1773
                    }
1774
1775
                    if (! $errorforactions)
1776
                    {
1777
                        $nbactiondoneforemail++;
1778
                    }
1779
                }
1780
1781
                // Error for email or not ?
1782
                if (! $errorforactions)
1783
                {
1784
                    if ($targetdir)
1785
                    {
1786
                        dol_syslog("EmailCollector::doCollectOneCollector move message ".$imapemail." to ".$connectstringtarget, LOG_DEBUG);
1787
                        $res = imap_mail_move($connection, $imapemail, $targetdir, 0);
1788
                        if ($res == false) {
1789
                            $errorforemail++;
1790
                            $this->error = imap_last_error();
1791
                            $this->errors[] = $this->error;
1792
                            dol_syslog(imap_last_error());
1793
                        }
1794
                    }
1795
                    else
1796
                    {
1797
                        dol_syslog("EmailCollector::doCollectOneCollector message ".$imapemail." to ".$connectstringtarget." was set to read", LOG_DEBUG);
1798
                    }
1799
                }
1800
                else
1801
                {
1802
                    $errorforemail++;
1803
                }
1804
1805
                unset($objectemail);
1806
                unset($projectstatic);
1807
                unset($thirdpartystatic);
1808
                unset($contactstatic);
1809
1810
                $nbemailprocessed++;
1811
1812
                if (! $errorforemail)
1813
                {
1814
                    $nbactiondone += $nbactiondoneforemail;
1815
                    $nbemailok++;
1816
1817
                    $this->db->commit();
1818
1819
                    // Stop the loop to process email if we reach maximum collected per collect
1820
                    if ($this->maxemailpercollect > 0 && $nbemailok >= $this->maxemailpercollect)
1821
                    {
1822
                        dol_syslog("EmailCollect::doCollectOneCollector We reach maximum of ".$nbemailok." collected with success, so we stop this collector now.");
1823
                        break;
1824
                    }
1825
                }
1826
                else
1827
                {
1828
                    $error++;
1829
1830
                    $this->db->rollback();
1831
                }
1832
            }
1833
1834
            $output=$langs->trans('XEmailsDoneYActionsDone', $nbemailprocessed, $nbemailok, $nbactiondone);
1835
1836
            dol_syslog("End of loop on emails", LOG_INFO, -1);
1837
        }
1838
        else
1839
        {
1840
            $output=$langs->trans('NoNewEmailToProcess');
1841
        }
1842
1843
        imap_expunge($connection);	// To validate any move
1844
1845
        imap_close($connection);
1846
1847
        $this->datelastresult = $now;
1848
        $this->lastresult = $output;
1849
        $this->debuginfo = 'IMAP search string used : '.$search;
1850
        if ($searchhead) $this->debuginfo .= '<br>Then search string into email header : '.$searchhead;
1851
1852
        if (! $error) $this->datelastok = $now;
1853
1854
        if (! empty($this->errors)) $this->lastresult.= " - ".join(" - ", $this->errors);
1855
        $this->codelastresult = ($error ? 'KO' : 'OK');
1856
        $this->update($user);
1857
1858
        dol_syslog("EmailCollector::doCollectOneCollector end", LOG_DEBUG);
1859
1860
        return $error?-1:1;
1861
    }
1862
1863
1864
1865
    // Loop to get part html and plain. Code found on PHP imap_fetchstructure documentation
1866
1867
    /**
1868
     * getmsg
1869
     *
1870
     * @param 	Object $mbox     	Structure
1871
     * @param 	string $mid		    prefix
1872
     * @return 	array				Array with number and object
1873
     */
1874
    private function getmsg($mbox, $mid)
1875
    {
1876
        // input $mbox = IMAP stream, $mid = message id
1877
        // output all the following:
1878
        global $charset,$htmlmsg,$plainmsg,$attachments;
1879
        $htmlmsg = $plainmsg = $charset = '';
1880
        $attachments = array();
1881
1882
        // HEADER
1883
        //$h = imap_header($mbox,$mid);
1884
        // add code here to get date, from, to, cc, subject...
1885
1886
        // BODY
1887
        $s = imap_fetchstructure($mbox, $mid);
1888
1889
        if (!$s->parts)  // simple
1890
            $this->getpart($mbox, $mid, $s, 0);  // pass 0 as part-number
1891
        else {  // multipart: cycle through each part
1892
            foreach ($s->parts as $partno0=>$p)
1893
            {
1894
               $this->getpart($mbox, $mid, $p, $partno0+1);
1895
            }
1896
        }
1897
    }
1898
1899
    /* partno string
1900
     0 multipart/mixed
1901
     1 multipart/alternative
1902
     1.1 text/plain
1903
     1.2 text/html
1904
     2 message/rfc822
1905
     2 multipart/mixed
1906
     2.1 multipart/alternative
1907
     2.1.1 text/plain
1908
     2.1.2 text/html
1909
     2.2 message/rfc822
1910
     2.2 multipart/alternative
1911
     2.2.1 text/plain
1912
     2.2.2 text/html
1913
     */
1914
    /**
1915
     * Sub function for getpart(). Only called by createPartArray() and itself.
1916
     *
1917
     * @param 	Object		$mbox			Structure
1918
     * @param 	string		$mid			Part no
1919
     * @param 	Object		$p              Object p
1920
     * @param   string      $partno         Partno
1921
     * @return	void
1922
     */
1923
    private function getpart($mbox, $mid, $p, $partno)
1924
    {
1925
        // $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
1926
        global $htmlmsg,$plainmsg,$charset,$attachments;
1927
1928
        // DECODE DATA
1929
        $data = ($partno)?
1930
        imap_fetchbody($mbox, $mid, $partno):  // multipart
1931
        imap_body($mbox, $mid);  // simple
1932
        // Any part may be encoded, even plain text messages, so check everything.
1933
        if ($p->encoding==4)
1934
            $data = quoted_printable_decode($data);
1935
        elseif ($p->encoding==3)
1936
            $data = base64_decode($data);
1937
1938
        // PARAMETERS
1939
        // get all parameters, like charset, filenames of attachments, etc.
1940
        $params = array();
1941
        if ($p->parameters)
1942
        {
1943
            foreach ($p->parameters as $x)
1944
            {
1945
                $params[strtolower($x->attribute)] = $x->value;
1946
            }
1947
        }
1948
        if ($p->dparameters)
1949
        {
1950
            foreach ($p->dparameters as $x)
1951
            {
1952
               $params[strtolower($x->attribute)] = $x->value;
1953
            }
1954
        }
1955
1956
        // ATTACHMENT
1957
        // Any part with a filename is an attachment,
1958
        // so an attached text file (type 0) is not mistaken as the message.
1959
        if ($params['filename'] || $params['name']) {
1960
            // filename may be given as 'Filename' or 'Name' or both
1961
            $filename = ($params['filename'])? $params['filename'] : $params['name'];
1962
            // filename may be encoded, so see imap_mime_header_decode()
1963
            $attachments[$filename] = $data;  // this is a problem if two files have same name
1964
        }
1965
1966
        // TEXT
1967
        if ($p->type==0 && $data) {
1968
            // Messages may be split in different parts because of inline attachments,
1969
            // so append parts together with blank row.
1970
            if (strtolower($p->subtype)=='plain')
1971
                $plainmsg .= trim($data) ."\n\n";
1972
            else
1973
                $htmlmsg .= $data ."<br><br>";
1974
            $charset = $params['charset'];  // assume all parts are same charset
1975
        }
1976
1977
        // EMBEDDED MESSAGE
1978
        // Many bounce notifications embed the original message as type 2,
1979
        // but AOL uses type 1 (multipart), which is not handled here.
1980
        // There are no PHP functions to parse embedded messages,
1981
        // so this just appends the raw source to the main message.
1982
        elseif ($p->type==2 && $data) {
1983
            $plainmsg .= $data."\n\n";
1984
        }
1985
1986
        // SUBPART RECURSION
1987
        if ($p->parts) {
1988
            foreach ($p->parts as $partno0=>$p2)
1989
            {
1990
                $this->getpart($mbox, $mid, $p2, $partno.'.'.($partno0+1));  // 1.2, 1.2.1, etc.
1991
            }
1992
        }
1993
    }
1994
}
1995