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
   IMAPCommandSUBSCRIBE::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, "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();
      }

      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();
   }
示例#3
0
   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
   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();
   }
   void
   IMAPCommandAppend::_Finish(shared_ptr<IMAPConnection> pConnection)
   {
      if (!m_pCurrentMessage)
         return;

      // Add this message to the folder.
      m_pCurrentMessage->SetSize(FileUtilities::FileSize(m_sMessageFileName));
      m_pCurrentMessage->SetState(Message::Delivered);

      // Set message flags.
      bool bSeen = (m_sFlagsToSet.FindNoCase(_T("\\Seen")) >= 0);
      bool bDeleted = (m_sFlagsToSet.FindNoCase(_T("\\Deleted")) >= 0);
      bool bDraft = (m_sFlagsToSet.FindNoCase(_T("\\Draft")) >= 0);
      bool bAnswered = (m_sFlagsToSet.FindNoCase(_T("\\Answered")) >= 0);
      bool bFlagged = (m_sFlagsToSet.FindNoCase(_T("\\Flagged")) >= 0);
      
      if (bSeen)
      {
         // ACL: If user tries to set the Seen flag, check that he has permission to do so.
         if (!pConnection->CheckPermission(m_pDestinationFolder, ACLPermission::PermissionWriteSeen))
         {
            // User does not have permission to set the Seen flag. 
            bSeen = false;
         }
      }

      m_pCurrentMessage->SetFlagDeleted(bDeleted);
      m_pCurrentMessage->SetFlagSeen(bSeen);
      m_pCurrentMessage->SetFlagDraft(bDraft);
      m_pCurrentMessage->SetFlagAnswered(bAnswered);
      m_pCurrentMessage->SetFlagFlagged(bFlagged);

      m_pCurrentMessage->SetFlagRecent(true);
         
      // Set the create time
      if (!m_sCreateTimeToSet.IsEmpty())
      {
         // Convert to internal format
         m_sCreateTimeToSet = Time::GetInternalDateFromIMAPInternalDate(m_sCreateTimeToSet);
         m_pCurrentMessage->SetCreateTime(m_sCreateTimeToSet);
      }

      PersistentMessage::SaveObject(m_pCurrentMessage);
      m_pDestinationFolder->SetFolderNeedsRefresh();

      String sResponse;
      if (pConnection->GetCurrentFolder() &&
          pConnection->GetCurrentFolder()->GetID() == m_pDestinationFolder->GetID())
      {
         shared_ptr<Messages> messages = m_pDestinationFolder->GetMessages();
         sResponse += IMAPNotificationClient::GenerateExistsString(messages->GetCount());
         sResponse += IMAPNotificationClient::GenerateRecentString(messages->GetNoOfRecent());
      }

      // Send the OK response to the client.
      sResponse += m_sCurrentTag + " OK APPEND completed\r\n";
      pConnection->SendAsciiData(sResponse);

      // Notify the mailbox notifier that the mailbox contents have changed. 
      shared_ptr<ChangeNotification> pNotification = 
         shared_ptr<ChangeNotification>(new ChangeNotification(m_pDestinationFolder->GetAccountID(), m_pDestinationFolder->GetID(), ChangeNotification::NotificationMessageAdded));
      Application::Instance()->GetNotificationServer()->SendNotification(pConnection->GetNotificationClient(), pNotification);

      m_pDestinationFolder.reset();
      m_pCurrentMessage.reset();
   }
