2
0
forked from Wavyzz/dolibarr

Debug email collector

This commit is contained in:
Laurent Destailleur
2019-04-25 17:37:54 +02:00
parent 091132de2f
commit 10dde837d0
9 changed files with 350 additions and 155 deletions

View File

@@ -452,19 +452,25 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
print '<tr class="oddeven">';
print '<td>';
$arrayoftypes=array(
'from'=>array('label'=>'MailFrom', 'data-placeholder'=>'SearchString'),
'to'=>array('label'=>'MailTo', 'data-placeholder'=>'SearchString'),
'cc'=>array('label'=>'Cc', 'data-placeholder'=>'SearchString'),
'bcc'=>array('label'=>'Bcc', 'data-placeholder'=>'SearchString'),
'subject'=>array('label'=>'Subject', 'data-placeholder'=>'SearchString'),
'body'=>array('label'=>'Body', 'data-placeholder'=>'SearchString'),
'header'=>array('label'=>'Header', 'data-placeholder'=>'HeaderKey SearchString'), // HEADER key value
'X1'=>'---',
'from'=>array('label'=>'MailFrom', 'data-placeholder'=>$langs->trans('SearchString')),
'to'=>array('label'=>'MailTo', 'data-placeholder'=>$langs->trans('SearchString')),
'cc'=>array('label'=>'Cc', 'data-placeholder'=>$langs->trans('SearchString')),
'bcc'=>array('label'=>'Bcc', 'data-placeholder'=>$langs->trans('SearchString')),
'subject'=>array('label'=>'Subject', 'data-placeholder'=>$langs->trans('SearchString')),
'body'=>array('label'=>'Body', 'data-placeholder'=>$langs->trans('SearchString')),
// disabled because PHP imap_search is not compatible IMAPv4, only IMAPv2
//'header'=>array('label'=>'Header', 'data-placeholder'=>'HeaderKey SearchString'), // HEADER key value
//'X1'=>'---',
//'notinsubject'=>array('label'=>'SubjectNotIn', 'data-placeholder'=>'SearchString'),
//'notinbody'=>array('label'=>'BodyNotIn', 'data-placeholder'=>'SearchString'),
'X2'=>'---',
'seen'=>array('label'=>'AlreadyRead', 'data-noparam'=>1),
'unseen'=>array('label'=>'NotRead', 'data-noparam'=>1),
'smaller'=>array('label'=>'SmallerThan', 'data-placeholder'=>'NumberOfBytes'),
'larger'=>array('label'=>'LargerThan', 'data-placeholder'=>'NumberOfBytes'),
'X2'=>'---',
'unanswered'=>array('label'=>'Unanswered', 'data-noparam'=>1),
'answered'=>array('label'=>'Answered', 'data-noparam'=>1),
'smaller'=>array('label'=>'SmallerThan', 'data-placeholder'=>$langs->trans('NumberOfBytes')),
'larger'=>array('label'=>'LargerThan', 'data-placeholder'=>$langs->trans('NumberOfBytes')),
'X3'=>'---',
'withtrackingid'=>array('label'=>'WithDolTrackingID', 'data-noparam'=>1),
'withouttrackingid'=>array('label'=>'WithoutDolTrackingID', 'data-noparam'=>1)
);
@@ -530,7 +536,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
'recordevent'=>'RecordEvent');
if ($conf->projet->enabled) $arrayoftypes['project']='CreateLeadAndThirdParty';
if ($conf->ticket->enabled) $arrayoftypes['ticket']='CreateTicketAndThirdParty';
print $form->selectarray('operationtype', $arrayoftypes, '', 1, 0, 0, '', 1);
print $form->selectarray('operationtype', $arrayoftypes, '', 1, 0, 0, '', 1, 0, 0, '', 'maxwidth300');
print '</td><td>';
print '<input type="text" name="operationparam">';
$htmltext=$langs->transnoentitiesnoconv("OperationParamDesc");

View File

