IMAPResult IMAPSearchParser::ParseSegment_(std::shared_ptr<IMAPSimpleCommandParser> pSimpleParser, int ¤tWord, std::shared_ptr<IMAPSearchCriteria> pCriteria, int iRecursion) { iRecursion++; if (iRecursion > 50) { return IMAPResult(IMAPResult::ResultNo, "Search failed due to excessive search expression recursion."); } int originalCriteriaCount = (int) pCriteria->GetSubCriterias().size(); for (; currentWord < (int) pSimpleParser->WordCount(); currentWord++) { std::shared_ptr<IMAPSimpleWord> pWord = pSimpleParser->Word(currentWord); String sCurCommand = pWord->Value().ToUpper(); if (sCurCommand == _T("OR")) { // We have a sub argument. std::shared_ptr<IMAPSearchCriteria> pSubCriteria = std::shared_ptr<IMAPSearchCriteria> (new IMAPSearchCriteria()); pSubCriteria->SetType(IMAPSearchCriteria::CTSubCriteria); pSubCriteria->SetIsOR(true); currentWord++; IMAPResult result = ParseSegment_(pSimpleParser, currentWord, pSubCriteria, iRecursion); if (result.GetResult() != IMAPResult::ResultOK) return result; pCriteria->GetSubCriterias().push_back(pSubCriteria); continue; } std::shared_ptr<IMAPSearchCriteria> pNewCriteria = std::shared_ptr<IMAPSearchCriteria> (new IMAPSearchCriteria); IMAPResult result = ParseWord_(pSimpleParser, pNewCriteria, currentWord ); if (result.GetResult() != IMAPResult::ResultOK) return result; if (pNewCriteria->GetType() != IMAPSearchCriteria::CTUnknown) pCriteria->GetSubCriterias().push_back(pNewCriteria); if (iRecursion > 1) { // This is a sub criteria. We only add two words here. if (originalCriteriaCount + 2 == pCriteria->GetSubCriterias().size()) { return IMAPResult(); } } } return IMAPResult(); }
IMAPResult IMAPCommandStore::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { String sTag = pArgument->Tag(); String sCommand = pArgument->Command(); if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!pConnection->GetCurrentFolder()) return IMAPResult(IMAPResult::ResultNo, "No folder selected."); shared_ptr<IMAPStore> pStore = shared_ptr<IMAPStore>(new IMAPStore()); pStore->SetIsUID(false); String sResponse; long lMailNoStart = 6; long lMailNoEnd = sCommand.Find(_T(" "), lMailNoStart); long lMailNoLen = lMailNoEnd - lMailNoStart; String sMailNo = sCommand.Mid(lMailNoStart, lMailNoLen); String sShowPart = sCommand.Mid(lMailNoEnd); pArgument->Command(sShowPart); IMAPResult result = pStore->DoForMails(pConnection, sMailNo, pArgument); if (result.GetResult() == IMAPResult::ResultOK) pConnection->SendAsciiData(pArgument->Tag() + " OK STORE completed\r\n"); return result; }
IMAPResult IMAPCommandUNSUBSCRIBE::ExecuteCommand(shared_ptr<HM::IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); // Parse the command shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() != 1) return IMAPResult(IMAPResult::ResultBad, "Command requires 1 parameter."); // Fetch the folder name. String sFolderName = pParser->GetParamValue(pArgument, 0); shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); IMAPResult result = ConfirmPossibleToUnsubscribe(pFolder); if (result.GetResult() != IMAPResult::ResultOK) return result; if (pFolder) { pFolder->SetIsSubscribed(false); PersistentIMAPFolder::SaveObject(pFolder); } String sResponse = pArgument->Tag() + " OK Unsubscribe completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandRangeAction::DoForMails(boost::shared_ptr<IMAPConnection> pConnection, const String &sMailNos, boost::shared_ptr<IMAPCommandArgument> pArgument) { long lColonPos = -1; std::vector<String> sSplitted = StringParser::SplitString(sMailNos, ","); if (_isUID) { boost_foreach(String sCur, sSplitted) { lColonPos = sCur.Find(_T(":")); if (lColonPos >= 0) { String sFirstPart = sCur.Mid(0, lColonPos); String sSecondPart = sCur.Mid(lColonPos + 1); unsigned int lStartDBID = _ttoi(sFirstPart); unsigned int lEndDBID = -1; if (sSecondPart != _T("*")) lEndDBID = _ttoi(sSecondPart); std::vector<boost::shared_ptr<Message>> messages = pConnection->GetCurrentFolder()->GetMessages()->GetCopy(); int index = 0; boost_foreach(boost::shared_ptr<Message> pMessage, messages) { index++; unsigned int uid = pMessage->GetUID(); if (uid >= lStartDBID) { if (lEndDBID == -1 || uid <= lEndDBID) { // UID doesn't fail just because the message is missing. // This is why we don't check the return value. IMAPResult result = DoAction(pConnection, index, pMessage, pArgument); if (result.GetResult() != IMAPResult::ResultOK) { return result; } } } } }
IMAPResult IMAPCommandCOPY::ExecuteCommand(boost::shared_ptr<IMAPConnection> pConnection, boost::shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!pConnection->GetCurrentFolder()) return IMAPResult(IMAPResult::ResultNo, "No folder selected."); boost::shared_ptr<IMAPCopy> pCopy = boost::shared_ptr<IMAPCopy>(new IMAPCopy()); pCopy->SetIsUID(false); String sResponse; boost::shared_ptr<IMAPSimpleCommandParser> pParser = boost::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() != 2) return IMAPResult(IMAPResult::ResultBad, "Command requires 2 parameters.\r\n"); String sMailNo = pParser->GetParamValue(pArgument, 0); String sFolderName = pParser->GetParamValue(pArgument, 1); pArgument->Command("\"" + sFolderName + "\""); // We should check if the folder exists. If not, notify user with trycreate boost::shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pFolder) { // Nope, doesn't exist. return IMAPResult(IMAPResult::ResultNo, "Can't find mailbox with that name.\r\n"); } IMAPResult result = pCopy->DoForMails(pConnection, sMailNo, pArgument); if (result.GetResult() == IMAPResult::ResultOK) pConnection->SendAsciiData(pArgument->Tag() + " OK COPY completed\r\n"); return result; }
IMAPResult IMAPSearchParser::ParseCommand(std::shared_ptr<IMAPCommandArgument> pArgument, bool bIsSort) { // Replace literals in the command. std::shared_ptr<IMAPSimpleCommandParser> pSimpleParser = std::shared_ptr<IMAPSimpleCommandParser> (new IMAPSimpleCommandParser); if (bIsSort) { pSimpleParser->Parse(pArgument); pSimpleParser->UnliteralData(); std::shared_ptr<IMAPSimpleWord> pSort = pSimpleParser->Word(0); if (pSort->Paranthezied()) { sort_parser_ = std::shared_ptr<IMAPSortParser>(new IMAPSortParser); sort_parser_->Parse(pSort->Value()); } // Second part should be character set. if (pSimpleParser->WordCount() < 2) { return IMAPResult(IMAPResult::ResultBad, "SearchCharacter set must be specified."); } charset_name_ = pSimpleParser->Word(1)->Value(); if (!IsValidCharset_(charset_name_)) return IMAPResult(IMAPResult::ResultNo, "[BADCHARSET]"); // Trim away the SORT part of the SEARCH expresson // since we only care about SEARCH below. String tempString = pArgument->Command(); if (tempString.Find(_T(")")) > 0) tempString = tempString.Mid(tempString.Find(_T(")"))+2); pArgument->Command(tempString); } /* Remove all parenthesis outside of strings. Some IMAP clients sends parenthesis, some doesn't. We remove them here to prevent the behaviors from differing. It should be safe to do this, since Criteria1 OR (Criteria2 Criteria 3) means the same as Criteria1 OR Criteria2 Criteria 3 */ String resultString; const String inputString = pArgument->Command(); bool insideString = false; for (int i = 0; i < inputString.GetLength(); i++) { wchar_t curChar = inputString.GetAt(i); switch (curChar) { case '"': insideString = !insideString; break; case '(': case ')': if (!insideString) continue; } resultString += curChar; } // Replace literals in the command. pSimpleParser = std::shared_ptr<IMAPSimpleCommandParser> (new IMAPSimpleCommandParser); pArgument->Command(resultString); pSimpleParser->Parse(pArgument); pSimpleParser->UnliteralData(); std::shared_ptr<IMAPSearchCriteria> pCriteria = std::shared_ptr<IMAPSearchCriteria> (new IMAPSearchCriteria); int currentWord = 0; IMAPResult result = ParseSegment_(pSimpleParser, currentWord, pCriteria, 0); if (result.GetResult() != IMAPResult::ResultOK) return result; result_criteria_ = pCriteria; return IMAPResult(); }
IMAPResult IMAPCommandUID::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); String sTag = pArgument->Tag(); String sCommand = pArgument->Command(); if (!pConnection->GetCurrentFolder()) return IMAPResult(IMAPResult::ResultNo, "No folder selected."); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->WordCount() < 2) return IMAPResult(IMAPResult::ResultBad, "Command requires at least 1 parameter."); String sTypeOfUID = pParser->Word(1)->Value(); if (sTypeOfUID.CompareNoCase(_T("FETCH")) == 0) { if (pParser->WordCount() < 4) return IMAPResult(IMAPResult::ResultBad, "Command requires at least 3 parameters."); command_ = shared_ptr<IMAPFetch>(new IMAPFetch()); } else if (sTypeOfUID.CompareNoCase(_T("COPY")) == 0) { if (pParser->WordCount() < 4) return IMAPResult(IMAPResult::ResultBad, "Command requires at least 3 parameters."); command_ = shared_ptr<IMAPCopy>(new IMAPCopy()); } else if (sTypeOfUID.CompareNoCase(_T("STORE")) == 0) { if (pParser->WordCount() < 4) return IMAPResult(IMAPResult::ResultBad, "Command requires at least 3 parameters."); command_ = shared_ptr<IMAPStore>(new IMAPStore()); } else if (sTypeOfUID.CompareNoCase(_T("SEARCH")) == 0) { shared_ptr<IMAPCommandSEARCH> pCommand = shared_ptr<IMAPCommandSEARCH> (new IMAPCommandSEARCH(false)); pCommand->SetIsUID(); IMAPResult result = pCommand->ExecuteCommand(pConnection, pArgument); if (result.GetResult() == IMAPResult::ResultOK) pConnection->SendAsciiData(sTag + " OK UID completed\r\n"); return result; } else if (sTypeOfUID.CompareNoCase(_T("SORT")) == 0) { shared_ptr<IMAPCommandSEARCH> pCommand = shared_ptr<IMAPCommandSEARCH> (new IMAPCommandSEARCH(true)); pCommand->SetIsUID(); IMAPResult result = pCommand->ExecuteCommand(pConnection, pArgument); if (result.GetResult() == IMAPResult::ResultOK) pConnection->SendAsciiData(sTag + " OK UID completed\r\n"); return result; } if (!command_) return IMAPResult(IMAPResult::ResultBad, "Bad command."); command_->SetIsUID(true); // Copy the first word containing the message sequence long lSecWordStartPos = sCommand.Find(_T(" "), 5) + 1; long lSecWordEndPos = sCommand.Find(_T(" "), lSecWordStartPos); long lSecWordLength = lSecWordEndPos - lSecWordStartPos; String sMailNo = sCommand.Mid(lSecWordStartPos, lSecWordLength); // Copy the second word containing the actual command. String sShowPart = sCommand.Mid(lSecWordEndPos + 1); if (sMailNo.IsEmpty()) return IMAPResult(IMAPResult::ResultBad, "No mail number specified"); if (!StringParser::ValidateString(sMailNo, "01234567890,.:*")) return IMAPResult(IMAPResult::ResultBad, "Incorrect mail number"); // Set the command to execute as argument pArgument->Command(sShowPart); // Execute the command. If we have gotten this far, it means that the syntax // of the command is correct. If we fail now, we should return NO. IMAPResult result = command_->DoForMails(pConnection, sMailNo, pArgument); if (result.GetResult() == IMAPResult::ResultOK) pConnection->SendAsciiData(pArgument->Tag() + " OK UID completed\r\n"); return result; }
IMAPResult IMAPCommandSEARCH::ExecuteCommand(std::shared_ptr<IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument) { if (is_sort_ && !Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPSort()) return IMAPResult(IMAPResult::ResultNo, "IMAP SORT is not enabled."); if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!pConnection->GetCurrentFolder()) return IMAPResult(IMAPResult::ResultNo, "No folder selected."); if (!pArgument) return IMAPResult(IMAPResult::ResultNo, "Internal error IMAP-SEARCH-1."); { // The IMAP Search parser should not parse // the beginning of the command, UID SEARCH // or SEARCH String sCommand = pArgument->Command(); int iCommandStartPos; if (is_uid_) iCommandStartPos = sCommand.Find(_T(" "), 4) + 1; else iCommandStartPos = sCommand.Find(_T(" ")) + 1; sCommand = sCommand.Mid(iCommandStartPos); // 3 as in UID pArgument->Command(sCommand); } std::shared_ptr<IMAPSearchParser> pParser = std::shared_ptr<IMAPSearchParser>(new IMAPSearchParser()); IMAPResult result = pParser->ParseCommand(pArgument, is_sort_); if (result.GetResult() != IMAPResult::ResultOK) return result; if (is_sort_ && !pParser->GetSortParser()) return IMAPResult(IMAPResult::ResultBad, "Incorrect search commands."); // Mails in current box std::shared_ptr<IMAPFolder> pCurFolder = pConnection->GetCurrentFolder(); if (!pCurFolder) return IMAPResult(IMAPResult::ResultBad, "No selected folder"); std::vector<std::shared_ptr<Message>> messages = pCurFolder->GetMessages()->GetCopy(); std::vector<String> sMatchingVec; if (messages.size() > 0) { // Iterate through the messages and see which ones match. std::vector<std::pair<int, std::shared_ptr<Message> > > vecMatchingMessages; int index = 0; for(std::shared_ptr<Message> pMessage : messages) { const String fileName = PersistentMessage::GetFileName(pConnection->GetAccount(), pMessage); index++; if (pMessage && DoesMessageMatch_(pParser->GetCriteria(), fileName, pMessage, index)) { // Yup we got a match. vecMatchingMessages.push_back(make_pair(index, pMessage)); } } if (is_sort_) { IMAPSort oSorter; oSorter.Sort(pConnection, vecMatchingMessages, pParser->GetSortParser()); // Sort the message vector } typedef std::pair<int, std::shared_ptr<Message> > MessagePair; for(MessagePair messagePair : vecMatchingMessages) { int index = messagePair.first; std::shared_ptr<Message> pMessage = messagePair.second; String sID; if (is_uid_) sID.Format(_T("%u"), pMessage->GetUID()); else sID.Format(_T("%d"), index); sMatchingVec.push_back(sID); } } // Send response String sMatching; if (sMatchingVec.size() > 0) { // If we don't find any matches, we shouldn't return a whitespace // after SEARCH/SORT below. That's why we add the white space here. sMatching = " " + StringParser::JoinVector(sMatchingVec, " ") ; } String sResponse; if (is_sort_) sResponse = "* SORT" + sMatching + "\r\n"; else sResponse = "* SEARCH" + sMatching + "\r\n"; if (!is_uid_) // if this is a UID command, IMAPCommandUID takes care of the below line. sResponse += pArgument->Tag() + " OK Search completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandCREATE::ExecuteCommand(std::shared_ptr<HM::IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); std::shared_ptr<IMAPSimpleCommandParser> pParser = std::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() != 1) return IMAPResult(IMAPResult::ResultBad, "CREATE Command requires 1 parameter."); // Fetch the name of the mailbox to create. String sFolderName = pParser->GetParamValue(pArgument, 0); if (sFolderName.IsEmpty()) return IMAPResult(IMAPResult::ResultNo, "Folder name not specified."); // Check so that it does not already exist. std::shared_ptr<IMAPFolder> pExistsCheck = pConnection->GetFolderByFullPath(sFolderName); if (pExistsCheck) return IMAPResult(IMAPResult::ResultNo, "Folder already exists."); String hierarchyDelimiter = Configuration::Instance()->GetIMAPConfiguration()->GetHierarchyDelimiter(); std::vector<String> vecFolderPath = StringParser::SplitString(sFolderName, hierarchyDelimiter); bool bIsPublicFolder = IMAPFolderUtilities::IsPublicFolder(vecFolderPath); if (bIsPublicFolder) vecFolderPath.erase(vecFolderPath.begin()); if (!IMAPFolder::IsValidFolderName(vecFolderPath, bIsPublicFolder)) return IMAPResult(IMAPResult::ResultNo, "CREATE The folder name is invalid."); IMAPResult result = ConfirmPossibleToCreate(pConnection, vecFolderPath, bIsPublicFolder); if (result.GetResult() != IMAPResult::ResultOK) return result; std::shared_ptr<IMAPFolders> pParentFolderContainer; if (!bIsPublicFolder) pParentFolderContainer = pConnection->GetAccountFolders(); else pParentFolderContainer = pConnection->GetPublicFolders(); bool bSubscribeToFolder = bIsPublicFolder; pParentFolderContainer->CreatePath(pParentFolderContainer, vecFolderPath, bSubscribeToFolder); String sResponse = pArgument->Tag() + " OK CREATE Completed\r\n"; pConnection->SendAsciiData(sResponse); assert(pParentFolderContainer->GetCount() > 0); // Send a notification to everyone subscribing to this event. std::shared_ptr<IMAPFolder> firstFolder = pParentFolderContainer->GetItem(0); return IMAPResult(); }
IMAPResult IMAPFetchParser::ParseCommand(const String &sCommand) { String sStringToParse = sCommand; IMAPResult result = _ValidateSyntax(sStringToParse); if (result.GetResult() != IMAPResult::ResultOK) return result; std::vector<String> vecResult = _ParseString(sStringToParse); std::vector<String>::iterator iter = vecResult.begin(); while (iter != vecResult.end()) { String sPart = (*iter); ePartType iType = _GetPartType(sPart); switch (iType) { case BODYPEEK: { IMAPFetchParser::BodyPart oPart = _ParseBODYPEEK(sPart); m_vecPartsToLookAt.push_back(oPart); break; } case ENVELOPE: { m_bShowEnvelope = true; break; } case RFC822SIZE: { m_bShowRFCSize = true; break; } case UID: { m_bShowUID = true; break; } case FLAGS: { m_bShowFlags = true; break; } case INTERNALDATE: { m_bShowInternalDate = true; break; } case BODYSTRUCTURE: { m_bShowBodyStructure = true; break; } case BODYSTRUCTURENONEXTENSIBLE: { m_bShowBodyStructureNonExtensible = true; break; } case BODY: { IMAPFetchParser::BodyPart oPart = _ParseBODY(sPart); m_vecPartsToLookAt.push_back(oPart); break; } case RFC822: { // Same as: IMAPFetchParser::BodyPart oPart = _ParseBODY(sPart); oPart.SetDescription("RFC822"); m_vecPartsToLookAt.push_back(oPart); break; } case ALL: { // ALL // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) m_bShowFlags = true; m_bShowInternalDate = true; m_bShowRFCSize = true; m_bShowEnvelope = true; break; } case FAST: { // FAST // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE) m_bShowFlags = true; m_bShowInternalDate = true; m_bShowRFCSize = true; break; } case FULL: { // FULL // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY) m_bShowFlags = true; m_bShowInternalDate = true; m_bShowRFCSize = true; m_bShowEnvelope = true; m_bShowBodyStructure = true; break; } case RFC822HEADER: { /* RFC822.HEADER Functionally equivalent to BODY.PEEK[HEADER], differing in the syntax of the resulting untagged FETCH data (RFC822.HEADER is returned). */ IMAPFetchParser::BodyPart oPart = _ParseBODYPEEK("BODY[HEADER]"); oPart.SetDescription("RFC822.HEADER"); m_vecPartsToLookAt.push_back(oPart); break; } case RFC822TEXT: { /* Functionally equivalent to BODY[TEXT], differing in the syntax of the resulting untagged FETCH data (RFC822.TEXT is returned). */ IMAPFetchParser::BodyPart oPart = _ParseBODY("BODY[TEXT]"); oPart.SetDescription("RFC822.TEXT"); m_vecPartsToLookAt.push_back(oPart); break; } } iter++; } return IMAPResult(); }
IMAPResult IMAPCommandRangeAction::DoForMails(std::shared_ptr<IMAPConnection> pConnection, const String &sMailNos, std::shared_ptr<IMAPCommandArgument> pArgument) { long lColonPos = -1; std::vector<String> sSplitted = StringParser::SplitString(sMailNos, ","); if (is_uid_) { for(String sCur : sSplitted) { lColonPos = sCur.Find(_T(":")); if (lColonPos >= 0) { String sFirstPart = sCur.Mid(0, lColonPos); String sSecondPart = sCur.Mid(lColonPos + 1); unsigned int lStartDBID = _ttoi(sFirstPart); unsigned int lEndDBID = -1; if (sSecondPart != _T("*")) lEndDBID = _ttoi(sSecondPart); std::vector<std::shared_ptr<Message>> messages = pConnection->GetCurrentFolder()->GetMessages()->GetCopy(); int index = 0; for(std::shared_ptr<Message> pMessage: messages) { index++; unsigned int uid = pMessage->GetUID(); if (uid >= lStartDBID) { if (lEndDBID == -1 || uid <= lEndDBID) { // UID doesn't fail just because the message is missing. // This is why we don't check the return value. IMAPResult result = DoAction(pConnection, index, pMessage, pArgument); if (result.GetResult() != IMAPResult::ResultOK) { return result; } } } } } else { unsigned int uid = _ttoi(sCur); unsigned int foundIndex = 0; std::shared_ptr<Messages> messages = pConnection->GetCurrentFolder()->GetMessages(); std::shared_ptr<Message> message = messages->GetItemByUID(uid, foundIndex); if (!message) continue; IMAPResult result = DoAction(pConnection, foundIndex, message, pArgument); if (result.GetResult() != IMAPResult::ResultOK) { return result; } } } } else { for(String sCur: sSplitted) { lColonPos = sCur.Find(_T(":")); if (lColonPos >= 0) { String sFirstPart = sCur.Mid(0, lColonPos); String sSecondPart = sCur.Mid(lColonPos + 1); int lStartIndex = _ttoi(sFirstPart); int lEndIndex = -1; if (sSecondPart != _T("*")) lEndIndex = _ttoi(sSecondPart); auto vecMessages = pConnection->GetCurrentFolder()->GetMessages()->GetCopy(); int index = 0; for(std::shared_ptr<Message> message : vecMessages) { index++; if (index >= lStartIndex) { if (lEndIndex == -1 || index <= lEndIndex) { IMAPResult result = DoAction(pConnection, index, message, pArgument); if (result.GetResult() != IMAPResult::ResultOK) { return result; } } } } } else { int messageIndex = _ttoi(sCur); std::shared_ptr<Message> pMessage = pConnection->GetCurrentFolder()->GetMessages()->GetItem(messageIndex-1); if (!pMessage) continue; IMAPResult result = DoAction(pConnection, messageIndex, pMessage, pArgument); if (result.GetResult() != IMAPResult::ResultOK) { return result; } } } } return IMAPResult(); }
IMAPResult IMAPCommandSEARCH::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (m_bIsSort && !Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPSort()) return IMAPResult(IMAPResult::ResultNo, "IMAP SORT is not enabled."); if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!pConnection->GetCurrentFolder()) return IMAPResult(IMAPResult::ResultNo, "No folder selected."); if (!pArgument) return IMAPResult(IMAPResult::ResultNo, "Internal error IMAP-SEARCH-1."); { // The IMAP Search parser should not parse // the beginning of the command, UID SEARCH // or SEARCH String sCommand = pArgument->Command(); int iCommandStartPos; if (m_bIsUID) iCommandStartPos = sCommand.Find(_T(" "), 4) + 1; else iCommandStartPos = sCommand.Find(_T(" ")) + 1; sCommand = sCommand.Mid(iCommandStartPos); // 3 as in UID pArgument->Command(sCommand); } shared_ptr<IMAPSearchParser> pParser = shared_ptr<IMAPSearchParser>(new IMAPSearchParser()); IMAPResult result = pParser->ParseCommand(pArgument, m_bIsSort); if (result.GetResult() != IMAPResult::ResultOK) return result; if (m_bIsSort && !pParser->GetSortParser()) return IMAPResult(IMAPResult::ResultBad, "Incorrect search commands."); // Mails in current box shared_ptr<IMAPFolder> pCurFolder = pConnection->GetCurrentFolder(); if (!pCurFolder) return IMAPResult(IMAPResult::ResultBad, "No selected folder"); vector<shared_ptr<Message>> messages = pCurFolder->GetMessages()->GetCopy(); std::vector<String> sMatchingVec; if (messages.size() > 0) { // Iterate through the messages and see which ones match. vector<pair<int, shared_ptr<Message> > > vecMatchingMessages; int index = 0; boost_foreach(shared_ptr<Message> pMessage, messages) { const String fileName = PersistentMessage::GetFileName(pConnection->GetAccount(), pMessage); index++; if (pMessage && _DoesMessageMatch(pParser->GetCriteria(), fileName, pMessage, index)) { // Yup we got a match. vecMatchingMessages.push_back(make_pair(index, pMessage)); } } if (m_bIsSort) { IMAPSort oSorter; oSorter.Sort(pConnection, vecMatchingMessages, pParser->GetSortParser()); // Sort the message vector } typedef pair<int, shared_ptr<Message> > MessagePair; boost_foreach(MessagePair messagePair, vecMatchingMessages) { int index = messagePair.first; shared_ptr<Message> pMessage = messagePair.second; String sID; if (m_bIsUID) sID.Format(_T("%u"), pMessage->GetUID()); else sID.Format(_T("%d"), index); sMatchingVec.push_back(sID); }