NS_IMETHODIMP nsImapMailFolder::UpdateFolderWithListener()

in mailnews/imap/src/nsImapMailFolder.cpp [604:836]


NS_IMETHODIMP nsImapMailFolder::UpdateFolderWithListener(
    nsIMsgWindow* aMsgWindow, nsIUrlListener* aUrlListener) {
  nsresult rv;
  // If this is the inbox, filters will be applied. Otherwise, we test the
  // inherited folder property "applyIncomingFilters" (which defaults to empty).
  // If this inherited property has the string value "true", we will apply
  // filters even if this is not the inbox folder.
  nsCString applyIncomingFilters;
  GetInheritedStringProperty("applyIncomingFilters", applyIncomingFilters);
  m_applyIncomingFilters = applyIncomingFilters.EqualsLiteral("true");

  nsCString folderName;
  GetPrettyName(folderName);
  MOZ_LOG(FILTERLOGMODULE, LogLevel::Debug,
          ("(Imap) nsImapMailFolder::UpdateFolderWithListener() on folder '%s'",
           folderName.get()));
  if (mFlags & nsMsgFolderFlags::Inbox || m_applyIncomingFilters) {
    MOZ_LOG(FILTERLOGMODULE, LogLevel::Info,
            ("(Imap) Preparing filter run on folder '%s'", folderName.get()));

    if (!m_filterList) {
      rv = GetFilterList(aMsgWindow, getter_AddRefs(m_filterList));
      if (NS_FAILED(rv)) {
        MOZ_LOG(FILTERLOGMODULE, LogLevel::Error,
                ("(Imap) Loading of filter list failed"));
      }
    }

    // if there's no msg window, but someone is updating the inbox, we're
    // doing something biff-like, and may download headers, so make biff notify.
    if (!aMsgWindow && mFlags & nsMsgFolderFlags::Inbox)
      SetPerformingBiff(true);
  }

  if (m_filterList) {
    nsCString listId;
    m_filterList->GetListId(listId);
    MOZ_LOG(FILTERLOGMODULE, LogLevel::Info,
            ("(Imap) Preparing filter list %s", listId.get()));
    nsCOMPtr<nsIMsgIncomingServer> server;
    rv = GetServer(getter_AddRefs(server));
    NS_ENSURE_SUCCESS(rv, rv);

    bool canFileMessagesOnServer = true;
    rv = server->GetCanFileMessagesOnServer(&canFileMessagesOnServer);
    // the mdn filter is for filing return receipts into the sent folder
    // some servers (like AOL mail servers)
    // can't file to the sent folder, so we don't add the filter for those
    // servers
    if (canFileMessagesOnServer) {
      rv = server->ConfigureTemporaryFilters(m_filterList);
      NS_ENSURE_SUCCESS(rv, rv);
    }

    // If a body filter is enabled for an offline folder, delay the filter
    // application until after message has been downloaded.
    m_filterListRequiresBody = false;

    if (mFlags & nsMsgFolderFlags::Offline) {
      nsCOMPtr<nsIMsgFilterService> filterService =
          do_GetService("@mozilla.org/messenger/services/filters;1", &rv);
      uint32_t filterCount = 0;
      m_filterList->GetFilterCount(&filterCount);
      for (uint32_t index = 0; index < filterCount && !m_filterListRequiresBody;
           ++index) {
        nsCOMPtr<nsIMsgFilter> filter;
        m_filterList->GetFilterAt(index, getter_AddRefs(filter));
        if (!filter) continue;
        nsMsgFilterTypeType filterType;
        filter->GetFilterType(&filterType);
        if (!(filterType & nsMsgFilterType::Incoming)) continue;
        bool enabled = false;
        filter->GetEnabled(&enabled);
        if (!enabled) continue;
        nsTArray<RefPtr<nsIMsgSearchTerm>> searchTerms;
        filter->GetSearchTerms(searchTerms);
        for (nsIMsgSearchTerm* term : searchTerms) {
          nsMsgSearchAttribValue attrib;
          rv = term->GetAttrib(&attrib);
          NS_ENSURE_SUCCESS(rv, rv);
          if (attrib == nsMsgSearchAttrib::Body)
            m_filterListRequiresBody = true;
          else if (attrib == nsMsgSearchAttrib::Custom) {
            nsAutoCString customId;
            rv = term->GetCustomId(customId);
            nsCOMPtr<nsIMsgSearchCustomTerm> customTerm;
            if (NS_SUCCEEDED(rv) && filterService)
              rv = filterService->GetCustomTerm(customId,
                                                getter_AddRefs(customTerm));
            bool needsBody = false;
            if (NS_SUCCEEDED(rv) && customTerm)
              rv = customTerm->GetNeedsBody(&needsBody);
            if (NS_SUCCEEDED(rv) && needsBody) m_filterListRequiresBody = true;
          }
          if (m_filterListRequiresBody) {
            break;
          }
        }

        // Also check if filter actions need the body, as this
        // is supported in custom actions.
        uint32_t numActions = 0;
        filter->GetActionCount(&numActions);
        for (uint32_t actionIndex = 0;
             actionIndex < numActions && !m_filterListRequiresBody;
             actionIndex++) {
          nsCOMPtr<nsIMsgRuleAction> action;
          rv = filter->GetActionAt(actionIndex, getter_AddRefs(action));
          if (NS_FAILED(rv) || !action) continue;

          nsCOMPtr<nsIMsgFilterCustomAction> customAction;
          rv = action->GetCustomAction(getter_AddRefs(customAction));
          if (NS_FAILED(rv) || !customAction) continue;

          bool needsBody = false;
          customAction->GetNeedsBody(&needsBody);
          if (needsBody) m_filterListRequiresBody = true;
        }
      }
    }
    MOZ_LOG(FILTERLOGMODULE, LogLevel::Info,
            ("(Imap) Filters require the message body: %s",
             (m_filterListRequiresBody ? "true" : "false")));
  }

  bool isServer;
  rv = GetIsServer(&isServer);
  if (NS_SUCCEEDED(rv) && isServer) {
    if (!m_haveDiscoveredAllFolders) {
      bool hasSubFolders = false;
      GetHasSubFolders(&hasSubFolders);
      if (!hasSubFolders) {
        rv = CreateClientSubfolderInfo(
            "Inbox"_ns, kOnlineHierarchySeparatorUnknown, 0, false);
        NS_ENSURE_SUCCESS(rv, rv);
      }
      m_haveDiscoveredAllFolders = true;
    }
  }

  rv = GetDatabase();
  if (NS_FAILED(rv)) {
    ThrowAlertMsg("errorGettingDB", aMsgWindow);
    return rv;
  }

  bool hasOfflineEvents = false;
  GetFlag(nsMsgFolderFlags::OfflineEvents, &hasOfflineEvents);

  if (!WeAreOffline()) {
    if (hasOfflineEvents) {
      // hold a reference to the offline sync object. If ProcessNextOperation
      // runs a url, a reference will be added to it. Otherwise, it will get
      // destroyed when the refptr goes out of scope.
      RefPtr<nsImapOfflineSync> goOnline = new nsImapOfflineSync();
      goOnline->Init(aMsgWindow, this, this, false);
      if (goOnline) {
        // Save the listener, so when we arrive here again later (below)
        // imapService->SelectFolder() gets the right listener.
        m_urlListener = aUrlListener;
        return goOnline->ProcessNextOperation();
      }
    }
  }

  // Check it we're password protecting the local store.
  if (!PromptForMasterPasswordIfNecessary()) return NS_ERROR_FAILURE;

  bool canOpenThisFolder = true;
  GetCanOpenFolder(&canOpenThisFolder);

  // Don't run select if we can't select the folder...
  if (!m_urlRunning && canOpenThisFolder && !isServer) {
    nsCOMPtr<nsIImapService> imapService =
        do_GetService("@mozilla.org/messenger/imapservice;1", &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    // Do a discovery in its own url if needed. Do before SELECT url.
    nsCOMPtr<nsIImapHostSessionList> hostSession =
        do_GetService(kCImapHostSessionList, &rv);
    if (NS_SUCCEEDED(rv) && hostSession) {
      bool foundMailboxesAlready = false;
      nsCString serverKey;
      GetServerKey(serverKey);
      hostSession->GetHaveWeEverDiscoveredFoldersForHost(serverKey.get(),
                                                         foundMailboxesAlready);
      if (!foundMailboxesAlready) {
        bool discoveryInProgress = false;
        // See if discovery in progress and not yet finished.
        hostSession->GetDiscoveryForHostInProgress(serverKey.get(),
                                                   discoveryInProgress);
        if (!discoveryInProgress) {
          nsCOMPtr<nsIMsgFolder> rootFolder;
          rv = GetRootFolder(getter_AddRefs(rootFolder));
          if (NS_SUCCEEDED(rv) && rootFolder) {
            rv = imapService->DiscoverAllFolders(rootFolder, this, aMsgWindow);
            if (NS_SUCCEEDED(rv))
              hostSession->SetDiscoveryForHostInProgress(serverKey.get(), true);
          }
        }
      }
    }

    nsCOMPtr<nsIURI> url;
    rv = imapService->SelectFolder(this, m_urlListener, aMsgWindow,
                                   getter_AddRefs(url));
    if (NS_SUCCEEDED(rv)) {
      m_urlRunning = true;
      m_updatingFolder = true;
    }
    if (url) {
      nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(url, &rv);
      NS_ENSURE_SUCCESS(rv, rv);
      mailnewsUrl->RegisterListener(this);
      m_urlListener = aUrlListener;
    }

    // Allow IMAP folder auto-compact to occur when online or offline.
    if (aMsgWindow) AutoCompact(aMsgWindow);

    if (rv == NS_MSG_ERROR_OFFLINE || rv == NS_BINDING_ABORTED) {
      rv = NS_OK;
      NotifyFolderEvent(kFolderLoaded);
    }
  } else {
    // Tell the front end that the folder is loaded if we're not going to
    // actually run a url.
    if (!m_updatingFolder)  // if we're already running an update url, we'll let
                            // that one send the folder loaded
      NotifyFolderEvent(kFolderLoaded);
  }
  return rv;
}