async query()

in mail/components/extensions/parent/ext-folders.js [624:998]


        async query(queryInfo) {
          // Generator function to flatten the folder structure.
          function* getFlatFolderStructure(folder) {
            yield folder;
            if (folder.hasSubFolders) {
              for (const subFolder of folder.subFolders) {
                yield* getFlatFolderStructure(subFolder);
              }
            }
          }

          // Evaluate query properties which can be specified as boolean
          // (none/some) or integer (min/max).
          function matchBooleanOrQueryRange(query, valueCallback) {
            if (query == null) {
              return true;
            }
            const value = valueCallback();

            if (typeof query == "boolean") {
              return query == (value != 0);
            }
            // If not a boolean, it is an object with min and max members.
            if (query.min != null && value < query.min) {
              return false;
            }
            if (query.max != null && value > query.max) {
              return false;
            }
            return true;
          }

          // Prepare query dates.
          const queryDates = {};
          const recentTime = Date.now() - FolderUtils.ONE_MONTH_IN_MILLISECONDS;
          if (
            queryInfo.recent === true ||
            queryInfo.lastUsed?.recent === true
          ) {
            queryDates.lastUsedAfter = recentTime;
          } else if (
            queryInfo.recent === false ||
            queryInfo.lastUsed?.recent === false
          ) {
            queryDates.lastUsedBefore = recentTime;
          } else {
            if (queryInfo.lastUsed?.after) {
              queryDates.lastUsedAfter = queryInfo.lastUsed.after.getTime();
            }
            if (queryInfo.lastUsed?.before) {
              queryDates.lastUsedBefore = queryInfo.lastUsed.before.getTime();
            }
          }

          if (queryInfo.lastUsedAsDestination?.recent === true) {
            queryDates.lastUsedAsDestinationAfter = recentTime;
          } else if (queryInfo.lastUsedAsDestination?.recent === false) {
            queryDates.lastUsedAsDestinationBefore = recentTime;
          } else {
            if (queryInfo.lastUsedAsDestination?.after) {
              queryDates.lastUsedAsDestinationAfter =
                queryInfo.lastUsedAsDestination.after.getTime();
            }
            if (queryInfo.lastUsedAsDestination?.before) {
              queryDates.lastUsedAsDestinationBefore =
                queryInfo.lastUsedAsDestination.before.getTime();
            }
          }

          // Prepare folders, which are to be searched.
          const parentFolders = [];
          if (queryInfo.folderId) {
            const { folder, accountKey } = getFolder(queryInfo.folderId);
            if (!queryInfo.accountId || queryInfo.accountId == accountKey) {
              parentFolders.push({
                rootFolder: folder,
                accountId: accountKey,
              });
            }
          } else if (queryInfo.isUnified || queryInfo.isTag) {
            const smartMailbox = SmartMailboxUtils.getSmartMailbox();
            // Unified mailbox folders are disjunct to virtual tag folders.
            // Manually suppress the case both are specified.
            if (
              smartMailbox.account &&
              queryInfo.isUnified &&
              !queryInfo.isTag
            ) {
              const allowedFolderFlags =
                SmartMailboxUtils.getFolderTypes().reduce(
                  (acc, { flag }) => acc | flag,
                  0
                );
              for (const folder of smartMailbox.rootFolder.subFolders) {
                // Require unified folders to have an allowed folder type.
                if (allowedFolderFlags & folder.flags) {
                  parentFolders.push({
                    rootFolder: folder,
                    accountId: smartMailbox.account.key,
                  });
                }
              }
            }
            if (
              smartMailbox.account &&
              !queryInfo.isUnified &&
              queryInfo.isTag
            ) {
              const tags = MailServices.tags.getAllTags();
              for (const tag of tags) {
                const folder = smartMailbox.getTagFolder(tag);
                if (!folder) {
                  continue;
                }
                parentFolders.push({
                  rootFolder: folder,
                  accountId: smartMailbox.account.key,
                });
              }
            }
          } else {
            for (const account of getMailAccounts()) {
              const accountId = account.key;
              if (!queryInfo.accountId || queryInfo.accountId == accountId) {
                parentFolders.push({
                  rootFolder: account.incomingServer.rootFolder,
                  accountId,
                });
              }
            }
          }

          // Prepare usage flags.
          const specialUse =
            !queryInfo.specialUse && queryInfo.type && manifestVersion < 3
              ? [queryInfo.type]
              : queryInfo.specialUse;
          const specialUseFlags =
            specialUse && Array.isArray(specialUse) && specialUse.length > 0
              ? [...specialUseMap.entries()]
                  .filter(([, specialUseName]) =>
                    specialUse.includes(specialUseName)
                  )
                  .map(([flag]) => flag)
                  .reduce((rv, f) => rv | f)
              : null;

          // Prepare regular expression for the name.
          let nameRegExp;
          if (queryInfo.name != null && queryInfo.name.regexp) {
            try {
              nameRegExp = new RegExp(
                queryInfo.name.regexp,
                queryInfo.name.flags || undefined
              );
            } catch (ex) {
              throw new ExtensionError(
                `Invalid Regular Expression: ${JSON.stringify(queryInfo.name)}`
              );
            }
          }

          // Prepare regular expression for the path.
          let pathRegExp;
          if (queryInfo.path != null && queryInfo.path.regexp) {
            try {
              pathRegExp = new RegExp(
                queryInfo.path.regexp,
                queryInfo.path.flags || undefined
              );
            } catch (ex) {
              throw new ExtensionError(
                `Invalid Regular Expression: ${JSON.stringify(queryInfo.path)}`
              );
            }
          }

          let foundFolders = [];
          for (const parentFolder of parentFolders) {
            const { accountId, rootFolder } = parentFolder;
            for (const folder of getFlatFolderStructure(rootFolder)) {
              // Apply lastUsed search criteria.
              if (
                queryDates.lastUsedAfter &&
                !(getFolderTime(folder, "MRUTime") > queryDates.lastUsedAfter)
              ) {
                continue;
              }
              if (
                queryDates.lastUsedBefore &&
                !(getFolderTime(folder, "MRUTime") < queryDates.lastUsedBefore)
              ) {
                continue;
              }

              // Apply lastUsedAsDestination search criteria.
              if (
                queryDates.lastUsedAsDestinationAfter &&
                !(
                  getFolderTime(folder, "MRMTime") >
                  queryDates.lastUsedAsDestinationAfter
                )
              ) {
                continue;
              }
              if (
                queryDates.lastUsedAsDestinationBefore &&
                !(
                  getFolderTime(folder, "MRMTime") <
                  queryDates.lastUsedAsDestinationBefore
                )
              ) {
                continue;
              }

              if (
                queryInfo.isFavorite != null &&
                queryInfo.isFavorite !=
                  !!folder.getFlag(Ci.nsMsgFolderFlags.Favorite)
              ) {
                continue;
              }

              const isServer = folder.isServer;
              if (queryInfo.isRoot != null && queryInfo.isRoot != isServer) {
                continue;
              }

              if (
                queryInfo.isUnified != null &&
                queryInfo.isUnified !=
                  (folder.server.hostName == "smart mailboxes")
              ) {
                continue;
              }

              if (
                queryInfo.isVirtual != null &&
                queryInfo.isVirtual !=
                  folder.getFlag(Ci.nsMsgFolderFlags.Virtual)
              ) {
                continue;
              }

              if (specialUseFlags && ~folder.flags & specialUseFlags) {
                continue;
              }

              if (
                !matchBooleanOrQueryRange(queryInfo.hasMessages, () =>
                  isServer ? 0 : folder.getTotalMessages(false)
                )
              ) {
                continue;
              }

              if (
                !matchBooleanOrQueryRange(queryInfo.hasNewMessages, () =>
                  isServer ? 0 : folder.msgDatabase.getNewList().length
                )
              ) {
                continue;
              }

              if (
                !matchBooleanOrQueryRange(queryInfo.hasUnreadMessages, () =>
                  isServer ? 0 : folder.getNumUnread(false)
                )
              ) {
                continue;
              }

              if (
                !matchBooleanOrQueryRange(
                  queryInfo.hasSubFolders,
                  () => folder.subFolders?.length || 0
                )
              ) {
                continue;
              }

              if (
                queryInfo.canAddMessages != null &&
                queryInfo.canAddMessages != folder.canFileMessages
              ) {
                continue;
              }

              if (
                queryInfo.canAddSubfolders != null &&
                queryInfo.canAddSubfolders != folder.canCreateSubfolders
              ) {
                continue;
              }

              if (
                queryInfo.canBeDeleted != null &&
                queryInfo.canBeDeleted != FolderManager.canBeDeleted(folder)
              ) {
                continue;
              }

              if (
                queryInfo.canBeRenamed != null &&
                queryInfo.canBeRenamed != FolderManager.canBeRenamed(folder)
              ) {
                continue;
              }

              if (
                queryInfo.canDeleteMessages != null &&
                queryInfo.canDeleteMessages != folder.canDeleteMessages
              ) {
                continue;
              }

              if (queryInfo.name) {
                const name = isServer ? "Root" : folder.prettyName;
                if (nameRegExp) {
                  if (!nameRegExp.test(name)) {
                    continue;
                  }
                } else if (queryInfo.name != name) {
                  continue;
                }
              }

              if (queryInfo.path) {
                const folderPath = folderURIToPath(accountId, folder.URI);
                if (pathRegExp) {
                  if (!pathRegExp.test(folderPath)) {
                    continue;
                  }
                } else if (queryInfo.path != folderPath) {
                  continue;
                }
              }

              foundFolders.push(folder);
            }
          }

          // Apply sort.
          if (queryInfo.recent || queryInfo.sort == "lastUsed") {
            foundFolders = sortFoldersByTime(foundFolders, "MRUTime");
          } else if (queryInfo.sort == "lastUsedAsDestination") {
            foundFolders = sortFoldersByTime(foundFolders, "MRMTime");
          } else if (queryInfo.sort == "name") {
            foundFolders.sort((a, b) =>
              a.prettyName.localeCompare(b.prettyName, undefined, {
                sensitivity: "base",
              })
            );
          }

          // Apply limit. It can be set to -1 = mail.folder_widget.max_recent for
          // recent queries.
          if (queryInfo.limit) {
            const recentQuery =
              queryInfo.recent ||
              queryInfo.lastUsed?.recent ||
              queryInfo.lastUsedAsDestination?.recent;
            const limit =
              queryInfo.limit == -1 && recentQuery
                ? Services.prefs.getIntPref("mail.folder_widget.max_recent")
                : queryInfo.limit;
            if (limit > 0) {
              foundFolders.splice(limit);
            }
          }

          return foundFolders.map(folder =>
            context.extension.folderManager.convert(folder)
          );
        },