Added search keywords:

has:(files,files,attachment,attachments), 
   (has,is):(flagged,starred|unflagged,unstarred|read,seen|unread,unseen),
   (larger,size,bigger,minsize): (10K|10M|10G),
   (smaller,maxsize): (10K|10M|10G)

Improved search (gmail special search X-GM-RAW)
Improved uids cache (reducing the number of cached tags)
This commit is contained in:
RainLoop Team 2014-04-23 16:26:18 +04:00
parent db5835a4c3
commit 3da3861545
2 changed files with 156 additions and 28 deletions

View file

@ -709,7 +709,7 @@ class MailClient
*/ */
public static function GenerateHash($sFolder, $iCount, $iUnseenCount, $sUidNext) public static function GenerateHash($sFolder, $iCount, $iUnseenCount, $sUidNext)
{ {
$iUnseenCount = 0; $iUnseenCount = 0; // unneccessery
return \md5($sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext); return \md5($sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext);
} }
@ -861,14 +861,15 @@ class MailClient
/** /**
* @param string $sSearch * @param string $sSearch
* @param bool $bDetectGmail = true
* *
* @return string * @return string
*/ */
private function escapeSearchString($sSearch) private function escapeSearchString($sSearch, $bDetectGmail = true)
{ {
return ('ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost())) // gmail return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) &&
? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost()))
: $this->oImapClient->EscapeString($sSearch); ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
} }
/** /**
@ -889,6 +890,42 @@ class MailClient
return $iResult; return $iResult;
} }
/**
* @param string $sSize
*
* @return int
*/
private function parseFriendlySize($sSize)
{
$sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize);
$iResult = 0;
$aMatch = array();
if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2]))
{
$iResult = (int) $aMatch[1];
switch (\strtoupper($aMatch[2]))
{
case 'K':
case 'KB':
$iResult *= 1024;
case 'M':
case 'MB':
$iResult *= 1024;
case 'G':
case 'GB':
$iResult *= 1024;
}
}
else
{
$iResult = (int) $sSize;
}
return $iResult;
}
/** /**
* @param string $sSearch * @param string $sSearch
* *
@ -902,8 +939,10 @@ class MailClient
$aCache = array(); $aCache = array();
$sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize';
$sSearch = \trim(\preg_replace('/[\s]+/', ' ', $sSearch)); $sSearch = \trim(\preg_replace('/[\s]+/', ' ', $sSearch));
$sSearch = \trim(\preg_replace('/(e?mail|from|to|subject|has|date|text|body): /i', '\\1:', $sSearch)); $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch));
$mMatch = array(); $mMatch = array();
\preg_match_all('/".*?(?<!\\\)"/', $sSearch, $mMatch); \preg_match_all('/".*?(?<!\\\)"/', $sSearch, $mMatch);
@ -939,7 +978,7 @@ class MailClient
} }
$mMatch = array(); $mMatch = array();
\preg_match_all('/(e?mail|from|to|subject|has|date|text|body):([^\s]*)/i', $sSearch, $mMatch); \preg_match_all('/('.$sReg.'):([^\s]*)/i', $sSearch, $mMatch);
if (\is_array($mMatch) && isset($mMatch[1]) && \is_array($mMatch[1]) && 0 < \count($mMatch[1])) if (\is_array($mMatch) && isset($mMatch[1]) && \is_array($mMatch[1]) && 0 < \count($mMatch[1]))
{ {
if (\is_array($mMatch[0])) if (\is_array($mMatch[0]))
@ -967,12 +1006,31 @@ class MailClient
case 'FROM': case 'FROM':
case 'TO': case 'TO':
case 'SUBJECT': case 'SUBJECT':
case 'IS':
case 'HAS': case 'HAS':
case 'SIZE':
case 'SMALLER':
case 'LARGER':
case 'BIGGER':
case 'MAXSIZE':
case 'MINSIZE':
case 'DATE': case 'DATE':
if ('MAIL' === $sName) if ('MAIL' === $sName)
{ {
$sName = 'EMAIL'; $sName = 'EMAIL';
} }
if ('BODY' === $sName)
{
$sName = 'TEXT';
}
if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName)
{
$sName = 'LARGER';
}
if ('MAXSIZE' === $sName)
{
$sName = 'SMALLER';
}
$aResult[$sName] = $sValue; $aResult[$sName] = $sValue;
break; break;
} }
@ -1003,11 +1061,15 @@ class MailClient
$oSearchBuilder = \MailSo\Imap\SearchBuilder::NewInstance(); $oSearchBuilder = \MailSo\Imap\SearchBuilder::NewInstance();
if (0 < \strlen(\trim($sSearch))) if (0 < \strlen(\trim($sSearch)))
{ {
$sGmailRawSearch = '';
$sResultBodyTextSearch = '';
$aLines = $this->parseSearchString($sSearch); $aLines = $this->parseSearchString($sSearch);
$bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1');
if (1 === \count($aLines) && isset($aLines['OTHER'])) if (1 === \count($aLines) && isset($aLines['OTHER']))
{ {
if (true) if (true) // headers only
{ {
$sValue = $this->escapeSearchString($aLines['OTHER']); $sValue = $this->escapeSearchString($aLines['OTHER']);
@ -1018,7 +1080,15 @@ class MailClient
} }
else else
{ {
$oSearchBuilder->AddAnd('TEXT', $this->escapeSearchString($aLines['OTHER'])); $sMainText = \trim(\trim(\preg_replace('/[\s]+/', ' ', $aLines['OTHER'])), '"');
if ($bIsGmail)
{
$sGmailRawSearch .= ' '.$sMainText;
}
else
{
$sResultBodyTextSearch .= ' '.$sMainText;
}
} }
} }
else else
@ -1060,23 +1130,59 @@ class MailClient
$oSearchBuilder->AddAnd('SUBJECT', $sValue); $oSearchBuilder->AddAnd('SUBJECT', $sValue);
break; break;
case 'OTHER': case 'OTHER':
case 'BODY':
case 'TEXT': case 'TEXT':
$sMainText .= ' '.$sRawValue; $sMainText .= ' '.$sRawValue;
break; break;
case 'HAS': case 'HAS':
if (false !== \strpos($sRawValue, 'attach')) $aValue = \explode(',', \strtolower($sRawValue));
$aValue = \array_map('trim', $aValue);
$aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
{ {
$oSearchBuilder->AddAnd('HEADER CONTENT-TYPE', '"MULTIPART/MIXED"'); if ($bIsGmail)
{
$sGmailRawSearch .= ' has:attachment';
}
else
{
// Simple, is not detailed search (Sometimes doesn't work)
$oSearchBuilder->AddAnd('HEADER CONTENT-TYPE', '"MULTIPART/MIXED"');
}
} }
if (false !== strpos($sRawValue, 'flag') || false !== strpos($sRawValue, 'star'))
case 'IS':
$aValue = \explode(',', \strtolower($sRawValue));
$aValue = \array_map('trim', $aValue);
$aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned');
$aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
{ {
$oSearchBuilder->AddAnd('FLAGGED'); $oSearchBuilder->AddAnd('FLAGGED');
} }
if (false !== strpos($sRawValue, 'unseen')) else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
{
$oSearchBuilder->AddAnd('UNFLAGGED');
}
$aCompareArray = array('unread', 'unseen');
$aCompareArray2 = array('read', 'seen');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
{ {
$oSearchBuilder->AddAnd('UNSEEN'); $oSearchBuilder->AddAnd('UNSEEN');
} }
else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
{
$oSearchBuilder->AddAnd('SEEN');
}
break;
case 'LARGER':
$oSearchBuilder->AddAnd('LARGER', $this->parseFriendlySize($sRawValue));
break;
case 'SMALLER':
$oSearchBuilder->AddAnd('SMALLER', $this->parseFriendlySize($sRawValue));
break; break;
case 'DATE': case 'DATE':
$iDateStampFrom = $iDateStampTo = 0; $iDateStampFrom = $iDateStampTo = 0;
@ -1119,12 +1225,31 @@ class MailClient
} }
} }
if ('' !== trim($sMainText)) if ('' !== \trim($sMainText))
{ {
$sMainText = trim(trim(preg_replace('/[\s]+/', ' ', $sMainText)), '"'); $sMainText = \trim(\trim(preg_replace('/[\s]+/', ' ', $sMainText)), '"');
$oSearchBuilder->AddAnd('TEXT', $this->escapeSearchString($sMainText)); if ($bIsGmail)
{
$sGmailRawSearch .= ' '.$sMainText;
}
else
{
$sResultBodyTextSearch .= ' '.$sMainText;
}
} }
} }
$sGmailRawSearch = \trim($sGmailRawSearch);
if ($bIsGmail && 0 < \strlen($sGmailRawSearch))
{
$oSearchBuilder->AddAnd('X-GM-RAW', $this->escapeSearchString($sGmailRawSearch, false));
}
$sResultBodyTextSearch = \trim($sResultBodyTextSearch);
if (0 < \strlen($sResultBodyTextSearch))
{
$oSearchBuilder->AddAnd('TEXT', $this->escapeSearchString($sResultBodyTextSearch));
}
} }
return $oSearchBuilder; return $oSearchBuilder;
@ -1427,6 +1552,7 @@ class MailClient
$iMessageCount = 0; $iMessageCount = 0;
$iMessageRealCount = 0; $iMessageRealCount = 0;
$iMessageUnseenCount = 0; $iMessageUnseenCount = 0;
$iMessageCacheCount = 100;
$sUidNext = '0'; $sUidNext = '0';
$sSerializedHash = ''; $sSerializedHash = '';
$bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false;
@ -1463,7 +1589,7 @@ class MailClient
$sSearchCriterias = $this->getSearchBuilder($sSearch)->Complete(); $sSearchCriterias = $this->getSearchBuilder($sSearch)->Complete();
if ($oCacher && $oCacher->IsInited()) if ($iMessageCacheCount < $iMessageRealCount && $oCacher && $oCacher->IsInited())
{ {
$sSerializedHash = $sSerializedHash =
($bUseSortIfSupported ? 'S': 'N').'/'. ($bUseSortIfSupported ? 'S': 'N').'/'.
@ -1472,16 +1598,17 @@ class MailClient
$this->oImapClient->GetConnectedHost().':'. $this->oImapClient->GetConnectedHost().':'.
$this->oImapClient->GetConnectedPort().'/'. $this->oImapClient->GetConnectedPort().'/'.
$oMessageCollection->FolderName.'/'. $oMessageCollection->FolderName.'/'.
$oMessageCollection->FolderHash.'/'.
$sSearchCriterias; $sSearchCriterias;
$sSerializedUids = $oCacher->Get($sSerializedHash); $sSerialized = $oCacher->Get($sSerializedHash);
if (!empty($sSerializedUids)) if (!empty($sSerialized))
{ {
$aSerializedUids = @\unserialize($sSerializedUids); $aSerialized = @\unserialize($sSerialized);
if (\is_array($aSerializedUids)) if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
\is_array($aSerialized['Uids']) &&
$oMessageCollection->FolderHash === $aSerialized['FolderHash'])
{ {
$aIndexOrUids = $aSerializedUids; $aIndexOrUids = $aSerialized['Uids'];
$bCacher = true; $bCacher = true;
} }
} }
@ -1541,7 +1668,10 @@ class MailClient
if ($bIndexAsUid && !$bCacher && \is_array($aIndexOrUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash)) if ($bIndexAsUid && !$bCacher && \is_array($aIndexOrUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash))
{ {
$oCacher->Set($sSerializedHash, \serialize($aIndexOrUids)); $oCacher->Set($sSerializedHash, \serialize(array(
'FolderHash' => $oMessageCollection->FolderHash,
'Uids' => $aIndexOrUids
)));
} }
if (\is_array($aIndexOrUids)) if (\is_array($aIndexOrUids))

View file

@ -174,10 +174,8 @@ class Service
$aData = $this->startUpData($bAdmin); $aData = $this->startUpData($bAdmin);
$bCacheEnabled = $this->oActions->Config()->Get('labs', 'cache_system_data', true);
$sCacheFileName = ''; $sCacheFileName = '';
if ($bCacheEnabled) if ($this->oActions->Config()->Get('labs', 'cache_system_data', true))
{ {
$sCacheFileName = 'TMPL:'.$aData['Hash']; $sCacheFileName = 'TMPL:'.$aData['Hash'];
$sResult = $this->oActions->Cacher()->Get($sCacheFileName); $sResult = $this->oActions->Cacher()->Get($sCacheFileName);