Back to index

lightning-sunbird  0.9+nobinonly
Core.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Roaming code.
00016  *
00017  * The Initial Developer of the Original Code is 
00018  *   Ben Bucksch <http://www.bucksch.org> of
00019  *   Beonex <http://www.beonex.com>
00020  * Portions created by the Initial Developer are Copyright (C) 2002-2004
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
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 #include "Core.h"
00040 #include "nsIComponentManager.h"
00041 #include "nsIRegistry.h"
00042 #include "nsIProfile.h"
00043 #include "nsDirectoryServiceUtils.h"
00044 #include "nsAppDirectoryServiceDefs.h"
00045 #include "Copy.h"
00046 #include "Stream.h"
00047 #include "nsILocalFile.h"
00048 #include "nsIObserverService.h"
00049 
00050 // UI
00051 #include "nsIDialogParamBlock.h"
00052 #include "nsIDOMWindow.h"
00053 #include "nsIWindowWatcher.h"
00054 #include "plstr.h"
00055 
00056 #define kRegTreeProfile (NS_LITERAL_STRING("Profiles"))
00057 
00058 #define kRegTreeRoaming (NS_LITERAL_STRING("Roaming"))
00059 #define kRegKeyEnabled (NS_LITERAL_CSTRING("Enabled"))
00060 #define kRegKeyMethod (NS_LITERAL_STRING("Method"))
00061 #define kRegKeyFiles (NS_LITERAL_STRING("Files"))
00062 #define kRegValMethodStream (NS_LITERAL_STRING("stream"))
00063 #define kRegValMethodCopy (NS_LITERAL_STRING("copy"))
00064 
00065 #define kConflDlg "chrome://sroaming/content/transfer/conflictResolve.xul"
00066 
00067 
00068 NS_IMPL_ISUPPORTS1(Core,
00069                    nsISessionRoaming)
00070 
00071 Core::Core()
00072     : mFiles(10), mIsRoaming(PR_FALSE), mMethod(0), mRegistry(0)
00073 {
00074 }
00075 
00076 /*
00077  * mozISRoaming implementation
00078  */
00079 
00080 NS_IMETHODIMP
00081 Core::BeginSession()
00082 {
00083   nsresult rv = ReadRoamingPrefs();
00084   NS_ENSURE_SUCCESS(rv, rv);
00085 
00086   if (!mIsRoaming)
00087     return NS_OK;
00088 
00089   Protocol* proto = CreateMethodHandler();
00090   if (!proto)
00091     return NS_ERROR_ABORT;
00092 
00093   rv = proto->Init(this);
00094   if (NS_FAILED(rv))
00095   {
00096     delete proto;
00097     return rv;
00098   }
00099 
00100   rv = proto->Download();
00101   if (NS_FAILED(rv))
00102   {
00103     delete proto;
00104     return rv;
00105   }
00106 
00107   delete proto;
00108   return NS_OK;
00109 }
00110 
00111 NS_IMETHODIMP
00112 Core::EndSession()
00113 {
00114   nsresult rv = ReadRoamingPrefs();
00115   NS_ENSURE_SUCCESS(rv, rv);
00116 
00117   if (!mIsRoaming)
00118     return NS_OK;
00119 
00120   Protocol* proto = CreateMethodHandler();
00121   if (!proto)
00122     return NS_ERROR_ABORT;
00123 
00124   rv = proto->Init(this);
00125   if (NS_FAILED(rv))
00126   {
00127     delete proto;
00128     return rv;
00129   }
00130 
00131   RestoreNet();
00132 
00133   rv = proto->Upload();
00134   if (NS_FAILED(rv))
00135   {
00136     delete proto;
00137     return rv;
00138   }
00139 
00140   CloseNet();
00141 
00142   delete proto;
00143   return NS_OK;
00144 }
00145 
00146 NS_IMETHODIMP
00147 Core::IsRoaming(PRBool *_retval)
00148 {
00149   ReadRoamingPrefs();
00150 
00151   *_retval = IsRoaming();
00152   return NS_OK;
00153 }
00154 
00155 
00156 
00157 /*
00158  * Public functions
00159  */
00160 
00161 nsresult Core::GetProfileDir(nsIFile** result)
00162 {
00163   return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, result);
00164 }
00165 
00166 nsresult
00167 Core::ConflictResolveUI(PRBool download, const nsCStringArray& files,
00168                                nsCStringArray* result)
00169 {
00170   if (files.Count() < 1)
00171     return NS_OK;
00172 
00173   /* nsIDialogParamBlock is a method to pass ints and strings
00174      to and from XUL dialogs.
00175      To dialog (upon open)
00176        Int array
00177          Item 0: 1 = download, 2 = upload
00178          Item 1: Number of files (n below)
00179        String array
00180          Item 1..(n): Either filename or comma-separated (no spaces) string:
00181                       - filename
00182                       - last modified (unix time) server
00183                       - size (bytes) server
00184                       - last modified (unix time) local
00185                       - size (bytes) local
00186                       e.g. "bookmarks.html,100024563,325,100024535,245" or
00187                       "bookmarks.html"
00188      From dialog (upon close)
00189        Int array
00190          Item 0:      3 = OK, 4 = Cancel
00191          Item 1..(n): if OK:
00192                       1 = Use server version, 2 = Use local version.
00193                       For each file. Indices are the same as To/String
00194   */
00195   nsresult rv;
00196 
00197   nsCOMPtr<nsIDialogParamBlock> ioParamBlock
00198              (do_CreateInstance("@mozilla.org/embedcomp/dialogparam;1", &rv));
00199   NS_ENSURE_SUCCESS(rv, rv);
00200 
00201   // download/upload
00202   ioParamBlock->SetInt(0, download ? 1 : 2);
00203 
00204   // filenames
00205   ioParamBlock->SetInt(1, files.Count());
00206   PRInt32 i;
00207   for (i = files.Count() - 1; i >= 0; i--)
00208   {
00209     NS_ConvertASCIItoUTF16 filename(*files.CStringAt(i));
00210     ioParamBlock->SetString(i + 1, filename.get());
00211   }
00212 
00213   nsCOMPtr<nsIWindowWatcher> windowWatcher
00214                              (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
00215   NS_ENSURE_SUCCESS(rv, rv);
00216 
00217   nsCOMPtr<nsIDOMWindow> window;
00218   rv = windowWatcher->OpenWindow(nsnull,
00219                                  kConflDlg,
00220                                  nsnull,
00221                                  "centerscreen,chrome,modal,titlebar",
00222                                  ioParamBlock,
00223                                  getter_AddRefs(window));
00224   NS_ENSURE_SUCCESS(rv, rv);
00225 
00226   PRInt32 value = 0;
00227   ioParamBlock->GetInt(0, &value);
00228   if (value != 3 && value != 4)
00229     return NS_ERROR_INVALID_ARG;
00230   if (value == 4) // cancel
00231   {
00232     return NS_ERROR_ABORT;
00233   }
00234 
00235   /* I am assuming that the sequence of iteration here is the same as in the
00236      last |for| statement. If that is not true, the indices gotten from
00237      param block will not match the array and we will interpret the result
00238      wrongly. */
00239   for (i = files.Count() - 1; i >= 0; i--)
00240   {
00241     ioParamBlock->GetInt(i + 1, &value);
00242     if (value != 1 && value != 2)
00243       return NS_ERROR_INVALID_ARG;
00244     if (download
00245         ? value == 1
00246         : value == 2)
00247       result->AppendCString(*files.CStringAt(i));
00248   }
00249 
00250   //*result = files;
00251   return NS_OK;
00252 }
00253 
00254 nsresult Core::GetRegistry(nsCOMPtr<nsIRegistry>& result)
00255 {
00256   if (mRegistry)
00257   {
00258     result = mRegistry;
00259     return NS_OK;
00260   }
00261 
00262   nsresult rv;
00263   nsCOMPtr<nsIRegistry> registry(do_CreateInstance(NS_REGISTRY_CONTRACTID,
00264                                                    &rv));
00265   NS_ENSURE_SUCCESS(rv, rv);
00266 
00267   rv = registry->OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry);
00268   NS_ENSURE_SUCCESS(rv, rv);
00269 
00270   mRegistry = registry;
00271   result = registry;
00272   return NS_OK;
00273 }
00274 
00275 nsresult Core::GetRegistryTree(nsRegistryKey& result)
00276 {
00277   nsRegistryKey regkey = 0;
00278 
00279   nsresult rv;
00280   nsCOMPtr<nsIProfile> profMan(do_GetService(NS_PROFILE_CONTRACTID, &rv));
00281   NS_ENSURE_SUCCESS(rv, rv);
00282 
00283   nsXPIDLString profile;
00284   rv = profMan->GetCurrentProfile(getter_Copies(profile));
00285   NS_ENSURE_SUCCESS(rv, rv);
00286 
00287   nsCOMPtr<nsIRegistry> registry;
00288   rv = GetRegistry(registry);
00289   NS_ENSURE_SUCCESS(rv, rv);
00290 
00291   rv = registry->GetKey(nsIRegistry::Common,
00292                         kRegTreeProfile.get(),
00293                         &regkey);
00294   NS_ENSURE_SUCCESS(rv, rv);
00295 
00296   rv = registry->GetKey(regkey,
00297                         profile.get(),
00298                         &regkey);
00299   NS_ENSURE_SUCCESS(rv, rv);
00300 
00301   rv = registry->GetKey(regkey,
00302                         kRegTreeRoaming.get(),
00303                         &regkey);
00304   NS_ENSURE_SUCCESS(rv, rv);
00305 
00306   result = regkey;
00307   return NS_OK;
00308 }
00309 
00310 
00311 /*
00312  * Internal functions
00313  */
00314 
00315 nsresult Core::ReadRoamingPrefs()
00316 {
00317   nsCOMPtr<nsIRegistry> registry;
00318   nsresult rv = GetRegistry(registry);
00319   NS_ENSURE_SUCCESS(rv, rv);
00320 
00321   nsRegistryKey regkey;
00322   rv = GetRegistryTree(regkey);
00323   if (NS_FAILED(rv)) // expected, if roaming not set up for this profile
00324     mIsRoaming = PR_FALSE;
00325   else
00326   {
00327     PRInt32 enabled;
00328     rv = registry->GetInt(regkey, kRegKeyEnabled.get(),
00329                           &enabled);
00330     if (NS_FAILED(rv))
00331     {
00332       mIsRoaming = PR_FALSE;
00333       return rv;
00334     }
00335     mIsRoaming = (enabled != 0);
00336   }
00337 
00338   if (!mIsRoaming)
00339     return NS_OK;
00340 
00341   // Method
00342   nsXPIDLString proto;
00343   rv = registry->GetString(regkey, kRegKeyMethod.get(),
00344                            getter_Copies(proto));
00345   NS_ENSURE_SUCCESS(rv, rv);
00346   if (proto == kRegValMethodStream)
00347     mMethod = 1;
00348   else if (proto == kRegValMethodCopy)
00349     mMethod = 2;
00350 
00351   // Files
00352   nsXPIDLString files_reg;
00353   rv = registry->GetString(regkey, kRegKeyFiles.get(),
00354                            getter_Copies(files_reg));
00355   NS_ENSURE_SUCCESS(rv, rv);
00356 
00357   NS_ConvertUTF16toUTF8 files_pref(files_reg);
00358 
00359   mFiles.Clear();
00360   mFiles.ParseString(files_pref.get(), ",");
00361 
00362   return NS_OK;
00363 }
00364 
00365 Protocol* Core::CreateMethodHandler()
00366 {
00367   if (mMethod == 1)
00368     return new Stream;
00369   else if (mMethod == 2)
00370     return new Copy;
00371 
00372   return 0;
00373 }
00374 
00375 /* A workaround for the fact that the network library is shut down during
00376    profile shutdown (for dynamic profile changing), *before* the
00377    app is told to write down profile changes and thus before we try to upload,
00378    so our upload will fail.
00379    So, I just power netlib up again and then power it down again by sending
00380    the corresponding profile change notification. Might not be the
00381    best solution, but has small impact on existing code and WFM. */
00382 nsresult Core::RestoreCloseNet(PRBool restore)
00383 {
00384   const char* topic = restore ? "profile-change-net-restore"
00385                               : "profile-change-net-teardown";
00386   nsresult rv;
00387   nsCOMPtr<nsIObserverService> observerService
00388                        (do_GetService("@mozilla.org/observer-service;1", &rv));
00389   NS_ENSURE_SUCCESS(rv, rv);
00390 
00391   nsCOMPtr<nsISupports> subject(do_GetService(NS_PROFILE_CONTRACTID, &rv));
00392   NS_ENSURE_SUCCESS(rv, rv);
00393 
00394   rv = observerService->NotifyObservers(subject, topic,
00395                                         NS_LITERAL_STRING("switch").get());
00396   return rv;
00397 }