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
   IMAPCommandStore::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument)
   {


      String sTag = pArgument->Tag();
      String sCommand = pArgument->Command();

      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");

      if (!pConnection->GetCurrentFolder())
         return IMAPResult(IMAPResult::ResultNo, "No folder selected.");


      shared_ptr<IMAPStore> pStore = shared_ptr<IMAPStore>(new IMAPStore());
      pStore->SetIsUID(false);

      String sResponse; 
      long lMailNoStart = 6;
      long lMailNoEnd = sCommand.Find(_T(" "), lMailNoStart);
      long lMailNoLen = lMailNoEnd - lMailNoStart;
      String sMailNo = sCommand.Mid(lMailNoStart, lMailNoLen);
      String sShowPart = sCommand.Mid(lMailNoEnd);

      pArgument->Command(sShowPart);

      IMAPResult result = pStore->DoForMails(pConnection, sMailNo, pArgument);

      if (result.GetResult() == IMAPResult::ResultOK)
         pConnection->SendAsciiData(pArgument->Tag() + " OK STORE completed\r\n");

      return result;
   }
   IMAPResult
   IMAPCommandUNSUBSCRIBE::ExecuteCommand(shared_ptr<HM::IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");

      // Parse the command
      shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser());

      pParser->Parse(pArgument);
      if (pParser->ParamCount() != 1)
         return IMAPResult(IMAPResult::ResultBad, "Command requires 1 parameter.");

      // Fetch the folder name. 
      String sFolderName = pParser->GetParamValue(pArgument, 0);

      shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName);

      IMAPResult result = ConfirmPossibleToUnsubscribe(pFolder);
      if (result.GetResult() != IMAPResult::ResultOK)
         return result;

      if (pFolder)
      {
         pFolder->SetIsSubscribed(false);
         PersistentIMAPFolder::SaveObject(pFolder);
      }
         
      String sResponse = pArgument->Tag() + " OK Unsubscribe completed\r\n";
      pConnection->SendAsciiData(sResponse);   

      return IMAPResult();
   }
