Back to index

lightning-sunbird  0.9+nobinonly
Stream.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 "Stream.h"
00040 #include "nsIComponentManager.h"
00041 #include "nsILocalFile.h"
00042 #include "nsXPIDLString.h"
00043 #include "nsIIOService.h"
00044 #include "nsNetUtil.h"
00045 
00046 // UI
00047 #include "nsIDialogParamBlock.h"
00048 #include "nsIDOMWindow.h"
00049 #include "nsIWindowWatcher.h"
00050 #include "plstr.h"
00051 
00052 // IID and CIDs of all the services needed
00053 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
00054 
00055 #define kRegTreeStream (NS_LITERAL_STRING("Stream"))
00056 #define kRegKeyURL (NS_LITERAL_STRING("BaseURL"))
00057 #define kRegKeyUsername (NS_LITERAL_STRING("Username"))
00058 #define kRegKeyPassword (NS_LITERAL_STRING("Password"))
00059 #define kRegKeySavePassword (NS_LITERAL_CSTRING("SavePassword"))
00060 
00061 #define kXferDlg "chrome://sroaming/content/transfer/progressDialog.xul"
00062 
00063 // Internal helper functions unrelated to class
00064 
00065 static void AppendElements(nsCStringArray& target, nsCStringArray& source)
00066 {
00067   for (PRInt32 i = source.Count() - 1; i >= 0; i--)
00068     target.AppendCString(*source.CStringAt(i));
00069 }
00070 
00071 /*
00072  * nsSRoamingMethod implementation
00073  */
00074 
00075 nsresult Stream::Init(Core* aController)
00076 {
00077   nsresult rv;
00078   mController = aController;
00079   NS_ASSERTION(mController, "mController is null");
00080 
00081   // Get prefs
00082   nsCOMPtr<nsIRegistry> registry;
00083   rv = mController->GetRegistry(registry);
00084   NS_ENSURE_SUCCESS(rv, rv);
00085 
00086   nsRegistryKey regkey;
00087   rv = mController->GetRegistryTree(regkey);
00088   NS_ENSURE_SUCCESS(rv, rv);
00089 
00090   rv = registry->GetKey(regkey,
00091                         kRegTreeStream.get(),
00092                         &regkey);
00093   NS_ENSURE_SUCCESS(rv, rv);
00094 
00095   mRegkeyStream = regkey;
00096 
00097   nsXPIDLString remoteUrlPref;
00098   rv = registry->GetString(regkey, kRegKeyURL.get(),
00099                            getter_Copies(remoteUrlPref));
00100   NS_ENSURE_SUCCESS(rv, rv);
00101 
00102   mRemoteBaseUrl = NS_ConvertUTF16toUTF8(remoteUrlPref);
00103 
00104   /* For easier mass-personalisation via scripts in corporate setups and
00105      for easier instructed setup by normal users,
00106      we allow the username to be separate from the URL. */
00107   nsXPIDLString usernamePref;
00108   rv = registry->GetString(regkey, kRegKeyUsername.get(),
00109                            getter_Copies(usernamePref));
00110   if (NS_SUCCEEDED(rv) && !usernamePref.IsEmpty() )
00111     /* failure is non-fatal, because username might be in the URL, and
00112        even if it isn't, the transfer will pull up a prompt. */
00113   {
00114     nsCOMPtr<nsIIOService> ioserv = do_GetService(kIOServiceCID, &rv);
00115     if (NS_SUCCEEDED(rv))
00116     {
00117       nsCOMPtr<nsIURI> uri;
00118       rv = NS_NewURI(getter_AddRefs(uri), mRemoteBaseUrl);
00119 
00120       if (NS_SUCCEEDED(rv))
00121       {
00122         rv = uri->SetUsername(NS_ConvertUTF16toUTF8(usernamePref));
00123         if (NS_SUCCEEDED(rv))
00124         {
00125           // Yikes. Did I mention that I hate that C/wide string crap?
00126           nsXPIDLCString spec;
00127           uri->GetSpec(spec);
00128           mRemoteBaseUrl = spec;
00129           mRemoteBaseUrl.ReplaceSubstring(NS_LITERAL_CSTRING("$USERID"),
00130                                           NS_ConvertUTF16toUTF8(usernamePref));
00131         }
00132       }
00133     }
00134   }
00135 
00136   // we need a / at the end (base URL), fix up, if user error
00137   if (mRemoteBaseUrl.Last() != (PRUnichar) '/')
00138     mRemoteBaseUrl += (PRUnichar) '/';
00139 
00140   nsXPIDLString passwordPref;
00141   rv = registry->GetString(regkey, kRegKeyPassword.get(),
00142                            getter_Copies(passwordPref));
00143   /* failure is non-fatal, because if there's no password, the
00144      transfer will pull up a prompt. */
00145   mPassword = passwordPref;
00146 
00147   PRInt32 savepw = 0;
00148   rv = registry->GetInt(regkey, kRegKeySavePassword.get(),
00149                         &savepw);
00150   mSavePassword = savepw == 0 ? PR_FALSE : PR_TRUE;
00151 
00152   nsCOMPtr<nsIFile> profiledir;
00153   rv = mController->GetProfileDir(getter_AddRefs(profiledir));
00154   NS_ENSURE_SUCCESS(rv, rv);
00155 
00156   nsCOMPtr<nsIIOService> ioserv = do_GetService(kIOServiceCID, &rv);
00157   NS_ENSURE_SUCCESS(rv, rv);
00158 
00159   rv = NS_NewFileURI(getter_AddRefs(mProfileDir), profiledir);
00160   NS_ENSURE_SUCCESS(rv, rv);
00161 
00162   return NS_OK;
00163 }
00164 
00165 nsresult Stream::Download()
00166 {
00167   return DownUpLoad(PR_TRUE);
00168 
00169 }
00170 
00171 nsresult Stream::Upload()
00172 {
00173   return DownUpLoad(PR_FALSE);
00174 }
00175 
00176 nsresult Stream::DownUpLoad(PRBool download)
00177 {
00178   nsresult rv = NS_OK;
00179 
00180   if (!mController)
00181     return NS_ERROR_UNEXPECTED;
00182 
00183   /* Design
00184 
00185   I'd really like to
00186   - open a few channels (one per file) here in this function,
00187   - attach |nsIProgressEventSink|s to each and
00188   - let a Progress dialog track/reflect the progress sinks.
00189   That way, I would have a generic dialog for the UI somewhere
00190   and the logic (transfer) here in this file, where it belongs.
00191 
00192   Unfortunately, this doesn't work. I have to
00193   block this function until the transfer is done, but have the transfer
00194   itself and the progress UI working. darin says, I will get threading
00195   issues then. He suggested to initiate the transfer from the dialog
00196   (because that dialog uses another event quene) and let the dialog
00197   close itself when the transfer is done. Here in this function, I can
00198   block until the dialog is dismissed.
00199   (At least, that's what I understood from darin.)
00200   That's what I do, and it seems to work. It's still a poor design.
00201 
00202   Actually, it's really crap. It destroys my whole design with the
00203   pluggable "method"s (like stream, copy etc.). Basically everything
00204   contacting remote servers (i.e. needing a progress dialog) now has to
00205   either mess around in sroamingTransfer.js or duplicate a certain
00206   portion of code.
00207   */
00208 
00209   nsCOMPtr<nsIWindowWatcher> windowWatcher
00210               (do_GetService("@mozilla.org/embedcomp/window-watcher;1", &rv));
00211   NS_ENSURE_SUCCESS(rv, rv);
00212 
00213   /* nsIDialogParamBlock is a method to pass ints and strings
00214      to and from XUL dialogs.
00215      To dialog (upon open)
00216        Int array
00217          Item 0: 1 = download, 2 = upload
00218          Item 1: 1 = serial (transfer one file after the other),
00219                  2 = parallel (start all file transfers at once)
00220          Item 2: Number of files (n below)
00221          Item 3: Save password (should pw be stored by default when asked?)
00222                  1 = true
00223                  0 = false
00224        String array
00225          Item 0: unused
00226          Item 1: URL of profile dir
00227          Item 2: URL of remote dir
00228          Item 3: Password
00229          Item 4..(n+3): filenames
00230      From dialog (upon close)
00231        Int array
00232          Item 0: 0 = do nothing
00233                  1 = Save Password (user checked the box in the prompt)
00234                  2 = Set SavePassword pref to false, ignore PW/Usern. retval
00235        String array
00236          Item 0: Saved username (as entered in the prompt)
00237          Item 1: Saved password (as entered in the prompt)
00238   */
00239   nsCOMPtr<nsIDialogParamBlock> ioParamBlock
00240              (do_CreateInstance("@mozilla.org/embedcomp/dialogparam;1", &rv));
00241   NS_ENSURE_SUCCESS(rv, rv);
00242 
00243   // download/upload
00244   ioParamBlock->SetInt(0, download ? 1 : 2);
00245   ioParamBlock->SetInt(1, 2);
00246 
00247   const nsCStringArray* files = mController->GetFilesToRoam();
00248   ioParamBlock->SetInt(2, files->Count());
00249 
00250   ioParamBlock->SetInt(3, mSavePassword ? 1 : 0);
00251 
00252   nsXPIDLCString profile;
00253   mProfileDir->GetSpec(profile);
00254   ioParamBlock->SetString(1, NS_ConvertUTF8toUTF16(profile).get());
00255   ioParamBlock->SetString(2, NS_ConvertUTF8toUTF16(mRemoteBaseUrl).get());
00256   ioParamBlock->SetString(3, mSavePassword
00257                           ? mPassword.get()
00258                           : EmptyString().get());
00259 
00260   // filenames
00261   for (PRInt32 i = files->Count() - 1; i >= 0; i--)
00262   {
00263     NS_ConvertASCIItoUTF16 filename(*files->CStringAt(i));
00264     ioParamBlock->SetString(i + 4, filename.get());
00265                                                  // filenames start at item 4
00266   }
00267 
00268   nsCOMPtr<nsIDOMWindow> window;
00269   rv = windowWatcher->OpenWindow(nsnull,
00270                                  kXferDlg,
00271                                  nsnull,
00272                                  "centerscreen,chrome,modal,titlebar",
00273                                  ioParamBlock,
00274                                  getter_AddRefs(window));
00275   NS_ENSURE_SUCCESS(rv, rv);
00276 
00277 
00278   PRInt32 savepw = 0;
00279   ioParamBlock->GetInt(0, &savepw);
00280        
00281   if (savepw == 1)
00282   {    
00283     nsXPIDLString password, username;
00284     ioParamBlock->GetString(0, getter_Copies(username));
00285     ioParamBlock->GetString(1, getter_Copies(password));
00286 
00287     mPassword = password;
00288     nsCOMPtr<nsIRegistry> registry;
00289     rv = mController->GetRegistry(registry);
00290     rv = registry->SetInt(mRegkeyStream, kRegKeySavePassword.get(),  1);
00291     rv = registry->SetString(mRegkeyStream, kRegKeyUsername.get(),
00292                              username.get());
00293     rv = registry->SetString(mRegkeyStream, kRegKeyPassword.get(),
00294                              mPassword.get());
00295     // failure is not fatal. then it's not saved *shrug*. ;-)
00296   }
00297     
00298   return NS_OK;
00299 }