@@ -6107,6 +6107,7 @@ $substitutionarray=array_merge($substitutionarray, array(
{
$substitutionarray['__DOL_MAIN_URL_ROOT__']=DOL_MAIN_URL_ROOT;
$substitutionarray['__(AnyTranslationKey)__']=$outputlangs->trans('TranslationOfKey');
$substitutionarray['__(AnyTranslationKey|langfile)__']=$outputlangs->trans('TranslationOfKey').' (load also language file before)';
$substitutionarray['__[AnyConstantKey]__']=$outputlangs->trans('ValueOfConstantKey');
}
@@ -6135,7 +6136,7 @@ function make_substitutions($text, $substitutionarray, $outputlangs = null)
if (empty($outputlangs)) $outputlangs=$langs;
// Make substitution for language keys
// Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
if (is_object($outputlangs))
{
while (preg_match('/__\(([^\)]+)\)__/', $text, $reg))
@@ -6151,8 +6152,8 @@ function make_substitutions($text, $substitutionarray, $outputlangs = null)
}
}
// Make substitution for constant keys. Must be after the substitution of translation, so if text of translation contains a constant,
// it is also converted.
// Make substitution for constant keys.
// Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
while (preg_match('/__\[([^\]]+)\]__/', $text, $reg))
{
$msgishtml = 0;

View File

@@ -49,7 +49,7 @@ foreach($object->fields as $key => $val)
print '<tr><td';
print ' class="titlefield';
if ($val['notnull'] > 0) print ' fieldrequired';
//if ($val['notnull'] > 0) print ' fieldrequired'; // No fieldrequired on the view output
if ($val['type'] == 'text' || $val['type'] == 'html') print ' tdtop';
print '">';
if (! empty($val['help'])) print $form->textwithpicto($langs->trans($val['label']), $langs->trans($val['help']));

View File

@@ -92,8 +92,8 @@ class EmailCollector extends CommonObject
*/
public $fields=array(
'rowid' => array('type'=>'integer', 'label'=>'TechnicalID','visible'=>2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1),
'entity' =>array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>20),
'ref' =>array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1, 'help'=>'Example: MyCollector1'),
'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>20),
'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1, 'help'=>'Example: MyCollector1'),
'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'notnull'=>-1, 'searchall'=>1, 'help'=>'Example: My Email collector'),
'description' => array('type'=>'text', 'label'=>'Description', 'visible'=>-1, 'enabled'=>1, 'position'=>60, 'notnull'=>-1),
'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'),
@@ -103,6 +103,7 @@ class EmailCollector extends CommonObject
//'filter' => array('type'=>'text', 'label'=>'Filter', 'visible'=>1, 'enabled'=>1, 'position'=>105),
//'actiontodo' => array('type'=>'varchar(255)', 'label'=>'ActionToDo', 'visible'=>1, 'enabled'=>1, 'position'=>106),
'target_directory' => array('type'=>'varchar(255)', 'label'=>'MailboxTargetDirectory', 'visible'=>1, 'enabled'=>1, 'position'=>110, 'notnull'=>0, 'comment'=>"Where to store messages once processed"),
'maxemailpercollect' => array('type'=>'integer', 'label'=>'MaxEmailCollectPerCollect','visible'=>-1, 'enabled'=>1, 'position'=>111, 'default'=>100),
'datelastresult' => array('type'=>'datetime', 'label'=>'DateLastCollectResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>121, 'notnull'=>-1,),
'codelastresult' => array('type'=>'varchar(16)', 'label'=>'CodeLastResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>122, 'notnull'=>-1,),
'lastresult' => array('type'=>'varchar(255)', 'label'=>'LastResult', 'visible'=>1, 'enabled'=>'$action != "create" && $action != "edit"', 'position'=>123, 'notnull'=>-1,),
@@ -167,6 +168,7 @@ class EmailCollector extends CommonObject
public $password;
public $source_directory;
public $target_directory;
public $maxemailpercollect;
public $datelastresult;
public $lastresult;
// END MODULEBUILDER PROPERTIES
@@ -717,12 +719,6 @@ class EmailCollector extends CommonObject
return $nberror;
}
/**
* overwitePropertiesOfObject
*
* @return int 0=OK, Nb of error if error
*/
/**
* overwitePropertiesOfObject
*
@@ -755,7 +751,8 @@ class EmailCollector extends CommonObject
}
if ($tmpclass && ($tmpclass != $object->element)) continue; // Property is for another type of object
if (property_exists($object, $tmpproperty) || preg_match('/^options_/', $tmpproperty))
//if (property_exists($object, $tmpproperty) || preg_match('/^options_/', $tmpproperty))
if ($tmpproperty)
{
$sourcestring='';
$sourcefield='';
@@ -782,8 +779,12 @@ class EmailCollector extends CommonObject
if ($sourcestring)
{
$regforval=array();
//var_dump($regexstring);var_dump($sourcestring);
if (preg_match('/'.$regexstring.'/ms', $sourcestring, $regforval))
$regexoptions='';
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
if (strtolower($sourcefield) == 'header') $regexoptions='m'; // The m means ^ and $ char is valid at each new line.
//var_dump($tmpproperty.' - '.$regexstring.' - '.$regexoptions.' - '.$sourcestring);
if (preg_match('/'.$regexstring.'/'.$regexoptions, $sourcestring, $regforval))
{
//var_dump($regforval[1]);exit;
// Overwrite param $tmpproperty
@@ -794,7 +795,6 @@ class EmailCollector extends CommonObject
// Regex not found
$object->$tmpproperty = null;
}
//var_dump($object->$tmpproperty);exit;
}
else
{
@@ -806,8 +806,27 @@ class EmailCollector extends CommonObject
}
elseif (preg_match('/^SET:(.*)$/', $valueforproperty, $reg))
{
if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $reg[1];
else $object->$tmpproperty = $reg[1];
$valuetouse = $reg[1];
$substitutionarray=array();
$matcharray=array();
preg_match_all('/__([a-z0-9]+(?:_[a-z0-9]+)?)__/i', $valuetouse, $matcharray);
//var_dump($tmpproperty.' - '.$object->$tmpproperty.' - '.$valuetouse); var_dump($matcharray);
if (is_array($matcharray[1])) // $matcharray[1] is array with list of substitution key found without the __
{
foreach($matcharray[1] as $keytoreplace)
{
if ($keytoreplace && isset($object->$keytoreplace))
{
$substitutionarray['__'.$keytoreplace.'__']=$object->$keytoreplace;
}
}
}
//var_dump($substitutionarray);
dol_syslog(var_export($substitutionarray, true));
//var_dump($substitutionarray);
$valuetouse = make_substitutions($valuetouse, $substitutionarray);
if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $valuetouse;
else $object->$tmpproperty = $valuetouse;
}
else
{
@@ -887,7 +906,8 @@ class EmailCollector extends CommonObject
$host=dol_getprefix('email');
// Define the IMAP search string
// See https://tools.ietf.org/html/rfc3501#section-6.4.4
// See https://tools.ietf.org/html/rfc3501#section-6.4.4 for IMAPv4 (PHP not yet compatible)
// See https://tools.ietf.org/html/rfc1064 page 13 for IMAPv2
//$search='ALL';
$search='UNDELETED'; // Seems not supported by some servers
$searchhead='';
@@ -905,8 +925,13 @@ class EmailCollector extends CommonObject
if ($rule['type'] == 'body') $search.=($search?' ':'').'BODY "'.str_replace('"', '', $rule['rulevalue']).'"';
if ($rule['type'] == 'header') $search.=($search?' ':'').'HEADER '.$rule['rulevalue'];
if ($rule['type'] == 'notinsubject') $search.=($search?' ':'').'SUBJECT NOT "'.str_replace('"', '', $rule['rulevalue']).'"';
if ($rule['type'] == 'notinbody') $search.=($search?' ':'').'BODY NOT "'.str_replace('"', '', $rule['rulevalue']).'"';
if ($rule['type'] == 'seen') $search.=($search?' ':'').'SEEN';
if ($rule['type'] == 'unseen') $search.=($search?' ':'').'UNSEEN';
if ($rule['type'] == 'unanswered') $search.=($search?' ':'').'UNANSWERED';
if ($rule['type'] == 'answered') $search.=($search?' ':'').'ANSWERED';
if ($rule['type'] == 'smaller') $search.=($search?' ':'').'SMALLER "'.str_replace('"', '', $rule['rulevalue']).'"';
if ($rule['type'] == 'larger') $search.=($search?' ':'').'LARGER "'.str_replace('"', '', $rule['rulevalue']).'"';
@@ -945,9 +970,87 @@ class EmailCollector extends CommonObject
// Loop on each email found
if (! $error && ! empty($arrayofemail) && count($arrayofemail) > 0)
{
// Loop to get part html and plain
/*
0 multipart/mixed
1 multipart/alternative
1.1 text/plain
1.2 text/html
2 message/rfc822
2 multipart/mixed
2.1 multipart/alternative
2.1.1 text/plain
2.1.2 text/html
2.2 message/rfc822
2.2 multipart/alternative
2.2.1 text/plain
2.2.2 text/html
*/
/**
* create_part_array
*
* @param Object $structure Structure
* @param string $prefix prefix
* @return array Array with number and object
*/
/*function createPartArray($structure, $prefix = "")
{
//print_r($structure);
$part_array=array();
if (count($structure->parts) > 0) { // There some sub parts
foreach ($structure->parts as $count => $part) {
addPartToArray($part, $prefix.($count+1), $part_array);
}
}else{ // Email does not have a seperate mime attachment for text
$part_array[] = array('part_number' => $prefix.'1', 'part_object' => $structure);
}
return $part_array;
}*/
/**
* Sub function for createPartArray(). Only called by createPartArray() and itself.
*
* @param Object $obj Structure
* @param string $partno Part no
* @param array $part_array array
* @return void
*/
/*function addPartToArray($obj, $partno, &$part_array)
{
$part_array[] = array('part_number' => $partno, 'part_object' => $obj);
if ($obj->type == 2) { // Check to see if the part is an attached email message, as in the RFC-822 type
//print_r($obj);
if (array_key_exists('parts', $obj)) { // Check to see if the email has parts
foreach ($obj->parts as $count => $part) {
// Iterate here again to compensate for the broken way that imap_fetchbody() handles attachments
if (count($part->parts) > 0) {
foreach ($part->parts as $count2 => $part2) {
addPartToArray($part2, $partno.".".($count2+1), $part_array);
}
}else{ // Attached email does not have a seperate mime attachment for text
$part_array[] = array('part_number' => $partno.'.'.($count+1), 'part_object' => $obj);
}
}
}else{ // Not sure if this is possible
$part_array[] = array('part_number' => $partno.'.1', 'part_object' => $obj);
}
}else{ // If there are more sub-parts, expand them out.
if (array_key_exists('parts', $obj)) {
foreach ($obj->parts as $count => $p) {
addPartToArray($p, $partno.".".($count+1), $part_array);
}
}
}
}*/
dol_syslog("Start of loop on email", LOG_INFO, 1);
foreach($arrayofemail as $imapemail)
{
if ($nbemailprocessed > 100) break; // Do not process more than 100 email per launch
if ($nbemailprocessed > 1000)
{
break; // Do not process more than 1000 email per launch (this is a different protection than maxnbcollectedpercollect
}
$header = imap_fetchheader($connection, $imapemail, 0);
$matches=array();
@@ -988,125 +1091,63 @@ class EmailCollector extends CommonObject
$this->db->begin();
//$message = imap_body($connection, $imapemail, 0);
// GET Email meta datas
$overview = imap_fetch_overview($connection, $imapemail, 0);
dol_syslog("** Process email - msgid=".$overview[0]->message_id." date=".dol_print_date($overview[0]->udate, 'dayrfc', 'gmt')." subject=".$overview[0]->subject);
// Parse IMAP email structure
global $htmlmsg, $plainmsg, $charset, $attachments;
$this->getmsg($connection, $imapemail);
//$htmlmsg,$plainmsg,$charset,$attachments
$messagetext = $plainmsg ? $plainmsg : dol_string_nohtmltag($htmlmsg, 0);
/*var_dump($plainmsg);
var_dump($htmlmsg);
var_dump($messagetext);*/
/*var_dump($charset);
var_dump($attachments);
exit;*/
// Parse IMAP email structure
/*
$structure = imap_fetchstructure($connection, $imapemail, 0);
$partplain = $parthtml = -1;
// Loop to get part html and plain
/*
0 multipart/mixed
1 multipart/alternative
1.1 text/plain
1.2 text/html
2 message/rfc822
2 multipart/mixed
2.1 multipart/alternative
2.1.1 text/plain
2.1.2 text/html
2.2 message/rfc822
2.2 multipart/alternative
2.2.1 text/plain
2.2.2 text/html
*/
/**
* create_part_array
*
* @param Object $structure Structure
* @param string $prefix prefix
* @return array Array with number and object
*/
function createPartArray($structure, $prefix = "")
{
//print_r($structure);
$part_array=array();
if (count($structure->parts) > 0) { // There some sub parts
foreach ($structure->parts as $count => $part) {
add_part_to_array($part, $prefix.($count+1), $part_array);
}
}else{ // Email does not have a seperate mime attachment for text
$part_array[] = array('part_number' => $prefix.'1', 'part_object' => $obj);
}
return $part_array;
}
/**
* Sub function for createPartArray(). Only called by createPartArray() and itself.
*
* @param Object $obj Structure
* @param string $partno Part no
* @param array $part_array array
* @return void
*/
function addPartToArray($obj, $partno, &$part_array)
{
$part_array[] = array('part_number' => $partno, 'part_object' => $obj);
if ($obj->type == 2) { // Check to see if the part is an attached email message, as in the RFC-822 type
//print_r($obj);
if (array_key_exists('parts', $obj)) { // Check to see if the email has parts
foreach ($obj->parts as $count => $part) {
// Iterate here again to compensate for the broken way that imap_fetchbody() handles attachments
if (count($part->parts) > 0) {
foreach ($part->parts as $count2 => $part2) {
addPartToArray($part2, $partno.".".($count2+1), $part_array);
}
}else{ // Attached email does not have a seperate mime attachment for text
$part_array[] = array('part_number' => $partno.'.'.($count+1), 'part_object' => $obj);
}
}
}else{ // Not sure if this is possible
$part_array[] = array('part_number' => $partno.'.1', 'part_object' => $obj);
}
}else{ // If there are more sub-parts, expand them out.
if (array_key_exists('parts', $obj)) {
foreach ($obj->parts as $count => $p) {
addPartToArray($p, $partno.".".($count+1), $part_array);
}
}
}
}
$encodingplain = $encodinghtml = '';
$result = createPartArray($structure, '');
//var_dump($result);exit;
foreach($result as $part)
{
if ($part['part_object']->subtype == 'HTML') $parthtml=$part['part_number'];
if ($part['part_object']->subtype == 'PLAIN') $partplain=$part['part_number'];
// $part['part_object']->type seems 0 for content
// $part['part_object']->type seems 5 for attachment
if (empty($part['part_object'])) continue;
if ($part['part_object']->subtype == 'HTML')
{
$parthtml=$part['part_number'];
if ($part['part_object']->encoding == 4)
{
$encodinghtml = 'aaa';
}
}
if ($part['part_object']->subtype == 'PLAIN')
{
$partplain=$part['part_number'];
if ($part['part_object']->encoding == 4)
{
$encodingplain = 'rr';
}
}
}
//var_dump($result); var_dump($partplain); var_dump($parthtml);
/* OLD CODE to get parthtml and partplain
if (count($structure->parts) > 0) { // There some sub parts
foreach($structure->parts as $key => $part)
{
if ($part->subtype == 'HTML') $parthtml=($key+1); // For example: $parthtml = 1 or 2
if ($part->subtype == 'PLAIN') $partplain=($key+1);
if ($part->subtype == 'ALTERNATIVE')
{
if (count($part->parts) > 0)
{
foreach($part->parts as $key2 => $part2)
{
if ($part2->subtype == 'HTML') $parthtml=($key+1).'.'.($key2+1); // For example: $parthtml = 1.1 or 1.2
if ($part2->subtype == 'PLAIN') $partplain=($key+1).'.'.($key2+1);
}
}
else
{
$partplain=($key+1).'.1';
}
}
}
}
else
{
$partplain=1;
}*/
/*var_dump($structure);
var_dump($structure);
var_dump($parthtml);
var_dump($partplain);*/
var_dump($partplain);
$messagetext = imap_fetchbody($connection, $imapemail, ($parthtml != '-1' ? $parthtml : ($partplain != '-1' ? $partplain : 1)), FT_PEEK);
*/
//var_dump($messagetext);
//var_dump($structure->parts[0]->parts);
@@ -1282,12 +1323,12 @@ class EmailCollector extends CommonObject
elseif ($operation['type'] == 'ticket') $descriptiontitle = $langs->trans("TicketCreatedByEmailCollector", $msgid);
else $descriptiontitle = $langs->trans("ActionAC_".$actioncode).' - '.$langs->trans("MailFrom").' '.$from;
$descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Topic").' : '.$subject);
$descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("From").' : '.$fromstring);
if ($sender) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Sender").' : '.$sender);
$descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("To").' : '.$to);
//if ($cc) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Cc").' : '.$cc);
//if ($bcc) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Bcc").' : '.$bcc);
$descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailTopic").' : '.dol_escape_htmltag($subject));
$descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailFrom").($langs->trans("MailFrom") != 'From' ? ' (From)':'').' : '.dol_escape_htmltag($fromstring));
if ($sender) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Sender").($langs->trans("Sender") != 'Sender' ? ' (Sender)':'').' : '.dol_escape_htmltag($sender));
$descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailTo").($langs->trans("MailTo") != 'To' ? ' (To)':'').' : '.dol_escape_htmltag($to));
if ($sendtocc) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("MailCC").($langs->trans("MailCC") != 'CC' ? ' (CC)':'').' : '.dol_escape_htmltag($sendtocc));
//if ($bcc) $descriptionmeta = dol_concatdesc($descriptionmeta, $langs->trans("Bcc").' : '.dol_escape_htmltag($bcc));
}
// Search and create thirdparty
@@ -1521,12 +1562,12 @@ class EmailCollector extends CommonObject
$percent_opp_status = dol_getIdFromCode($this->db, 'PROSP', 'c_lead_status', 'code', 'percent');
$projecttocreate->title = $subject;
$projecttocreate->date_start = $now;
$projecttocreate->date_start = $date;
$projecttocreate->date_end = '';
$projecttocreate->opp_status = $id_opp_status;
$projecttocreate->opp_percent = $percent_opp_status;
$projecttocreate->description = dol_concatdesc(dolGetFirstLineOfText(dol_string_nohtmltag($description, 2), 10), '...'.$langs->transnoentities("SeePrivateNote").'...');
$projecttocreate->note_private = dol_concatdesc($descriptionfull, dol_string_nohtmltag($descriptionfull, 2));
$projecttocreate->note_private = $descriptionfull;
$projecttocreate->entity = $conf->entity;
// Get next project Ref
@@ -1616,11 +1657,12 @@ class EmailCollector extends CommonObject
$tickettocreate->severity_code = 0;
$tickettocreate->origin_email = $from;
$tickettocreate->fk_user_create = $user->id;
$tickettocreate->entity = $conf->entity;
$tickettocreate->datec = $date;
$tickettocreate->fk_project = $projectstatic->id;
$tickettocreate->fk_soc = $thirdpartystatic->id;
$tickettocreate->notify_tiers_at_create = 0;
$tickettocreate->note_private = $descriptionfull;
$tickettocreate->entity = $conf->entity;
//$tickettocreate->fk_contact = $contactstatic->id;
// Get next project Ref
@@ -1709,12 +1751,26 @@ class EmailCollector extends CommonObject
$errorforemail++;
}
unset($objectemail);
unset($projectstatic);
unset($thirdpartystatic);
unset($contactstatic);
$nbemailprocessed++;
if (! $errorforemail)
{
$nbactiondone += $nbactiondoneforemail;
$nbemailok++;
$this->db->commit();
// Stop the loop to process email if we reach maximum collected per collect
if ($this->maxemailpercollect > 0 && $nbemailok >= $this->maxemailpercollect)
{
dol_syslog("EmailCollect::doCollectOneCollector We reach maximum of ".$nbemailok." collected with success, so we stop this collector now.");
break;
}
}
else
{
@@ -1722,16 +1778,11 @@ class EmailCollector extends CommonObject
$this->db->rollback();
}
$nbemailprocessed++;
unset($objectemail);
unset($projectstatic);
unset($thirdpartystatic);
unset($contactstatic);
}
$output=$langs->trans('XEmailsDoneYActionsDone', $nbemailprocessed, $nbemailok, $nbactiondone);
dol_syslog("End of loop on emails", LOG_INFO, -1);
}
else
{
@@ -1757,4 +1808,134 @@ class EmailCollector extends CommonObject
return $error?-1:1;
}
// Loop to get part html and plain. Code found on PHP imap_fetchstructure documentation
/**
* getmsg
*
* @param Object $mbox Structure
* @param string $mid prefix
* @return array Array with number and object
*/
function getmsg($mbox, $mid) {
// input $mbox = IMAP stream, $mid = message id
// output all the following:
global $charset,$htmlmsg,$plainmsg,$attachments;
$htmlmsg = $plainmsg = $charset = '';
$attachments = array();
// HEADER
//$h = imap_header($mbox,$mid);
// add code here to get date, from, to, cc, subject...
// BODY
$s = imap_fetchstructure($mbox,$mid);
if (!$s->parts) // simple
$this->getpart($mbox,$mid,$s,0); // pass 0 as part-number
else { // multipart: cycle through each part
foreach ($s->parts as $partno0=>$p)
{
$this->getpart($mbox, $mid, $p, $partno0+1);
}
}
}
/* partno string
0 multipart/mixed
1 multipart/alternative
1.1 text/plain
1.2 text/html
2 message/rfc822
2 multipart/mixed
2.1 multipart/alternative
2.1.1 text/plain
2.1.2 text/html
2.2 message/rfc822
2.2 multipart/alternative
2.2.1 text/plain
2.2.2 text/html
*/
/**
* Sub function for getpart(). Only called by createPartArray() and itself.
*
* @param Object $mbox Structure
* @param string $mid Part no
* @param Object $p Object p
* @param string $partno Partno
* @return void
*/
private function getpart($mbox, $mid, $p, $partno) {
// $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
global $htmlmsg,$plainmsg,$charset,$attachments;
// DECODE DATA
$data = ($partno)?
imap_fetchbody($mbox,$mid,$partno): // multipart
imap_body($mbox,$mid); // simple
// Any part may be encoded, even plain text messages, so check everything.
if ($p->encoding==4)
$data = quoted_printable_decode($data);
elseif ($p->encoding==3)
$data = base64_decode($data);
// PARAMETERS
// get all parameters, like charset, filenames of attachments, etc.
$params = array();
if ($p->parameters)
{
foreach ($p->parameters as $x)
{
$params[strtolower($x->attribute)] = $x->value;
}
}
if ($p->dparameters)
{
foreach ($p->dparameters as $x)
{
$params[strtolower($x->attribute)] = $x->value;
}
}
// ATTACHMENT
// Any part with a filename is an attachment,
// so an attached text file (type 0) is not mistaken as the message.
if ($params['filename'] || $params['name']) {
// filename may be given as 'Filename' or 'Name' or both
$filename = ($params['filename'])? $params['filename'] : $params['name'];
// filename may be encoded, so see imap_mime_header_decode()
$attachments[$filename] = $data; // this is a problem if two files have same name
}
// TEXT
if ($p->type==0 && $data) {
// Messages may be split in different parts because of inline attachments,
// so append parts together with blank row.
if (strtolower($p->subtype)=='plain')
$plainmsg .= trim($data) ."\n\n";
else
$htmlmsg .= $data ."<br><br>";
$charset = $params['charset']; // assume all parts are same charset
}
// EMBEDDED MESSAGE
// Many bounce notifications embed the original message as type 2,
// but AOL uses type 1 (multipart), which is not handled here.
// There are no PHP functions to parse embedded messages,
// so this just appends the raw source to the main message.
elseif ($p->type==2 && $data) {
$plainmsg .= $data."\n\n";
}
// SUBPART RECURSION
if ($p->parts) {
foreach ($p->parts as $partno0=>$p2)
{
$this->getpart($mbox,$mid,$p2,$partno.'.'.($partno0+1)); // 1.2, 1.2.1, etc.
}
}
}
}