IMAPResult
IMAPCommandRangeAction::DoForMails(boost::shared_ptr<IMAPConnection> pConnection, const String &sMailNos, boost::shared_ptr<IMAPCommandArgument> pArgument)
{
    long lColonPos = -1;

    std::vector<String> sSplitted = StringParser::SplitString(sMailNos, ",");

    if (_isUID)
    {
        boost_foreach(String sCur, sSplitted)
        {
            lColonPos = sCur.Find(_T(":"));

            if (lColonPos >= 0)
            {
                String sFirstPart = sCur.Mid(0, lColonPos);
                String sSecondPart = sCur.Mid(lColonPos + 1);

                unsigned int lStartDBID = _ttoi(sFirstPart);
                unsigned int lEndDBID = -1;
                if (sSecondPart != _T("*"))
                    lEndDBID = _ttoi(sSecondPart);

                std::vector<boost::shared_ptr<Message>> messages = pConnection->GetCurrentFolder()->GetMessages()->GetCopy();

                int index = 0;
                boost_foreach(boost::shared_ptr<Message> pMessage, messages)
                {
                    index++;
                    unsigned int uid = pMessage->GetUID();

                    if (uid >= lStartDBID)
                    {
                        if (lEndDBID == -1 || uid <= lEndDBID)
                        {
                            // UID doesn't fail just because the message is missing.
                            // This is why we don't check the return value.
                            IMAPResult result = DoAction(pConnection, index, pMessage, pArgument);
                            if (result.GetResult() != IMAPResult::ResultOK)
                            {
                                return result;
                            }
                        }
                    }
                }

            }
   IMAPResult
   IMAPCommandCOPY::ExecuteCommand(boost::shared_ptr<IMAPConnection> pConnection, boost::shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");
      
      if (!pConnection->GetCurrentFolder())
         return IMAPResult(IMAPResult::ResultNo, "No folder selected.");

      boost::shared_ptr<IMAPCopy> pCopy = boost::shared_ptr<IMAPCopy>(new IMAPCopy());
      pCopy->SetIsUID(false);

      String sResponse; 

      boost::shared_ptr<IMAPSimpleCommandParser> pParser = boost::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser());
      pParser->Parse(pArgument);
      if (pParser->ParamCount() != 2)
         return IMAPResult(IMAPResult::ResultBad, "Command requires 2 parameters.\r\n");

      String sMailNo = pParser->GetParamValue(pArgument, 0);
      String sFolderName = pParser->GetParamValue(pArgument, 1);

      pArgument->Command("\"" + sFolderName + "\"");

      // We should check if the folder exists. If not, notify user with trycreate
      boost::shared_ptr<IMAPFolder> pFolder = pConnection->GetFolderByFullPath(sFolderName);

      if (!pFolder)
      {
         // Nope, doesn't exist.
         return IMAPResult(IMAPResult::ResultNo, "Can't find mailbox with that name.\r\n");
      }

      IMAPResult result = pCopy->DoForMails(pConnection, sMailNo, pArgument);

      if (result.GetResult() == IMAPResult::ResultOK)
          pConnection->SendAsciiData(pArgument->Tag() + " OK COPY completed\r\n");

      return result;
   }
   IMAPResult 
   IMAPSearchParser::ParseCommand(std::shared_ptr<IMAPCommandArgument> pArgument, bool bIsSort)
   {
      // Replace literals in the command.
      std::shared_ptr<IMAPSimpleCommandParser> pSimpleParser = std::shared_ptr<IMAPSimpleCommandParser> (new IMAPSimpleCommandParser);

      if (bIsSort)
      {
         pSimpleParser->Parse(pArgument);
         pSimpleParser->UnliteralData();

         std::shared_ptr<IMAPSimpleWord> pSort = pSimpleParser->Word(0);
         if (pSort->Paranthezied())
         {
            sort_parser_ = std::shared_ptr<IMAPSortParser>(new IMAPSortParser);
            sort_parser_->Parse(pSort->Value());
         }

         
         // Second part should be character set.
         if (pSimpleParser->WordCount() < 2)
         {
            return IMAPResult(IMAPResult::ResultBad, "SearchCharacter set must be specified.");
         }

         charset_name_ = pSimpleParser->Word(1)->Value();
         if (!IsValidCharset_(charset_name_))
            return IMAPResult(IMAPResult::ResultNo, "[BADCHARSET]");

         // Trim away the SORT part of the SEARCH expresson 
         // since we only care about SEARCH below.
         String tempString = pArgument->Command();

         if (tempString.Find(_T(")")) > 0)
            tempString = tempString.Mid(tempString.Find(_T(")"))+2);

         pArgument->Command(tempString);
      }

      /* 
         Remove all parenthesis outside of strings. Some IMAP
         clients sends parenthesis, some doesn't. We remove
         them here to prevent the behaviors from differing.

         It should be safe to do this, since
            Criteria1 OR (Criteria2 Criteria 3)
         means the same as
            Criteria1 OR Criteria2 Criteria 3
      */

      String resultString;
      const String inputString = pArgument->Command();
      bool insideString = false;
      for (int i = 0; i < inputString.GetLength(); i++)
      {
         wchar_t curChar = inputString.GetAt(i);

         switch (curChar)
         {
         case '"':
            insideString = !insideString;
            break;
         case '(':
         case ')':
            if (!insideString)
               continue;
         }

         resultString += curChar;
      }

      // Replace literals in the command.
      pSimpleParser = std::shared_ptr<IMAPSimpleCommandParser> (new IMAPSimpleCommandParser);
      pArgument->Command(resultString);

      pSimpleParser->Parse(pArgument);
      pSimpleParser->UnliteralData();

      std::shared_ptr<IMAPSearchCriteria> pCriteria = std::shared_ptr<IMAPSearchCriteria> (new IMAPSearchCriteria);

      int currentWord = 0;
      IMAPResult result = ParseSegment_(pSimpleParser, currentWord, pCriteria, 0);
      if (result.GetResult() != IMAPResult::ResultOK)
         return result;

      result_criteria_ = pCriteria;

      return IMAPResult();
   }
   IMAPResult
   IMAPCommandUID::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");

      String sTag = pArgument->Tag();
      String sCommand = pArgument->Command();

      if (!pConnection->GetCurrentFolder())
         return IMAPResult(IMAPResult::ResultNo, "No folder selected.");

      shared_ptr<IMAPSimpleCommandParser> pParser = shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser());

      pParser->Parse(pArgument);
      
      if (pParser->WordCount() < 2)
         return IMAPResult(IMAPResult::ResultBad, "Command requires at least 1 parameter.");

      String sTypeOfUID = pParser->Word(1)->Value();

      if (sTypeOfUID.CompareNoCase(_T("FETCH")) == 0)
      {
         if (pParser->WordCount() < 4)
            return IMAPResult(IMAPResult::ResultBad, "Command requires at least 3 parameters.");

         command_ = shared_ptr<IMAPFetch>(new IMAPFetch());
      }
      else if (sTypeOfUID.CompareNoCase(_T("COPY")) == 0)
      {

         if (pParser->WordCount() < 4)
            return IMAPResult(IMAPResult::ResultBad, "Command requires at least 3 parameters.");

         command_ = shared_ptr<IMAPCopy>(new IMAPCopy());
      }
      else if (sTypeOfUID.CompareNoCase(_T("STORE")) == 0)
      {
         if (pParser->WordCount() < 4)
            return IMAPResult(IMAPResult::ResultBad, "Command requires at least 3 parameters.");

         command_ = shared_ptr<IMAPStore>(new IMAPStore());
      }
      else if (sTypeOfUID.CompareNoCase(_T("SEARCH")) == 0)
      {
         shared_ptr<IMAPCommandSEARCH> pCommand = shared_ptr<IMAPCommandSEARCH> (new IMAPCommandSEARCH(false));
         pCommand->SetIsUID();
         IMAPResult result = pCommand->ExecuteCommand(pConnection, pArgument);

         if (result.GetResult() == IMAPResult::ResultOK)
            pConnection->SendAsciiData(sTag + " OK UID completed\r\n");

         return result;
      }
      else if (sTypeOfUID.CompareNoCase(_T("SORT")) == 0)
      {
         shared_ptr<IMAPCommandSEARCH> pCommand = shared_ptr<IMAPCommandSEARCH> (new IMAPCommandSEARCH(true));
         pCommand->SetIsUID();
         IMAPResult result = pCommand->ExecuteCommand(pConnection, pArgument);
         
         if (result.GetResult() == IMAPResult::ResultOK)
            pConnection->SendAsciiData(sTag + " OK UID completed\r\n");

         return result;
      }


      if (!command_)
         return IMAPResult(IMAPResult::ResultBad, "Bad command.");

      command_->SetIsUID(true);

      // Copy the first word containing the message sequence
      long lSecWordStartPos = sCommand.Find(_T(" "), 5) + 1;
      long lSecWordEndPos = sCommand.Find(_T(" "), lSecWordStartPos);
      long lSecWordLength = lSecWordEndPos - lSecWordStartPos;
      String sMailNo = sCommand.Mid(lSecWordStartPos, lSecWordLength);
      
      // Copy the second word containing the actual command.
      String sShowPart = sCommand.Mid(lSecWordEndPos + 1);

      if (sMailNo.IsEmpty())
         return IMAPResult(IMAPResult::ResultBad, "No mail number specified");

      if (!StringParser::ValidateString(sMailNo, "01234567890,.:*"))
         return IMAPResult(IMAPResult::ResultBad, "Incorrect mail number");

      // Set the command to execute as argument
      pArgument->Command(sShowPart);

      // Execute the command. If we have gotten this far, it means that the syntax
      // of the command is correct. If we fail now, we should return NO. 
      IMAPResult result = command_->DoForMails(pConnection, sMailNo, pArgument);

      if (result.GetResult() == IMAPResult::ResultOK)
         pConnection->SendAsciiData(pArgument->Tag() + " OK UID completed\r\n");

      return result;
   }
   IMAPResult
   IMAPCommandSEARCH::ExecuteCommand(std::shared_ptr<IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (is_sort_ && !Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPSort())
         return IMAPResult(IMAPResult::ResultNo, "IMAP SORT is not enabled.");

      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");

      if (!pConnection->GetCurrentFolder())
         return IMAPResult(IMAPResult::ResultNo, "No folder selected.");

      if (!pArgument)
         return IMAPResult(IMAPResult::ResultNo, "Internal error IMAP-SEARCH-1.");

      {
         // The IMAP Search parser should not parse
         // the beginning of the command, UID SEARCH
         // or SEARCH
         String sCommand = pArgument->Command();

         int iCommandStartPos;
         
         if (is_uid_)
            iCommandStartPos = sCommand.Find(_T(" "), 4) + 1;
         else
            iCommandStartPos = sCommand.Find(_T(" ")) + 1;

         sCommand = sCommand.Mid(iCommandStartPos); // 3 as in UID

         pArgument->Command(sCommand);
      }

      std::shared_ptr<IMAPSearchParser> pParser = std::shared_ptr<IMAPSearchParser>(new IMAPSearchParser());
      IMAPResult result = pParser->ParseCommand(pArgument, is_sort_);
      if (result.GetResult() != IMAPResult::ResultOK)
         return result;

      if (is_sort_ && !pParser->GetSortParser())
         return IMAPResult(IMAPResult::ResultBad, "Incorrect search commands.");

      // Mails in current box
      std::shared_ptr<IMAPFolder> pCurFolder =  pConnection->GetCurrentFolder();

      if (!pCurFolder)
         return IMAPResult(IMAPResult::ResultBad, "No selected folder");

      std::vector<std::shared_ptr<Message>> messages = pCurFolder->GetMessages()->GetCopy();

      std::vector<String> sMatchingVec;
      if (messages.size() > 0)
      {
         // Iterate through the messages and see which ones match.
         std::vector<std::pair<int, std::shared_ptr<Message> > > vecMatchingMessages;

         int index = 0;
         for(std::shared_ptr<Message> pMessage : messages)
         {
            const String fileName = PersistentMessage::GetFileName(pConnection->GetAccount(), pMessage);

            index++;
            if (pMessage && DoesMessageMatch_(pParser->GetCriteria(), fileName, pMessage, index))
            {
               // Yup we got a match.
               vecMatchingMessages.push_back(make_pair(index, pMessage));
            }
         }

         if (is_sort_)
         {
            IMAPSort oSorter;
            oSorter.Sort(pConnection, vecMatchingMessages, pParser->GetSortParser());
            // Sort the message vector
         }

         typedef std::pair<int, std::shared_ptr<Message> > MessagePair;
         for(MessagePair messagePair : vecMatchingMessages)
         {
            int index = messagePair.first;
            std::shared_ptr<Message> pMessage = messagePair.second;

            String sID;
            if (is_uid_)
               sID.Format(_T("%u"), pMessage->GetUID());
            else
               sID.Format(_T("%d"), index);

            sMatchingVec.push_back(sID);
         }

      }

      // Send response
      String sMatching;
      if (sMatchingVec.size() > 0)
      {
         // If we don't find any matches, we shouldn't return a whitespace
         // after SEARCH/SORT below. That's why we add the white space here.
         sMatching = " " + StringParser::JoinVector(sMatchingVec, " ") ;
      }
      
      String sResponse;
      if (is_sort_)
         sResponse = "* SORT" + sMatching + "\r\n";
      else
         sResponse = "* SEARCH" + sMatching + "\r\n";

      if (!is_uid_) 
         // if this is a UID command, IMAPCommandUID takes care of the below line.
         sResponse += pArgument->Tag() + " OK Search completed\r\n";

      pConnection->SendAsciiData(sResponse);

      return IMAPResult();
   }
   IMAPResult
   IMAPCommandCREATE::ExecuteCommand(std::shared_ptr<HM::IMAPConnection> pConnection, std::shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");

     
      std::shared_ptr<IMAPSimpleCommandParser> pParser = std::shared_ptr<IMAPSimpleCommandParser>(new IMAPSimpleCommandParser());

      pParser->Parse(pArgument);

      if (pParser->ParamCount() != 1)
         return IMAPResult(IMAPResult::ResultBad, "CREATE Command requires 1 parameter.");

      // Fetch the name of the mailbox to create.
      String sFolderName = pParser->GetParamValue(pArgument, 0);

      if (sFolderName.IsEmpty())
         return IMAPResult(IMAPResult::ResultNo, "Folder name not specified.");
         
      // Check so that it does not already exist.
      std::shared_ptr<IMAPFolder> pExistsCheck = pConnection->GetFolderByFullPath(sFolderName);
      if (pExistsCheck)
         return IMAPResult(IMAPResult::ResultNo, "Folder already exists.");

      String hierarchyDelimiter = Configuration::Instance()->GetIMAPConfiguration()->GetHierarchyDelimiter();

      std::vector<String> vecFolderPath = StringParser::SplitString(sFolderName, hierarchyDelimiter);
   
      bool bIsPublicFolder = IMAPFolderUtilities::IsPublicFolder(vecFolderPath);
      if (bIsPublicFolder)
         vecFolderPath.erase(vecFolderPath.begin());

      if (!IMAPFolder::IsValidFolderName(vecFolderPath, bIsPublicFolder))
         return IMAPResult(IMAPResult::ResultNo, "CREATE The folder name is invalid.");

      IMAPResult result = ConfirmPossibleToCreate(pConnection, vecFolderPath, bIsPublicFolder);
      if (result.GetResult() != IMAPResult::ResultOK)
         return result;

      std::shared_ptr<IMAPFolders> pParentFolderContainer;
      if (!bIsPublicFolder)
         pParentFolderContainer = pConnection->GetAccountFolders();
      else
         pParentFolderContainer = pConnection->GetPublicFolders();

      bool bSubscribeToFolder = bIsPublicFolder;

      pParentFolderContainer->CreatePath(pParentFolderContainer, vecFolderPath, bSubscribeToFolder);

      String sResponse = pArgument->Tag() + " OK CREATE Completed\r\n";

      pConnection->SendAsciiData(sResponse);   

      assert(pParentFolderContainer->GetCount() > 0);

      // Send a notification to everyone subscribing to this event.
      std::shared_ptr<IMAPFolder> firstFolder = pParentFolderContainer->GetItem(0);
   
      return IMAPResult();
   }
   IMAPResult
   IMAPFetchParser::ParseCommand(const String &sCommand)
   {
      String sStringToParse = sCommand;
      
      IMAPResult result = _ValidateSyntax(sStringToParse);
      if (result.GetResult() != IMAPResult::ResultOK)
         return result;
      
      std::vector<String> vecResult = _ParseString(sStringToParse);
      std::vector<String>::iterator iter = vecResult.begin();
      while (iter != vecResult.end())
      {
         String sPart = (*iter);

         
         ePartType iType = _GetPartType(sPart);

         switch (iType)
         {
            case BODYPEEK:
            {
               IMAPFetchParser::BodyPart oPart = _ParseBODYPEEK(sPart);
               m_vecPartsToLookAt.push_back(oPart);
               break;
            }
            
            case ENVELOPE:
            {
               m_bShowEnvelope = true;
               break;
            }
            
            case RFC822SIZE:
            {
               m_bShowRFCSize = true;
               break;
            }

            case UID:
            {
               m_bShowUID = true;
               break;
            }

            case FLAGS:
            {
               m_bShowFlags = true;
               break;
            }

            case INTERNALDATE:
            {
               m_bShowInternalDate = true;
               break;
            }

            case BODYSTRUCTURE:
            {
               m_bShowBodyStructure = true;
               break;
            }
            
            case BODYSTRUCTURENONEXTENSIBLE:
            {
               m_bShowBodyStructureNonExtensible = true;
               break;
            }

            case BODY:
            {
               IMAPFetchParser::BodyPart oPart = _ParseBODY(sPart);
               m_vecPartsToLookAt.push_back(oPart);
               break;
            }
            case RFC822:
            {
               // Same as:
               IMAPFetchParser::BodyPart oPart = _ParseBODY(sPart);
               oPart.SetDescription("RFC822");
               m_vecPartsToLookAt.push_back(oPart);
               break;

            }
            case ALL:
            {
               // ALL
               // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)

               m_bShowFlags = true;
               m_bShowInternalDate = true;
               m_bShowRFCSize = true;
               m_bShowEnvelope = true;
               break;
            }

            case FAST:
            {
               // FAST
               // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)

               m_bShowFlags = true;
               m_bShowInternalDate = true;
               m_bShowRFCSize = true;
               break;
            }

            case FULL:
            {
               // FULL
               // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)
               m_bShowFlags = true;
               m_bShowInternalDate = true;
               m_bShowRFCSize = true;
               m_bShowEnvelope = true;
               m_bShowBodyStructure = true;
               break;
            }
            case RFC822HEADER:
            {
               /* 
                  RFC822.HEADER
                  Functionally equivalent to BODY.PEEK[HEADER], differing in the
                  syntax of the resulting untagged FETCH data (RFC822.HEADER is
                  returned).
                  */
            
               IMAPFetchParser::BodyPart oPart = _ParseBODYPEEK("BODY[HEADER]");
               oPart.SetDescription("RFC822.HEADER");
               m_vecPartsToLookAt.push_back(oPart);
               break;
            }
            case RFC822TEXT:
               {
                  /* 
                  Functionally equivalent to BODY[TEXT], differing in the syntax
                  of the resulting untagged FETCH data (RFC822.TEXT is returned).
                  */

                  IMAPFetchParser::BodyPart oPart = _ParseBODY("BODY[TEXT]");
                  oPart.SetDescription("RFC822.TEXT");
                  m_vecPartsToLookAt.push_back(oPart);

                  break;
               }
         }

         iter++;
      }

      return IMAPResult();
   }
   IMAPResult
   IMAPCommandRangeAction::DoForMails(std::shared_ptr<IMAPConnection> pConnection, const String &sMailNos, std::shared_ptr<IMAPCommandArgument> pArgument)
   {
      long lColonPos = -1;

      std::vector<String> sSplitted = StringParser::SplitString(sMailNos, ",");

      if (is_uid_)
      {
         for(String sCur : sSplitted)
         {
            lColonPos = sCur.Find(_T(":"));

            if (lColonPos >= 0)
            {
               String sFirstPart = sCur.Mid(0, lColonPos);
               String sSecondPart = sCur.Mid(lColonPos + 1);

               unsigned int lStartDBID = _ttoi(sFirstPart);
               unsigned int lEndDBID = -1;
               if (sSecondPart != _T("*"))
                  lEndDBID = _ttoi(sSecondPart);

               std::vector<std::shared_ptr<Message>> messages = pConnection->GetCurrentFolder()->GetMessages()->GetCopy();

               int index = 0;
               for(std::shared_ptr<Message> pMessage: messages)
               {
                  index++;
                  unsigned int uid = pMessage->GetUID();

                  if (uid >= lStartDBID)
                  {
                     if (lEndDBID == -1 || uid <= lEndDBID)
                     {
                        // UID doesn't fail just because the message is missing.
                        // This is why we don't check the return value.
                        IMAPResult result = DoAction(pConnection, index, pMessage, pArgument);
                        if (result.GetResult() != IMAPResult::ResultOK)
                        {
                           return result;
                        }
                     }
                  }
               }

            }
            else 
            {
               unsigned int uid = _ttoi(sCur);

               unsigned int foundIndex = 0;
               std::shared_ptr<Messages> messages = pConnection->GetCurrentFolder()->GetMessages();
               std::shared_ptr<Message> message = messages->GetItemByUID(uid, foundIndex);
               if (!message)
                  continue;
               
               IMAPResult result = DoAction(pConnection, foundIndex, message, pArgument);
               if (result.GetResult() != IMAPResult::ResultOK)
               {
                  return result;
               }
            }
         }            

      }
      else
      {
         for(String sCur: sSplitted)
         {
            lColonPos = sCur.Find(_T(":"));

            if (lColonPos >= 0)
            {
               String sFirstPart = sCur.Mid(0, lColonPos);
               String sSecondPart = sCur.Mid(lColonPos + 1);

               int lStartIndex = _ttoi(sFirstPart);
               int lEndIndex = -1;
               if (sSecondPart != _T("*"))
                  lEndIndex = _ttoi(sSecondPart);

               auto vecMessages = pConnection->GetCurrentFolder()->GetMessages()->GetCopy();
               
               int index = 0;
               for(std::shared_ptr<Message> message : vecMessages)
               {
                  index++;

                  if (index >= lStartIndex)
                  {
                     if (lEndIndex == -1 || index <= lEndIndex)
                     {
                        IMAPResult result = DoAction(pConnection, index, message, pArgument);
                        if (result.GetResult() != IMAPResult::ResultOK)
                        {
                           return result;
                        }
                     }
                  }
               }

            }
            else 
            {
               int messageIndex = _ttoi(sCur);
               std::shared_ptr<Message> pMessage = pConnection->GetCurrentFolder()->GetMessages()->GetItem(messageIndex-1);

               if (!pMessage)
                  continue;

               IMAPResult result = DoAction(pConnection, messageIndex, pMessage, pArgument);
               if (result.GetResult() != IMAPResult::ResultOK)
               {
                  return result;
               }
            }
         }   

      }

      return IMAPResult();

   }
   IMAPResult
   IMAPCommandSEARCH::ExecuteCommand(shared_ptr<IMAPConnection> pConnection, shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (m_bIsSort && !Configuration::Instance()->GetIMAPConfiguration()->GetUseIMAPSort())
         return IMAPResult(IMAPResult::ResultNo, "IMAP SORT is not enabled.");

      if (!pConnection->IsAuthenticated())
         return IMAPResult(IMAPResult::ResultNo, "Authenticate first");

      if (!pConnection->GetCurrentFolder())
         return IMAPResult(IMAPResult::ResultNo, "No folder selected.");

      if (!pArgument)
         return IMAPResult(IMAPResult::ResultNo, "Internal error IMAP-SEARCH-1.");

      {
         // The IMAP Search parser should not parse
         // the beginning of the command, UID SEARCH
         // or SEARCH
         String sCommand = pArgument->Command();

         int iCommandStartPos;
         
         if (m_bIsUID)
            iCommandStartPos = sCommand.Find(_T(" "), 4) + 1;
         else
            iCommandStartPos = sCommand.Find(_T(" ")) + 1;

         sCommand = sCommand.Mid(iCommandStartPos); // 3 as in UID

         pArgument->Command(sCommand);
      }

      shared_ptr<IMAPSearchParser> pParser = shared_ptr<IMAPSearchParser>(new IMAPSearchParser());
      IMAPResult result = pParser->ParseCommand(pArgument, m_bIsSort);
      if (result.GetResult() != IMAPResult::ResultOK)
         return result;

      if (m_bIsSort && !pParser->GetSortParser())
         return IMAPResult(IMAPResult::ResultBad, "Incorrect search commands.");

      // Mails in current box
      shared_ptr<IMAPFolder> pCurFolder =  pConnection->GetCurrentFolder();

      if (!pCurFolder)
         return IMAPResult(IMAPResult::ResultBad, "No selected folder");

      vector<shared_ptr<Message>> messages = pCurFolder->GetMessages()->GetCopy();

      std::vector<String> sMatchingVec;
      if (messages.size() > 0)
      {
         // Iterate through the messages and see which ones match.
         vector<pair<int, shared_ptr<Message> > > vecMatchingMessages;

         int index = 0;
         boost_foreach(shared_ptr<Message> pMessage, messages)
         {
            const String fileName = PersistentMessage::GetFileName(pConnection->GetAccount(), pMessage);

            index++;
            if (pMessage && _DoesMessageMatch(pParser->GetCriteria(), fileName, pMessage, index))
            {
               // Yup we got a match.
               vecMatchingMessages.push_back(make_pair(index, pMessage));
            }
         }

         if (m_bIsSort)
         {
            IMAPSort oSorter;
            oSorter.Sort(pConnection, vecMatchingMessages, pParser->GetSortParser());
            // Sort the message vector
         }

         typedef pair<int, shared_ptr<Message> > MessagePair;
         boost_foreach(MessagePair messagePair, vecMatchingMessages)
         {
            int index = messagePair.first;
            shared_ptr<Message> pMessage = messagePair.second;

            String sID;
            if (m_bIsUID)
               sID.Format(_T("%u"), pMessage->GetUID());
            else
               sID.Format(_T("%d"), index);

            sMatchingVec.push_back(sID);
         }