NS_IMETHODIMP
nsCharsetConverterManager::GetUnicodeEncoderRaw(const char * aDest, 
                                                nsIUnicodeEncoder ** aResult)
{
  *aResult= nullptr;
  nsCOMPtr<nsIUnicodeEncoder> encoder;

  nsresult rv = NS_OK;

  nsAutoCString
    contractid(NS_LITERAL_CSTRING(NS_UNICODEENCODER_CONTRACTID_BASE) +
               nsDependentCString(aDest));

  // Always create an instance since encoders hold state.
  encoder = do_CreateInstance(contractid.get(), &rv);

  if (NS_FAILED(rv))
    rv = NS_ERROR_UCONV_NOCONV;
  else
  {
    *aResult = encoder.get();
    NS_ADDREF(*aResult);
  }
  return rv;
}
NS_IMETHODIMP
nsDOMScriptObjectFactory::GetScriptRuntimeByID(PRUint32 aLanguageID, 
                                               nsIScriptRuntime **aLanguage)
{
  if (!NS_STID_VALID(aLanguageID)) {
    NS_WARNING("Unknown script language");
    return NS_ERROR_UNEXPECTED;
  }
  *aLanguage = mLanguageArray[NS_STID_INDEX(aLanguageID)];
  if (!*aLanguage) {
    nsCAutoString contractid(NS_LITERAL_CSTRING(
                        "@mozilla.org/script-language;1?id="));
    char langIdStr[25]; // space for an int.
    sprintf(langIdStr, "%d", aLanguageID);
    contractid += langIdStr;
    nsresult rv;
    nsCOMPtr<nsIScriptRuntime> lang = do_GetService(contractid.get(), &rv);

    if (NS_FAILED(rv)) {
      NS_ERROR("Failed to get the script language");
      return rv;
    }

    // Stash it away in our array for fast lookup by ID.
    mLanguageArray[NS_STID_INDEX(aLanguageID)] = lang;
    *aLanguage = lang;
  }
  NS_IF_ADDREF(*aLanguage);
  return NS_OK;
}
PRBool
nsMsgAccountManagerDataSource::canGetIncomingMessages(nsIMsgIncomingServer *aServer)
{
  nsXPIDLCString type;
  nsresult rv = aServer->GetType(getter_Copies(type));
  NS_ENSURE_SUCCESS(rv, PR_FALSE);

  nsCAutoString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX);
  contractid.Append(type);

  nsCOMPtr<nsIMsgProtocolInfo> protocolInfo = do_GetService(contractid.get(), &rv);
  NS_ENSURE_SUCCESS(rv, PR_FALSE);

  PRBool canGetIncomingMessages = PR_FALSE;
  protocolInfo->GetCanGetIncomingMessages(&canGetIncomingMessages);

  return canGetIncomingMessages;
}
NS_IMETHODIMP
nsDOMScriptObjectFactory::GetScriptRuntime(const nsAString &aLanguageName,
                                           nsIScriptRuntime **aLanguage)
{
  // Note that many callers have optimized detection for JS (along with
  // supporting various alternate names for JS), so don't call this.
  // One exception is for the new "script-type" attribute on a node - and
  // there is no need to support backwards compatible names.
  // As JS is the default language, this is still rarely called for JS -
  // only when a node explicitly sets JS - so that is done last.
  nsCAutoString contractid(NS_LITERAL_CSTRING(
                          "@mozilla.org/script-language;1?script-type="));
  // Arbitrarily use utf8 encoding should the name have extended chars
  AppendUTF16toUTF8(aLanguageName, contractid);
  nsresult rv;
  nsCOMPtr<nsIScriptRuntime> lang =
        do_GetService(contractid.get(), &rv);

  if (NS_FAILED(rv)) {
    if (aLanguageName.Equals(NS_LITERAL_STRING("application/javascript")))
      return GetScriptRuntimeByID(nsIProgrammingLanguage::JAVASCRIPT, aLanguage);
    // Not JS and nothing else we know about.
    NS_WARNING("No script language registered for this mime-type");
    return NS_ERROR_FACTORY_NOT_REGISTERED;
  }
  // And stash it away in our array for fast lookup by ID.
  PRUint32 lang_ndx = NS_STID_INDEX(lang->GetScriptTypeID());
  if (mLanguageArray[lang_ndx] == nsnull) {
    mLanguageArray[lang_ndx] = lang;
  } else {
    // All languages are services - we should have an identical object!
    NS_ASSERTION(mLanguageArray[lang_ndx] == lang,
                 "Got a different language for this ID???");
  }
  *aLanguage = lang;
  NS_IF_ADDREF(*aLanguage);
  return NS_OK;
}
// This is the function that looks for the first folder to purge. It also
// applies retention settings to any folder that hasn't had retention settings
// applied in mMinDelayBetweenPurges minutes (default, 8 hours).
// However, if we've spent more than .5 seconds in this loop, don't
// apply any more retention settings because it might lock up the UI.
// This might starve folders later on in the hierarchy, since we always
// start at the top, but since we also apply retention settings when you
// open a folder, or when you compact all folders, I think this will do
// for now, until we have a cleanup on shutdown architecture.
nsresult nsMsgPurgeService::PerformPurge()
{
    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("performing purge"));

    nsresult rv;

    nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv,rv);
    bool keepApplyingRetentionSettings = true;

    nsCOMPtr<nsISupportsArray> allServers;
    rv = accountManager->GetAllServers(getter_AddRefs(allServers));
    if (NS_SUCCEEDED(rv) && allServers)
    {
        PRUint32 numServers;
        rv = allServers->Count(&numServers);
        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%d servers", numServers));
        nsCOMPtr<nsIMsgFolder> folderToPurge;
        PRIntervalTime startTime = PR_IntervalNow();
        PRInt32 purgeIntervalToUse;
        PRTime oldestPurgeTime = 0; // we're going to pick the least-recently purged folder

        // apply retention settings to folders that haven't had retention settings
        // applied in mMinDelayBetweenPurges minutes (default 8 hours)
        // Because we get last purge time from the folder cache,
        // this code won't open db's for folders until it decides it needs
        // to apply retention settings, and since nsIMsgFolder::ApplyRetentionSettings
        // will close any db's it opens, this code won't leave db's open.
        for (PRUint32 serverIndex=0; serverIndex < numServers; serverIndex++)
        {
            nsCOMPtr <nsIMsgIncomingServer> server =
                do_QueryElementAt(allServers, serverIndex, &rv);
            if (NS_SUCCEEDED(rv) && server)
            {
                if (keepApplyingRetentionSettings)
                {
                    nsCOMPtr <nsIMsgFolder> rootFolder;
                    rv = server->GetRootFolder(getter_AddRefs(rootFolder));
                    NS_ENSURE_SUCCESS(rv, rv);

                    nsCOMPtr <nsISupportsArray> childFolders = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
                    NS_ENSURE_SUCCESS(rv, rv);
                    rv = rootFolder->ListDescendents(childFolders);

                    PRUint32 cnt = 0;
                    childFolders->Count(&cnt);

                    nsCOMPtr<nsISupports> supports;
                    nsCOMPtr<nsIUrlListener> urlListener;
                    nsCOMPtr<nsIMsgFolder> childFolder;

                    for (PRUint32 index = 0; index < cnt; index++)
                    {
                        childFolder = do_QueryElementAt(childFolders, index);
                        if (childFolder)
                        {
                            PRUint32 folderFlags;
                            (void) childFolder->GetFlags(&folderFlags);
                            if (folderFlags & nsMsgFolderFlags::Virtual)
                                continue;
                            PRTime curFolderLastPurgeTime = 0;
                            nsCString curFolderLastPurgeTimeString, curFolderUri;
                            rv = childFolder->GetStringProperty("LastPurgeTime", curFolderLastPurgeTimeString);
                            if (NS_FAILED(rv))
                                continue; // it is ok to fail, go on to next folder

                            if (!curFolderLastPurgeTimeString.IsEmpty())
                            {
                                PRInt64 theTime;
                                PR_ParseTimeString(curFolderLastPurgeTimeString.get(), PR_FALSE, &theTime);
                                curFolderLastPurgeTime = theTime;
                            }

                            childFolder->GetURI(curFolderUri);
                            PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%s curFolderLastPurgeTime=%s (if blank, then never)", curFolderUri.get(), curFolderLastPurgeTimeString.get()));

                            // check if this folder is due to purge
                            // has to have been purged at least mMinDelayBetweenPurges minutes ago
                            // we don't want to purge the folders all the time - once a day is good enough
                            PRInt64 minDelayBetweenPurges(mMinDelayBetweenPurges);
                            PRInt64 microSecondsPerMinute(60000000);
                            PRTime nextPurgeTime = curFolderLastPurgeTime + (minDelayBetweenPurges * microSecondsPerMinute);
                            if (nextPurgeTime < PR_Now())
                            {
                                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("purging %s", curFolderUri.get()));
                                childFolder->ApplyRetentionSettings();
                            }
                            PRIntervalTime elapsedTime;
                            LL_SUB(elapsedTime, PR_IntervalNow(), startTime);
                            // check if more than 500 milliseconds have elapsed in this purge process
                            if (PR_IntervalToMilliseconds(elapsedTime) > 500)
                            {
                                keepApplyingRetentionSettings = PR_FALSE;
                                break;
                            }
                        }
                    }
                }
                nsCString type;
                nsresult rv = server->GetType(type);
                NS_ENSURE_SUCCESS(rv, rv);

                nsCAutoString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX);
                contractid.Append(type);

                nsCOMPtr<nsIMsgProtocolInfo> protocolInfo =
                    do_GetService(contractid.get(), &rv);
                NS_ENSURE_SUCCESS(rv, PR_FALSE);

                nsCString realHostName;
                server->GetRealHostName(realHostName);
                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s (%s)", serverIndex, realHostName.get(), type.get()));

                nsCOMPtr <nsISpamSettings> spamSettings;
                rv = server->GetSpamSettings(getter_AddRefs(spamSettings));
                NS_ENSURE_SUCCESS(rv, rv);

                PRInt32 spamLevel;
                spamSettings->GetLevel(&spamLevel);
                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] spamLevel=%d (if 0, don't purge)", serverIndex, spamLevel));
                if (!spamLevel)
                    continue;

                // check if we are set up to purge for this server
                // if not, skip it.
                bool purgeSpam;
                spamSettings->GetPurge(&purgeSpam);

                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purgeSpam=%s (if false, don't purge)", serverIndex, purgeSpam ? "true" : "false"));
                if (!purgeSpam)
                    continue;

                // check if the spam folder uri is set for this server
                // if not skip it.
                nsCString junkFolderURI;
                rv = spamSettings->GetSpamFolderURI(getter_Copies(junkFolderURI));
                NS_ENSURE_SUCCESS(rv,rv);

                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] junkFolderURI=%s (if empty, don't purge)", serverIndex, junkFolderURI.get()));
                if (junkFolderURI.IsEmpty())
                    continue;

                // if the junk folder doesn't exist
                // because the folder pane isn't built yet, for example
                // skip this account
                nsCOMPtr<nsIMsgFolder> junkFolder;
                GetExistingFolder(junkFolderURI, getter_AddRefs(junkFolder));

                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s exists? %s (if doesn't exist, don't purge)", serverIndex, junkFolderURI.get(), junkFolder ? "true" : "false"));
                if (!junkFolder)
                    continue;

                PRTime curJunkFolderLastPurgeTime = 0;
                nsCString curJunkFolderLastPurgeTimeString;
                rv = junkFolder->GetStringProperty("curJunkFolderLastPurgeTime", curJunkFolderLastPurgeTimeString);
                if (NS_FAILED(rv))
                    continue; // it is ok to fail, junk folder may not exist

                if (!curJunkFolderLastPurgeTimeString.IsEmpty())
                {
                    PRInt64 theTime;
                    PR_ParseTimeString(curJunkFolderLastPurgeTimeString.get(), PR_FALSE, &theTime);
                    curJunkFolderLastPurgeTime = theTime;
                }

                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s curJunkFolderLastPurgeTime=%s (if blank, then never)", serverIndex, junkFolderURI.get(), curJunkFolderLastPurgeTimeString.get()));

                // check if this account is due to purge
                // has to have been purged at least mMinDelayBetweenPurges minutes ago
                // we don't want to purge the folders all the time
                PRTime nextPurgeTime = curJunkFolderLastPurgeTime + mMinDelayBetweenPurges * 60000000 /* convert mMinDelayBetweenPurges to into microseconds */;
                if (nextPurgeTime < PR_Now())
                {
                    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge greater than min delay", serverIndex));

                    nsCOMPtr <nsIMsgIncomingServer> junkFolderServer;
                    rv = junkFolder->GetServer(getter_AddRefs(junkFolderServer));
                    NS_ENSURE_SUCCESS(rv,rv);

                    bool serverBusy = false;
                    bool serverRequiresPassword = true;
                    bool passwordPromptRequired;
                    bool canSearchMessages = false;
                    junkFolderServer->GetPasswordPromptRequired(&passwordPromptRequired);
                    junkFolderServer->GetServerBusy(&serverBusy);
                    junkFolderServer->GetServerRequiresPasswordForBiff(&serverRequiresPassword);
                    junkFolderServer->GetCanSearchMessages(&canSearchMessages);
                    // Make sure we're logged on before doing the search (assuming we need to be)
                    // and make sure the server isn't already in the middle of downloading new messages
                    // and make sure a search isn't already going on
                    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (search in progress? %s)", serverIndex, mSearchSession ? "true" : "false"));
                    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (server busy? %s)", serverIndex, serverBusy ? "true" : "false"));
                    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (serverRequiresPassword? %s)", serverIndex, serverRequiresPassword ? "true" : "false"));
                    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (passwordPromptRequired? %s)", serverIndex, passwordPromptRequired ? "true" : "false"));
                    if (canSearchMessages && !mSearchSession && !serverBusy && (!serverRequiresPassword || !passwordPromptRequired))
                    {
                        PRInt32 purgeInterval;
                        spamSettings->GetPurgeInterval(&purgeInterval);

                        if ((oldestPurgeTime == 0) || (curJunkFolderLastPurgeTime < oldestPurgeTime))
                        {
                            PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purging! searching for messages older than %d days", serverIndex, purgeInterval));
                            oldestPurgeTime = curJunkFolderLastPurgeTime;
                            purgeIntervalToUse = purgeInterval;
                            folderToPurge = junkFolder;
                            // if we've never purged this folder, do it...
                            if (curJunkFolderLastPurgeTime == 0)
                                break;
                        }
                    }
                    else {
                        NS_ASSERTION(canSearchMessages, "unexpected, you should be able to search");
                        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] not a good time for this server, try again later", serverIndex));
                    }
                }
                else {
                    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge too recent", serverIndex));
                }
            }
        }
        if (folderToPurge)
            rv = SearchFolderToPurge(folderToPurge, purgeIntervalToUse);
    }

    // set up timer to check accounts again
    SetupNextPurge();
    return rv;
}