From 87ca5c40c3bc451e81ffaf5fc1fd1a894c04dbab Mon Sep 17 00:00:00 2001 From: Eric Espie Date: Thu, 17 Nov 2022 16:06:19 +0100 Subject: [PATCH 01/16] =?UTF-8?q?N=C2=B0544=20-=20Kerberos=20notice=20mess?= =?UTF-8?q?age=20-=20add=20"imap=5Fopen=5Foptions"=20as=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classes/imapemailsource.class.inc.php | 19 ++++++++++--------- module.combodo-email-synchro.php | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/classes/imapemailsource.class.inc.php b/classes/imapemailsource.class.inc.php index e2a98fd..0c0c8e4 100644 --- a/classes/imapemailsource.class.inc.php +++ b/classes/imapemailsource.class.inc.php @@ -49,18 +49,19 @@ public function __construct($sServer, $iPort, $sLogin, $sPwd, $sMailbox, $aOptio if (!function_exists('imap_open')) throw new Exception('The imap_open function is missing. Did you forget to install the PHP module "IMAP" on the server?'); + $aImapOpenOptions = MetaModel::GetModuleSetting('combodo-email-synchro', 'imap_open_options', []); $sIMAPConnStr = "{{$sServer}:{$iPort}$sOptions}$sMailbox"; - $this->rImapConn = imap_open($sIMAPConnStr, $sLogin, $sPwd ); - if ($this->rImapConn === false) + $this->rImapConn = imap_open($sIMAPConnStr, $sLogin, $sPwd, 0, 0, $aImapOpenOptions ); + if ($this->rImapConn === false) + { + if (class_exists('EventHealthIssue')) { - if (class_exists('EventHealthIssue')) - { - EventHealthIssue::LogHealthIssue('combodo-email-synchro', "Cannot connect to IMAP server: '$sIMAPConnStr', with credentials: '$sLogin'/***"); - } - $sMessage = "Cannot connect to IMAP server: '$sIMAPConnStr', with credentials: '$sLogin'/***'"; - IssueLog::Error($sMessage.' '.var_export(imap_errors(), true)); - throw new Exception($sMessage); + EventHealthIssue::LogHealthIssue('combodo-email-synchro', "Cannot connect to IMAP server: '$sIMAPConnStr', with credentials: '$sLogin'/***"); } + $sMessage = "Cannot connect to IMAP server: '$sIMAPConnStr', with credentials: '$sLogin'/***'"; + IssueLog::Error($sMessage.' '.var_export(imap_errors(), true)); + throw new Exception($sMessage); + } } /** diff --git a/module.combodo-email-synchro.php b/module.combodo-email-synchro.php index 88cbdd3..cb7499b 100644 --- a/module.combodo-email-synchro.php +++ b/module.combodo-email-synchro.php @@ -36,6 +36,7 @@ 'body_parts_order' => 'text/html,text/plain', // Order in which to read the parts of the incoming emails 'pop3_auth_option' => 'USER', 'imap_options' => array('imap'), + 'imap_open_options' => array(), 'maximum_email_size' => '10M', // Maximum allowed size for incoming emails 'big_files_dir' => '', 'exclude_attachment_types' => array('application/exe'), // Example: 'application/exe', 'application/x-winexe', 'application/msdos-windows' From ac76909c2a7e095b756bba3f63ca347636dad6ae Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 24 Nov 2022 15:30:59 +0100 Subject: [PATCH 02/16] =?UTF-8?q?N=C2=B05633=20More=20info=20logged=20when?= =?UTF-8?q?=20error=20in=20mailbox=20content=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ajax.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ajax.php b/ajax.php index 4c94da8..fb4f023 100644 --- a/ajax.php +++ b/ajax.php @@ -57,8 +57,15 @@ function GetMailboxContent($oPage, $oInbox) } catch(Exception $e) { - IssueLog::Error('Failed to initialize the mailbox: '.$oInbox->GetName().'. Reason: '.$e->getMessage()); + $aContext = array( + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'exception.class' => get_class($e), + 'exception.stack' => $e->getTraceAsString(), + ); + IssueLog::Error('Failed to initialize the mailbox: '.$oInbox->GetName().'. Reason: '.$e->getMessage(), null, $aContext); $oPage->p("Failed to initialize the mailbox: ".$oInbox->GetName().". Reason: ".$e->getMessage()); + return; } From eef8c1bb9cf0251784e8660b027c2a9ac027712e Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 23 Nov 2022 17:36:29 +0100 Subject: [PATCH 03/16] =?UTF-8?q?N=C2=B05633=20Change=20visibility=20of=20?= =?UTF-8?q?\MailInboxBase::Trace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- datamodel.combodo-email-synchro.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datamodel.combodo-email-synchro.xml b/datamodel.combodo-email-synchro.xml index 3b411f8..ac800cb 100644 --- a/datamodel.combodo-email-synchro.xml +++ b/datamodel.combodo-email-synchro.xml @@ -894,9 +894,9 @@ JS * @param string $sText */ false - protected + public Overload-DBObject - protected function Trace($sText) + public function Trace($sText) { MailInboxesEmailProcessor::Trace($sText); } From 3ff97e4a1fb80c9836b37c2f4f47523e30af68cc Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 1 Dec 2022 09:21:42 +0100 Subject: [PATCH 04/16] =?UTF-8?q?N=C2=B05633=20Create=20\EmailSource::GetS?= =?UTF-8?q?ourceId=20for=20logging=20purposes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classes/emailsource.class.inc.php | 17 +++++++++++- classes/imapemailsource.class.inc.php | 17 +++++++++--- classes/pop3emailsource.class.inc.php | 35 +++++++++++++++---------- classes/testemailsource.class.inc.php | 37 ++++++++++++++++----------- 4 files changed, 72 insertions(+), 34 deletions(-) diff --git a/classes/emailsource.class.inc.php b/classes/emailsource.class.inc.php index 63ad755..9e51bc0 100644 --- a/classes/emailsource.class.inc.php +++ b/classes/emailsource.class.inc.php @@ -49,15 +49,18 @@ abstract public function GetMessage($index); /** * Deletes the message of the given index [0..Count] from the mailbox + * * @param $index integer The index between zero and count */ abstract public function DeleteMessage($index); /** * Move the message of the given index [0..Count] from the mailbox to another folder + * * @param $index integer The index between zero and count */ - public function MoveMessage($index){ + public function MoveMessage($index) + { // Do nothing ! return false; } @@ -67,6 +70,18 @@ public function MoveMessage($index){ */ abstract public function GetName(); + /** + * This impl is bad, but it will lower the risk for children classes in extensions ! + * + * @return string something to identify the source in a log + * this is useful as for example EmailBackgroundProcess is working on this class and not persisted mailboxes ({@link \MailInboxBase}) + * @since 3.6.1 N°5633 method creation + */ + public function GetSourceId() + { + return $this->token; + } + /** * Mailbox path of the eMail source */ diff --git a/classes/imapemailsource.class.inc.php b/classes/imapemailsource.class.inc.php index 0c0c8e4..ff378f2 100644 --- a/classes/imapemailsource.class.inc.php +++ b/classes/imapemailsource.class.inc.php @@ -28,6 +28,7 @@ class IMAPEmailSource extends EmailSource { protected $rImapConn = null; + protected $sServer = ''; protected $sLogin = ''; protected $sMailbox = ''; protected $sTargetFolder = ''; @@ -37,6 +38,7 @@ public function __construct($sServer, $iPort, $sLogin, $sPwd, $sMailbox, $aOptio parent::__construct(); $this->sLastErrorSubject = ''; $this->sLastErrorMessage = ''; + $this->sServer = $sServer; $this->sLogin = $sLogin; $this->sMailbox = $sMailbox; $this->sTargetFolder = $sTargetFolder; @@ -118,15 +120,22 @@ public function MoveMessage($index) print_r(imap_errors()); throw new Exception("Error : Cannot move message to folder ".$this->sTargetFolder); } + return $ret; } + /** * Name of the eMail source */ - public function GetName() - { - return $this->sLogin; - } + public function GetName() + { + return $this->sLogin; + } + + public function GetSourceId() + { + return $this->sServer.'/'.$this->sLogin; + } /** * Mailbox path of the eMail source diff --git a/classes/pop3emailsource.class.inc.php b/classes/pop3emailsource.class.inc.php index 0f4e8d5..354c5fe 100644 --- a/classes/pop3emailsource.class.inc.php +++ b/classes/pop3emailsource.class.inc.php @@ -90,7 +90,8 @@ public function GetMessage($index) */ public function DeleteMessage($index) { - $ret = $this->oPop3->deleteMsg(1+$index); + $ret = $this->oPop3->deleteMsg(1 + $index); + return $ret; } @@ -98,27 +99,33 @@ public function DeleteMessage($index) /** * Name of the eMail source */ - public function GetName() - { - return $this->sLogin; - } + public function GetName() + { + return $this->sLogin; + } + + public function GetSourceId() + { + return $this->sServer.'/'.$this->sLogin; + } /** * Get the list (with their IDs) of all the messages + * * @return Array An array of hashes: 'msg_id' => index 'uild' => message identifier */ - public function GetListing() - { + public function GetListing() + { $ret = $this->oPop3->_cmdUidl(); - if ($ret == null) - { + if ($ret == null) { $ret = array(); } + return $ret; - } - - public function Disconnect() - { - $this->oPop3->disconnect(); + } + + public function Disconnect() + { + $this->oPop3->disconnect(); } } diff --git a/classes/testemailsource.class.inc.php b/classes/testemailsource.class.inc.php index 2bd1a43..babd8c5 100644 --- a/classes/testemailsource.class.inc.php +++ b/classes/testemailsource.class.inc.php @@ -84,30 +84,37 @@ public function DeleteMessage($index) /** * Name of the eMail source */ - public function GetName() - { - if (!empty($this->sName)) - { - return $this->sName; - } - return 'Test Source (from '.$this->sSourceDir.')'; - } + public function GetName() + { + if (!empty($this->sName)) { + return $this->sName; + } + + return 'Test Source (from '.$this->sSourceDir.')'; + } + + public function GetSourceId() + { + return $this->sName.' ('.$this->sSourceDir.')'; + } /** * Get the list (with their IDs) of all the messages + * * @return Array An array of hashes: 'msg_id' => index 'uild' => message identifier */ - public function GetListing() - { + public function GetListing() + { $aListing = array(); foreach($this->aMessages as $index => $sName) { $aListing[] = array('msd_id' => $index, 'uidl' => basename($sName)); } + return $aListing; - } - - public function Disconnect() - { - } + } + + public function Disconnect() + { + } } From 695652e0dd6bb020fda417269243e153371e7ee3 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 1 Dec 2022 09:21:47 +0100 Subject: [PATCH 05/16] =?UTF-8?q?N=C2=B05633=20Fix=20EmailBackgroundProces?= =?UTF-8?q?s=20crashing=20on=20mailbox=20count=20or=20listing=20exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now the errors when getting mailbox count and listing are catched ! If one occurs then we are logging + going on with next source Before this change we were just crashing, up to cron.php (which is catching each iProcess exceptions) For the 3 exception catch (the one already there when processing email, and the 2 added on mailbox count and listing) we are now logging to : - the background process (this was the only log done in the existing catch block) - the mailbox if it can be found (depends on the EmailProcessor used) - IssueLog, error level, 'CLI' channel --- ajax.php | 44 +++--- classes/emailbackgroundprocess.class.inc.php | 138 +++++++++++++------ classes/emailsource.class.inc.php | 3 +- classes/imapemailsource.class.inc.php | 4 - classes/pop3emailsource.class.inc.php | 5 - classes/testemailsource.class.inc.php | 10 +- 6 files changed, 123 insertions(+), 81 deletions(-) diff --git a/ajax.php b/ajax.php index fb4f023..5e8c077 100644 --- a/ajax.php +++ b/ajax.php @@ -76,7 +76,11 @@ function GetMailboxContent($oPage, $oInbox) for($iMessage = 0; $iMessage < $iTotalMsgCount; $iMessage++) { // Assume that EmailBackgroundProcess::IsMultiSourceMode() is always set to true - $aUIDLs[] = $oSource->GetName().'_'.$aMessages[$iMessage]['uidl']; + $sMessageUidl = $aMessages[$iMessage]['uidl']; + if (is_null($sMessageUidl)) { + continue; + } + $aUIDLs[] = $oSource->GetName().'_'.$sMessageUidl; } $sOQL = 'SELECT EmailReplica WHERE uidl IN ('.implode(',', CMDBSource::Quote($aUIDLs)).') AND mailbox_path = ' . CMDBSource::Quote($oInbox->Get('mailbox')); IssueLog::Info("Searching EmailReplica: $sOQL"); @@ -106,9 +110,11 @@ function GetMailboxContent($oPage, $oInbox) ); $aData = array(); - for($iMessage = $iStart; $iMessage < $iStart+$iMsgCount; $iMessage++) - { + for ($iMessage = $iStart; $iMessage < $iStart + $iMsgCount; $iMessage++) { $oRawEmail = $oSource->GetMessage($iMessage); + if (is_null($oRawEmail)) { + continue; + } $oEmail = $oRawEmail->Decode($oSource->GetPartsOrder()); // Assume that EmailBackgroundProcess::IsMultiSourceMode() is always set to true @@ -117,27 +123,25 @@ function GetMailboxContent($oPage, $oInbox) $sLink = ''; $sErrorMsg = ''; $sDetailsLink = ''; - if (array_key_exists($sUIDLs, $aProcessed)) - { - switch ($aProcessed[$sUIDLs]['status']) - { - case 'ok': - $sStatus = Dict::S('MailInbox:Status/Processed'); - break; + if (array_key_exists($sUIDLs, $aProcessed)) { + switch ($aProcessed[$sUIDLs]['status']) { + case 'ok': + $sStatus = Dict::S('MailInbox:Status/Processed'); + break; - case 'error': - $sStatus = Dict::S('MailInbox:Status/Error'); - break; + case 'error': + $sStatus = Dict::S('MailInbox:Status/Error'); + break; - case 'undesired': - $sStatus = Dict::S('MailInbox:Status/Undesired'); - break; + case 'undesired': + $sStatus = Dict::S('MailInbox:Status/Undesired'); + break; - case 'ignored': - $sStatus = Dict::S('MailInbox:Status/Ignored'); - break; + case 'ignored': + $sStatus = Dict::S('MailInbox:Status/Ignored'); + break; - } + } $sErrorMsg = $aProcessed[$sUIDLs]['error_message']; if ($aProcessed[$sUIDLs]['ticket_id'] != '') { diff --git a/classes/emailbackgroundprocess.class.inc.php b/classes/emailbackgroundprocess.class.inc.php index ebca4c0..56a176b 100644 --- a/classes/emailbackgroundprocess.class.inc.php +++ b/classes/emailbackgroundprocess.class.inc.php @@ -190,34 +190,45 @@ public function Process($iTimeLimit) $aSources = $oProcessor->ListEmailSources(); foreach($aSources as $oSource) { - $iMsgCount = $oSource->GetMessagesCount(); - $this->Trace("-----------------------------------------------------------------------------------------"); - $this->Trace("Processing Message Source: ".$oSource->GetName()." GetMessagesCount returned: $iMsgCount"); + $this->Trace("-----------------------------------------------------------------------------------------"); + $this->Trace("Processing Message Source: ".$oSource->GetName()); + try { + $iMsgCount = $oSource->GetMessagesCount(); + } + catch (Exception $e) { + $this->LogProcessException($e, $oSource); + $oSource->Disconnect(); + continue; + } + $this->Trace("GetMessagesCount returned: $iMsgCount"); - if ($iMsgCount != 0) - { - $aMessages = $oSource->GetListing(); + if ($iMsgCount != 0) { + try { + $aMessages = $oSource->GetListing(); + } + catch (Exception $e) { + $this->LogProcessException($e, $oSource); + $oSource->Disconnect(); + continue; + } $iMsgCount = count($aMessages); - + // Get the corresponding EmailReplica object for each message $aUIDLs = array(); - for($iMessage = 0; $iMessage < $iMsgCount; $iMessage++) - { - if (self::IsMultiSourceMode()) - { - $aUIDLs[] = $oSource->GetName().'_'.$aMessages[$iMessage]['uidl']; - } - else - { - $aUIDLs[] = $aMessages[$iMessage]['uidl']; + for ($iMessage = 0; $iMessage < $iMsgCount; $iMessage++) { + $sUIDL = $aMessages[$iMessage]['uidl']; + if (false === is_null($sUIDL)) { + if (self::IsMultiSourceMode()) { + $sUIDL = $oSource->GetName().'_'.$sUIDL; + } + $aUIDLs[] = $sUIDL; } } - $sOQL = 'SELECT EmailReplica WHERE uidl IN (' . implode(',', CMDBSource::Quote($aUIDLs)) . ') AND mailbox_path = ' . CMDBSource::Quote($oSource->GetMailbox()); + $sOQL = 'SELECT EmailReplica WHERE uidl IN ('.implode(',', CMDBSource::Quote($aUIDLs)).') AND mailbox_path = '.CMDBSource::Quote($oSource->GetMailbox()); $this->Trace("Searching EmailReplicas: '$sOQL'"); $oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); $aReplicas = array(); - while($oReplica = $oReplicaSet->Fetch()) - { + while ($oReplica = $oReplicaSet->Fetch()) { $aReplicas[$oReplica->Get('uidl')] = $oReplica; } for ($iMessage = 0; $iMessage < $iMsgCount; $iMessage++) @@ -234,17 +245,17 @@ public function Process($iTimeLimit) try { $this->InitMessageTrace($oSource, $iMessage); $iTotalMessages++; + $sUIDL = $aMessages[$iMessage]['uidl']; + if (is_null($sUIDL)) { + continue; // invalid email, see \EmailSource::GetListing and N°5633 + } if (self::IsMultiSourceMode()) { - $sUIDL = $oSource->GetName().'_'.$aMessages[$iMessage]['uidl']; - } else - { - $sUIDL = $aMessages[$iMessage]['uidl']; + $sUIDL = $oSource->GetName().'_'.$sUIDL; } $oEmailReplica = array_key_exists($sUIDL, $aReplicas) ? $aReplicas[$sUIDL] : null; - if ($oEmailReplica == null) - { + if ($oEmailReplica == null) { $this->Trace("\nDispatching new message: uidl=$sUIDL index=$iMessage"); // Create a replica to keep track that we've processed this email $oEmailReplica = new EmailReplica(); @@ -253,33 +264,23 @@ public function Process($iTimeLimit) $oEmailReplica->Set('message_id', $iMessage); $oEmailReplica->Set('last_seen', date('Y-m-d H:i:s')); - } - else - { - if ($oEmailReplica->Get('status') == 'error') - { + } else { + if ($oEmailReplica->Get('status') == 'error') { $this->Trace("\nSkipping old (already processed) message: uidl=$sUIDL index=$iMessage marked as 'error'"); $iTotalSkipped++; continue; - } - elseif ($oEmailReplica->Get('status') == 'ignored') - { + } elseif ($oEmailReplica->Get('status') == 'ignored') { $this->Trace("\nSkipping old (already processed) message: uidl=$sUIDL index=$iMessage marked as 'ignored'"); $iTotalSkipped++; continue; - } - else - { - if ($oEmailReplica->Get('status') == 'undesired') - { + } else { + if ($oEmailReplica->Get('status') == 'undesired') { $this->Trace("\nUndesired message: uidl=$sUIDL index=$iMessage"); $iDelay = MetaModel::GetModuleSetting('combodo-email-synchro', 'undesired-purge-delay', 7) * 86400; - if ($iDelay > 0) - { + if ($iDelay > 0) { $sDate = $oEmailReplica->Get('message_date'); $oDate = DateTime::createFromFormat('Y-m-d H:i:s', $sDate); - if ($oDate !== false) - { + if ($oDate !== false) { $iDate = $oDate->getTimestamp(); $iDelay -= time() - $iDate; } @@ -448,10 +449,11 @@ public function Process($iTimeLimit) } catch (Exception $e) { if (!empty($oEmailReplica)) { - $this->Trace($e->getMessage()); $this->UpdateEmailReplica($oEmailReplica, $oProcessor); } + $this->LogProcessException($e, $oSource); + return $e->getMessage(); } } @@ -497,9 +499,59 @@ public function Process($iTimeLimit) break; // We'll do the rest later } } + return "Message(s) read: $iTotalMessages, message(s) skipped: $iTotalSkipped, message(s) processed: $iTotalProcessed, message(s) deleted: $iTotalDeleted, message(s) marked as error: $iTotalMarkedAsError, undesired message(s): $iTotalUndesired, message(s) moved: $iTotalMoved,"; } + /** + * @param \Exception $e + * @param \EmailSource $oSource + * + * @return void + * + * @since 3.6.1 N°5633 Method creation + */ + protected function LogProcessException($e, $oSource) + { + $sExceptionMessage = $e->getMessage(); + $sSourceId = $oSource->GetSourceId(); + $sSimpleErrorMessage = __CLASS__.': an exception occurred when reading content for mailbox'; + + // MailInboxStandard + $sMailboxId = $oSource->GetToken(); // see init in \MailInboxesEmailProcessor::ListEmailSources + /** @var \MailInboxStandard $oMailbox */ + try { + $oMailbox = MetaModel::GetObject(MailInboxStandard::class, $sMailboxId, false); + } + catch (ArchivedObjectException $e) { // cannot group exceptions before PHP 7.1.0 (see https://www.php.net/manual/en/language.exceptions.php) + $oMailbox = null; + } + catch (CoreException $e) { + $oMailbox = null; + } + $sDetailedErrorMessage = $sSimpleErrorMessage; + if (is_null($oMailbox)) { + $sDetailedErrorMessage .= " `{$sSourceId}`: {$sExceptionMessage}"; + } else { + $oMailbox->Trace($sSimpleErrorMessage); + + try { + $sMailboxName = $oMailbox->GetName(); + } + catch (CoreException $e) { + // shouldn't happen, but trying to be defensive ! + $sMailboxName = 'N/A'; + } + $sDetailedErrorMessage .= " `{$sMailboxName}::id=$sMailboxId`: {$sExceptionMessage}"; + } + + // BackgroundProcess + $this->Trace($sDetailedErrorMessage); + + // LogAPI + IssueLog::Error($sDetailedErrorMessage, 'CLI'); // \LogChannels::CLI isn't available in iTop < 3.0.0 + } + private function InitMessageTrace($oSource, $iMessage) { $this->oCurrentSource = $oSource; diff --git a/classes/emailsource.class.inc.php b/classes/emailsource.class.inc.php index 9e51bc0..fa8e062 100644 --- a/classes/emailsource.class.inc.php +++ b/classes/emailsource.class.inc.php @@ -92,7 +92,8 @@ public function GetMailbox() /** * Get the list (with their IDs) of all the messages - * @return array An array of hashes: 'msg_id' => index 'uild' => message identifier + * + * @return array{msg_id: int, uidl: ?string} 'msg_id' => index, 'uidl' => message identifier (null if message cannot be decoded) */ abstract public function GetListing(); diff --git a/classes/imapemailsource.class.inc.php b/classes/imapemailsource.class.inc.php index ff378f2..9dfff50 100644 --- a/classes/imapemailsource.class.inc.php +++ b/classes/imapemailsource.class.inc.php @@ -145,10 +145,6 @@ public function GetMailbox() return $this->sMailbox; } - /** - * Get the list (with their IDs) of all the messages - * @return Array An array of hashes: 'msg_id' => index 'uild' => message identifier - */ public function GetListing() { $ret = null; diff --git a/classes/pop3emailsource.class.inc.php b/classes/pop3emailsource.class.inc.php index 354c5fe..7da51f9 100644 --- a/classes/pop3emailsource.class.inc.php +++ b/classes/pop3emailsource.class.inc.php @@ -109,11 +109,6 @@ public function GetSourceId() return $this->sServer.'/'.$this->sLogin; } - /** - * Get the list (with their IDs) of all the messages - * - * @return Array An array of hashes: 'msg_id' => index 'uild' => message identifier - */ public function GetListing() { $ret = $this->oPop3->_cmdUidl(); diff --git a/classes/testemailsource.class.inc.php b/classes/testemailsource.class.inc.php index babd8c5..ad13873 100644 --- a/classes/testemailsource.class.inc.php +++ b/classes/testemailsource.class.inc.php @@ -98,17 +98,11 @@ public function GetSourceId() return $this->sName.' ('.$this->sSourceDir.')'; } - /** - * Get the list (with their IDs) of all the messages - * - * @return Array An array of hashes: 'msg_id' => index 'uild' => message identifier - */ public function GetListing() { $aListing = array(); - foreach($this->aMessages as $index => $sName) - { - $aListing[] = array('msd_id' => $index, 'uidl' => basename($sName)); + foreach ($this->aMessages as $index => $sName) { + $aListing[] = array('msg_id' => $index, 'uidl' => basename($sName)); } return $aListing; From 60980c3580f7c22a1bc260caa2d7ebcabd237868 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Mon, 28 Nov 2022 16:47:10 +0100 Subject: [PATCH 06/16] =?UTF-8?q?N=C2=B05654=20Factorize=20`use=5Fmessage?= =?UTF-8?q?=5Fid=5Fas=5Fuid`=20config=20param=20handling=20Only=201=20LOC?= =?UTF-8?q?=20but=20lot=20of=20inline=20comments=20:=20now=20we=20have=20a?= =?UTF-8?q?=20method=20PHPDoc=20block,=20it's=20better=20!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classes/emailsource.class.inc.php | 20 ++++++++++- classes/imapemailsource.class.inc.php | 49 +++++++++++---------------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/classes/emailsource.class.inc.php b/classes/emailsource.class.inc.php index fa8e062..ee6c725 100644 --- a/classes/emailsource.class.inc.php +++ b/classes/emailsource.class.inc.php @@ -102,11 +102,29 @@ abstract public function GetListing(); */ abstract public function Disconnect(); + /** + * Workaround for some email servers (like gMail!) where the UID may change between two sessions, so let's use the MessageID + * as a replacement for the UID ! + * + * Note that it is possible to receive twice a message with the same MessageID, but since the content of the message + * will be the same, it's a safe to process such messages only once... + * + * BEWARE: Make sure that you empty the mailbox before toggling this setting in the config file, since all the messages + * present in the mailbox at the time of the toggle will be considered as "new" and thus processed again. + * + * @return boolean + * @uses `use_message_id_as_uid` config parameter + */ + public static function UseMessageIdAsUid() + { + return (bool)MetaModel::GetModuleSetting('combodo-email-synchro', 'use_message_id_as_uid', false); + } + public function GetLastErrorSubject() { return $this->sLastErrorSubject; } - + public function GetLastErrorMessage() { return $this->sLastErrorMessage; diff --git a/classes/imapemailsource.class.inc.php b/classes/imapemailsource.class.inc.php index 9dfff50..89bcea6 100644 --- a/classes/imapemailsource.class.inc.php +++ b/classes/imapemailsource.class.inc.php @@ -90,7 +90,7 @@ public function GetMessage($index) $aOverviews = imap_fetch_overview($this->rImapConn, 1+$index); $oOverview = array_pop($aOverviews); - $bUseMessageId = (bool) MetaModel::GetModuleSetting('combodo-email-synchro', 'use_message_id_as_uid', false); + $bUseMessageId = static::UseMessageIdAsUid(); if ($bUseMessageId) { $oOverview->uid = $oOverview->message_id; @@ -147,35 +147,24 @@ public function GetMailbox() public function GetListing() { - $ret = null; - - $oInfo = imap_check($this->rImapConn); - if (($oInfo !== false) && ($oInfo->Nmsgs > 0)) - { - $sRange = "1:".$oInfo->Nmsgs; - // Workaround for some email servers (like gMail!) where the UID may change between two sessions, so let's use the - // MessageID as a replacement for the UID. - // Note that it is possible to receive two times a message with the same MessageID, but since the content of the message - // will be the same, it's safe to process such messages only once... - // BEWARE: Make sure that you empty the mailbox before toggling this setting in the config file, since all the messages - // present in the mailbox at the time of the toggle will be considered as "new" and thus processed again. - $bUseMessageId = (bool)MetaModel::GetModuleSetting('combodo-email-synchro', 'use_message_id_as_uid', false); - - $ret = array(); - $aResponse = imap_fetch_overview($this->rImapConn,$sRange); - - foreach ($aResponse as $aMessage) - { - if ($bUseMessageId) - { - $ret[] = array('msg_id' => $aMessage->msgno, 'uidl' => $aMessage->message_id); - } - else - { - $ret[] = array('msg_id' => $aMessage->msgno, 'uidl' => $aMessage->uid); - } - } - } + $ret = null; + + $oInfo = imap_check($this->rImapConn); + if (($oInfo !== false) && ($oInfo->Nmsgs > 0)) { + $sRange = "1:".$oInfo->Nmsgs; + $bUseMessageId = static::UseMessageIdAsUid(); + + $ret = array(); + $aResponse = imap_fetch_overview($this->rImapConn, $sRange); + + foreach ($aResponse as $aMessage) { + if ($bUseMessageId) { + $ret[] = array('msg_id' => $aMessage->msgno, 'uidl' => $aMessage->message_id); + } else { + $ret[] = array('msg_id' => $aMessage->msgno, 'uidl' => $aMessage->uid); + } + } + } return $ret; } From 194f43735ced9d0eda6cd1251bb4b7204787efb5 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 1 Dec 2022 15:28:40 +0100 Subject: [PATCH 07/16] :bookmark: Update module version from 3.6.1-dev to 3.7.0-dev PHP 8.0 compat + lots of new stuff : we should update the middle digit ! --- module.combodo-email-synchro.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.combodo-email-synchro.php b/module.combodo-email-synchro.php index cb7499b..2ea3419 100644 --- a/module.combodo-email-synchro.php +++ b/module.combodo-email-synchro.php @@ -2,7 +2,7 @@ SetupWebPage::AddModule( __FILE__, // Path to the current file, all other file names are relative to the directory containing this file - 'combodo-email-synchro/3.6.1-dev', + 'combodo-email-synchro/3.7.0-dev', array( // Identification 'label' => 'Tickets synchronization via e-mail', From 62def0147f61b2601de0c964d2fd965d93f40aaa Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Fri, 2 Dec 2022 10:25:03 +0100 Subject: [PATCH 08/16] =?UTF-8?q?N=C2=B05633=20Fix=20"Unexpected=20token?= =?UTF-8?q?=20in=20SELECT=20EmailReplica"=20when=20mailbox=20contains=20on?= =?UTF-8?q?ly=20unreadable=20emails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ajax.php | 60 ++++++++++---------- classes/emailbackgroundprocess.class.inc.php | 53 +++++++---------- 2 files changed, 51 insertions(+), 62 deletions(-) diff --git a/ajax.php b/ajax.php index 5e8c077..3873052 100644 --- a/ajax.php +++ b/ajax.php @@ -69,12 +69,11 @@ function GetMailboxContent($oPage, $oInbox) return; } - if ($iMsgCount > 0) - { + $iMsgOkCount = 0; + if ($iMsgCount > 0) { // Get the corresponding EmailReplica object for each message $aUIDLs = array(); - for($iMessage = 0; $iMessage < $iTotalMsgCount; $iMessage++) - { + for ($iMessage = 0; $iMessage < $iTotalMsgCount; $iMessage++) { // Assume that EmailBackgroundProcess::IsMultiSourceMode() is always set to true $sMessageUidl = $aMessages[$iMessage]['uidl']; if (is_null($sMessageUidl)) { @@ -82,31 +81,35 @@ function GetMailboxContent($oPage, $oInbox) } $aUIDLs[] = $oSource->GetName().'_'.$sMessageUidl; } - $sOQL = 'SELECT EmailReplica WHERE uidl IN ('.implode(',', CMDBSource::Quote($aUIDLs)).') AND mailbox_path = ' . CMDBSource::Quote($oInbox->Get('mailbox')); + + $iMsgOkCount = count($aUIDLs); + } + + if ($iMsgOkCount > 0) { + $sOQL = 'SELECT EmailReplica WHERE uidl IN ('.implode(',', CMDBSource::Quote($aUIDLs)).') AND mailbox_path = '.CMDBSource::Quote($oInbox->Get('mailbox')); IssueLog::Info("Searching EmailReplica: $sOQL"); $oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); $oReplicaSet->OptimizeColumnLoad(array('EmailReplica' => array('uidl', 'ticket_id', 'status', 'error_message'))); $iProcessedCount = $oReplicaSet->Count(); $aProcessed = array(); - while($oReplica = $oReplicaSet->Fetch()) - { + while ($oReplica = $oReplicaSet->Fetch()) { $aProcessed[$oReplica->Get('uidl')] = array( - 'status' => $oReplica->Get('status'), - 'ticket_id' => $oReplica->Get('ticket_id'), - 'error_message' => $oReplica->Get('error_message'), - 'id' => $oReplica->GetKey(), + 'status' => $oReplica->Get('status'), + 'ticket_id' => $oReplica->Get('ticket_id'), + 'error_message' => $oReplica->Get('error_message'), + 'id' => $oReplica->GetKey(), ); } $aTableConfig = array( 'checkbox' => array('label' => '', 'description' => ''), - 'status' => array('label' => Dict::S('MailInbox:Status'), 'description' => ''), - 'date' => array('label' => Dict::S('MailInbox:Date'), 'description' => ''), - 'from' => array('label' => Dict::S('MailInbox:From'), 'description' => ''), - 'subject' => array('label' => Dict::S('MailInbox:Subject'), 'description' => ''), - 'ticket' => array('label' => Dict::S('MailInbox:RelatedTicket'), 'description' => ''), - 'error' => array('label' => Dict::S('MailInbox:ErrorMessage'), 'description' => ''), - 'details' => array('label' => Dict::S('MailInbox:MessageDetails'), 'description' => ''), + 'status' => array('label' => Dict::S('MailInbox:Status'), 'description' => ''), + 'date' => array('label' => Dict::S('MailInbox:Date'), 'description' => ''), + 'from' => array('label' => Dict::S('MailInbox:From'), 'description' => ''), + 'subject' => array('label' => Dict::S('MailInbox:Subject'), 'description' => ''), + 'ticket' => array('label' => Dict::S('MailInbox:RelatedTicket'), 'description' => ''), + 'error' => array('label' => Dict::S('MailInbox:ErrorMessage'), 'description' => ''), + 'details' => array('label' => Dict::S('MailInbox:MessageDetails'), 'description' => ''), ); $aData = array(); @@ -143,8 +146,7 @@ function GetMailboxContent($oPage, $oInbox) } $sErrorMsg = $aProcessed[$sUIDLs]['error_message']; - if ($aProcessed[$sUIDLs]['ticket_id'] != '') - { + if ($aProcessed[$sUIDLs]['ticket_id'] != '') { $sTicketUrl = ApplicationContext::MakeObjectUrl($oInbox->Get('target_class'), $aProcessed[$sUIDLs]['ticket_id']); $sLink = ''.$oInbox->Get('target_class').'::'.$aProcessed[$sUIDLs]['ticket_id'].''; } @@ -154,21 +156,19 @@ function GetMailboxContent($oPage, $oInbox) } $aData[] = array( 'checkbox' => '', - 'status' => $sStatus, - 'date' => $oEmail->sDate, - 'from' => $oEmail->sCallerEmail, - 'subject' => $oEmail->sSubject, - 'ticket' => $sLink, - 'error' => $sErrorMsg, - 'details' => $sDetailsLink, + 'status' => $sStatus, + 'date' => $oEmail->sDate, + 'from' => $oEmail->sCallerEmail, + 'subject' => $oEmail->sSubject, + 'ticket' => $sLink, + 'error' => $sErrorMsg, + 'details' => $sDetailsLink, ); } $oPage->p(Dict::Format('MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox', $iMsgCount, $iTotalMsgCount, ($iTotalMsgCount - $iProcessedCount))); $oPage->table($aTableConfig, $aData); $oPage->add('
 '.Dict::S('MailInbox:WithSelectedDo').'      
'); - } - else - { + } else { $oPage->p(Dict::Format('MailInbox:EmptyMailbox')); } } diff --git a/classes/emailbackgroundprocess.class.inc.php b/classes/emailbackgroundprocess.class.inc.php index 56a176b..a0a9707 100644 --- a/classes/emailbackgroundprocess.class.inc.php +++ b/classes/emailbackgroundprocess.class.inc.php @@ -202,6 +202,7 @@ public function Process($iTimeLimit) } $this->Trace("GetMessagesCount returned: $iMsgCount"); + $iMsgOkCount = 0; if ($iMsgCount != 0) { try { $aMessages = $oSource->GetListing(); @@ -224,15 +225,19 @@ public function Process($iTimeLimit) $aUIDLs[] = $sUIDL; } } + + $iMsgOkCount = count($aUIDLs); + } + + if ($iMsgOkCount > 0) { $sOQL = 'SELECT EmailReplica WHERE uidl IN ('.implode(',', CMDBSource::Quote($aUIDLs)).') AND mailbox_path = '.CMDBSource::Quote($oSource->GetMailbox()); $this->Trace("Searching EmailReplicas: '$sOQL'"); $oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); $aReplicas = array(); while ($oReplica = $oReplicaSet->Fetch()) { $aReplicas[$oReplica->Get('uidl')] = $oReplica; - } - for ($iMessage = 0; $iMessage < $iMsgCount; $iMessage++) - { + } + for ($iMessage = 0; $iMessage < $iMsgCount; $iMessage++) { // N°3218 initialize a new CMDBChange for each message // we cannot use \CMDBObject::SetCurrentChange($oChange) as this would force to persist our change for each message // even if no CMDBChangeOp is created during the message processing ! @@ -285,8 +290,7 @@ public function Process($iTimeLimit) $iDelay -= time() - $iDate; } } - if ($iDelay <= 0) - { + if ($iDelay <= 0) { $iDelay = MetaModel::GetModuleSetting('combodo-email-synchro', 'undesired-purge-delay', 7); $this->Trace("\nDeleting undesired message (AND replica) due to purge delay threshold ({$iDelay}): uidl=$sUIDL index=$iMessage"); $iTotalDeleted++; @@ -296,9 +300,7 @@ public function Process($iTimeLimit) } $iTotalSkipped++; continue; - } - else - { + } else { $this->Trace("\nDispatching old (already read) message: uidl=$sUIDL index=$iMessage"); } } @@ -306,8 +308,7 @@ public function Process($iTimeLimit) $iActionCode = $oProcessor->DispatchMessage($oSource, $iMessage, $sUIDL, $oEmailReplica); - switch ($iActionCode) - { + switch ($iActionCode) { case EmailProcessor::MARK_MESSAGE_AS_ERROR: $iTotalMarkedAsError++; $this->Trace("Marking the message (and replica): uidl=$sUIDL index=$iMessage as in error."); @@ -323,25 +324,20 @@ public function Process($iTimeLimit) case EmailProcessor::PROCESS_MESSAGE: $iTotalProcessed++; - if ($oEmailReplica->IsNew()) - { + if ($oEmailReplica->IsNew()) { $this->Trace("Processing new message: $sUIDL"); - } - else - { + } else { $this->Trace("Processing old (already read) message: $sUIDL"); } $oRawEmail = $oSource->GetMessage($iMessage); - if ((self::$iMaxEmailSize > 0) && ($oRawEmail->GetSize() > self::$iMaxEmailSize)) - { + if ((self::$iMaxEmailSize > 0) && ($oRawEmail->GetSize() > self::$iMaxEmailSize)) { $aErrors = array(); $iNextActionCode = $oProcessor->OnDecodeError($oSource, $sUIDL, null, $oRawEmail, $aErrors); $sMessage = implode("\n", $aErrors); $this->Trace($sMessage); - switch ($iNextActionCode) - { + switch ($iNextActionCode) { case EmailProcessor::MARK_MESSAGE_AS_ERROR: $iTotalMarkedAsError++; $this->Trace("Email too big, marking the message (and replica): uidl=$sUIDL index=$iMessage as in error."); @@ -355,18 +351,14 @@ public function Process($iTimeLimit) $oSource->DeleteMessage($iMessage); break; } - } - else - { + } else { $oEmail = $oRawEmail->Decode($oSource->GetPartsOrder()); - if (!$oEmail->IsValid()) - { + if (!$oEmail->IsValid()) { $aErrors = array(); $iNextActionCode = $oProcessor->OnDecodeError($oSource, $sUIDL, $oEmail, $oRawEmail, $aErrors); $sMessage = implode("\n", $aErrors); $this->Trace($sMessage); - switch ($iNextActionCode) - { + switch ($iNextActionCode) { case EmailProcessor::MARK_MESSAGE_AS_ERROR: $iTotalMarkedAsError++; $this->Trace("Failed to decode the message, marking the message (and replica): uidl=$sUIDL index=$iMessage as in error."); @@ -380,15 +372,12 @@ public function Process($iTimeLimit) $oSource->DeleteMessage($iMessage); break; } - } - else - { + } else { $aErrors = array(); $iNextActionCode = $oProcessor->ProcessMessage($oSource, $iMessage, $oEmail, $oEmailReplica, $aErrors); $sMessage = implode("\n", $aErrors); $this->Trace($sMessage); - switch ($iNextActionCode) - { + switch ($iNextActionCode) { case EmailProcessor::MARK_MESSAGE_AS_ERROR: $iTotalMarkedAsError++; $this->Trace("Marking the message (and replica): uidl=$sUIDL index=$iMessage as in error."); @@ -472,7 +461,7 @@ public function Process($iTimeLimit) $aIDs[] = $oUsedReplica->GetKey(); } } - + // Cleanup the unused replicas based on the pattern of their UIDL, unfortunately this is not possible in NON multi-source mode $iRetentionPeriod = MetaModel::GetModuleSetting('combodo-email-synchro', 'retention_period', '1'); $sOQL = "SELECT EmailReplica WHERE uidl LIKE " . CMDBSource::Quote($oSource->GetName() . '_%') . From 34307311f528a5a68e88189471e14b3cd7cc296f Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Fri, 2 Dec 2022 11:00:16 +0100 Subject: [PATCH 09/16] =?UTF-8?q?N=C2=B05633=20Fix=20mailbox=20display=20*?= =?UTF-8?q?=20add=20nb=20of=20messages=20in=20error=20*=20display=20readab?= =?UTF-8?q?le=20messages=20count=20in=20the=20interval=20instead=20of=20re?= =?UTF-8?q?al=20mails=20in=20the=20mailbox=20(eg=20if=20there=20are=2010?= =?UTF-8?q?=20messages=20in=20the=20mailbox=20and=203=20in=20error=20we=20?= =?UTF-8?q?are=20displaying=207=20messages,=20but=20the=20count=20was=2010?= =?UTF-8?q?=20:=20now=20it=20is=207)=20*=20handle=20when=20we=20have=20mes?= =?UTF-8?q?sages=20in=20the=20mailbox=20but=20no=20message=20to=20display?= =?UTF-8?q?=20in=20the=20interval=20(eg=2032=20mails=20in=20the=20mailbox?= =?UTF-8?q?=20but=20we=20are=20asking=20to=20display=2010=20messages=20fro?= =?UTF-8?q?m=20position=2040)=20:=20display=20the=20count=20and=20change?= =?UTF-8?q?=20the=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ajax.php | 31 +++++++++++++++++++++------- cs.dict.combodo-email-synchro.php | 4 ++-- da.dict.combodo-email-synchro.php | 4 ++-- de.dict.combodo-email-synchro.php | 4 ++-- en.dict.combodo-email-synchro.php | 4 ++-- es_cr.dict.combodo-email-synchro.php | 4 ++-- fr.dict.combodo-email-synchro.php | 4 ++-- hu.dict.combodo-email-synchro.php | 4 ++-- it.dict.combodo-email-synchro.php | 4 ++-- ja.dict.combodo-email-synchro.php | 4 ++-- nl.dict.combodo-email-synchro.php | 4 ++-- pt_br.dict.combodo-email-synchro.php | 4 ++-- ru.dict.combodo-email-synchro.php | 4 ++-- sk.dict.combodo-email-synchro.php | 4 ++-- tr.dict.combodo-email-synchro.php | 4 ++-- zh_cn.dict.combodo-email-synchro.php | 4 ++-- 16 files changed, 54 insertions(+), 37 deletions(-) diff --git a/ajax.php b/ajax.php index 3873052..1c016a8 100644 --- a/ajax.php +++ b/ajax.php @@ -69,7 +69,7 @@ function GetMailboxContent($oPage, $oInbox) return; } - $iMsgOkCount = 0; + $iTotalMsgOkCount = 0; if ($iMsgCount > 0) { // Get the corresponding EmailReplica object for each message $aUIDLs = array(); @@ -82,10 +82,14 @@ function GetMailboxContent($oPage, $oInbox) $aUIDLs[] = $oSource->GetName().'_'.$sMessageUidl; } - $iMsgOkCount = count($aUIDLs); + /** @var int $iTotalMsgOkCount number of readable emails in total (whole mailbox content) */ + $iTotalMsgOkCount = count($aUIDLs); } - if ($iMsgOkCount > 0) { + /** @var int $iMsgOkCount number of readable emails between start and end index */ + $iMsgOkCount = 0; + $iProcessedCount = 0; + if ($iTotalMsgOkCount > 0) { $sOQL = 'SELECT EmailReplica WHERE uidl IN ('.implode(',', CMDBSource::Quote($aUIDLs)).') AND mailbox_path = '.CMDBSource::Quote($oInbox->Get('mailbox')); IssueLog::Info("Searching EmailReplica: $sOQL"); $oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); @@ -107,9 +111,9 @@ function GetMailboxContent($oPage, $oInbox) 'date' => array('label' => Dict::S('MailInbox:Date'), 'description' => ''), 'from' => array('label' => Dict::S('MailInbox:From'), 'description' => ''), 'subject' => array('label' => Dict::S('MailInbox:Subject'), 'description' => ''), - 'ticket' => array('label' => Dict::S('MailInbox:RelatedTicket'), 'description' => ''), - 'error' => array('label' => Dict::S('MailInbox:ErrorMessage'), 'description' => ''), - 'details' => array('label' => Dict::S('MailInbox:MessageDetails'), 'description' => ''), + 'ticket' => array('label' => Dict::S('MailInbox:RelatedTicket'), 'description' => ''), + 'error' => array('label' => Dict::S('MailInbox:ErrorMessage'), 'description' => ''), + 'details' => array('label' => Dict::S('MailInbox:MessageDetails'), 'description' => ''), ); $aData = array(); @@ -118,6 +122,7 @@ function GetMailboxContent($oPage, $oInbox) if (is_null($oRawEmail)) { continue; } + $iMsgOkCount++; $oEmail = $oRawEmail->Decode($oSource->GetPartsOrder()); // Assume that EmailBackgroundProcess::IsMultiSourceMode() is always set to true @@ -165,7 +170,19 @@ function GetMailboxContent($oPage, $oInbox) 'details' => $sDetailsLink, ); } - $oPage->p(Dict::Format('MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox', $iMsgCount, $iTotalMsgCount, ($iTotalMsgCount - $iProcessedCount))); + } + + if ($iTotalMsgCount > 0) { + // If we have messages in the mailbox, even if none can be read (meaning they can't be displayed), we are displaying the mailbox stats + // This will greatly help the user understanding what's going on ! + $oPage->p(Dict::Format('MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox', + $iMsgOkCount, + $iTotalMsgCount, + ($iTotalMsgCount - $iProcessedCount), + ($iTotalMsgCount - $iTotalMsgOkCount)) + ); + } + if ($iMsgOkCount > 0) { $oPage->table($aTableConfig, $aData); $oPage->add('
 '.Dict::S('MailInbox:WithSelectedDo').'      
'); } else { diff --git a/cs.dict.combodo-email-synchro.php b/cs.dict.combodo-email-synchro.php index af341f7..5011aef 100644 --- a/cs.dict.combodo-email-synchro.php +++ b/cs.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/da.dict.combodo-email-synchro.php b/da.dict.combodo-email-synchro.php index bae7461..38afebc 100644 --- a/da.dict.combodo-email-synchro.php +++ b/da.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/de.dict.combodo-email-synchro.php b/de.dict.combodo-email-synchro.php index 3b50a1a..450159f 100644 --- a/de.dict.combodo-email-synchro.php +++ b/de.dict.combodo-email-synchro.php @@ -32,8 +32,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Inhalt', 'MailInbox:MailboxContent:ConfirmMessage' => 'Sind Sie sicher?', - 'MailInbox:EmptyMailbox' => 'Die Mailbox ist leer', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d Mails angezeigt. Es sind %2$d EMail(s) in der Mailbox (%3$d neu).', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'Der MySQL-Parameter max_allowed_packet in "my.ini" ist zu klein: %1$s. Der empfohlene Wert ist mindestens: %2$s', 'MailInbox:Status' => 'Status', 'MailInbox:Subject' => 'Betreff', diff --git a/en.dict.combodo-email-synchro.php b/en.dict.combodo-email-synchro.php index 48b71d7..ebc889b 100644 --- a/en.dict.combodo-email-synchro.php +++ b/en.dict.combodo-email-synchro.php @@ -40,8 +40,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).', + 'MailInbox:EmptyMailbox' => 'No message to display', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s', 'MailInbox:Status' => 'Status', 'MailInbox:Subject' => 'Subject', diff --git a/es_cr.dict.combodo-email-synchro.php b/es_cr.dict.combodo-email-synchro.php index f16a36c..ae7cca1 100644 --- a/es_cr.dict.combodo-email-synchro.php +++ b/es_cr.dict.combodo-email-synchro.php @@ -32,8 +32,8 @@ 'MailInbox:MailboxContent' => 'Contenido de Buzón', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'El buzón está vacío', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d mensajes mostrados. Existen %2$d mensaje(s) en el buzón (%3$d new).', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Estatus', 'MailInbox:Subject' => 'Asunto', diff --git a/fr.dict.combodo-email-synchro.php b/fr.dict.combodo-email-synchro.php index ba3dcc4..9729546 100644 --- a/fr.dict.combodo-email-synchro.php +++ b/fr.dict.combodo-email-synchro.php @@ -32,8 +32,8 @@ 'MailInbox:MailboxContent' => 'Contenu de la boîte mail', 'MailInbox:MailboxContent:ConfirmMessage' => 'Etes-vous sûr(e) ?', - 'MailInbox:EmptyMailbox' => 'La boîte mail est vide.', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails affichés. Il y a au total %2$d eMail(s) dans la boîte (dont %3$d nouveaux).', + 'MailInbox:EmptyMailbox' => 'Aucun message à afficher', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails affichés. Il y a au total %2$d eMail(s) dans la boîte (dont %3$d nouveaux et %4$d en erreur).', 'MailInbox:MaxAllowedPacketTooSmall' => 'Le paramètre MySQL max_allowed_packet dans le fichier "my.ini" est trop petit : %1$s. La valeur recommandée est au moins : %2$s', 'MailInbox:Status' => 'Etat', 'MailInbox:Subject' => 'Objet', diff --git a/hu.dict.combodo-email-synchro.php b/hu.dict.combodo-email-synchro.php index a47071a..e17ca1b 100644 --- a/hu.dict.combodo-email-synchro.php +++ b/hu.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/it.dict.combodo-email-synchro.php b/it.dict.combodo-email-synchro.php index e38e34f..917fa02 100644 --- a/it.dict.combodo-email-synchro.php +++ b/it.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/ja.dict.combodo-email-synchro.php b/ja.dict.combodo-email-synchro.php index b077a22..590b47d 100644 --- a/ja.dict.combodo-email-synchro.php +++ b/ja.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/nl.dict.combodo-email-synchro.php b/nl.dict.combodo-email-synchro.php index 2495294..0748d89 100644 --- a/nl.dict.combodo-email-synchro.php +++ b/nl.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/pt_br.dict.combodo-email-synchro.php b/pt_br.dict.combodo-email-synchro.php index 828b827..4158556 100644 --- a/pt_br.dict.combodo-email-synchro.php +++ b/pt_br.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/ru.dict.combodo-email-synchro.php b/ru.dict.combodo-email-synchro.php index 79d5af2..0de9c58 100644 --- a/ru.dict.combodo-email-synchro.php +++ b/ru.dict.combodo-email-synchro.php @@ -26,8 +26,8 @@ 'MailInbox:MailboxContent' => 'Содержимое ящика', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'Ящик пуст', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d сообщений показано. Всего %2$d сообщений в ящике (%3$d новых).', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Статус', 'MailInbox:Subject' => 'Тема', diff --git a/sk.dict.combodo-email-synchro.php b/sk.dict.combodo-email-synchro.php index 1e91b7f..84aa176 100644 --- a/sk.dict.combodo-email-synchro.php +++ b/sk.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/tr.dict.combodo-email-synchro.php b/tr.dict.combodo-email-synchro.php index ecb1129..9743741 100644 --- a/tr.dict.combodo-email-synchro.php +++ b/tr.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/zh_cn.dict.combodo-email-synchro.php b/zh_cn.dict.combodo-email-synchro.php index 0e0e827..16ff18f 100644 --- a/zh_cn.dict.combodo-email-synchro.php +++ b/zh_cn.dict.combodo-email-synchro.php @@ -39,8 +39,8 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', - 'MailInbox:EmptyMailbox' => 'The mailbox is empty~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new).~~', + 'MailInbox:EmptyMailbox' => 'No message to display~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', From 3d32af249664a97470bdc24314bb7b3bd5ea8880 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Fri, 2 Dec 2022 14:29:31 +0100 Subject: [PATCH 10/16] =?UTF-8?q?N=C2=B05633=20EmailBackgroundProcess=20:?= =?UTF-8?q?=20add=20unreadable=20messages=20stat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classes/emailbackgroundprocess.class.inc.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/classes/emailbackgroundprocess.class.inc.php b/classes/emailbackgroundprocess.class.inc.php index a0a9707..f7b0933 100644 --- a/classes/emailbackgroundprocess.class.inc.php +++ b/classes/emailbackgroundprocess.class.inc.php @@ -180,16 +180,15 @@ public function Process($iTimeLimit) $iTotalProcessed = 0; $iTotalMarkedAsError = 0; $iTotalSkipped = 0; - $iTotalDeleted = 0; + $iTotalDeleted = 0; $iTotalMoved = 0; - $iTotalUndesired = 0; - foreach(self::$aEmailProcessors as $sProcessorClass) - { + $iTotalUndesired = 0; + $iTotalUnreadable = 0; // cannot be read by the mail library, see N°5633 + foreach (self::$aEmailProcessors as $sProcessorClass) { /** @var \EmailProcessor $oProcessor */ $oProcessor = new $sProcessorClass(); $aSources = $oProcessor->ListEmailSources(); - foreach($aSources as $oSource) - { + foreach ($aSources as $oSource) { $this->Trace("-----------------------------------------------------------------------------------------"); $this->Trace("Processing Message Source: ".$oSource->GetName()); try { @@ -252,6 +251,7 @@ public function Process($iTimeLimit) $iTotalMessages++; $sUIDL = $aMessages[$iMessage]['uidl']; if (is_null($sUIDL)) { + $iTotalUnreadable++; continue; // invalid email, see \EmailSource::GetListing and N°5633 } if (self::IsMultiSourceMode()) { @@ -489,7 +489,7 @@ public function Process($iTimeLimit) } } - return "Message(s) read: $iTotalMessages, message(s) skipped: $iTotalSkipped, message(s) processed: $iTotalProcessed, message(s) deleted: $iTotalDeleted, message(s) marked as error: $iTotalMarkedAsError, undesired message(s): $iTotalUndesired, message(s) moved: $iTotalMoved,"; + return "Message(s) read: $iTotalMessages, message(s) skipped: $iTotalSkipped, message(s) processed: $iTotalProcessed, message(s) deleted: $iTotalDeleted, message(s) marked as error: $iTotalMarkedAsError, undesired message(s): $iTotalUndesired, message(s) moved: $iTotalMoved, unereable: $iTotalUnreadable"; } /** From df90418d08545d1c2e1d28d7903fb58b360c93aa Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Fri, 2 Dec 2022 17:03:40 +0100 Subject: [PATCH 11/16] =?UTF-8?q?N=C2=B05633=20Mailbox=20content=20:=20cha?= =?UTF-8?q?nge=20stat=20message=20*=20In=20stat=20message=20replace=20"err?= =?UTF-8?q?or"=20by=20"unreadable"=20(error=20correspond=20to=20a=20specif?= =?UTF-8?q?ic=20replica=20status=20!)=20*=20Make=20clearer=20that=20"unrea?= =?UTF-8?q?dable"=20are=20part=20of=20"new"=20status=20*=20Display=20proce?= =?UTF-8?q?ssed=20count?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ajax.php | 5 +++-- cs.dict.combodo-email-synchro.php | 2 +- da.dict.combodo-email-synchro.php | 2 +- de.dict.combodo-email-synchro.php | 2 +- en.dict.combodo-email-synchro.php | 2 +- es_cr.dict.combodo-email-synchro.php | 2 +- fr.dict.combodo-email-synchro.php | 2 +- hu.dict.combodo-email-synchro.php | 2 +- it.dict.combodo-email-synchro.php | 2 +- ja.dict.combodo-email-synchro.php | 2 +- nl.dict.combodo-email-synchro.php | 2 +- pt_br.dict.combodo-email-synchro.php | 2 +- ru.dict.combodo-email-synchro.php | 2 +- sk.dict.combodo-email-synchro.php | 2 +- tr.dict.combodo-email-synchro.php | 2 +- zh_cn.dict.combodo-email-synchro.php | 2 +- 16 files changed, 18 insertions(+), 17 deletions(-) diff --git a/ajax.php b/ajax.php index 1c016a8..6719e6a 100644 --- a/ajax.php +++ b/ajax.php @@ -179,8 +179,9 @@ function GetMailboxContent($oPage, $oInbox) $iMsgOkCount, $iTotalMsgCount, ($iTotalMsgCount - $iProcessedCount), - ($iTotalMsgCount - $iTotalMsgOkCount)) - ); + ($iTotalMsgCount - $iTotalMsgOkCount), + $iProcessedCount + )); } if ($iMsgOkCount > 0) { $oPage->table($aTableConfig, $aData); diff --git a/cs.dict.combodo-email-synchro.php b/cs.dict.combodo-email-synchro.php index 5011aef..cc59fd1 100644 --- a/cs.dict.combodo-email-synchro.php +++ b/cs.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/da.dict.combodo-email-synchro.php b/da.dict.combodo-email-synchro.php index 38afebc..8dff928 100644 --- a/da.dict.combodo-email-synchro.php +++ b/da.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/de.dict.combodo-email-synchro.php b/de.dict.combodo-email-synchro.php index 450159f..6646be4 100644 --- a/de.dict.combodo-email-synchro.php +++ b/de.dict.combodo-email-synchro.php @@ -33,7 +33,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Inhalt', 'MailInbox:MailboxContent:ConfirmMessage' => 'Sind Sie sicher?', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'Der MySQL-Parameter max_allowed_packet in "my.ini" ist zu klein: %1$s. Der empfohlene Wert ist mindestens: %2$s', 'MailInbox:Status' => 'Status', 'MailInbox:Subject' => 'Betreff', diff --git a/en.dict.combodo-email-synchro.php b/en.dict.combodo-email-synchro.php index ebc889b..afc86f5 100644 --- a/en.dict.combodo-email-synchro.php +++ b/en.dict.combodo-email-synchro.php @@ -41,7 +41,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?', 'MailInbox:EmptyMailbox' => 'No message to display', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s', 'MailInbox:Status' => 'Status', 'MailInbox:Subject' => 'Subject', diff --git a/es_cr.dict.combodo-email-synchro.php b/es_cr.dict.combodo-email-synchro.php index ae7cca1..42e3ec4 100644 --- a/es_cr.dict.combodo-email-synchro.php +++ b/es_cr.dict.combodo-email-synchro.php @@ -33,7 +33,7 @@ 'MailInbox:MailboxContent' => 'Contenido de Buzón', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Estatus', 'MailInbox:Subject' => 'Asunto', diff --git a/fr.dict.combodo-email-synchro.php b/fr.dict.combodo-email-synchro.php index 9729546..14fa998 100644 --- a/fr.dict.combodo-email-synchro.php +++ b/fr.dict.combodo-email-synchro.php @@ -33,7 +33,7 @@ 'MailInbox:MailboxContent' => 'Contenu de la boîte mail', 'MailInbox:MailboxContent:ConfirmMessage' => 'Etes-vous sûr(e) ?', 'MailInbox:EmptyMailbox' => 'Aucun message à afficher', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails affichés. Il y a au total %2$d eMail(s) dans la boîte (dont %3$d nouveaux et %4$d en erreur).', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails affichés. Il y a au total %2$d eMail(s) dans la boîte : %3$d nouveaux (dont %4$d illisibles), et %4$d traités.', 'MailInbox:MaxAllowedPacketTooSmall' => 'Le paramètre MySQL max_allowed_packet dans le fichier "my.ini" est trop petit : %1$s. La valeur recommandée est au moins : %2$s', 'MailInbox:Status' => 'Etat', 'MailInbox:Subject' => 'Objet', diff --git a/hu.dict.combodo-email-synchro.php b/hu.dict.combodo-email-synchro.php index e17ca1b..a32f5cc 100644 --- a/hu.dict.combodo-email-synchro.php +++ b/hu.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/it.dict.combodo-email-synchro.php b/it.dict.combodo-email-synchro.php index 917fa02..9fcc4d8 100644 --- a/it.dict.combodo-email-synchro.php +++ b/it.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/ja.dict.combodo-email-synchro.php b/ja.dict.combodo-email-synchro.php index 590b47d..74bfc55 100644 --- a/ja.dict.combodo-email-synchro.php +++ b/ja.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/nl.dict.combodo-email-synchro.php b/nl.dict.combodo-email-synchro.php index 0748d89..e8c8b68 100644 --- a/nl.dict.combodo-email-synchro.php +++ b/nl.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/pt_br.dict.combodo-email-synchro.php b/pt_br.dict.combodo-email-synchro.php index 4158556..3f92b1e 100644 --- a/pt_br.dict.combodo-email-synchro.php +++ b/pt_br.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/ru.dict.combodo-email-synchro.php b/ru.dict.combodo-email-synchro.php index 0de9c58..8a9e09f 100644 --- a/ru.dict.combodo-email-synchro.php +++ b/ru.dict.combodo-email-synchro.php @@ -27,7 +27,7 @@ 'MailInbox:MailboxContent' => 'Содержимое ящика', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Статус', 'MailInbox:Subject' => 'Тема', diff --git a/sk.dict.combodo-email-synchro.php b/sk.dict.combodo-email-synchro.php index 84aa176..b3d797a 100644 --- a/sk.dict.combodo-email-synchro.php +++ b/sk.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/tr.dict.combodo-email-synchro.php b/tr.dict.combodo-email-synchro.php index 9743741..f81393d 100644 --- a/tr.dict.combodo-email-synchro.php +++ b/tr.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', diff --git a/zh_cn.dict.combodo-email-synchro.php b/zh_cn.dict.combodo-email-synchro.php index 16ff18f..01803b9 100644 --- a/zh_cn.dict.combodo-email-synchro.php +++ b/zh_cn.dict.combodo-email-synchro.php @@ -40,7 +40,7 @@ 'MailInbox:MailboxContent' => 'Mailbox Content~~', 'MailInbox:MailboxContent:ConfirmMessage' => 'Are you sure ?~~', 'MailInbox:EmptyMailbox' => 'No message to display~~', - 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox (%3$d new, %4$d in error).~~', + 'MailInbox:Z_DisplayedThereAre_X_Msg_Y_NewInTheMailbox' => '%1$d eMails displayed. There are %2$d email(s) in the mailbox : %3$d new (including %4$d unreadable), %5$d processed.~~', 'MailInbox:MaxAllowedPacketTooSmall' => 'MySQL parameter max_allowed_packet in "my.ini" is too small: %1$s. The recommended value is at least: %2$s~~', 'MailInbox:Status' => 'Status~~', 'MailInbox:Subject' => 'Subject~~', From d4e5f8b18819e880611be83eadf12669e12dae5a Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Fri, 2 Dec 2022 17:19:27 +0100 Subject: [PATCH 12/16] =?UTF-8?q?N=C2=B05633=20Fix=20false=20unreadable=20?= =?UTF-8?q?count=20when=20no=20messages=20in=20current=20interval=20For=20?= =?UTF-8?q?example=20only=20one=20valid=20email=20in=20the=20mailbox,=20an?= =?UTF-8?q?d=20trying=20to=20display=2010=20messages=20from=20index=2010.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ajax.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ajax.php b/ajax.php index 6719e6a..1043c83 100644 --- a/ajax.php +++ b/ajax.php @@ -70,7 +70,7 @@ function GetMailboxContent($oPage, $oInbox) } $iTotalMsgOkCount = 0; - if ($iMsgCount > 0) { + if ($iTotalMsgCount > 0) { // Get the corresponding EmailReplica object for each message $aUIDLs = array(); for ($iMessage = 0; $iMessage < $iTotalMsgCount; $iMessage++) { From 5c5fa2dc7d4eb5e19b4c0076753664fbb3f8396a Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 7 Dec 2022 15:16:51 +0100 Subject: [PATCH 13/16] :memo: CONTRIBUTING: update "Pull Request" chapter Reflects Combodo/iTop#371 --- CONTRIBUTING.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e83574..af32d05 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,8 +90,10 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file When your code is working, please: -* stash as much as possible your commits, -* rebase your branch on our repo last commit, -* create a pull request. - -Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). +* Squash as much as possible your commits, +* Rebase your branch on our repo last commit, +* Create a pull request. _Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)_. +* Pull request description: mind to add all the information useful to understand why you're suggesting this modification and anything necessary to dive into your work. Especially: + - Bugfixes: exact steps to reproduce the bug (given/when/then), description of the bug cause and what solution is implemented + - Enhancements: use cases, implementation details if needed +* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option ! From cf86046cfe6807bcdacf177a1bf50a68f86e0a1f Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 8 Dec 2022 09:10:57 +0100 Subject: [PATCH 14/16] =?UTF-8?q?N=C2=B05633=20Fix=20cron=20message=20typo?= =?UTF-8?q?=20Thanks=20@Molkobain=20!=20(reported=20in=20https://github.co?= =?UTF-8?q?m/Combodo/combodo-email-synchro/commit/3d32af249664a97470bdc243?= =?UTF-8?q?14bb7b3bd5ea8880#diff-7d43513bf911d97bd5836eb4fe1bfb20f525bf088?= =?UTF-8?q?0fe6417c8bc20e3719493c9R492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classes/emailbackgroundprocess.class.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/emailbackgroundprocess.class.inc.php b/classes/emailbackgroundprocess.class.inc.php index f7b0933..e72726b 100644 --- a/classes/emailbackgroundprocess.class.inc.php +++ b/classes/emailbackgroundprocess.class.inc.php @@ -489,7 +489,7 @@ public function Process($iTimeLimit) } } - return "Message(s) read: $iTotalMessages, message(s) skipped: $iTotalSkipped, message(s) processed: $iTotalProcessed, message(s) deleted: $iTotalDeleted, message(s) marked as error: $iTotalMarkedAsError, undesired message(s): $iTotalUndesired, message(s) moved: $iTotalMoved, unereable: $iTotalUnreadable"; + return "Message(s) read: $iTotalMessages, message(s) skipped: $iTotalSkipped, message(s) processed: $iTotalProcessed, message(s) deleted: $iTotalDeleted, message(s) marked as error: $iTotalMarkedAsError, undesired message(s): $iTotalUndesired, message(s) moved: $iTotalMoved, unreadable: $iTotalUnreadable"; } /** From a3f9809587f1784fecc0260498a289c233d0dfe4 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Mon, 12 Dec 2022 11:08:51 +0100 Subject: [PATCH 15/16] :bookmark: Update module version from 3.7.0-dev to 3.7.0 --- module.combodo-email-synchro.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.combodo-email-synchro.php b/module.combodo-email-synchro.php index 2ea3419..505a6d1 100644 --- a/module.combodo-email-synchro.php +++ b/module.combodo-email-synchro.php @@ -2,7 +2,7 @@ SetupWebPage::AddModule( __FILE__, // Path to the current file, all other file names are relative to the directory containing this file - 'combodo-email-synchro/3.7.0-dev', + 'combodo-email-synchro/3.7.0', array( // Identification 'label' => 'Tickets synchronization via e-mail', From b8d3797bf56146313b796f721bf687c5eb890857 Mon Sep 17 00:00:00 2001 From: jbostoen <6421683+jbostoen@users.noreply.github.com> Date: Tue, 13 Dec 2022 18:32:34 +0100 Subject: [PATCH 16/16] =?UTF-8?q?=F0=9F=90=9B=20N=C2=B04170=20-=20Fix=20en?= =?UTF-8?q?coding=20issue=20for=20long=20subjects=20(and=20other=20MIME=20?= =?UTF-8?q?UTF8=20encoded=20data=20on=20multiple=20lines)=20(#11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * * fix encoding issue for long subjects (and other MIME UTF8 encoded data on multiple lines) * * add sample email and test * Update test/emailsSample/readme.txt Co-authored-by: Molkobain * :recycle: Extract test long subject to a dedicated test method * Add other messages with non utf-8 encoded subjects * :bulb: Comment why UTF-8 is hardcoded Co-authored-by: jbostoen <-> Co-authored-by: Molkobain Co-authored-by: Pierre Goiffon --- classes/rawemailmessage.class.inc.php | 12 ++ test/TestEmlFiles.php | 34 ++- ...133_kb4170_multiple_lines_encoded_data.eml | 194 ++++++++++++++++++ test/emailsSample/readme.txt | 3 +- 4 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 test/emailsSample/email_133_kb4170_multiple_lines_encoded_data.eml diff --git a/classes/rawemailmessage.class.inc.php b/classes/rawemailmessage.class.inc.php index 9fa5a1f..27119e5 100644 --- a/classes/rawemailmessage.class.inc.php +++ b/classes/rawemailmessage.class.inc.php @@ -612,6 +612,18 @@ protected function ExtractHeadersAndRawBody($aLines) */ static protected function DecodeHeaderString($sInput) { + // Fix an encoding issue which may occur in multiline headers if it is indeed a utf-8 encoded string. + // Check if the string starts with =?utf-8? (sometimes with space in front) and ends with ?= + // This could happen also for other charsets but we weren't able to reproduce the same problem with another charset => so we're keeping UTF-8 hardcoded for now ! + if(preg_match('/^(\s|){1,}=\?utf-8\?(.*)\?=/', $sInput)) { + // Remove leading white space + $sInput = preg_replace('/^(\s)/', '', $sInput); + // Remove any space of UTF8 seperation in the lines which were merged in the ExtractHeadersAndRawBody() method + // Mind that it's possible that some lines of a multiline subject have different encodings! (utf-8-b; utf-8-q; ...) + // Examples: ?==?utf-8? , ?= =?utf-8? + $sInput = preg_replace('/\?=(\s|){1,}=\?utf-8\?/', '?==?utf-8?', $sInput); + } + $sOutput = iconv_mime_decode($sInput, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8'); return $sOutput; // Don't be too strict, continue on errors } diff --git a/test/TestEmlFiles.php b/test/TestEmlFiles.php index 587b59d..9ad15b5 100644 --- a/test/TestEmlFiles.php +++ b/test/TestEmlFiles.php @@ -36,10 +36,6 @@ public function testEmailMessage($sFileName, $sComment, $bToIsEmpty) $sSubject = $oEmail->GetSubject(); $this->assertNotEmpty($sSubject); - // - if (str_replace(APPROOT . 'env-production/combodo-email-synchro/test/emailsSample/','',$sFileName) == "multi_lines_header_parsing.eml"){ - $this->assertEquals( 'Re: autonet backup: nanobeam-ma15-sec-kunde.mgmt (1047) [Space.NET R-201909190397]',$sSubject); - } $aSender = $oEmail->GetSender(); $this->assertValidEmailCollection($aSender, 'Sender is valid'); @@ -71,7 +67,6 @@ public function testEmailMessage($sFileName, $sComment, $bToIsEmpty) $this->assertArrayHasKey('mimeType', $aAttachment); $this->assertArrayHasKey('content', $aAttachment); } - } private function assertEmptyCollection($aEmails, $message = '') @@ -129,12 +124,37 @@ public function EmailMessageProvider() $sTestName = basename($sFile); $aReturn[$sTestName] = array( - 'sFile' => $sFile, - 'sComment' => isset($aMetaData[$sTestName]['sComment']) ? $aMetaData[$sTestName]['sComment'] : '', + 'sFile' => $sFile, + 'sComment' => isset($aMetaData[$sTestName]['sComment']) ? $aMetaData[$sTestName]['sComment'] : '', 'bToIsEmpty' => isset($aMetaData[$sTestName]['bToIsEmpty']) ? $aMetaData[$sTestName]['bToIsEmpty'] : false, ); } return $aReturn; } + + /** + * @dataProvider MultilineLongSubjectsProvider + */ + public function testMultilineLongSubjects($sEmailFilename, $sSubjectExpectedValue): void + { + $sEmlFilePath = APPROOT.'env-production/combodo-email-synchro/test/emailsSample/'.$sEmailFilename; + $this->assertFileExists($sEmlFilePath, 'EML file is not existing'); + + $oEmail = RawEmailMessage::FromFile($sEmlFilePath); + $sSubjectActualValue = $oEmail->GetSubject(); + $this->assertSame($sSubjectExpectedValue, $sSubjectActualValue, "File `{$sEmailFilename}` : decoded subject has a wrong value"); + } + + public function MultilineLongSubjectsProvider(): array + { + return [ + ['multi_lines_header_parsing.eml', 'Re: autonet backup: nanobeam-ma15-sec-kunde.mgmt (1047) [Space.NET R-201909190397]'], + ['email_133_kb4170_multiple_lines_encoded_data.eml', 'FW: ⚠ This is a test with an emoji in the subject and a long subject message which will cause multi line subjects and encoding'], + ['email_065.eml', 'Re: iTop - Enhancement request - Classes et héritage'], + ['email_077.eml', 'Vente Flash Otto Office ! Spécial High-Tech, attention stocks limités !'], + ['email_107.eml', 'Fwd: Suite entretien téléphonique de ce jour'], + ['test gmail.eml', 'Test de mail envoyé avec Gmail et contenant un très très long sujet avec d\'aillleurs aussi des caractères accentués histoire de voir ce qui se passe dans ce cas là. Je sais c\'est un peu exagéré, enfin à peine...'], + ]; + } } diff --git a/test/emailsSample/email_133_kb4170_multiple_lines_encoded_data.eml b/test/emailsSample/email_133_kb4170_multiple_lines_encoded_data.eml new file mode 100644 index 0000000..3f6f9e3 --- /dev/null +++ b/test/emailsSample/email_133_kb4170_multiple_lines_encoded_data.eml @@ -0,0 +1,194 @@ +Received: from DB3PR0202MB3497.eurprd02.prod.outlook.com (2603:10a6:8:5::27) + by AM9PR02MB6595.eurprd02.prod.outlook.com with HTTPS; Sat, 17 Jul 2021 + 08:50:16 +0000 +Received: from DBBPR09CA0036.eurprd09.prod.outlook.com (2603:10a6:10:d4::24) + by DB3PR0202MB3497.eurprd02.prod.outlook.com (2603:10a6:8:5::27) with + Microsoft SMTP Server (version=TLS1_2, + cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.26; Sat, 17 Jul + 2021 08:50:15 +0000 +Received: from DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com + (2603:10a6:10:d4:cafe::cb) by DBBPR09CA0036.outlook.office365.com + (2603:10a6:10:d4::24) with Microsoft SMTP Server (version=TLS1_2, + cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.21 via Frontend + Transport; Sat, 17 Jul 2021 08:50:15 +0000 +Received: from EUR03-VE1-obe.outbound.protection.outlook.com (40.92.72.92) by + DB5EUR03FT053.mail.protection.outlook.com (10.152.21.119) with Microsoft SMTP + Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id + 15.20.4331.21 via Frontend Transport; Sat, 17 Jul 2021 08:50:15 +0000 +Received: from AM9PR02MB6595.eurprd02.prod.outlook.com (2603:10a6:20b:2c8::23) + by AM9PR02MB6753.eurprd02.prod.outlook.com (2603:10a6:20b:2c6::14) with + Microsoft SMTP Server (version=TLS1_2, + cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.23; Sat, 17 Jul + 2021 08:50:15 +0000 +Received: from AM9PR02MB6595.eurprd02.prod.outlook.com + ([fe80::aca0:a91f:91e5:6368]) by AM9PR02MB6595.eurprd02.prod.outlook.com + ([fe80::aca0:a91f:91e5:6368%4]) with mapi id 15.20.4331.021; Sat, 17 Jul 2021 + 08:50:15 +0000 +From: Jeffrey Bostoen +To: Jeffrey Bostoen +Subject: + =?utf-8?B?Rlc6IOKaoCBUaGlzIGlzIGEgdGVzdCB3aXRoIGFuIGVtb2ppIGluIHRoZSBz?= + =?utf-8?B?dWJqZWN0IGFuZCBhIGxvbmcgc3ViamVjdCBtZXNzYWdlIHdoaWNoIHdpbGwg?= + =?utf-8?Q?cause_multi_line_subjects_and_encoding?= +Thread-Topic: + =?utf-8?B?4pqgIFRoaXMgaXMgYSB0ZXN0IHdpdGggYW4gZW1vamkgaW4gdGhlIHN1Ympl?= + =?utf-8?B?Y3QgYW5kIGEgbG9uZyBzdWJqZWN0IG1lc3NhZ2Ugd2hpY2ggd2lsbCBjYXVz?= + =?utf-8?Q?e_multi_line_subjects_and_encoding?= +Thread-Index: Add66Lz27pXF+0kbR2eqDdtHTwhijQ== +X-MS-Exchange-MessageSentRepresentingType: 1 +Date: Sat, 17 Jul 2021 08:50:15 +0000 +Message-ID: + +Accept-Language: en-US +Content-Language: en-US +X-MS-Exchange-Organization-AuthAs: Anonymous +X-MS-Exchange-Organization-AuthSource: + DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com +X-MS-Has-Attach: +X-MS-Exchange-Organization-Network-Message-Id: + 4be8244d-5fbc-4542-d46b-08d948ffe5cb +X-MS-Exchange-Organization-SCL: -1 +X-MS-Exchange-Organization-PCL: 2 +X-MS-TNEF-Correlator: +X-MS-Exchange-Organization-RecordReviewCfmType: 0 +received-spf: Pass (protection.outlook.com: domain of outlook.com designates + 40.92.72.92 as permitted sender) receiver=protection.outlook.com; + client-ip=40.92.72.92; helo=EUR03-VE1-obe.outbound.protection.outlook.com; +x-ms-publictraffictype: Email +authentication-results: spf=pass (sender IP is 40.92.72.92) + smtp.mailfrom=outlook.com; outlook.com; dkim=pass (signature was verified) + header.d=outlook.com;outlook.com; dmarc=pass action=none + header.from=outlook.com;compauth=pass reason=100 +x-ms-traffictypediagnostic: AM9PR02MB6753:|DB3PR0202MB3497: +x-ms-office365-filtering-correlation-id: 4be8244d-5fbc-4542-d46b-08d948ffe5cb +x-microsoft-antispam: BCL:0; +dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; + s=selector1; + h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; + bh=mspojGaONsq902WbV1dQkLi61Jr9QSSvKY60AaXuLTo=; + b=i4c8oK+yTOVtEN8JBkwonO6Jz1zNi2lCWd/55AtNM16kJ+Wa8bYInJsQXkKrlKT1q/qouXvJ32G2l18SRHncA9doCACzodaa7MXcJM/sospSjsCv+aJY31GlEdoCot+8FXqnzhlJKmellrWSEen6e17zUosE8tsx+XpOZGsmgsnWNqQM+DbvKyMg/qguEnsYdVGHgbVXD4LaS8rxwePP9AdZotA6CkeRIt24wb8xHbsxu4FGpAeXVVmJ6+APHHP0p4c4gy3Wm8I/CEP8mhaJuSCBSYXjYlx/h7AfT4/58ZH00rCFgq8bJnLOosjLqC5BubgkARt+6nR6Kii3ER11pg== +arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; + b=QZGy2tiY7WJYbcXjdlB7F2qBV9CZ+zJdBnZzj3qyL4mHbLWnZF7cpwj1y4P4TfNKDYoOMLzNwKyPJat1pWp53hTvtu+yNB3kNuu3Jfe0eT9fUuFSWRUjdn+v7sdVGFfWsDOFhWNLV3kEkd8iqa2fAS6gp4QBoCce3CTsg/L/zL5x/jNPg9xDwQ5687idhlBXhFBMTijv4PwFLEtQWmAcr0+b02BgMdohLLuEIRTnvI8C/PE1Bab0B1oHIuXevpsd9EDka/KsJ9EsaTxVblfrNzBwefYSgMi8+SLL57IBZoaKmFHunhGyv/8BdIApRPEs3RIfK2NUi0azNN2xDSQCVg== +arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; + s=arcselector9901; + h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; + bh=mspojGaONsq902WbV1dQkLi61Jr9QSSvKY60AaXuLTo=; + b=lyH2zb57kZNoayfxaaDltoCBfblTMtLjDlVFMTSH+YPzELLSCyCWF8IM+3kcAArcRka/JVE5xmzkpe5gRfiaiTMqqfQ01zPKSwqmR/CaNS/AP/xW/M29Bqt9zEFvKMc7afmHdKrrwyUrzc6/CMSbD66kdi8ld4uYC4DtYWBt0fDI8FzZLOqmmgoxEzrQokm9+hgL8m8+tqAjnKxqbr33FZBdEmHwYW1HDHcM5f/chaqDopKTjeLd0KirYAX4zRPJuIoqrc73qLPtLInlB7K/j2SXeW8d72aIr/TBaildM1rGgdTrQRVlWu8G1EsI4G+i00fPNMmCEEsBPpeBvHr5Sg== +arc-authentication-results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; + dkim=none; arc=none +x-incomingtopheadermarker: + OriginalChecksum:A96AD7D2022476EF961C4282BE21E36BEA2BD06C46E27FFBC59610BA4A9B1B0C;UpperCasedChecksum:283449498150FF2E4E1E7B15F9DD0162FB1D71220C11312CECA6811C4C237384;SizeAsReceived:5742;Count:39 +x-tmn: + [OMEt7oPA69SRnbkhgllIM0tC3985XvwqKrKLRR1r0+hZNnsyRXLazITMUzhOcNbtg7Drft9omUQ=] +x-incomingheadercount: 39 +x-eopattributedmessage: 0 +x-microsoft-antispam-message-info: + qanjKyCfCofkS5dtt6yFCfQLLfPUntrA1RgtL6hl07681qUWanZmjp4LuN4DQWwfEpJ1b7Ki0+yLxzFoTH6eIBbjGylrN2r1p9TrWnaWaeBgi15ihsdf+E9FKuLaDy7FV9zQUJ/oECk4hGaqjlmywFurN1/v8IO+hA9+Enf/VhT8pjIHl52WwMUri6vc2iBevME6CAwpCKAfJAlKJdf/jxwvfTwub6fqM3STHFR5mY8F3SiBywv3BPoZ/Ro72RWojMrgIW7Ri7HHP1YhsNK+nLO90SSxoE8uwBLz4znyJF7nGgKSnkg3Ct0TU0Rsq0Ezkau6B8rBADETgQtwjYuJYErUpUETlzznepEVGxtur1sf9FojL6zslayFVK7GoyWWHp67QxRVnzxoJL1L7kz9fYjb/71K8yU0imz8uS3GW0N/WggW+c+Izxor1upNwvES +x-ms-exchange-transport-forked: True +x-ms-exchange-crosstenant-rms-persistedconsumerorg: + 00000000-0000-0000-0000-000000000000 +x-ms-exchange-crosstenant-network-message-id: + 4be8244d-5fbc-4542-d46b-08d948ffe5cb +x-ms-exchange-crosstenant-originalarrivaltime: 17 Jul 2021 08:50:15.8033 (UTC) +x-ms-exchange-crosstenant-fromentityheader: Internet +x-ms-exchange-crosstenant-id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa +x-ms-exchange-transport-crosstenantheadersstamped: DB3PR0202MB3497 +x-microsoft-antispam-untrusted: BCL:0; +x-microsoft-antispam-message-info-original: + qanjKyCfCofkS5dtt6yFCfQLLfPUntrA1RgtL6hl07681qUWanZmjp4LuN4DQWwfEpJ1b7Ki0+yLxzFoTH6eIBbjGylrN2r1p9TrWnaWaeBgi15ihsdf+E9FKuLaDy7FV9zQUJ/oECk4hGaqjlmywFurN1/v8IO+hA9+Enf/VhT8pjIHl52WwMUri6vc2iBevME6CAwpCKAfJAlKJdf/jxwvfTwub6fqM3STHFR5mY8F3SiBywv3BPoZ/Ro72RWojMrgIW7Ri7HHP1YhsNK+nLO90SSxoE8uwBLz4znyJF7nGgKSnkg3Ct0TU0Rsq0Ezkau6B8rBADETgQtwjYuJYErUpUETlzznepEVGxtur1sf9FojL6zslayFVK7GoyWWHp67QxRVnzxoJL1L7kz9fYjb/71K8yU0imz8uS3GW0N/WggW+c+Izxor1upNwvES +x-eoptenantattributedmessage: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa:0 +x-ms-exchange-transport-crosstenantheadersstripped: + DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com +x-ms-exchange-transport-crosstenantheaderspromoted: + DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com +x-ms-office365-filtering-correlation-id-prvs: + c8cc0d18-4814-4f4e-6695-08d948ffe55f +x-ms-exchange-crosstenant-authsource: + DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com +x-ms-exchange-crosstenant-authas: Anonymous +x-ms-exchange-slblob-mailprops: + 79Jo46q8hhDyTo9P99hRQAQ3TG/q6CYJf2dXUHgPxhw5xFlpSmqJC8wUeSrekrU8DDIi3vzhSqXfeINCEzIM6uLn8G1c0L34Q6fAuTRwufNl6eq7FX2JxXAu5dwXTGDBCq6YVzLJU49nwMsarBnBK544bmPfWTwYZvQYKll5d5+SkUtp2IG4O+kp9apkPS2FpXfzuNXqordYzucgThu8AhlD8mfSdrCo+4Fl9sTTqzLnwtWbGTfP3JRsHRXjTN1rGUEQvUFkQup1a01Oee0fGvIxuDOkua4k+wIFI9cfPQHkxmWv+4CRUv/MD23lWRPzYJvldH1UczWlAf9lZ+IyW0p8ozoZ8LEaG8McRSMqzlA/0T/OJqJpNpReFgKCZCUsJXYUWGVAURuHCqVKyYnmQEMoHmAcjnWG+2JHRrNkpVSGrB5vAffGQz/GFBk/XahlqzOH4Nv/cFQvikhqIgGeebD3jDocphMmdm35gK6DM6apvvOqAKk5Bm0P1wtoApOvo+4kUTW+AznV+sTX7pFsn0rLt/BMEzLKedljqawkg3StPPhq9HwMF9l9kPMlMt4Kg5rO3c01gSEvA4YLRtFS16OqLFo2O3xdfLq7feEUZuwb7JWfqsXBPshJwecJH0ZmQlH/2jSSwOOMuzAzxUJfujF9c1wY7At+P/o3oOQ485A2H/nApQteD6fuqx8/Yg1S +x-ms-exchange-transport-endtoendlatency: 00:00:00.6262636 +x-ms-exchange-processed-by-bccfoldering: 15.20.4331.021 +x-ms-exchange-antispam-messagedata-chunkcount: 1 +x-ms-exchange-antispam-messagedata-0: + pJtUE+mtq1sTHMEFg0TYjuiYhAxLcsifIYf1DfRjvESscVRBijtQnb5V+MN+rRl69EO+xP5QRwLB0CmVt6xugOLTjCyBvQpMgN8iF4giPCjYtxQ3sa7zGWVL0dPI3GWDyQzaP6I0dB1AZGEWkjlfQI4c83EqKphtfy20SEjC1s1+zpDnfXJeu2BVBSyguiGaPiPYtqLe6F50wegrNYFN1Q== +X-Microsoft-Antispam-Mailbox-Delivery: + dkl:0;rwl:0;ucf:0;jmr:0;ex:0;auth:1;dest:I;OFR:SpamFilterPass;ENG:(5062000282)(90000117)(90011020)(91015020)(91040095)(91045095)(9050020)(9060116)(9100314)(5061607266)(5061608174)(1004385)(4900115)(2008001114)(2008000189)(4920090)(6220004)(4950131)(4990090)(9110004); +X-Message-Info: + 5vMbyqxGkde5GadX+p2DKVRC3kqp4YEKtp6xwUwTfx2EBD4z0gVgwEJnEqnROXg9dqSxmrjAVFySW9dYMXxyta/ta8og7xGFmMwdx2+feSgPJ3v44XMRsBF1EOVfJjSiq5PaML3nnQz1WjI1bAvAj00oNtVmfDokGAWzuyaB2Muy3alrxMFLFY7fo39L9mRLsGu+qOZzJDw8YCB+05PxQw== +X-Message-Delivery: Vj0xLjE7dXM9MDtsPTA7YT0xO0Q9MTtHRD0xO1NDTD0tMQ== +X-Microsoft-Antispam-Message-Info: + =?utf-8?B?bStoU1RIcVpiQU9SaVUxRFBuZDJvVDAreDBFalR3ditiVnJSTzFKemhUMEJx?= + =?utf-8?B?WWdoSko3UTJheVdhVmlYUk1rd1NSM3VlbWlrNWNGK0VyZHJCckIxVThRc0c2?= + =?utf-8?B?Z1BzUmphWG1IaTFIbk9vT0VvcWVPNGlCdStwSUJaeVhpTmpJbEt2RVRFbXhJ?= + =?utf-8?B?SFVhOFpUdllqSlFQWUZLbS9QemR5YlFKKytobmQ2ZXArRmhlbU80dHJGeDBE?= + =?utf-8?B?U0tpckRqd3N6TzJmWmZnZUU2WGVaOEk2R1ZSYmFWZ1NsYitvL0tJMkI4c2Rs?= + =?utf-8?B?NVV2bS9uTXhoSjE0RGo1dVB3cXFkVmZuMks3NVd1Q2FXOUc5alkzSitkdzhq?= + =?utf-8?B?YkVocVVvcndoK1RLTk9CODJPZHBmditXdjBMMnRDRnFZelk0a3ErV3NwbVFJ?= + =?utf-8?B?dGJkeVJBU2hHKzFRcUE3L2VjSlhBSVA5TVI5SS9QeDhtVk1EOHRxWGVMTzJo?= + =?utf-8?B?bStkZWRyYjhZNXFKM2x2ZThaemdCZTh6bjRuN0JTNzhDcm5SeFJ2QzVTZVVB?= + =?utf-8?B?anRkNmZjUXY1cm1RZTRCSndka3J0Y0pvK3RTeVlJakdiV3dSTzBtRVVWZ0xQ?= + =?utf-8?B?ay9lVlBMbU8vdjArcDlTaHcvc2RFUDYycEI2Z2NCa0R1ZDA0ZFk1RldRUGpC?= + =?utf-8?B?d3lidUVXUmpnajNneVBEUjNSZFh5MktKenBWUldOS3M2VHFtM1FmRG5kYUwr?= + =?utf-8?B?bWY2TnVPTExsS3VrZGI0Rmt1b3hQRHJ0ZVJjRWQ3OTBYZDN2akN5dm1EdVRr?= + =?utf-8?B?QXZ6SmR3OGhrMGFwRlpuRCt1TGhJS0IxZjB4MHJtMzFsbUdLRDQraEEyNFUz?= + =?utf-8?B?TXJsRm5EeVc4dGtOT0pPWEYvTSttMm1VM01RUjNKYytXY0NhZy9GZHd4N0d0?= + =?utf-8?B?Yy9yZUttV2wwK1NzcXF2cGpPa0FXSlZqOFVVSlE4TDRZeEx5QURhOHZJa3Z2?= + =?utf-8?B?WjIwZi9FZk5XQ1pjOWFOZUVJdjVBTWh4MFhxWWg5enVWQzV3MkIzTE1YOWUw?= + =?utf-8?B?blZBcW4xY0M5QjJLTEdYNUg3MGFPMWFYTmdMdUp4MlhmYVhsQmhvYU9HMUZo?= + =?utf-8?B?bllBRFBSODlIa2RYSG9hdy9PNTlIZ0kyOThXNEczZE9GdXprSENaZEJHUEkr?= + =?utf-8?B?YlJUQTJHOW5LeWd5b3JrR3UwOEdVQ0oxMHlNOHVMTFRPblhyVEp1UHpxNTZT?= + =?utf-8?B?SEh0dFFKTmhUVmpwa1ZvV1dRcmFlV0pVb1hZMnB5enNwd01udXB6N1pEcG1t?= + =?utf-8?B?R2NUaVVsVDhoNnhYY0wyU1p0WTh2Zm8rU0hKOGp1S0pqcVdpcDBCMEc3NHY0?= + =?utf-8?B?VnJ5VDRidGJlSEgzRjhIaVRVR0RVZVIwVXhhMlYwVmVkS3VjUklVWG1yR2pm?= + =?utf-8?B?T2lwR2Z3NERwK3pFYk1Nek5SUkZydmNMcmJDUlZFLzBlNkdnNTVhelNDeHh3?= + =?utf-8?B?SEhmR2xJbXEwRTVCN21NNTVEZzlhR3oxTVczOTRnPT0=?= +Content-Type: multipart/alternative; + boundary="_000_AM9PR02MB6595D89D8644FDF29ECF88CAD8109AM9PR02MB6595eurp_" +MIME-Version: 1.0 + +--_000_AM9PR02MB6595D89D8644FDF29ECF88CAD8109AM9PR02MB6595eurp_ +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: base64 + +DQoNCktpbmQgcmVnYXJkcw0KTWV0IHZyaWVuZGVsaWprZSBncm9ldGVuDQoNCkplZmZyZXkgQm9z +dG9lbg0KDQo= + +--_000_AM9PR02MB6595D89D8644FDF29ECF88CAD8109AM9PR02MB6595eurp_ +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: base64 + +PGh0bWw+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0i +dGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29udGVu +dD0iTWljcm9zb2Z0IFdvcmQgMTUgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPHN0eWxlPjwhLS0NCi8q +IEZvbnQgRGVmaW5pdGlvbnMgKi8NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6IkNhbWJyaWEg +TWF0aCI7DQoJcGFub3NlLTE6MiA0IDUgMyA1IDQgNiAzIDIgNDt9DQpAZm9udC1mYWNlDQoJe2Zv +bnQtZmFtaWx5OkNhbGlicmk7DQoJcGFub3NlLTE6MiAxNSA1IDIgMiAyIDQgMyAyIDQ7fQ0KLyog +U3R5bGUgRGVmaW5pdGlvbnMgKi8NCnAuTXNvTm9ybWFsLCBsaS5Nc29Ob3JtYWwsIGRpdi5Nc29O +b3JtYWwNCgl7bWFyZ2luOjBjbTsNCglmb250LXNpemU6MTEuMHB0Ow0KCWZvbnQtZmFtaWx5OiJD +YWxpYnJpIixzYW5zLXNlcmlmOw0KCW1zby1mYXJlYXN0LWxhbmd1YWdlOkVOLVVTO30NCnNwYW4u +RW1haWxTdHlsZTE3DQoJe21zby1zdHlsZS10eXBlOnBlcnNvbmFsLWNvbXBvc2U7DQoJZm9udC1m +YW1pbHk6IkNhbGlicmkiLHNhbnMtc2VyaWY7DQoJY29sb3I6d2luZG93dGV4dDt9DQouTXNvQ2hw +RGVmYXVsdA0KCXttc28tc3R5bGUtdHlwZTpleHBvcnQtb25seTsNCglmb250LWZhbWlseToiQ2Fs +aWJyaSIsc2Fucy1zZXJpZjsNCgltc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUzt9DQpAcGFnZSBX +b3JkU2VjdGlvbjENCgl7c2l6ZTo2MTIuMHB0IDc5Mi4wcHQ7DQoJbWFyZ2luOjcyLjBwdCA3Mi4w +cHQgNzIuMHB0IDcyLjBwdDt9DQpkaXYuV29yZFNlY3Rpb24xDQoJe3BhZ2U6V29yZFNlY3Rpb24x +O30NCi0tPjwvc3R5bGU+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFwZWRlZmF1bHRz +IHY6ZXh0PSJlZGl0IiBzcGlkbWF4PSIxMDI2IiAvPg0KPC94bWw+PCFbZW5kaWZdLS0+PCEtLVtp +ZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFwZWxheW91dCB2OmV4dD0iZWRpdCI+DQo8bzppZG1h +cCB2OmV4dD0iZWRpdCIgZGF0YT0iMSIgLz4NCjwvbzpzaGFwZWxheW91dD48L3htbD48IVtlbmRp +Zl0tLT4NCjwvaGVhZD4NCjxib2R5IGxhbmc9ImVuLUJFIiBsaW5rPSIjMDU2M0MxIiB2bGluaz0i +Izk1NEY3MiIgc3R5bGU9IndvcmQtd3JhcDpicmVhay13b3JkIj4NCjxkaXYgY2xhc3M9IldvcmRT +ZWN0aW9uMSI+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBsYW5nPSJlbi1CRSI+PG86cD4m +bmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gbGFuZz0i +ZW4tQkUiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi +PjxzcGFuIGxhbmc9Ik5MLUJFIiBzdHlsZT0iY29sb3I6YmxhY2siPktpbmQgcmVnYXJkczxvOnA+ +PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIGxhbmc9Ik5MLUJF +IiBzdHlsZT0iY29sb3I6YmxhY2siPk1ldCB2cmllbmRlbGlqa2UgZ3JvZXRlbjxicj4NCjxicj4N +CkplZmZyZXkgQm9zdG9lbjwvc3Bhbj48c3BhbiBsYW5nPSJOTC1CRSIgc3R5bGU9ImNvbG9yOmJs +YWNrO21zby1mYXJlYXN0LWxhbmd1YWdlOiMyMDAwIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8 +cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBsYW5nPSJlbi1CRSI+PG86cD4mbmJzcDs8L286cD48 +L3NwYW4+PC9wPg0KPC9kaXY+DQo8L2JvZHk+DQo8L2h0bWw+DQo= + +--_000_AM9PR02MB6595D89D8644FDF29ECF88CAD8109AM9PR02MB6595eurp_-- diff --git a/test/emailsSample/readme.txt b/test/emailsSample/readme.txt index 8382cd5..1f71d5a 100644 --- a/test/emailsSample/readme.txt +++ b/test/emailsSample/readme.txt @@ -1,2 +1,3 @@ email_131.eml: Email with "us-ascii" charset and binary attachment. (Issue was that attachment was converted through iconv() when it should not) -email_132.eml: Email with uppercase content-transfer-encoding ("BASE64"). (Issue was that mail had "Quote-Printable" and "BASE64" instead of lowercase ones) \ No newline at end of file +email_132.eml: Email with uppercase content-transfer-encoding ("BASE64"). (Issue was that mail had "Quote-Printable" and "BASE64" instead of lowercase ones) +email_133_kb4170_multiple_lines_encoded_data.eml: Email with a multiline subject with different MIME encodings (Issue that caused white space in front of subject)