extensions/pref/autoconfig/src/nsAutoConfig.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifdef MOZ_LOGGING
     7 // sorry, this has to be before the pre-compiled header
     8 #define FORCE_PR_LOG /* Allow logging in the release build */
     9 #endif
    10 #include "nsAutoConfig.h"
    11 #include "nsIURI.h"
    12 #include "nsIHttpChannel.h"
    13 #include "nsIFileStreams.h"
    14 #include "nsThreadUtils.h"
    15 #include "nsAppDirectoryServiceDefs.h"
    16 #include "prmem.h"
    17 #include "nsIObserverService.h"
    18 #include "nsLiteralString.h"
    19 #include "nsIPromptService.h"
    20 #include "nsIServiceManager.h"
    21 #include "nsIStringBundle.h"
    22 #include "nsCRT.h"
    23 #include "nspr.h"
    24 #include <algorithm>
    26 PRLogModuleInfo *MCD;
    28 extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
    29                                           const char *filename, 
    30                                           bool bGlobalContext, 
    31                                           bool bCallbacks, 
    32                                           bool skipFirstLine);
    34 // nsISupports Implementation
    36 NS_IMPL_ISUPPORTS(nsAutoConfig, nsIAutoConfig, nsITimerCallback, nsIStreamListener, nsIObserver, nsIRequestObserver, nsISupportsWeakReference)
    38 nsAutoConfig::nsAutoConfig()
    39 {
    40 }
    42 nsresult nsAutoConfig::Init()
    43 {
    44     // member initializers and constructor code
    46     nsresult rv;
    47     mLoaded = false;
    49     // Registering the object as an observer to the profile-after-change topic
    50     nsCOMPtr<nsIObserverService> observerService =
    51         do_GetService("@mozilla.org/observer-service;1", &rv);
    52     if (NS_FAILED(rv)) 
    53         return rv;
    55     rv = observerService->AddObserver(this,"profile-after-change", true);
    57     return rv;
    58 }
    60 nsAutoConfig::~nsAutoConfig()
    61 {
    62 }
    64 // attribute string configURL
    65 NS_IMETHODIMP nsAutoConfig::GetConfigURL(char **aConfigURL)
    66 {
    67     if (!aConfigURL) 
    68         return NS_ERROR_NULL_POINTER;
    70     if (mConfigURL.IsEmpty()) {
    71         *aConfigURL = nullptr;
    72         return NS_OK;
    73     }
    75     *aConfigURL = ToNewCString(mConfigURL);
    76     if (!*aConfigURL)
    77         return NS_ERROR_OUT_OF_MEMORY;
    78     return NS_OK;
    79 }
    80 NS_IMETHODIMP nsAutoConfig::SetConfigURL(const char *aConfigURL)
    81 {
    82     if (!aConfigURL)
    83         return NS_ERROR_NULL_POINTER;
    84     mConfigURL.Assign(aConfigURL);
    85     return NS_OK;
    86 }
    88 NS_IMETHODIMP
    89 nsAutoConfig::OnStartRequest(nsIRequest *request, nsISupports *context)
    90 {
    91     return NS_OK;
    92 }
    95 NS_IMETHODIMP
    96 nsAutoConfig::OnDataAvailable(nsIRequest *request, 
    97                               nsISupports *context,
    98                               nsIInputStream *aIStream, 
    99                               uint64_t aSourceOffset,
   100                               uint32_t aLength)
   101 {    
   102     uint32_t amt, size;
   103     nsresult rv;
   104     char buf[1024];
   106     while (aLength) {
   107         size = std::min<size_t>(aLength, sizeof(buf));
   108         rv = aIStream->Read(buf, size, &amt);
   109         if (NS_FAILED(rv))
   110             return rv;
   111         mBuf.Append(buf, amt);
   112         aLength -= amt;
   113     }
   114     return NS_OK;
   115 }
   118 NS_IMETHODIMP
   119 nsAutoConfig::OnStopRequest(nsIRequest *request, nsISupports *context,
   120                             nsresult aStatus)
   121 {
   122     nsresult rv;
   124     // If the request is failed, go read the failover.jsc file
   125     if (NS_FAILED(aStatus)) {
   126         PR_LOG(MCD, PR_LOG_DEBUG, ("mcd request failed with status %x\n", aStatus));
   127         return readOfflineFile();
   128     }
   130     // Checking for the http response, if failure go read the failover file.
   131     nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(request));
   132     if (pHTTPCon) {
   133         uint32_t httpStatus;
   134         pHTTPCon->GetResponseStatus(&httpStatus);
   135         if (httpStatus != 200) 
   136         {
   137             PR_LOG(MCD, PR_LOG_DEBUG, ("mcd http request failed with status %x\n", httpStatus));
   138             return readOfflineFile();
   139         }
   140     }
   142     // Send the autoconfig.jsc to javascript engine.
   144     rv = EvaluateAdminConfigScript(mBuf.get(), mBuf.Length(),
   145                               nullptr, false,true, false);
   146     if (NS_SUCCEEDED(rv)) {
   148         // Write the autoconfig.jsc to failover.jsc (cached copy) 
   149         rv = writeFailoverFile(); 
   151         if (NS_FAILED(rv)) 
   152             NS_WARNING("Error writing failover.jsc file");
   154         // Releasing the lock to allow the main thread to start execution
   155         mLoaded = true;  
   157         return NS_OK;
   158     }
   159     // there is an error in parsing of the autoconfig file.
   160     NS_WARNING("Error reading autoconfig.jsc from the network, reading the offline version");
   161     return readOfflineFile();
   162 }
   164 // Notify method as a TimerCallBack function 
   165 NS_IMETHODIMP nsAutoConfig::Notify(nsITimer *timer) 
   166 {
   167     downloadAutoConfig();
   168     return NS_OK;
   169 }
   171 /* Observe() is called twice: once at the instantiation time and other 
   172    after the profile is set. It doesn't do anything but return NS_OK during the
   173    creation time. Second time it calls  downloadAutoConfig().
   174 */
   176 NS_IMETHODIMP nsAutoConfig::Observe(nsISupports *aSubject, 
   177                                     const char *aTopic, 
   178                                     const char16_t *someData)
   179 {
   180     nsresult rv = NS_OK;
   181     if (!nsCRT::strcmp(aTopic, "profile-after-change")) {
   183         // We will be calling downloadAutoConfig even if there is no profile 
   184         // name. Nothing will be passed as a parameter to the URL and the
   185         // default case will be picked up by the script.
   187         rv = downloadAutoConfig();
   189     }  
   191     return rv;
   192 }
   194 nsresult nsAutoConfig::downloadAutoConfig()
   195 {
   196     nsresult rv;
   197     nsAutoCString emailAddr;
   198     nsXPIDLCString urlName;
   199     static bool firstTime = true;
   201     if (mConfigURL.IsEmpty()) {
   202         PR_LOG(MCD, PR_LOG_DEBUG, ("global config url is empty - did you set autoadmin.global_config_url?\n"));
   203         NS_WARNING("AutoConfig called without global_config_url");
   204         return NS_OK;
   205     }
   207     // If there is an email address appended as an argument to the ConfigURL
   208     // in the previous read, we need to remove it when timer kicks in and 
   209     // downloads the autoconfig file again. 
   210     // If necessary, the email address will be added again as an argument.
   211     int32_t index = mConfigURL.RFindChar((char16_t)'?');
   212     if (index != -1)
   213         mConfigURL.Truncate(index);
   215     // Clean up the previous read, the new read is going to use the same buffer
   216     if (!mBuf.IsEmpty())
   217         mBuf.Truncate(0);
   219     // Get the preferences branch and save it to the member variable
   220     if (!mPrefBranch) {
   221         nsCOMPtr<nsIPrefService> prefs =
   222             do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   223         if (NS_FAILED(rv)) 
   224             return rv;
   226         rv = prefs->GetBranch(nullptr,getter_AddRefs(mPrefBranch));
   227         if (NS_FAILED(rv))
   228             return rv;
   229     }
   231     // Check to see if the network is online/offline 
   232     nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
   233     if (NS_FAILED(rv)) 
   234         return rv;
   236     bool offline;
   237     rv = ios->GetOffline(&offline);
   238     if (NS_FAILED(rv)) 
   239         return rv;
   241     if (offline) {
   242         bool offlineFailover;
   243         rv = mPrefBranch->GetBoolPref("autoadmin.offline_failover", 
   244                                       &offlineFailover);
   245         // Read the failover.jsc if the network is offline and the pref says so
   246         if (NS_SUCCEEDED(rv) && offlineFailover)
   247             return readOfflineFile();
   248     }
   250     /* Append user's identity at the end of the URL if the pref says so.
   251        First we are checking for the user's email address but if it is not
   252        available in the case where the client is used without messenger, user's
   253        profile name will be used as an unique identifier
   254     */
   255     bool appendMail;
   256     rv = mPrefBranch->GetBoolPref("autoadmin.append_emailaddr", &appendMail);
   257     if (NS_SUCCEEDED(rv) && appendMail) {
   258         rv = getEmailAddr(emailAddr);
   259         if (NS_SUCCEEDED(rv) && emailAddr.get()) {
   260             /* Adding the unique identifier at the end of autoconfig URL. 
   261                In this case the autoconfig URL is a script and 
   262                emailAddr as passed as an argument 
   263             */
   264             mConfigURL.Append("?");
   265             mConfigURL.Append(emailAddr); 
   266         }
   267     }
   269     // create a new url 
   270     nsCOMPtr<nsIURI> url;
   271     nsCOMPtr<nsIChannel> channel;
   273     rv = NS_NewURI(getter_AddRefs(url), mConfigURL.get(), nullptr, nullptr);
   274     if (NS_FAILED(rv))
   275     {
   276         PR_LOG(MCD, PR_LOG_DEBUG, ("failed to create URL - is autoadmin.global_config_url valid? - %s\n", mConfigURL.get()));
   277         return rv;
   278     }
   280     PR_LOG(MCD, PR_LOG_DEBUG, ("running MCD url %s\n", mConfigURL.get()));
   281     // open a channel for the url
   282     rv = NS_NewChannel(getter_AddRefs(channel),url, nullptr, nullptr, nullptr, nsIRequest::INHIBIT_PERSISTENT_CACHING | nsIRequest::LOAD_BYPASS_CACHE);
   283     if (NS_FAILED(rv)) 
   284         return rv;
   286     rv = channel->AsyncOpen(this, nullptr); 
   287     if (NS_FAILED(rv)) {
   288         readOfflineFile();
   289         return rv;
   290     }
   292     // Set a repeating timer if the pref is set.
   293     // This is to be done only once.
   294     // Also We are having the event queue processing only for the startup
   295     // It is not needed with the repeating timer.
   296     if (firstTime) {
   297         firstTime = false;
   299         // Getting the current thread. If we start an AsyncOpen, the thread
   300         // needs to wait before the reading of autoconfig is done
   302         nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
   303         NS_ENSURE_STATE(thread);
   305         /* process events until we're finished. AutoConfig.jsc reading needs
   306            to be finished before the browser starts loading up
   307            We are waiting for the mLoaded which will be set through 
   308            onStopRequest or readOfflineFile methods
   309            There is a possibility of deadlock so we need to make sure
   310            that mLoaded will be set to true in any case (success/failure)
   311         */
   313         while (!mLoaded)
   314             NS_ENSURE_STATE(NS_ProcessNextEvent(thread));
   316         int32_t minutes;
   317         rv = mPrefBranch->GetIntPref("autoadmin.refresh_interval", 
   318                                      &minutes);
   319         if (NS_SUCCEEDED(rv) && minutes > 0) {
   320             // Create a new timer and pass this nsAutoConfig 
   321             // object as a timer callback. 
   322             mTimer = do_CreateInstance("@mozilla.org/timer;1",&rv);
   323             if (NS_FAILED(rv)) 
   324                 return rv;
   325             rv = mTimer->InitWithCallback(this, minutes * 60 * 1000, 
   326                              nsITimer::TYPE_REPEATING_SLACK);
   327             if (NS_FAILED(rv)) 
   328                 return rv;
   329         }
   330     } //first_time
   332     return NS_OK;
   333 } // nsPref::downloadAutoConfig()
   337 nsresult nsAutoConfig::readOfflineFile()
   338 {
   339     nsresult rv;
   341     /* Releasing the lock to allow main thread to start 
   342        execution. At this point we do not need to stall 
   343        the thread since all network activities are done.
   344     */
   345     mLoaded = true; 
   347     bool failCache;
   348     rv = mPrefBranch->GetBoolPref("autoadmin.failover_to_cached", &failCache);
   349     if (NS_SUCCEEDED(rv) && !failCache) {
   350         // disable network connections and return.
   352         nsCOMPtr<nsIIOService> ios =
   353             do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
   354         if (NS_FAILED(rv)) 
   355             return rv;
   357         bool offline;
   358         rv = ios->GetOffline(&offline);
   359         if (NS_FAILED(rv)) 
   360             return rv;
   362         if (!offline) {
   363             rv = ios->SetOffline(true);
   364             if (NS_FAILED(rv)) 
   365                 return rv;
   366         }
   368         // lock the "network.online" prference so user cannot toggle back to
   369         // online mode.
   370         rv = mPrefBranch->SetBoolPref("network.online", false);
   371         if (NS_FAILED(rv)) 
   372             return rv;
   374         mPrefBranch->LockPref("network.online");
   375         return NS_OK;
   376     }
   378     /* faiover_to_cached is set to true so 
   379        Open the file and read the content.
   380        execute the javascript file
   381     */
   383     nsCOMPtr<nsIFile> failoverFile; 
   384     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
   385                                 getter_AddRefs(failoverFile));
   386     if (NS_FAILED(rv)) 
   387         return rv;
   389     failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc"));
   390     rv = evaluateLocalFile(failoverFile);
   391     if (NS_FAILED(rv)) 
   392         NS_WARNING("Couldn't open failover.jsc, going back to default prefs");
   393     return NS_OK;
   394 }
   396 nsresult nsAutoConfig::evaluateLocalFile(nsIFile *file)
   397 {
   398     nsresult rv;
   399     nsCOMPtr<nsIInputStream> inStr;
   401     rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file);
   402     if (NS_FAILED(rv)) 
   403         return rv;
   405     int64_t fileSize;
   406     file->GetFileSize(&fileSize);
   407     uint32_t fs = fileSize; // Converting 64 bit structure to unsigned int
   408     char *buf = (char *)PR_Malloc(fs * sizeof(char));
   409     if (!buf) 
   410         return NS_ERROR_OUT_OF_MEMORY;
   412     uint32_t amt = 0;
   413     rv = inStr->Read(buf, fs, &amt);
   414     if (NS_SUCCEEDED(rv)) {
   415       EvaluateAdminConfigScript(buf, fs, nullptr, false, 
   416                                 true, false);
   417     }
   418     inStr->Close();
   419     PR_Free(buf);
   420     return rv;
   421 }
   423 nsresult nsAutoConfig::writeFailoverFile()
   424 {
   425     nsresult rv;
   426     nsCOMPtr<nsIFile> failoverFile; 
   427     nsCOMPtr<nsIOutputStream> outStr;
   428     uint32_t amt;
   430     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
   431                                 getter_AddRefs(failoverFile));
   432     if (NS_FAILED(rv)) 
   433         return rv;
   435     failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc"));
   437     rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStr), failoverFile);
   438     if (NS_FAILED(rv)) 
   439         return rv;
   440     rv = outStr->Write(mBuf.get(),mBuf.Length(),&amt);
   441     outStr->Close();
   442     return rv;
   443 }
   445 nsresult nsAutoConfig::getEmailAddr(nsACString & emailAddr)
   446 {
   448     nsresult rv;
   449     nsXPIDLCString prefValue;
   451     /* Getting an email address through set of three preferences:
   452        First getting a default account with 
   453        "mail.accountmanager.defaultaccount"
   454        second getting an associated id with the default account
   455        Third getting an email address with id
   456     */
   458     rv = mPrefBranch->GetCharPref("mail.accountmanager.defaultaccount", 
   459                                   getter_Copies(prefValue));
   460     if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty()) {
   461         emailAddr = NS_LITERAL_CSTRING("mail.account.") +
   462             prefValue + NS_LITERAL_CSTRING(".identities");
   463         rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(),
   464                                       getter_Copies(prefValue));
   465         if (NS_FAILED(rv) || prefValue.IsEmpty())
   466             return PromptForEMailAddress(emailAddr);
   467         int32_t commandIndex = prefValue.FindChar(',');
   468         if (commandIndex != kNotFound)
   469           prefValue.Truncate(commandIndex);
   470         emailAddr = NS_LITERAL_CSTRING("mail.identity.") +
   471             prefValue + NS_LITERAL_CSTRING(".useremail");
   472         rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(),
   473                                       getter_Copies(prefValue));
   474         if (NS_FAILED(rv)  || prefValue.IsEmpty())
   475             return PromptForEMailAddress(emailAddr);
   476         emailAddr = prefValue;
   477     }
   478     else {
   479         // look for 4.x pref in case we just migrated.
   480         rv = mPrefBranch->GetCharPref("mail.identity.useremail", 
   481                                   getter_Copies(prefValue));
   482         if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty())
   483             emailAddr = prefValue;
   484         else
   485             PromptForEMailAddress(emailAddr);
   486     }
   488     return NS_OK;
   489 }
   491 nsresult nsAutoConfig::PromptForEMailAddress(nsACString &emailAddress)
   492 {
   493     nsresult rv;
   494     nsCOMPtr<nsIPromptService> promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
   495     NS_ENSURE_SUCCESS(rv, rv);
   496     nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   497     NS_ENSURE_SUCCESS(rv, rv);
   499     nsCOMPtr<nsIStringBundle> bundle;
   500     rv = bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties",
   501                                 getter_AddRefs(bundle));
   502     NS_ENSURE_SUCCESS(rv, rv);
   504     nsXPIDLString title;
   505     rv = bundle->GetStringFromName(MOZ_UTF16("emailPromptTitle"), getter_Copies(title));
   506     NS_ENSURE_SUCCESS(rv, rv);
   508     nsXPIDLString err;
   509     rv = bundle->GetStringFromName(MOZ_UTF16("emailPromptMsg"), getter_Copies(err));
   510     NS_ENSURE_SUCCESS(rv, rv);
   511     bool check = false;
   512     nsXPIDLString emailResult;
   513     bool success;
   514     rv = promptService->Prompt(nullptr, title.get(), err.get(), getter_Copies(emailResult), nullptr, &check, &success);
   515     if (!success)
   516       return NS_ERROR_FAILURE;
   517     NS_ENSURE_SUCCESS(rv, rv);
   518     LossyCopyUTF16toASCII(emailResult, emailAddress);
   519     return NS_OK;
   520 }

mercurial