IMAPResult IMAPCommandCLOSE::ExecuteCommand(boost::shared_ptr<HM::IMAPConnection> pConnection, boost::shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); // Iterate through mail boxes and delete messages marked for deletion. boost::shared_ptr<IMAPFolder> pCurFolder = pConnection->GetCurrentFolder(); if (!pCurFolder) return IMAPResult(IMAPResult::ResultBad, "No folder selected."); // Check if user has permission to expunge. If so, do that. if (!pConnection->GetCurrentFolderReadOnly() && pConnection->CheckPermission(pConnection->GetCurrentFolder(), ACLPermission::PermissionExpunge)) { pCurFolder->Expunge(); } pConnection->CloseCurrentFolder(); String sResponse = pArgument->Tag() + " OK CLOSE completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandCREATE::ConfirmPossibleToCreate(std::shared_ptr<HM::IMAPConnection> pConnection, const std::vector<String> &vecNewPath, bool bIsPublicFolder) { if (bIsPublicFolder) { std::shared_ptr<IMAPFolders> pFolders = pConnection->GetPublicFolders(); std::vector<String> vecTempPath = vecNewPath; vecTempPath.erase(vecTempPath.end()-1); std::shared_ptr<IMAPFolder> pParentFolder = IMAPFolderUtilities::GetTopMostExistingFolder(pFolders, vecTempPath); // Check if the user has permission to create a folder in the parent folder if (pParentFolder) { if (!pConnection->CheckPermission(pParentFolder, ACLPermission::PermissionCreate)) return IMAPResult(IMAPResult::ResultNo, "ACL: Create permission denied (Required for CREATE command)."); } // Check if the user is trying to create a new root public folder, such as Public folders/Test if (bIsPublicFolder && !pParentFolder) return IMAPResult(IMAPResult::ResultNo, "ACL: Root public folders can only be created using administration tools."); } return IMAPResult(); }
IMAPResult IMAPCommandEXAMINE::ExecuteCommand(boost::shared_ptr<HM::IMAPConnection> pConnection, boost::shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); boost::shared_ptr<IMAPSimpleCommandParser> pParser = boost::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() < 1) return IMAPResult(IMAPResult::ResultBad, "EXAMINE Command requires at least 1 parameter."); // Fetch the folder String sFolderName = pParser->GetParamValue(pArgument, 0); boost::shared_ptr<IMAPFolder> pSelectedFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pSelectedFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); if (!pConnection->CheckPermission(pSelectedFolder, ACLPermission::PermissionRead)) return IMAPResult(IMAPResult::ResultBad, "ACL: Read permission denied (Required for EXAMINE command)."); pConnection->SetCurrentFolder(pSelectedFolder, true); boost::shared_ptr<Messages> pMessages = pSelectedFolder->GetMessages(); long lCount = pMessages->GetCount(); __int64 lFirstUnseenID = pMessages->GetFirstUnseenUID(); long lRecentCount = pMessages->GetNoOfRecent(); String sRespTemp; sRespTemp.Format(_T("* %d EXISTS\r\n"), lCount); String sResponse = sRespTemp; // EXISTS sRespTemp.Format(_T("* %d RECENT\r\n"), lRecentCount); sResponse += sRespTemp; sResponse += _T("* FLAGS (\\Deleted \\Seen \\Draft \\Answered \\Flagged)\r\n"); sRespTemp.Format(_T("* OK [UIDVALIDITY %d] current uidvalidity\r\n"), pSelectedFolder->GetCreationTime().ToInt()); sResponse += sRespTemp; if (lFirstUnseenID > 0) { sRespTemp.Format(_T("* OK [UNSEEN %d] unseen messages\r\n"), lFirstUnseenID); sResponse += sRespTemp; } sRespTemp.Format(_T("* OK [UIDNEXT %d] next uid\r\n"), pSelectedFolder->GetCurrentUID()+1); sResponse += sRespTemp; sResponse += _T("* OK [PERMANENTFLAGS ()] limited\r\n"); sResponse += pArgument->Tag() + _T(" OK [READ-ONLY] EXAMINE completed\r\n"); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandNamespace::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->WordCount() < 1) return IMAPResult(IMAPResult::ResultBad, "NAMESPACE command requires exactly 0 parameter."); String sPublicFolderName = Configuration::Instance()->GetIMAPConfiguration()->GetIMAPPublicFolderName(); String hierarchyDelimiter = Configuration::Instance()->GetIMAPConfiguration()->GetHierarchyDelimiter(); hierarchyDelimiter.Replace(_T("\\"), _T("\\\\")); String sPersonalNamespace = "((\"\" \"" + hierarchyDelimiter + "\"))"; String sOtherUsersNamespace = "NIL"; String sSharedNamespaces = "((\"" + sPublicFolderName + "\" \"" + hierarchyDelimiter + "\"))"; String sResponse; sResponse.Format(_T("* NAMESPACE %s %s %s\r\n"), sPersonalNamespace.c_str(), sOtherUsersNamespace.c_str(), sSharedNamespaces.c_str()); sResponse += pArgument->Tag() + _T(" OK namespace command complete\r\n"); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
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 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 IMAPCommandGetQuotaRoot::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPQuota()) return IMAPResult(IMAPResult::ResultNo, "IMAP QUOTA is not enabled."); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() < 1) return IMAPResult(IMAPResult::ResultBad, "GETQUOTAROOT Command requires at least 1 parameter."); String sFolderName = pParser->GetParamValue(pArgument, 0); if (pParser->Word(1)->Quoted()) { // If there was quotes in the command, readd // them now. For example, if there's a space // in the folder name it should be in quotes. sFolderName = "\"" + sFolderName + "\""; } shared_ptr<const Account> pAccount = CacheContainer::Instance()->GetAccount(pConnection->GetAccount()->GetID()); // According to the RFC, these values should be counted in kilobytes. __int64 iCurrentSize = AccountSizeCache::Instance()->GetSize(pAccount->GetID()) / 1024; // Convert from Bytes to KB __int64 iMaxSize = ((__int64) pAccount->GetAccountMaxSize() * 1024); // Convert from MB to KB String sResponse; if (iMaxSize > 0) { sResponse.Format(_T("* QUOTAROOT %s \"\"\r\n") _T("* QUOTA \"\" (STORAGE %I64d %I64d)\r\n") _T("%s OK GETQUOTAROOT completed\r\n"), sFolderName, iCurrentSize, iMaxSize, pArgument->Tag()); } else { // NO QUOTA DEFINED sResponse.Format(_T("* QUOTAROOT %s \"\"\r\n") _T("* QUOTA \"\" ()\r\n") _T("%s OK GETQUOTAROOT completed\r\n"), sFolderName, pArgument->Tag()); } pConnection->SendAsciiData(sResponse); return IMAPResult(); }
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 IMAPCommandUNSUBSCRIBE::ConfirmPossibleToUnsubscribe(shared_ptr<IMAPFolder> pFolder) { if (!pFolder) return IMAPResult(IMAPResult::ResultNo, "That mailbox does not exist."); if (pFolder->GetAccountID() == 0) return IMAPResult(IMAPResult::ResultNo, "It is not possible to unsubscribe from public folders."); return IMAPResult(); }
IMAPResult IMAPCommandMyRights::ExecuteCommand(std::shared_ptr<HM::IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPACL()) return IMAPResult(IMAPResult::ResultBad, "ACL is not enabled."); std::shared_ptr<IMAPSimpleCommandParser> pParser = std::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->WordCount() < 2) return IMAPResult(IMAPResult::ResultBad, "MYRIGHTS command requires at least 1 parameter."); String sOriginalFolderName; String sFolderName; if (pParser->Word(1)->Clammerized()) { sFolderName = pArgument->Literal(0); sOriginalFolderName = sFolderName; } else { sOriginalFolderName = pParser->Word(1)->Value(); sFolderName = sOriginalFolderName; IMAPFolder::UnescapeFolderString(sFolderName); } std::shared_ptr<IMAPFolder> pSelectedFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pSelectedFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); ACLManager aclManager; std::shared_ptr<ACLPermission> pPermission = aclManager.GetPermissionForFolder(pConnection->GetAccount()->GetID(), pSelectedFolder); String sRightsString; if (pPermission) sRightsString = pPermission->GetRights(); String sResponse; sResponse.Format(_T("* MYRIGHTS \"%s\" %s\r\n"), sOriginalFolderName.c_str(), sRightsString.c_str()); sResponse += pArgument->Tag() + _T(" OK Myrights complete\r\n"); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandListRights::ExecuteCommand(std::shared_ptr<HM::IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPACL()) return IMAPResult(IMAPResult::ResultBad, "ACL is not enabled."); std::shared_ptr<IMAPSimpleCommandParser> pParser = std::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() != 2) return IMAPResult(IMAPResult::ResultBad, "ListRights command requires 2 parameter."); String sOriginalFolderName; String sFolderName; if (pParser->Word(1)->Clammerized()) { sFolderName = pArgument->Literal(0); sOriginalFolderName = sFolderName; } else { sOriginalFolderName = pParser->Word(1)->Value(); sFolderName = sOriginalFolderName; IMAPFolder::UnescapeFolderString(sFolderName); } std::shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); // Always produce the same output. String sIdentifier = pParser->Word(2)->Value(); String sPermissions = "l r s w i k x t e a"; String sResponse; sResponse.Format(_T("* LISTRIGHTS %s %s %s\r\n"), sOriginalFolderName.c_str(), sIdentifier.c_str(), sPermissions.c_str()); sResponse += pArgument->Tag() + _T(" OK ListRights complete\r\n"); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandCapability::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { String sResponse = "* CAPABILITY IMAP4 IMAP4rev1 CHILDREN"; shared_ptr<IMAPConfiguration> pConfig = Configuration::Instance()->GetIMAPConfiguration(); if (pConfig->GetUseIMAPIdle()) sResponse += " IDLE"; if (pConfig->GetUseIMAPQuota()) sResponse += " QUOTA"; if (pConfig->GetUseIMAPSort()) sResponse += " SORT"; if (pConfig->GetUseIMAPACL()) sResponse += " ACL"; sResponse += " NAMESPACE RIGHTS=texk"; sResponse += "\r\n"; sResponse += pArgument->Tag() + " OK CAPABILITY completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandUNKNOWN::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { pConnection->SendResponseString(pArgument->Tag(), "BAD", "Unknown or NULL command"); return IMAPResult(); }
IMAPResult IMAPCommandDeleteAcl::ExecuteCommand(shared_ptr<HM::IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPACL()) return IMAPResult(IMAPResult::ResultBad, "ACL is not enabled."); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() != 2) return IMAPResult(IMAPResult::ResultBad, "DELETEACL command requires 2 parameter."); String sOriginalFolderName; String sFolderName; if (pParser->Word(1)->Clammerized()) { sFolderName = pArgument->Literal(0); sOriginalFolderName = sFolderName; } else { sOriginalFolderName = pParser->Word(1)->Value(); sFolderName = sOriginalFolderName; IMAPFolder::UnescapeFolderString(sFolderName); } String sIdentifier = pParser->Word(2)->Value(); shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); // Check if the user has access to delete ACL for this folder if (!pConnection->CheckPermission(pFolder, ACLPermission::PermissionAdminister)) return IMAPResult(IMAPResult::ResultNo, "ACL: DeleteACL permission denied"); // Assume identifier is a user and not a group. shared_ptr<const Account> pAccount = CacheContainer::Instance()->GetAccount(sIdentifier); if (!pAccount) { // Do something. We cannot give permissions to an object which does not exist. return IMAPResult(IMAPResult::ResultNo, "DeleteACL failed. Identifier not found"); } if (!pFolder->GetPermissions()->DeletePermissionsForAccount(pAccount->GetID())) return IMAPResult(IMAPResult::ResultNo, "DeleteACL failed"); String sResponse = pArgument->Tag() + _T(" OK DeleteACL complete\r\n"); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandNOOP::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { pConnection->SendAsciiData(pArgument->Tag() + " OK NOOP completed\r\n"); return IMAPResult(); }
IMAPResult IMAPCommandLOGIN::ExecuteCommand(shared_ptr<HM::IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() != 2) { return IMAPResult(IMAPResult::ResultBad, "Command requires 2 parameters"); } // The folder wildcard could be sent in a seperate buffer. String sUsername = pParser->GetParamValue(pArgument, 0); String sPassword = pParser->GetParamValue(pArgument, 1); AccountLogon accountLogon; bool disconnect = false; shared_ptr<const Account> pAccount = accountLogon.Logon(pConnection->GetIPAddress(), sUsername, sPassword, disconnect); if (disconnect) { String sResponse = "* Too many invalid logon attempts.\r\n"; sResponse += pArgument->Tag() + " BAD Goodbye\r\n"; pConnection->Logout(sResponse); return IMAPResult(); } if (!pAccount) { if (sUsername.Find(_T("@")) == -1) return IMAPResult(IMAPResult::ResultNo, "Invalid user name or password. Please use full email address as user name."); else return IMAPResult(IMAPResult::ResultNo, "Invalid user name or password."); } // Load mail boxes pConnection->Login(pAccount); String sResponse = pArgument->Tag() + " OK LOGIN completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPFetchParser::_ValidateSyntax(const String &sString) { long lNoOfLeftPar = sString.NumberOf(_T("(")); long lNoOfRightPar = sString.NumberOf(_T(")")); long lNoOfLeftBrack = sString.NumberOf(_T("[")); long lNoOfRightBrack = sString.NumberOf(_T("]")); if (lNoOfLeftBrack != lNoOfRightBrack) return IMAPResult(IMAPResult::ResultBad, "Brackets are mismatching."); if (lNoOfLeftPar != lNoOfRightPar) return IMAPResult(IMAPResult::ResultBad, "Parenthesises are mismatching."); return IMAPResult(); }
IMAPResult IMAPCommandStartTls::ExecuteCommand(std::shared_ptr<IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument) { pConnection->SendAsciiData(pArgument->Tag() + " OK Begin TLS negotiation now\r\n"); pConnection->StartHandshake(); return IMAPResult(IMAPResult::ResultOKSupressRead, ""); }
IMAPResult IMAPCommandGetAcl::ExecuteCommand(shared_ptr<HM::IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPACL()) return IMAPResult(IMAPResult::ResultBad, "ACL is not enabled."); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->WordCount() != 2) return IMAPResult(IMAPResult::ResultBad, "MYRIGHTS command requires 1 parameter."); String sOriginalFolderName; String sFolderName; if (pParser->Word(1)->Clammerized()) { sOriginalFolderName = pArgument->Literal(0); sOriginalFolderName = sFolderName; } else { sOriginalFolderName = pParser->Word(1)->Value(); sFolderName = sOriginalFolderName; IMAPFolder::UnescapeFolderString(sFolderName); } shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); String sResponse = IMAPACLHelper::CreateACLList(pFolder, sOriginalFolderName); sResponse += pArgument->Tag() + _T(" OK GetAcl complete\r\n"); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandEXPUNGE::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (pConnection->GetCurrentFolderReadOnly()) { return IMAPResult(IMAPResult::ResultNo, "Expunge command on read-only folder."); } // Iterate through mail boxes and delete messages marked for deletion. shared_ptr<IMAPFolder> pCurFolder = pConnection->GetCurrentFolder(); if (!pCurFolder) return IMAPResult(IMAPResult::ResultNo, "No folder selected."); if (!pConnection->CheckPermission(pCurFolder, ACLPermission::PermissionExpunge)) return IMAPResult(IMAPResult::ResultBad, "ACL: Expunge permission denied (Required for EXPUNGE command)."); std::vector<int> vecExpungedMessages = pCurFolder->Expunge(); std::vector<int>::iterator iterExpunged = vecExpungedMessages.begin(); String sResponse; while (iterExpunged != vecExpungedMessages.end()) { String sTemp; sTemp.Format(_T("* %d EXPUNGE\r\n"), (*iterExpunged)); sResponse += sTemp; iterExpunged++; } pConnection->SendAsciiData(sResponse); if (!vecExpungedMessages.empty()) { std::vector<__int64> affectedMessages; boost_foreach(__int64 messageIndex, vecExpungedMessages) { affectedMessages.push_back(messageIndex); }
IMAPResult IMAPCommandGetQuota::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); if (!Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPQuota()) return IMAPResult(IMAPResult::ResultNo, "IMAP QUOTA is not enabled."); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->WordCount() < 2) return IMAPResult(IMAPResult::ResultBad, "GETQUOTA Command requires at least 1 parameter."); shared_ptr<const Account> pAccount = CacheContainer::Instance()->GetAccount(pConnection->GetAccount()->GetID()); // According to the RFC, these values should be counted in kilobytes. __int64 iCurrentSize = AccountSizeCache::Instance()->GetSize(pAccount->GetID()) / 1024; __int64 iMaxSize = ((__int64) pAccount->GetAccountMaxSize()) * 1024; // Convert from MB to KB String sResponse; if (iMaxSize > 0) { sResponse.Format(_T("* QUOTA \"\" (STORAGE %I64d %I64d)\r\n") _T("%s OK GETRUOTA completed\r\n"), iCurrentSize, iMaxSize, pArgument->Tag()); } else { // NO QUOTA DEFINED sResponse.Format(_T("* QUOTA \"\" (STORAGE)\r\n") _T("%s OK GETRUOTA completed\r\n"), pArgument->Tag()); } pConnection->SendAsciiData(sResponse); return IMAPResult(); }
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 IMAPCommandSUBSCRIBE::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, "Command requires at least 1 parameter."); // Fetch the folder name. String sFolderName = pParser->GetParamValue(pArgument, 0); if (sFolderName == Configuration::Instance()->GetIMAPConfiguration()->GetIMAPPublicFolderName()) { // Silently accept this. If we don't, some email clients (such as OE) will complain that it won't // be possible to subscribe to sub folders String sResponse = pArgument->Tag() + " OK Subscribe completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); } std::shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pFolder) return IMAPResult(IMAPResult::ResultNo, "Folder could not be found."); // Check if ther user has access to see this folder. if (!pConnection->CheckPermission(pFolder, ACLPermission::PermissionLookup)) return IMAPResult(IMAPResult::ResultNo, "ACL: Lookup permission denied (required for SUBSCRIBE)."); if (!pFolder) return IMAPResult(IMAPResult::ResultNo, "That mailbox does not exist."); pFolder->SetIsSubscribed(true); PersistentIMAPFolder::SaveObject(pFolder); String sResponse = pArgument->Tag() + " OK Subscribe completed\r\n"; pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCommandAppend::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); m_sCurrentTag = pArgument->Tag(); // Reset these two so we don't re-use old values. m_sFlagsToSet = ""; m_sCreateTimeToSet = ""; shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->WordCount() < 3) return IMAPResult(IMAPResult::ResultBad, "APPEND Command requires at least 2 parameter."); // Create a new mailbox String sFolderName = pParser->GetParamValue(pArgument, 0); if (!pParser->Word(1)->Clammerized()) IMAPFolder::UnescapeFolderString(sFolderName); if (pParser->ParantheziedWord()) m_sFlagsToSet = pParser->ParantheziedWord()->Value(); // last word. shared_ptr<IMAPSimpleWord> pWord = pParser->Word(pParser->WordCount()-1); if (!pWord || !pWord->Clammerized()) return IMAPResult(IMAPResult::ResultBad, "Missing literal"); AnsiString literalSize = pWord->Value(); m_lBytesLeftToReceive = atoi(literalSize); if (m_lBytesLeftToReceive == 0) return IMAPResult(IMAPResult::ResultBad, "Empty message not permitted."); // Add an extra two bytes since we expect a <newline> in the end. m_lBytesLeftToReceive += 2; shared_ptr<const Domain> domain = CacheContainer::Instance()->GetDomain(pConnection->GetAccount()->GetDomainID()); int maxMessageSizeKB = _GetMaxMessageSize(domain); if (maxMessageSizeKB > 0 && m_lBytesLeftToReceive / 1024 > maxMessageSizeKB) { String sMessage; sMessage.Format(_T("Message size exceeds fixed maximum message size. Size: %d KB, Max size: %d KB"), m_lBytesLeftToReceive / 1024, maxMessageSizeKB); return IMAPResult(IMAPResult::ResultNo, sMessage); } // Locate the parameter containing the date to set. // Can't use pParser->QuotedWord() since there may // be many quoted words in the command. for (int i = 2; i < pParser->WordCount(); i++) { shared_ptr<IMAPSimpleWord> pWord = pParser->Word(i); if (pWord->Quoted()) { m_sCreateTimeToSet = pWord->Value(); // date-day-fixed = (SP DIGIT) / 2DIGIT // ; Fixed-format version of date-day // If the date given starts with <space>number, we need // to Trim. Doesn't hurt to always do this. m_sCreateTimeToSet.TrimLeft(); } } m_pDestinationFolder = pConnection->GetFolderByFullPath(sFolderName); if (!m_pDestinationFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); if (!m_pDestinationFolder->IsPublicFolder()) { // Make sure that this message fits in the mailbox. shared_ptr<const Account> pAccount = CacheContainer::Instance()->GetAccount(pConnection->GetAccount()->GetID()); if (!pAccount) return IMAPResult(IMAPResult::ResultNo, "Account could not be fetched."); if (!pAccount->SpaceAvailable(m_lBytesLeftToReceive)) return IMAPResult(IMAPResult::ResultNo, "Your quota has been exceeded."); } if (!pConnection->CheckPermission(m_pDestinationFolder, ACLPermission::PermissionInsert)) return IMAPResult(IMAPResult::ResultBad, "ACL: Insert permission denied (Required for APPEND command)."); __int64 lFolderID = m_pDestinationFolder->GetID(); m_pCurrentMessage = shared_ptr<Message>(new Message); m_pCurrentMessage->SetAccountID(m_pDestinationFolder->GetAccountID()); m_pCurrentMessage->SetFolderID(lFolderID); // Construct a file name which we'll write the message to. // Should we connect this message to an account? Yes, if this is not a public folder. shared_ptr<const Account> pMessageOwner; if (!m_pDestinationFolder->IsPublicFolder()) pMessageOwner = pConnection->GetAccount(); m_sMessageFileName = PersistentMessage::GetFileName(pMessageOwner, m_pCurrentMessage); String sResponse = "+ Ready for literal data\r\n"; pConnection->SetReceiveBinary(true); pConnection->SendAsciiData(sResponse); return IMAPResult(); }
IMAPResult IMAPCopy::DoAction(shared_ptr<IMAPConnection> pConnection, int messageIndex, shared_ptr<Message> pOldMessage, const shared_ptr<IMAPCommandArgument> pArgument) { if (!pArgument || !pOldMessage) return IMAPResult(IMAPResult::ResultBad, "Invalid parameters"); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->WordCount() <= 0) return IMAPResult(IMAPResult::ResultNo, "The command requires parameters."); String sFolderName; if (pParser->Word(0)->Clammerized()) sFolderName = pArgument->Literal(0); else { sFolderName = pParser->Word(0)->Value(); IMAPFolder::UnescapeFolderString(sFolderName); } shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pFolder) return IMAPResult(IMAPResult::ResultBad, "The folder could not be found."); shared_ptr<const Account> pAccount = pConnection->GetAccount(); if (!pFolder->IsPublicFolder()) { if (!pAccount->SpaceAvailable(pOldMessage->GetSize())) return IMAPResult(IMAPResult::ResultNo, "Your quota has been exceeded."); } // Check if the user has permission to copy to this destination folder if (!pConnection->CheckPermission(pFolder, ACLPermission::PermissionInsert)) return IMAPResult(IMAPResult::ResultBad, "ACL: Insert permission denied (Required for COPY command)."); shared_ptr<Message> pNewMessage = PersistentMessage::CopyToIMAPFolder(pAccount, pOldMessage, pFolder); if (!pNewMessage) return IMAPResult(IMAPResult::ResultBad, "Failed to copy message"); // Check if the user has access to set the Seen flag, otherwise if (!pConnection->CheckPermission(pFolder, ACLPermission::PermissionWriteSeen)) pNewMessage->SetFlagSeen(false); if (!PersistentMessage::SaveObject(pNewMessage)) return IMAPResult(IMAPResult::ResultBad, "Failed to save copy of message."); pFolder->SetFolderNeedsRefresh(); // Set a delayed notification so that the any IMAP idle client is notified when this // command has been finished. shared_ptr<ChangeNotification> pNotification = shared_ptr<ChangeNotification>(new ChangeNotification(pFolder->GetAccountID(), pFolder->GetID(), ChangeNotification::NotificationMessageAdded)); pConnection->SetDelayedChangeNotification(pNotification); return IMAPResult(); }
IMAPResult IMAPSearchParser::ParseWord_(std::shared_ptr<IMAPSimpleCommandParser> pSimpleParser, std::shared_ptr<IMAPSearchCriteria> pNewCriteria, int &iCurrentWord) { String sCurCommand = pSimpleParser->Word(iCurrentWord)->Value(); if (sCurCommand == _T("NOT")) { pNewCriteria->SetPositive(false); iCurrentWord++; if (iCurrentWord > (int) pSimpleParser->WordCount() - 1) return IMAPResult(IMAPResult::ResultBad, "Syntax error. NOT used but no search criteria specified."); std::shared_ptr<IMAPSimpleWord> pWord = pSimpleParser->Word(iCurrentWord); sCurCommand = pWord->Value().ToUpper(); } else pNewCriteria->SetPositive(true); IMAPSearchCriteria::CriteriaType ct = IMAPSearchCriteria::GetCriteriaTypeByName(sCurCommand); if (ct == IMAPSearchCriteria::CTHeader) { // The client want's to search for a // header field. iCurrentWord++; if (iCurrentWord > (int) pSimpleParser->WordCount() - 1) return IMAPResult(IMAPResult::ResultBad, "Syntax error. No header specified in header-search."); String sHeaderField = pSimpleParser->Word(iCurrentWord)->Value(); // Go to the header value. iCurrentWord++; if (iCurrentWord > (int) pSimpleParser->WordCount() - 1) return IMAPResult(IMAPResult::ResultBad, "Syntax error. No value specified in header-search."); String sHeaderValue = pSimpleParser->Word(iCurrentWord)->Value(); sHeaderValue = DecodeWordAccordingToCharset_(sHeaderValue); pNewCriteria->SetHeaderField(sHeaderField); pNewCriteria->SetText(sHeaderValue); pNewCriteria->SetType(IMAPSearchCriteria::CTHeader); } else if (ct == IMAPSearchCriteria::CTText || ct == IMAPSearchCriteria::CTSentOn || ct == IMAPSearchCriteria::CTSentBefore || ct == IMAPSearchCriteria::CTSentSince || ct == IMAPSearchCriteria::CTBody || ct == IMAPSearchCriteria::CTSubject || ct == IMAPSearchCriteria::CTTo || ct == IMAPSearchCriteria::CTFrom || ct == IMAPSearchCriteria::CTCC || ct == IMAPSearchCriteria::CTSince || ct == IMAPSearchCriteria::CTBefore || ct == IMAPSearchCriteria::CTLarger || ct == IMAPSearchCriteria::CTSmaller || ct == IMAPSearchCriteria::CTOn) { iCurrentWord++; if (iCurrentWord > (int) pSimpleParser->WordCount() - 1) return IMAPResult(IMAPResult::ResultBad, "Syntax error. Missing value."); std::shared_ptr<IMAPSimpleWord> pWord = pSimpleParser->Word(iCurrentWord); if (pWord) { String searchValue = pWord->Value(); if (NeedsDecoding_(ct)) searchValue = DecodeWordAccordingToCharset_(searchValue); pNewCriteria->SetText(searchValue); pNewCriteria->SetType(ct); } } else if (ct == IMAPSearchCriteria::CTUID) { // Check which UID's we should send back. // iCurrentWord++; if (iCurrentWord > (int) pSimpleParser->WordCount() - 1) return IMAPResult(IMAPResult::ResultBad, "Syntax error. UID parameters missing."); std::shared_ptr<IMAPSimpleWord> pWord = pSimpleParser->Word(iCurrentWord); if (pWord) { String sTemp = pWord->Value(); std::vector<String> vecSplit = StringParser::SplitString(sTemp, ","); pNewCriteria->SetSequenceSet(vecSplit); pNewCriteria->SetType(ct); } } else if (ct == IMAPSearchCriteria::CTDeleted || ct == IMAPSearchCriteria::CTUndeleted || ct == IMAPSearchCriteria::CTSeen || ct == IMAPSearchCriteria::CTUnseen || ct == IMAPSearchCriteria::CTRecent || ct == IMAPSearchCriteria::CTAnswered || ct == IMAPSearchCriteria::CTDraft || ct == IMAPSearchCriteria::CTFlagged || ct == IMAPSearchCriteria::CTNew || ct == IMAPSearchCriteria::CTOld || ct == IMAPSearchCriteria::CTUnanswered || ct == IMAPSearchCriteria::CTUndraft || ct == IMAPSearchCriteria::CTUnflagged || ct == IMAPSearchCriteria::CTAll) { pNewCriteria->SetType(ct); } else if (ct == IMAPSearchCriteria::CTSequenceSet) { pNewCriteria->SetType(ct); pNewCriteria->SetSequenceSet(StringParser::SplitString(sCurCommand, ",")); } else if (ct == IMAPSearchCriteria::CTCharset) { iCurrentWord++; if (iCurrentWord > (int) pSimpleParser->WordCount() - 1) return IMAPResult(IMAPResult::ResultBad, "Syntax error. Missing charset name."); std::shared_ptr<IMAPSimpleWord> pWord = pSimpleParser->Word(iCurrentWord); if (pWord) { String charsetName = pWord->Value(); if (!IsValidCharset_(charsetName)) return IMAPResult(IMAPResult::ResultNo, "[BADCHARSET]"); charset_name_ = charsetName; } } return IMAPResult(); }
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 IMAPCommandSELECT::ExecuteCommand(shared_ptr<HM::IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument) { if (!pConnection->IsAuthenticated()) return IMAPResult(IMAPResult::ResultNo, "Authenticate first"); shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser()); pParser->Parse(pArgument); if (pParser->ParamCount() < 1) return IMAPResult(IMAPResult::ResultBad, "SELECT Command requires at least 1 parameter."); String sFolderName = pParser->GetParamValue(pArgument, 0); if (sFolderName == Configuration::Instance()->GetIMAPConfiguration()->GetIMAPPublicFolderName()) return IMAPResult(IMAPResult::ResultBad, "SELECT Only sub folders of the root shared folder can be selected."); shared_ptr<IMAPFolder> pSelectedFolder = pConnection->GetFolderByFullPath(sFolderName); if (!pSelectedFolder) return IMAPResult(IMAPResult::ResultBad, "Folder could not be found."); bool readAccess = false; bool writeAccess = false; pConnection->CheckFolderPermissions(pSelectedFolder, readAccess, writeAccess); // Check if the user has access to read this folder. if (!readAccess) return IMAPResult(IMAPResult::ResultBad, "ACL: Read permission denied (Required for SELECT command)."); pConnection->SetCurrentFolder(pSelectedFolder, false); shared_ptr<Messages> pMessages = pSelectedFolder->GetMessages(); long lCount = pMessages->GetCount(); __int64 lFirstUnseenID = pMessages->GetFirstUnseenUID(); long lRecentCount = pMessages->GetNoOfRecent(); String sRespTemp; sRespTemp.Format(_T("* %d EXISTS\r\n"), lCount); String sResponse = sRespTemp; // EXISTS sRespTemp.Format(_T("* %d RECENT\r\n"), lRecentCount); sResponse += sRespTemp; sResponse += _T("* FLAGS (\\Deleted \\Seen \\Draft \\Answered \\Flagged)\r\n"); sRespTemp.Format(_T("* OK [UIDVALIDITY %d] current uidvalidity\r\n"), pSelectedFolder->GetCreationTime().ToInt()); sResponse += sRespTemp; if (lFirstUnseenID > 0) { sRespTemp.Format(_T("* OK [UNSEEN %d] unseen messages\r\n"), lFirstUnseenID); sResponse += sRespTemp; } sRespTemp.Format(_T("* OK [UIDNEXT %d] next uid\r\n"), pSelectedFolder->GetCurrentUID()+1); sResponse += sRespTemp; sResponse += _T("* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Draft \\Answered \\Flagged)] limited\r\n"); if (writeAccess) sResponse += pArgument->Tag() + _T(" OK [READ-WRITE] SELECT completed\r\n"); else sResponse += pArgument->Tag() + _T(" OK [READ-ONLY] SELECT completed\r\n"); pConnection->SendAsciiData(sResponse); 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 IMAPCommandAUTHENTICATE::ExecuteCommand(boost::shared_ptr<IMAPConnection> pConnection, boost::shared_ptr<IMAPCommandArgument> pArgument) { return IMAPResult(IMAPResult::ResultNo, "Unsupported authentication mechanism."); }