示例#6
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();
}
示例#7
0
   IMAPResult
   IMAPStore::DoAction(shared_ptr<IMAPConnection> pConnection, int messageIndex,  shared_ptr<Message> pMessage, const shared_ptr<IMAPCommandArgument> pArgument)
   {
      if (!pMessage || !pArgument)
         return IMAPResult(IMAPResult::ResultBad, "Invalid parameters");

      if (pConnection->GetCurrentFolderReadOnly())
      {
         return IMAPResult(IMAPResult::ResultNo, "Store command on read-only folder.");
      }

      bool bSilent = false;

      String sCommand = pArgument->Command();
      if (sCommand.FindNoCase(_T("FLAGS.SILENT")) >= 0)
         bSilent = true;
      else
         bSilent = false;

      // Read flags from command.
      bool bSeen = (sCommand.FindNoCase(_T("\\Seen")) >= 0);
      bool bDeleted = (sCommand.FindNoCase(_T("\\Deleted")) >= 0);
      bool bDraft = (sCommand.FindNoCase(_T("\\Draft")) >= 0);
      bool bAnswered = (sCommand.FindNoCase(_T("\\Answered")) >= 0);
      bool bFlagged = (sCommand.FindNoCase(_T("\\Flagged")) >= 0);
   
      if (bSeen)
      {
         // ACL: If user tries to change the Seen flag, check that he has permission to do so.
         if (!pConnection->CheckPermission(pConnection->GetCurrentFolder(), ACLPermission::PermissionWriteSeen))
            return IMAPResult(IMAPResult::ResultNo, "ACL: WriteSeen permission denied (Required for STORE command).");
      }

      if (bDeleted)
      {
         if (!pConnection->CheckPermission(pConnection->GetCurrentFolder(), ACLPermission::PermissionWriteDeleted))
            return IMAPResult(IMAPResult::ResultNo, "ACL: DeleteMessages permission denied (Required for STORE command).");
      }

      if (bDraft || bAnswered || bFlagged)
      {
         if (!pConnection->CheckPermission(pConnection->GetCurrentFolder(), ACLPermission::PermissionWriteOthers))
            return IMAPResult(IMAPResult::ResultNo, "ACL: WriteOthers permission denied (Required for STORE command).");
      }


      if (sCommand.FindNoCase(_T("-FLAGS")) >= 0)
      {
         // Remove flags
         if (bSeen)
            pMessage->SetFlagSeen(false);
         if (bDeleted)
            pMessage->SetFlagDeleted(false);
         if (bDraft)
            pMessage->SetFlagDraft(false);
         if (bAnswered)
            pMessage->SetFlagAnswered(false);
         if (bFlagged)
            pMessage->SetFlagFlagged(false);



      }
      else if (sCommand.FindNoCase(_T("+FLAGS")) >= 0)
      {
         // Add flags
         if (bSeen)
            pMessage->SetFlagSeen(true);
         if (bDeleted)
            pMessage->SetFlagDeleted(true);
         if (bDraft)
            pMessage->SetFlagDraft(true);
         if (bAnswered)
            pMessage->SetFlagAnswered(true);
         if (bFlagged)
            pMessage->SetFlagFlagged(true);
       
      }
      else if (sCommand.FindNoCase(_T("FLAGS")) >= 0)
      {
         // Set flags
         pMessage->SetFlagSeen(bSeen);
         pMessage->SetFlagDeleted(bDeleted);
         pMessage->SetFlagDraft(bDraft);
         pMessage->SetFlagAnswered(bAnswered);
         pMessage->SetFlagFlagged(bFlagged);
      }


      Application::Instance()->GetFolderManager()->UpdateMessageFlags(
         (int) pConnection->GetCurrentFolder()->GetAccountID(), 
         (int) pConnection->GetCurrentFolder()->GetID(),
         pMessage->GetID(), pMessage->GetFlags());

      if (!bSilent)
      {
         pConnection->SendAsciiData(GetMessageFlags(pMessage, messageIndex));
      }

      // BEGIN IMAP IDLE

      // Notify the mailbox notifier that the mailbox contents have changed.
      std::vector<__int64> effectedMessages;
      effectedMessages.push_back(pMessage->GetID());

      shared_ptr<ChangeNotification> pNotification = 
         shared_ptr<ChangeNotification>(new ChangeNotification(pConnection->GetCurrentFolder()->GetAccountID(), pConnection->GetCurrentFolder()->GetID(),  ChangeNotification::NotificationMessageFlagsChanged, effectedMessages));

      Application::Instance()->GetNotificationServer()->SendNotification(pConnection->GetNotificationClient(), pNotification);
      // END IMAP IDLE

      return IMAPResult();
   }