Back to index

lightning-sunbird  0.9+nobinonly
nsAutoConfig.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mitesh Shah <mitesh@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifdef MOZ_LOGGING
00040 // sorry, this has to be before the pre-compiled header
00041 #define FORCE_PR_LOG /* Allow logging in the release build */
00042 #endif
00043 #include "nsAutoConfig.h"
00044 #include "nsIURI.h"
00045 #include "nsIHttpChannel.h"
00046 #include "nsIFileStreams.h"
00047 #include "nsAppDirectoryServiceDefs.h"
00048 #include "prmem.h"
00049 #include "nsIProfile.h"
00050 #include "nsIObserverService.h"
00051 #include "nsIEventQueueService.h"
00052 #include "nsLiteralString.h"
00053 #include "nsIPromptService.h"
00054 #include "nsIServiceManager.h"
00055 #include "nsIStringBundle.h"
00056 #include "nsCRT.h"
00057 #include "nspr.h"
00058 
00059 PRLogModuleInfo *MCD;
00060 
00061 extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
00062                                           const char *filename, 
00063                                           PRBool bGlobalContext, 
00064                                           PRBool bCallbacks, 
00065                                           PRBool skipFirstLine);
00066 
00067 // nsISupports Implementation
00068 
00069 NS_IMPL_THREADSAFE_ISUPPORTS6(nsAutoConfig, nsIAutoConfig, nsITimerCallback, nsIStreamListener, nsIObserver, nsIRequestObserver, nsISupportsWeakReference)
00070 
00071 nsAutoConfig::nsAutoConfig()
00072 {
00073 }
00074 
00075 nsresult nsAutoConfig::Init()
00076 {
00077     // member initializers and constructor code
00078 
00079     nsresult rv;
00080     mLoaded = PR_FALSE;
00081     
00082     // Registering the object as an observer to the profile-after-change topic
00083     nsCOMPtr<nsIObserverService> observerService =
00084         do_GetService("@mozilla.org/observer-service;1", &rv);
00085     if (NS_FAILED(rv)) 
00086         return rv;
00087 
00088     rv = observerService->AddObserver(this,"profile-after-change", PR_TRUE);
00089     
00090     return rv;
00091 }
00092 
00093 nsAutoConfig::~nsAutoConfig()
00094 {
00095 }
00096 
00097 // attribute string configURL
00098 NS_IMETHODIMP nsAutoConfig::GetConfigURL(char **aConfigURL)
00099 {
00100     if (!aConfigURL) 
00101         return NS_ERROR_NULL_POINTER;
00102 
00103     if (mConfigURL.IsEmpty()) {
00104         *aConfigURL = nsnull;
00105         return NS_OK;
00106     }
00107     
00108     *aConfigURL = ToNewCString(mConfigURL);
00109     if (!*aConfigURL)
00110         return NS_ERROR_OUT_OF_MEMORY;
00111     return NS_OK;
00112 }
00113 NS_IMETHODIMP nsAutoConfig::SetConfigURL(const char *aConfigURL)
00114 {
00115     if (!aConfigURL)
00116         return NS_ERROR_NULL_POINTER;
00117     mConfigURL.Assign(aConfigURL);
00118     return NS_OK;
00119 }
00120 
00121 NS_IMETHODIMP
00122 nsAutoConfig::OnStartRequest(nsIRequest *request, nsISupports *context)
00123 {
00124     return NS_OK;
00125 }
00126 
00127 
00128 NS_IMETHODIMP
00129 nsAutoConfig::OnDataAvailable(nsIRequest *request, 
00130                               nsISupports *context,
00131                               nsIInputStream *aIStream, 
00132                               PRUint32 aSourceOffset,
00133                               PRUint32 aLength)
00134 {    
00135     PRUint32 amt, size;
00136     nsresult rv;
00137     char buf[1024];
00138     
00139     while (aLength) {
00140         size = PR_MIN(aLength, sizeof(buf));
00141         rv = aIStream->Read(buf, size, &amt);
00142         if (NS_FAILED(rv))
00143             return rv;
00144         mBuf.Append(buf, amt);
00145         aLength -= amt;
00146     }
00147     return NS_OK;
00148 }
00149 
00150 
00151 NS_IMETHODIMP
00152 nsAutoConfig::OnStopRequest(nsIRequest *request, nsISupports *context,
00153                             nsresult aStatus)
00154 {
00155     nsresult rv;
00156 
00157     // If the request is failed, go read the failover.jsc file
00158     if (NS_FAILED(aStatus)) {
00159         PR_LOG(MCD, PR_LOG_DEBUG, ("mcd request failed with status %x\n", aStatus));
00160         return readOfflineFile();
00161     }
00162 
00163     // Checking for the http response, if failure go read the failover file.
00164     nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(request));
00165     if (pHTTPCon) {
00166         PRUint32 httpStatus;
00167         pHTTPCon->GetResponseStatus(&httpStatus);
00168         if (httpStatus != 200) 
00169         {
00170             PR_LOG(MCD, PR_LOG_DEBUG, ("mcd http request failed with status %x\n", httpStatus));
00171             return readOfflineFile();
00172         }
00173     }
00174     
00175     // Send the autoconfig.jsc to javascript engine.
00176     
00177     rv = EvaluateAdminConfigScript(mBuf.get(), mBuf.Length(),
00178                               nsnull, PR_FALSE,PR_TRUE, PR_FALSE);
00179     if (NS_SUCCEEDED(rv)) {
00180 
00181         // Write the autoconfig.jsc to failover.jsc (cached copy) 
00182         rv = writeFailoverFile(); 
00183 
00184         if (NS_FAILED(rv)) 
00185             NS_WARNING("Error writing failover.jsc file");
00186 
00187         // Releasing the lock to allow the main thread to start execution
00188         mLoaded = PR_TRUE;  
00189 
00190         return NS_OK;
00191     }
00192     // there is an error in parsing of the autoconfig file.
00193     NS_WARNING("Error reading autoconfig.jsc from the network, reading the offline version");
00194     return readOfflineFile();
00195 }
00196 
00197 // Notify method as a TimerCallBack function 
00198 NS_IMETHODIMP nsAutoConfig::Notify(nsITimer *timer) 
00199 {
00200     downloadAutoConfig();
00201     return NS_OK;
00202 }
00203 
00204 /* Observe() is called twice: once at the instantiation time and other 
00205    after the profile is set. It doesn't do anything but return NS_OK during the
00206    creation time. Second time it calls  downloadAutoConfig().
00207 */
00208 
00209 NS_IMETHODIMP nsAutoConfig::Observe(nsISupports *aSubject, 
00210                                     const char *aTopic, 
00211                                     const PRUnichar *someData)
00212 {
00213     nsresult rv = NS_OK;
00214     if (!nsCRT::strcmp(aTopic, "profile-after-change")) {
00215 
00216         // Getting the current profile name since we already have the 
00217         // pointer to the object.
00218         nsCOMPtr<nsIProfile> profile = do_QueryInterface(aSubject);
00219         if (profile) {
00220             nsXPIDLString profileName;
00221             rv = profile->GetCurrentProfile(getter_Copies(profileName));
00222             if (NS_SUCCEEDED(rv)) {
00223                 // setting the member variable to the current profile name
00224                 CopyUTF16toUTF8(profileName, mCurrProfile);
00225             }
00226             else {
00227                 NS_WARNING("nsAutoConfig::GetCurrentProfile() failed");
00228             }
00229         } 
00230 
00231         // We will be calling downloadAutoConfig even if there is no profile 
00232         // name. Nothing will be passed as a parameter to the URL and the
00233         // default case will be picked up by the script.
00234         
00235         rv = downloadAutoConfig();
00236 
00237     }  
00238    
00239     return rv;
00240 }
00241 
00242 nsresult nsAutoConfig::downloadAutoConfig()
00243 {
00244     nsresult rv;
00245     nsCAutoString emailAddr;
00246     nsXPIDLCString urlName;
00247     PRBool appendMail = PR_FALSE, offline = PR_FALSE;
00248     static PRBool firstTime = PR_TRUE;
00249     
00250     if (mConfigURL.IsEmpty()) {
00251         PR_LOG(MCD, PR_LOG_DEBUG, ("global config url is empty - did you set autoadmin.global_config_url?\n"));
00252         NS_WARNING("AutoConfig called without global_config_url");
00253         return NS_OK;
00254     }
00255     
00256     // If there is an email address appended as an argument to the ConfigURL
00257     // in the previous read, we need to remove it when timer kicks in and 
00258     // downloads the autoconfig file again. 
00259     // If necessary, the email address will be added again as an argument.
00260     PRInt32 index = mConfigURL.RFindChar((PRUnichar)'?');
00261     if (index != -1)
00262         mConfigURL.Truncate(index);
00263 
00264     // Clean up the previous read, the new read is going to use the same buffer
00265     if (!mBuf.IsEmpty())
00266         mBuf.Truncate(0);
00267 
00268     // Get the preferences branch and save it to the member variable
00269     if (!mPrefBranch) {
00270 
00271         nsCOMPtr<nsIPrefService> prefs =
00272             do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00273         if (NS_FAILED(rv)) 
00274             return rv;
00275     
00276         rv = prefs->GetBranch(nsnull,getter_AddRefs(mPrefBranch));
00277         if (NS_FAILED(rv))
00278             return rv;
00279     }
00280     
00281     // Check to see if the network is online/offline 
00282     nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
00283     if (NS_FAILED(rv)) 
00284         return rv;
00285     
00286     rv = ios->GetOffline(&offline);
00287     if (NS_FAILED(rv)) 
00288         return rv;
00289     
00290     if (offline) {
00291         
00292         PRBool offlineFailover = PR_FALSE;
00293         rv = mPrefBranch->GetBoolPref("autoadmin.offline_failover", 
00294                                       &offlineFailover);
00295         
00296         // Read the failover.jsc if the network is offline and the pref says so
00297         if (offlineFailover) {
00298             return readOfflineFile();
00299         }
00300     }
00301 
00302 
00303     /* Append user's identity at the end of the URL if the pref says so.
00304        First we are checking for the user's email address but if it is not
00305        available in the case where the client is used without messenger, user's
00306        profile name will be used as an unique identifier
00307     */
00308     
00309     rv = mPrefBranch->GetBoolPref("autoadmin.append_emailaddr", &appendMail);
00310     
00311     if (NS_SUCCEEDED(rv) && appendMail) {
00312         rv = getEmailAddr(emailAddr);
00313         if (NS_SUCCEEDED(rv) && emailAddr.get()) {
00314 
00315             /* Adding the unique identifier at the end of autoconfig URL. 
00316                In this case the autoconfig URL is a script and 
00317                emailAddr as passed as an argument 
00318             */
00319             mConfigURL.Append("?");
00320             mConfigURL.Append(emailAddr); 
00321         }
00322     }
00323     
00324     // create a new url 
00325     nsCOMPtr<nsIURI> url;
00326     nsCOMPtr<nsIChannel> channel;
00327     
00328     rv = NS_NewURI(getter_AddRefs(url), mConfigURL.get(), nsnull, nsnull);
00329     if (NS_FAILED(rv))
00330     {
00331         PR_LOG(MCD, PR_LOG_DEBUG, ("failed to create URL - is autoadmin.global_config_url valid? - %s\n", mConfigURL.get()));
00332         return rv;
00333     }
00334 
00335     PR_LOG(MCD, PR_LOG_DEBUG, ("running MCD url %s\n", mConfigURL.get()));
00336     // open a channel for the url
00337     rv = NS_NewChannel(getter_AddRefs(channel),url, nsnull, nsnull, nsnull, nsIRequest::INHIBIT_PERSISTENT_CACHING | nsIRequest::LOAD_BYPASS_CACHE);
00338     if (NS_FAILED(rv)) 
00339         return rv;
00340 
00341     
00342     rv = channel->AsyncOpen(this, nsnull); 
00343     if (NS_FAILED(rv)) {
00344         readOfflineFile();
00345         return rv;
00346     }
00347     
00348     // Set a repeating timer if the pref is set.
00349     // This is to be done only once.
00350     // Also We are having the event queue processing only for the startup
00351     // It is not needed with the repeating timer.
00352     if (firstTime) {
00353 
00354         firstTime = PR_FALSE;
00355     
00356         // Getting an event queue. If we start an AsyncOpen, the thread
00357         // needs to wait before the reading of autoconfig is done
00358 
00359         nsCOMPtr<nsIEventQueueService> service = 
00360             do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00361         if (NS_FAILED(rv)) 
00362             return rv;
00363 
00364         nsCOMPtr<nsIEventQueue> currentThreadQ;
00365         rv = service->GetThreadEventQueue(NS_CURRENT_THREAD,
00366                                           getter_AddRefs(currentThreadQ));
00367         if (NS_FAILED(rv)) 
00368             return rv;
00369     
00370         /* process events until we're finished. AutoConfig.jsc reading needs
00371            to be finished before the browser starts loading up
00372            We are waiting for the mLoaded which will be set through 
00373            onStopRequest or readOfflineFile methods
00374            There is a possibility of deadlock so we need to make sure
00375            that mLoaded will be set to true in any case (success/failure)
00376         */
00377         
00378         while (!mLoaded) {
00379 
00380             PRBool isEventPending;
00381             rv = currentThreadQ->PendingEvents(&isEventPending);
00382             if (NS_FAILED(rv)) 
00383                 return rv;        
00384             if (isEventPending) {
00385                 rv = currentThreadQ->ProcessPendingEvents();
00386                 if (NS_FAILED(rv)) 
00387                     return rv;        
00388             }
00389         }
00390         
00391         PRInt32 minutes = 0;
00392         rv = mPrefBranch->GetIntPref("autoadmin.refresh_interval", 
00393                                      &minutes);
00394         if (NS_SUCCEEDED(rv) && minutes > 0) {
00395 
00396             // Create a new timer and pass this nsAutoConfig 
00397             // object as a timer callback. 
00398             mTimer = do_CreateInstance("@mozilla.org/timer;1",&rv);
00399             if (NS_FAILED(rv)) 
00400                 return rv;
00401             rv = mTimer->InitWithCallback(this, minutes * 60 * 1000, 
00402                              nsITimer::TYPE_REPEATING_SLACK);
00403             if (NS_FAILED(rv)) 
00404                 return rv;
00405         }
00406     
00407     } //first_time
00408     
00409     return NS_OK;
00410 
00411 } // nsPref::downloadAutoConfig()
00412 
00413 
00414 
00415 nsresult nsAutoConfig::readOfflineFile()
00416 {
00417     PRBool failCache = PR_TRUE;
00418     nsresult rv;
00419     PRBool offline;
00420     
00421     /* Releasing the lock to allow main thread to start 
00422        execution. At this point we do not need to stall 
00423        the thread since all network activities are done.
00424     */
00425     mLoaded = PR_TRUE; 
00426 
00427     rv = mPrefBranch->GetBoolPref("autoadmin.failover_to_cached", &failCache);
00428     
00429     if (failCache == PR_FALSE) {
00430         
00431         // disable network connections and return.
00432         
00433         nsCOMPtr<nsIIOService> ios =
00434             do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
00435         if (NS_FAILED(rv)) 
00436             return rv;
00437         
00438         rv = ios->GetOffline(&offline);
00439         if (NS_FAILED(rv)) 
00440             return rv;
00441 
00442         if (!offline) {
00443             rv = ios->SetOffline(PR_TRUE);
00444             if (NS_FAILED(rv)) 
00445                 return rv;
00446         }
00447         
00448         // lock the "network.online" prference so user cannot toggle back to
00449         // online mode.
00450         rv = mPrefBranch->SetBoolPref("network.online", PR_FALSE);
00451         if (NS_FAILED(rv)) 
00452             return rv;
00453         mPrefBranch->LockPref("network.online");
00454         return NS_OK;
00455     }
00456     
00457     /* faiover_to_cached is set to true so 
00458        Open the file and read the content.
00459        execute the javascript file
00460     */
00461     
00462     nsCOMPtr<nsIFile> failoverFile; 
00463     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
00464                                 getter_AddRefs(failoverFile));
00465     if (NS_FAILED(rv)) 
00466         return rv;
00467     
00468     failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc"));
00469     rv = evaluateLocalFile(failoverFile);
00470     if (NS_FAILED(rv)) 
00471         NS_WARNING("Couldn't open failover.jsc, going back to default prefs");
00472     return NS_OK;
00473 }
00474 
00475 nsresult nsAutoConfig::evaluateLocalFile(nsIFile *file)
00476 {
00477     nsresult rv;
00478     nsCOMPtr<nsIInputStream> inStr;
00479     
00480     rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file);
00481     if (NS_FAILED(rv)) 
00482         return rv;
00483         
00484     PRInt64 fileSize;
00485     PRUint32 fs, amt=0;
00486     file->GetFileSize(&fileSize);
00487     LL_L2UI(fs, fileSize); // Converting 64 bit structure to unsigned int
00488     char *buf = (char *)PR_Malloc(fs * sizeof(char));
00489     if (!buf) 
00490         return NS_ERROR_OUT_OF_MEMORY;
00491     
00492     rv = inStr->Read(buf, fs, &amt);
00493     if (NS_SUCCEEDED(rv)) {
00494       EvaluateAdminConfigScript(buf, fs, nsnull, PR_FALSE, 
00495                                 PR_TRUE, PR_FALSE);
00496     }
00497     inStr->Close();
00498     PR_Free(buf);
00499     return rv;
00500 }
00501 
00502 nsresult nsAutoConfig::writeFailoverFile()
00503 {
00504     nsresult rv;
00505     nsCOMPtr<nsIFile> failoverFile; 
00506     nsCOMPtr<nsIOutputStream> outStr;
00507     PRUint32 amt;
00508     
00509     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
00510                                 getter_AddRefs(failoverFile));
00511     if (NS_FAILED(rv)) 
00512         return rv;
00513     
00514     failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc"));
00515     
00516     rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStr), failoverFile);
00517     if (NS_FAILED(rv)) 
00518         return rv;
00519     rv = outStr->Write(mBuf.get(),mBuf.Length(),&amt);
00520     outStr->Close();
00521     return rv;
00522 }
00523 
00524 nsresult nsAutoConfig::getEmailAddr(nsACString & emailAddr)
00525 {
00526     
00527     nsresult rv;
00528     nsXPIDLCString prefValue;
00529     
00530     /* Getting an email address through set of three preferences:
00531        First getting a default account with 
00532        "mail.accountmanager.defaultaccount"
00533        second getting an associated id with the default account
00534        Third getting an email address with id
00535     */
00536     
00537     rv = mPrefBranch->GetCharPref("mail.accountmanager.defaultaccount", 
00538                                   getter_Copies(prefValue));
00539     
00540     if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty()) {
00541         emailAddr = NS_LITERAL_CSTRING("mail.account.") +
00542             prefValue + NS_LITERAL_CSTRING(".identities");
00543         rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(),
00544                                       getter_Copies(prefValue));
00545         if (NS_FAILED(rv) || prefValue.IsEmpty())
00546             return PromptForEMailAddress(emailAddr);
00547         PRInt32 commandIndex = prefValue.FindChar(',');
00548         if (commandIndex != kNotFound)
00549           prefValue.Truncate(commandIndex);
00550         emailAddr = NS_LITERAL_CSTRING("mail.identity.") +
00551             prefValue + NS_LITERAL_CSTRING(".useremail");
00552         rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(),
00553                                       getter_Copies(prefValue));
00554         if (NS_FAILED(rv)  || prefValue.IsEmpty())
00555             return PromptForEMailAddress(emailAddr);
00556         emailAddr = prefValue;
00557     }
00558     else {
00559         // look for 4.x pref in case we just migrated.
00560         rv = mPrefBranch->GetCharPref("mail.identity.useremail", 
00561                                   getter_Copies(prefValue));
00562         if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty())
00563             emailAddr = prefValue;
00564         else if (NS_FAILED(PromptForEMailAddress(emailAddr))  && (!mCurrProfile.IsEmpty()))
00565             emailAddr = mCurrProfile;
00566     }
00567     
00568     return NS_OK;
00569 }
00570         
00571 nsresult nsAutoConfig::PromptForEMailAddress(nsACString &emailAddress)
00572 {
00573     nsresult rv;
00574     nsCOMPtr<nsIPromptService> promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
00575     NS_ENSURE_SUCCESS(rv, rv);
00576     nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00577     NS_ENSURE_SUCCESS(rv, rv);
00578 
00579     nsCOMPtr<nsIStringBundle> bundle;
00580     rv = bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties",
00581                                 getter_AddRefs(bundle));
00582     NS_ENSURE_SUCCESS(rv, rv);
00583 
00584     nsXPIDLString title;
00585     rv = bundle->GetStringFromName(NS_LITERAL_STRING("emailPromptTitle").get(), getter_Copies(title));
00586     NS_ENSURE_SUCCESS(rv, rv);
00587 
00588     nsXPIDLString err;
00589     rv = bundle->GetStringFromName(NS_LITERAL_STRING("emailPromptMsg").get(), getter_Copies(err));
00590     NS_ENSURE_SUCCESS(rv, rv);
00591     PRBool check = PR_FALSE;
00592     nsXPIDLString emailResult;
00593     PRBool success;
00594     rv = promptService->Prompt(nsnull, title.get(), err.get(), getter_Copies(emailResult), nsnull, &check, &success);
00595     if (!success)
00596       return NS_ERROR_FAILURE;
00597     NS_ENSURE_SUCCESS(rv, rv);
00598     CopyUCS2toASCII(emailResult, emailAddress);
00599     return NS_OK;
00600 }
00601