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 &currentWord, 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();
   
   }
Beispiel #16
0
   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();
   }
Beispiel #25
0
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.");
 }