View File

@@ -159,7 +159,7 @@ class EmailCollectorFilter extends CommonObject
$this->errors[]=$langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type"));
return -1;
}
if (! in_array($this->type, array('seen','unseen','withtrackingid','withouttrackingid')) && empty($this->rulevalue))
if (! in_array($this->type, array('seen', 'unseen', 'unanswered', 'answered', 'withtrackingid', 'withouttrackingid')) && empty($this->rulevalue))
{
$langs->load("errors");
$this->errors[]=$langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("SearchString"));

View File

@@ -285,6 +285,7 @@ ALTER TABLE llx_product ADD INDEX idx_product_fk_project (fk_project);
ALTER TABLE llx_actioncomm ADD COLUMN calling_duration integer;
ALTER TABLE llx_emailcollector_emailcollector ADD COLUMN datelastok datetime;
ALTER TABLE llx_emailcollector_emailcollector ADD COLUMN maxemailpercollect integer DEFAULT 100;
DELETE FROM llx_const WHERE name = 'THEME_ELDY_USE_HOVER' AND value = '0';
DELETE FROM llx_const WHERE name = 'THEME_ELDY_USE_CHECKED' AND value = '0';

View File

@@ -26,6 +26,7 @@ CREATE TABLE llx_emailcollector_emailcollector(
password varchar(128),
source_directory varchar(255) NOT NULL,
target_directory varchar(255),
maxemailpercollect integer DEFAULT 100,
datelastresult datetime,
codelastresult varchar(16),
lastresult varchar(255),

View File

@@ -72,6 +72,8 @@ UseSearchToSelectContactTooltip=Also if you have a large number of third parties
DelaiedFullListToSelectCompany=Wait until a key is pressed before loading content of Third Parties combo list.<br>This may increase performance if you have a large number of third parties, but it is less convenient.
DelaiedFullListToSelectContact=Wait until a key is pressed before loading content of Contact combo list.<br>This may increase performance if you have a large number of contacts, but it is less convenient)
NumberOfKeyToSearch=Number of characters to trigger search: %s
NumberOfBytes=Number of Bytes
SearchString=Search string
NotAvailableWhenAjaxDisabled=Not available when Ajax disabled
AllowToSelectProjectFromOtherCompany=On document of a third party, can choose a project linked to another third party
JavascriptDisabled=JavaScript disabled
@@ -1828,6 +1830,7 @@ EMailHost=Host of email IMAP server
MailboxSourceDirectory=Mailbox source directory
MailboxTargetDirectory=Mailbox target directory
EmailcollectorOperations=Operations to do by collector
MaxEmailCollectPerCollect=Max number of emails collected per collect
CollectNow=Collect now
ConfirmCloneEmailCollector=Are you sure you want to clone the Email collector %s ?
DateLastCollectResult=Date latest collect tried

View File

@@ -19,6 +19,8 @@ MailTopic=Email topic
MailText=Message
MailFile=Attached files
MailMessage=Email body
SubjectNotIn=Not in Subject
BodyNotIn=Not in Body
ShowEMailing=Show emailing
ListOfEMailings=List of emailings
NewMailing=New emailing