Back to index

lightning-sunbird  0.9+nobinonly
wallet.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 Communicator client 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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039    wallet.cpp
00040 */
00041 
00042 #include "wallet.h"
00043 #include "singsign.h"
00044 
00045 #include "nsNetUtil.h"
00046 #include "nsILineInputStream.h"
00047 #include "nsReadableUtils.h"
00048 #include "nsUnicharUtils.h"
00049 #include "nsILocalFile.h"
00050 
00051 #include "nsIServiceManager.h"
00052 #include "nsIDocument.h"
00053 #include "nsIDOMHTMLDocument.h"
00054 #include "nsIDOMHTMLCollection.h"
00055 #include "nsIDOMHTMLFormElement.h"
00056 #include "nsIDOMHTMLInputElement.h"
00057 #include "nsIDOMHTMLSelectElement.h"
00058 #include "nsIDOMHTMLOptionElement.h"
00059 #include "nsIURL.h"
00060 #include "nsIDOMWindowCollection.h"
00061 #include "nsIPrompt.h"
00062 #include "nsIWindowWatcher.h"
00063 
00064 #include "nsAppDirectoryServiceDefs.h"
00065 
00066 #include "nsIStringBundle.h"
00067 #include "prmem.h"
00068 #include "prprf.h"
00069 #include "nsIContent.h"
00070 #include "nsIObserverService.h"
00071 
00072 #include "nsIWalletService.h"
00073 
00074 #include <time.h>
00075 
00076 #include "prlong.h"
00077 #include "prinrval.h"
00078 
00079 #include "prlog.h"
00080 //
00081 // To enable logging (see prlog.h for full details):
00082 //
00083 //    set NSPR_LOG_MODULES=nsWallet:5
00084 //    set NSPR_LOG_FILE=nspr.log
00085 //
00086 PRLogModuleInfo* gWalletLog = nsnull;
00087 
00088 
00089 /********************************************************/
00090 /* The following data and procedures are for preference */
00091 /********************************************************/
00092 
00093 static const char pref_Caveat[] = "wallet.caveat";
00094 static const char pref_captureForms[] = "wallet.captureForms";
00095 static const char pref_enabled[] = "wallet.enabled";
00096 static const char pref_WalletSchemaValueFileName[] = "wallet.SchemaValueFileName";
00097 
00098 static PRBool wallet_captureForms = PR_FALSE;
00099 
00100 static void
00101 wallet_SetFormsCapturingPref(PRBool x)
00102 {
00103     /* do nothing if new value of pref is same as current value */
00104     if (x == wallet_captureForms) {
00105         return;
00106     }
00107 
00108     /* change the pref */
00109     wallet_captureForms = x;
00110 }
00111 
00112 int PR_CALLBACK
00113 wallet_FormsCapturingPrefChanged(const char * newpref, void * data)
00114 {
00115     PRBool x;
00116     x = SI_GetBoolPref(pref_captureForms, PR_TRUE);
00117     wallet_SetFormsCapturingPref(x);
00118     return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */
00119 }
00120 
00121 static void
00122 wallet_RegisterCapturePrefCallbacks(void)
00123 {
00124     PRBool x;
00125     static PRBool first_time = PR_TRUE;
00126 
00127     if(first_time)
00128     {
00129         first_time = PR_FALSE;
00130         x = SI_GetBoolPref(pref_captureForms, PR_TRUE);
00131         wallet_SetFormsCapturingPref(x);
00132         SI_RegisterCallback(pref_captureForms, wallet_FormsCapturingPrefChanged, NULL);
00133     }
00134 }
00135 
00136 static PRBool
00137 wallet_GetFormsCapturingPref(void)
00138 {
00139     wallet_RegisterCapturePrefCallbacks();
00140     return wallet_captureForms;
00141 }
00142 
00143 static PRBool
00144 wallet_GetEnabledPref(void)
00145 {
00146   /* This pref is not in the prefs panel.  It's purpose is to remove wallet from all UI */
00147   static PRBool first_time = PR_TRUE;
00148   static PRBool enabled = PR_TRUE;
00149   if (first_time) {
00150     first_time = PR_FALSE;
00151     PRBool x = SI_GetBoolPref(pref_enabled, PR_TRUE);
00152     enabled = x;
00153   }
00154   return enabled;
00155 }
00156 
00157 
00158 /***************************************************/
00159 /* The following declarations define the data base */
00160 /***************************************************/
00161 
00162 #define WALLET_FREE(_ptr) { nsMemory::Free((void*)_ptr); (_ptr) = nsnull; }
00163 #define WALLET_FREEIF(_ptr) if (_ptr) WALLET_FREE(_ptr)
00164 
00165 enum PlacementType {DUP_IGNORE, DUP_OVERWRITE, DUP_BEFORE, DUP_AFTER, AT_END, BY_LENGTH};
00166 #define LIST_COUNT(list)  ((list) ? (list)->Count() : 0)
00167 
00168 MOZ_DECL_CTOR_COUNTER(wallet_Sublist)
00169 
00170 class wallet_Sublist {
00171 public:
00172   wallet_Sublist()
00173   {
00174     MOZ_COUNT_CTOR(wallet_Sublist);
00175   }
00176   ~wallet_Sublist()
00177   {
00178     WALLET_FREEIF(item);
00179     MOZ_COUNT_DTOR(wallet_Sublist);
00180   }
00181   const char* item;
00182 };
00183 
00184 /*
00185  * The data structure below consists of mapping tables that map one item into another.
00186  * The actual interpretation of the items depend on which table we are in.  For
00187  * example, if in the field-to-schema table, item1 is a field name and item2 is a
00188  * schema name.  Whereas in the schema-to-value table, item1 is a schema name and
00189  * item2 is a value.  Therefore this generic data structure refers to them simply as
00190  * item1 and item2.
00191  */
00192 MOZ_DECL_CTOR_COUNTER(wallet_MapElement)
00193 
00194 class wallet_MapElement {
00195 public:
00196   wallet_MapElement() : itemList(nsnull)
00197   {
00198     MOZ_COUNT_CTOR(wallet_MapElement);
00199   }
00200   ~wallet_MapElement()
00201   {
00202     WALLET_FREEIF(item1);
00203     WALLET_FREEIF(item2);
00204     if (itemList) {
00205       PRInt32 count = LIST_COUNT(itemList);
00206       wallet_Sublist * sublistPtr;
00207       for (PRInt32 i=0; i<count; i++) {
00208         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, itemList->ElementAt(i));
00209         delete sublistPtr;
00210       }
00211       delete itemList;
00212     }
00213     MOZ_COUNT_DTOR(wallet_MapElement);
00214   }
00215   const char* item1;
00216   const char* item2;
00217   nsVoidArray * itemList;
00218 };
00219 
00220 /* Purpose of this class is to speed up startup time on the mac
00221  *
00222  * These strings are used over and over again inside an inner loop.  Rather
00223  * then allocating them and then deallocating them, they will be allocated
00224  * only once and left sitting on the heap
00225  */
00226 
00227 MOZ_DECL_CTOR_COUNTER(wallet_HelpMac)
00228 
00229 class wallet_HelpMac {
00230 public:
00231   wallet_HelpMac() {
00232     MOZ_COUNT_CTOR(wallet_HelpMac);
00233   }
00234   ~wallet_HelpMac() {
00235     MOZ_COUNT_DTOR(wallet_HelpMac);
00236   }
00237   nsCString item1;
00238   nsCString item2;
00239   nsCString item3;
00240 };
00241 wallet_HelpMac * helpMac;
00242 
00243 static nsVoidArray * wallet_FieldToSchema_list = 0;
00244 static nsVoidArray * wallet_VcardToSchema_list = 0;
00245 static nsVoidArray * wallet_SchemaToValue_list = 0;
00246 static nsVoidArray * wallet_SchemaConcat_list = 0;
00247 static nsVoidArray * wallet_SchemaStrings_list = 0;
00248 static nsVoidArray * wallet_PositionalSchema_list = 0;
00249 static nsVoidArray * wallet_StateSchema_list = 0;
00250 static nsVoidArray * wallet_URL_list = 0;
00251 static nsVoidArray * wallet_DistinguishedSchema_list = 0;
00252 
00253 #define NO_CAPTURE(x) x[0]
00254 #define NO_PREVIEW(x) x[1]
00255 
00256 MOZ_DECL_CTOR_COUNTER(wallet_PrefillElement)
00257 
00258 class wallet_PrefillElement {
00259 public:
00260   wallet_PrefillElement() : inputElement(nsnull), selectElement(nsnull)
00261   {
00262     schema = nsnull;
00263     MOZ_COUNT_CTOR(wallet_PrefillElement);
00264   }
00265   ~wallet_PrefillElement()
00266   {
00267     WALLET_FREEIF(schema);
00268     NS_IF_RELEASE(inputElement);
00269     NS_IF_RELEASE(selectElement);
00270     MOZ_COUNT_DTOR(wallet_PrefillElement);
00271   }
00272   nsIDOMHTMLInputElement* inputElement;
00273   nsIDOMHTMLSelectElement* selectElement;
00274   char* schema;
00275   nsString value;
00276   PRInt32 selectIndex;
00277   PRUint32 count;
00278 };
00279 
00280 nsIURI * wallet_lastUrl = NULL;
00281 
00282 /***********************************************************/
00283 /* The following routines are for diagnostic purposes only */
00284 /***********************************************************/
00285 
00286 #ifdef DEBUG_morse
00287 
00288 static void
00289 wallet_Pause(){
00290   fprintf(stdout,"%cpress y to continue\n", '\007');
00291   char c;
00292   for (;;) {
00293     c = getchar();
00294     if (tolower(c) == 'y') {
00295       fprintf(stdout,"OK\n");
00296       break;
00297     }
00298   }
00299   while (c != '\n') {
00300     c = getchar();
00301   }
00302 }
00303 
00304 static void
00305 wallet_DumpAutoString(const nsString& as){
00306   fprintf(stdout, "%s\n", NS_LossyConvertUCS2toASCII(as).get());
00307 }
00308 
00309 static void
00310 wallet_Dump(nsVoidArray * list) {
00311   wallet_MapElement * mapElementPtr;
00312   PRInt32 count = LIST_COUNT(list);
00313   for (PRInt32 i=0; i<count; i++) {
00314     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, list->ElementAt(i));
00315     fprintf(stdout, "%s %s \n", (mapElementPtr->item1), (mapElementPtr->item2));
00316     wallet_Sublist * sublistPtr;
00317     PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
00318     for (PRInt32 i2=0; i2<count2; i2++) {
00319       sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(i2));
00320       fprintf(stdout, "     %s \n", (sublistPtr->item));
00321     }
00322   }
00323   wallet_Pause();
00324 }
00325 
00326 /******************************************************************/
00327 /* The following diagnostic routines are for timing purposes only */
00328 /******************************************************************/
00329 
00330 const PRInt32 timing_max = 1000;
00331 PRInt64 timings [timing_max];
00332 char timingID [timing_max];
00333 PRInt32 timing_index = 0;
00334 
00335 PRInt64 stopwatch = LL_Zero();
00336 PRInt64 stopwatchBase;
00337 PRBool stopwatchRunning = PR_FALSE;
00338 
00339 static void
00340 wallet_ClearTiming() {
00341   timing_index = 0;
00342   LL_I2L(timings[timing_index++], PR_IntervalNow());
00343 }
00344 
00345 static void
00346 wallet_DumpTiming() {
00347   PRInt32 i, r4;
00348   PRInt64 r1, r2, r3;
00349   for (i=1; i<timing_index; i++) {
00350     LL_SUB(r1, timings[i], timings[i-1]);
00351     LL_I2L(r2, 100);
00352     LL_DIV(r3, r1, r2);
00353     LL_L2I(r4, r3);
00354     fprintf(stdout, "time %c = %ld\n", timingID[i], (long)r4);
00355     if (i%20 == 0) {
00356       wallet_Pause();
00357     }
00358   }
00359   wallet_Pause();
00360 }
00361 
00362 static void
00363 wallet_AddTiming(char c) {
00364   if (timing_index<timing_max) {
00365     timingID[timing_index] = c;
00366     // note: PR_IntervalNow returns a 32 bit value!
00367     LL_I2L(timings[timing_index++], PR_IntervalNow());
00368   }
00369 }
00370 
00371 static void
00372 wallet_ClearStopwatch() {
00373   stopwatch = LL_Zero();
00374   stopwatchRunning = PR_FALSE;
00375 }
00376 
00377 static void
00378 wallet_ResumeStopwatch() {
00379   if (!stopwatchRunning) {
00380     // note: PR_IntervalNow returns a 32 bit value!
00381     LL_I2L(stopwatchBase, PR_IntervalNow());
00382     stopwatchRunning = PR_TRUE;
00383   }
00384 }
00385 
00386 static void
00387 wallet_PauseStopwatch() {
00388   PRInt64 r1, r2;
00389   if (stopwatchRunning) {
00390     // note: PR_IntervalNow returns a 32 bit value!
00391     LL_I2L(r1, PR_IntervalNow());
00392     LL_SUB(r2, r1, stopwatchBase);
00393     LL_ADD(stopwatch, stopwatch, r2);
00394     stopwatchRunning = PR_FALSE;
00395   }
00396 }
00397 
00398 static void
00399 wallet_DumpStopwatch() {
00400   PRInt64 r1, r2;
00401   PRInt32 r3;
00402   if (stopwatchRunning) {
00403     // note: PR_IntervalNow returns a 32 bit value!
00404     LL_I2L(r1, PR_IntervalNow());
00405     LL_SUB(r2, r1, stopwatchBase);
00406     LL_ADD(stopwatch, stopwatch, r2);
00407     LL_I2L(stopwatchBase, PR_IntervalNow());
00408   }
00409   LL_I2L(r1, 100);
00410   LL_DIV(r2, stopwatch, r1);
00411   LL_L2I(r3, r2);
00412   fprintf(stdout, "stopwatch = %ld\n", (long)r3);
00413 }
00414 #endif /* DEBUG_morse */
00415 
00416 
00417 /*************************************************************************/
00418 /* The following routines are used for accessing strings to be localized */
00419 /*************************************************************************/
00420 
00421 #define PROPERTIES_URL "chrome://communicator/locale/wallet/wallet.properties"
00422 
00423 PRUnichar *
00424 Wallet_Localize(const char* genericString) {
00425   nsresult ret;
00426   nsAutoString v;
00427 
00428   /* create a bundle for the localization */
00429   nsCOMPtr<nsIStringBundleService> pStringService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &ret);
00430   if (NS_FAILED(ret)) {
00431 #ifdef DEBUG
00432     printf("cannot get string service\n");
00433 #endif
00434     return ToNewUnicode(v);
00435   }
00436   nsCOMPtr<nsIStringBundle> bundle;
00437   ret = pStringService->CreateBundle(PROPERTIES_URL, getter_AddRefs(bundle));
00438   if (NS_FAILED(ret)) {
00439 #ifdef DEBUG
00440     printf("cannot create instance\n");
00441 #endif
00442     return ToNewUnicode(v);
00443   }
00444 
00445   /* localize the given string */
00446   NS_ConvertASCIItoUTF16 strtmp(genericString);
00447   PRUnichar *ptrv = nsnull;
00448   ret = bundle->GetStringFromName(strtmp.get(), &ptrv);
00449   if (NS_FAILED(ret)) {
00450 #ifdef DEBUG
00451     printf("cannot get string from name\n");
00452 #endif
00453     return ToNewUnicode(v);
00454   }
00455   v = ptrv;
00456   nsCRT::free(ptrv);
00457 
00458   /* convert # to newlines */
00459   PRUint32 i;
00460   for (i=0; i<v.Length(); i++) {
00461     if (v.CharAt(i) == '#') {
00462       v.SetCharAt('\n', i);
00463     }
00464   }
00465 
00466   return ToNewUnicode(v);
00467 }
00468 
00469 
00470 /**********************/
00471 /* Modal dialog boxes */
00472 /**********************/
00473 
00474 PRBool
00475 Wallet_Confirm(PRUnichar * szMessage, nsIDOMWindowInternal* window)
00476 {
00477   PRBool retval = PR_TRUE; /* default value */
00478 
00479   nsresult res;
00480   nsCOMPtr<nsIPrompt> dialog;
00481   window->GetPrompter(getter_AddRefs(dialog));
00482   if (!dialog) {
00483     return retval;
00484   } 
00485 
00486   const nsAutoString message( szMessage );
00487   retval = PR_FALSE; /* in case user exits dialog by clicking X */
00488   res = dialog->Confirm(nsnull, message.get(), &retval);
00489   return retval;
00490 }
00491 
00492 PRBool
00493 Wallet_ConfirmYN(PRUnichar * szMessage, nsIDOMWindowInternal* window) {
00494   nsresult res;
00495   nsCOMPtr<nsIPrompt> dialog;
00496   window->GetPrompter(getter_AddRefs(dialog));
00497   if (!dialog) {
00498     return PR_FALSE;
00499   } 
00500 
00501   PRInt32 buttonPressed = 1; /* in case user exits dialog by clickin X */
00502   PRUnichar * confirm_string = Wallet_Localize("Confirm");
00503 
00504   res = dialog->ConfirmEx(confirm_string, szMessage,
00505                           (nsIPrompt::BUTTON_TITLE_YES * nsIPrompt::BUTTON_POS_0) +
00506                           (nsIPrompt::BUTTON_TITLE_NO * nsIPrompt::BUTTON_POS_1),
00507                           nsnull, nsnull, nsnull, nsnull, nsnull, &buttonPressed);
00508 
00509   WALLET_FREE(confirm_string);
00510   return (buttonPressed == 0);
00511 }
00512 
00513 PRInt32
00514 Wallet_3ButtonConfirm(PRUnichar * szMessage, nsIDOMWindowInternal* window)
00515 {
00516   nsresult res;
00517   nsCOMPtr<nsIPrompt> dialog;
00518   window->GetPrompter(getter_AddRefs(dialog));
00519   if (!dialog) {
00520     return 0; /* default value is NO */
00521   } 
00522 
00523   PRInt32 buttonPressed = 1; /* default of NO if user exits dialog by clickin X */
00524   PRUnichar * never_string = Wallet_Localize("Never");
00525   PRUnichar * confirm_string = Wallet_Localize("Confirm");
00526 
00527   res = dialog->ConfirmEx(confirm_string, szMessage,
00528                           nsIPrompt::BUTTON_POS_1_DEFAULT +
00529                           (nsIPrompt::BUTTON_TITLE_YES * nsIPrompt::BUTTON_POS_0) +
00530                           (nsIPrompt::BUTTON_TITLE_NO * nsIPrompt::BUTTON_POS_1) +
00531                           (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2),
00532                           nsnull, nsnull, never_string, nsnull, nsnull, &buttonPressed);
00533 
00534   WALLET_FREE(never_string);
00535   WALLET_FREE(confirm_string);
00536 
00537   return buttonPressed;
00538 }
00539 
00540 static void
00541 wallet_Alert(PRUnichar * szMessage, nsIDOMWindowInternal* window)
00542 {
00543   nsresult res;
00544   nsCOMPtr<nsIPrompt> dialog;
00545   window->GetPrompter(getter_AddRefs(dialog));
00546   if (!dialog) {
00547     return;     // XXX should return the error
00548   } 
00549 
00550   const nsAutoString message( szMessage );
00551   PRUnichar * title = Wallet_Localize("CaveatTitle");
00552   res = dialog->Alert(title, message.get());
00553   WALLET_FREE(title);
00554   return;     // XXX should return the error
00555 }
00556 
00557 static void
00558 wallet_Alert(PRUnichar * szMessage, nsIPrompt* dialog)
00559 {
00560   nsresult res;
00561   const nsAutoString message( szMessage );
00562   PRUnichar * title = Wallet_Localize("CaveatTitle");
00563   res = dialog->Alert(title, message.get());
00564   WALLET_FREE(title);
00565   return;     // XXX should return the error
00566 }
00567 
00568 PRBool
00569 Wallet_CheckConfirmYN
00570     (PRUnichar * szMessage, PRUnichar * szCheckMessage, PRBool* checkValue,
00571      nsIDOMWindowInternal* window) {
00572   nsresult res;
00573   nsCOMPtr<nsIPrompt> dialog;
00574   window->GetPrompter(getter_AddRefs(dialog));
00575   if (!dialog) {
00576     return PR_FALSE;
00577   } 
00578 
00579   PRInt32 buttonPressed = 1; /* in case user exits dialog by clickin X */
00580   PRUnichar * confirm_string = Wallet_Localize("Confirm");
00581 
00582   res = dialog->ConfirmEx(confirm_string, szMessage,
00583                           (nsIPrompt::BUTTON_TITLE_YES * nsIPrompt::BUTTON_POS_0) +
00584                           (nsIPrompt::BUTTON_TITLE_NO * nsIPrompt::BUTTON_POS_1),
00585                           nsnull, nsnull, nsnull, szCheckMessage, checkValue, &buttonPressed);
00586 
00587   if (NS_FAILED(res)) {
00588     *checkValue = 0;
00589   }
00590   if (*checkValue!=0 && *checkValue!=1) {
00591     NS_ASSERTION(PR_FALSE, "Bad result from checkbox");
00592     *checkValue = 0; /* this should never happen but it is happening!!! */
00593   }
00594   WALLET_FREE(confirm_string);
00595   return (buttonPressed == 0);
00596 }
00597 
00598 
00599 /*******************************************************/
00600 /* The following routines are for Encyption/Decryption */
00601 /*******************************************************/
00602 
00603 #include "nsISecretDecoderRing.h"
00604 nsISecretDecoderRing* gSecretDecoderRing = nsnull;
00605 PRBool gEncryptionFailure = PR_FALSE;
00606 PRInt32 gReencryptionLevel = 0;
00607 
00608 static nsresult
00609 wallet_CryptSetup() {
00610   if (!gSecretDecoderRing)
00611   {
00612     /* Get a secret decoder ring */
00613     nsresult rv = NS_OK;
00614     nsCOMPtr<nsISecretDecoderRing> secretDecoderRing
00615       = do_CreateInstance("@mozilla.org/security/sdr;1", &rv);
00616     if (NS_FAILED(rv)) {
00617       return NS_ERROR_FAILURE;
00618     }
00619     gSecretDecoderRing = secretDecoderRing.get();
00620     NS_ADDREF(gSecretDecoderRing);
00621   }
00622   return NS_OK;
00623 }
00624 
00625 #define PREFIX "~"
00626 #include "plbase64.h"
00627 
00628 static nsresult EncryptString (const char * text, char *& crypt) {
00629 
00630   /* use SecretDecoderRing if encryption pref is set */
00631   nsresult rv;
00632   if (SI_GetBoolPref(pref_Crypto, PR_FALSE)) {
00633     rv = wallet_CryptSetup();
00634     if (NS_SUCCEEDED(rv)) {
00635       rv = gSecretDecoderRing->EncryptString(text, &crypt);
00636     }
00637     if (NS_FAILED(rv)) {
00638       gEncryptionFailure = PR_TRUE;
00639     }
00640     return rv;
00641   }
00642 
00643   /* otherwise do our own obscuring using Base64 encoding */
00644   char * crypt0 = PL_Base64Encode(text, 0, NULL);
00645   if (!crypt0) {
00646     return NS_ERROR_FAILURE;
00647   }
00648   PRUint32 PREFIX_len = sizeof (PREFIX) - 1;
00649   PRUint32 crypt0_len = PL_strlen(crypt0);
00650   crypt = (char *)PR_Malloc(PREFIX_len + crypt0_len + 1);
00651   PRUint32 i;
00652   for (i=0; i<PREFIX_len; i++) {
00653     crypt[i] = PREFIX[i];
00654   }
00655   for (i=0; i<crypt0_len; i++) {
00656     crypt[PREFIX_len+i] = crypt0[i];
00657   }
00658   crypt[PREFIX_len + crypt0_len] = '\0';
00659   WALLET_FREE(crypt0);
00660 
00661   return NS_OK;
00662 }
00663 
00664 static nsresult DecryptString (const char * crypt, char *& text) {
00665 
00666   /* treat zero-length crypt string as a special case */
00667   if (crypt[0] == '\0') {
00668     text = (char *)PR_Malloc(1);
00669     text[0] = '\0';
00670     return NS_OK;
00671   }
00672 
00673   /* use SecretDecoderRing if crypt doesn't starts with prefix */
00674   if (crypt[0] != PREFIX[0]) {
00675     if ((gReencryptionLevel == 0) && !SI_GetBoolPref(pref_Crypto, PR_FALSE)) {
00676       /*
00677        * User's data is encrypted but pref says it's not.
00678        * This should never occur but it has been observed.
00679        * Consequence of it happening is that user will be asked for master password
00680        * when doing such mundane things as opening edit menu or context menu.
00681        *
00682        * Note that we do not want to make this test if we are in the middle of
00683        * reencypting the entire database (i.e., while execute wallet_ReencryptAll).
00684        * In that case the pref has already been changed and this test will always
00685        * fail.  That is why we test the gReencryptionLevel indicator.
00686        */
00687       NS_ASSERTION(PR_FALSE, "wallet.crypto pref is set incorrectly");
00688       return NS_ERROR_FAILURE;
00689     }
00690     nsresult rv = wallet_CryptSetup();
00691     if (NS_SUCCEEDED(rv)) {
00692       rv = gSecretDecoderRing->DecryptString(crypt, &text);
00693     }
00694     if (NS_FAILED(rv)) {
00695       gEncryptionFailure = PR_TRUE;
00696     }
00697     return rv;
00698   }
00699 
00700   /* otherwise do our own de-obscuring */
00701 
00702   PRUint32 PREFIX_len = sizeof(PREFIX) - 1;
00703   if (PL_strlen(crypt) == PREFIX_len) {
00704     text = (char *)PR_Malloc(1);
00705     text[0] = '\0';
00706     return NS_OK;
00707   }
00708   text = PL_Base64Decode(&crypt[PREFIX_len], 0, NULL);
00709   if (!text) {
00710     return NS_ERROR_FAILURE;
00711   }
00712   return NS_OK;
00713 }
00714 
00715 void
00716 WLLT_ExpirePassword(PRBool* status) {
00717   if (gSecretDecoderRing) {
00718     gSecretDecoderRing->LogoutAndTeardown();
00719   }
00720   *status = PR_TRUE;
00721 }
00722 
00723 void
00724 WLLT_ExpirePasswordOnly(PRBool* status) {
00725   nsresult rv = wallet_CryptSetup();
00726   if (NS_SUCCEEDED(rv)) {
00727     rv = gSecretDecoderRing->Logout();
00728   }
00729   *status = NS_SUCCEEDED(rv);
00730 }
00731 
00732 PRBool changingPassword = PR_FALSE;
00733 
00734 void
00735 WLLT_ChangePassword(PRBool* status) {
00736   nsresult rv = wallet_CryptSetup();
00737   if (NS_SUCCEEDED(rv)) {
00738     changingPassword = PR_TRUE;
00739     rv = gSecretDecoderRing->ChangePassword();
00740     changingPassword = PR_FALSE;
00741   }
00742   *status = NS_SUCCEEDED(rv);
00743 }
00744 
00745 nsresult
00746 wallet_Encrypt(const nsCString& text, nsCString& crypt) {
00747 
00748   /* encrypt text to crypt */
00749   char * cryptCString = nsnull;
00750   nsresult rv = EncryptString(text.get(), cryptCString);
00751   if NS_FAILED(rv) {
00752     return rv;
00753   }
00754   crypt = cryptCString;
00755   WALLET_FREE(cryptCString);
00756   return NS_OK;
00757 }
00758 
00759 nsresult
00760 wallet_Decrypt(const nsCString& crypt, nsCString& text) {
00761 
00762   /* decrypt crypt to text */
00763   char * textCString = nsnull;
00764   nsresult rv = DecryptString(crypt.get(), textCString);
00765   if NS_FAILED(rv) {
00766     return rv;
00767   }
00768 
00769   text = textCString;
00770   WALLET_FREE(textCString);
00771   return NS_OK;
00772 }
00773 
00774 nsresult
00775 Wallet_Encrypt (const nsAString& textUCS2, nsAString& cryptUCS2) {
00776   nsCAutoString cryptUTF8;
00777   nsresult rv = wallet_Encrypt(NS_ConvertUCS2toUTF8(textUCS2), cryptUTF8);
00778   CopyUTF8toUTF16(cryptUTF8, cryptUCS2);
00779   return rv;
00780 }
00781 
00782 nsresult
00783 Wallet_Decrypt(const nsAString& cryptUCS2, nsAString& textUCS2) {
00784   nsCAutoString textUTF8;
00785   nsresult rv = wallet_Decrypt(NS_ConvertUCS2toUTF8(cryptUCS2), textUTF8);
00786   CopyUTF8toUTF16(textUTF8, textUCS2);
00787   return rv;
00788 }
00789 
00790 
00791 /**********************************************************/
00792 /* The following routines are for accessing the data base */
00793 /**********************************************************/
00794 
00795 /*
00796  * clear out the designated list
00797  */
00798 static void
00799 wallet_Clear(nsVoidArray ** list) {
00800   if (*list == wallet_SchemaToValue_list || *list == wallet_URL_list) {
00801     /* the other lists were allocated in blocks and need to be deallocated the same way */
00802     wallet_MapElement * mapElementPtr;
00803     PRInt32 count = LIST_COUNT((*list));
00804     for (PRInt32 i=count-1; i>=0; i--) {
00805       mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, (*list)->ElementAt(i));
00806       delete mapElementPtr;
00807     }
00808   }
00809   delete (*list);
00810   *list = nsnull;
00811 }
00812 
00813 /*
00814  * allocate another mapElement
00815  * We are going to buffer up allocations because it was found that alocating one
00816  * element at a time was very inefficient on the mac
00817  */
00818 
00819 static nsVoidArray * wallet_MapElementAllocations_list = 0;
00820 const PRInt32 kAllocBlockElems = 500;
00821 static PRInt32 wallet_NextAllocSlot = kAllocBlockElems;
00822 
00823 static nsresult
00824 wallet_AllocateMapElement(wallet_MapElement*& mapElement) {
00825   static wallet_MapElement* mapElementTable;
00826   if (wallet_NextAllocSlot >= kAllocBlockElems) {
00827     mapElementTable = new wallet_MapElement[kAllocBlockElems];
00828     if (!mapElementTable) {
00829       return NS_ERROR_OUT_OF_MEMORY;
00830     }
00831     if(!wallet_MapElementAllocations_list) {
00832       wallet_MapElementAllocations_list = new nsVoidArray();
00833     }
00834     if(wallet_MapElementAllocations_list) {
00835       wallet_MapElementAllocations_list->AppendElement(mapElementTable);
00836     }
00837     wallet_NextAllocSlot = 0;
00838   }
00839   mapElement = &mapElementTable[wallet_NextAllocSlot++];
00840   return NS_OK;
00841 }
00842 
00843 static void
00844 wallet_DeallocateMapElements() {
00845   wallet_MapElement * mapElementPtr;
00846   PRInt32 count = LIST_COUNT(wallet_MapElementAllocations_list);
00847 
00848   // initialize remainder of last allocated block so we don't crash on []delete
00849   for (PRInt32 j=wallet_NextAllocSlot; j<kAllocBlockElems; j++) {
00850     mapElementPtr =
00851       NS_STATIC_CAST(wallet_MapElement*,
00852                      (wallet_MapElementAllocations_list)->ElementAt(count-1));
00853     mapElementPtr[j].item1 = nsnull;
00854     mapElementPtr[j].item2 = nsnull;
00855     mapElementPtr[j].itemList = nsnull;
00856   }
00857 
00858   for (PRInt32 i=count-1; i>=0; i--) {
00859     mapElementPtr =
00860       NS_STATIC_CAST(wallet_MapElement*, (wallet_MapElementAllocations_list)->ElementAt(i));
00861     delete [] mapElementPtr;
00862   }  
00863   delete wallet_MapElementAllocations_list;
00864   wallet_MapElementAllocations_list = nsnull;
00865   wallet_NextAllocSlot = kAllocBlockElems;
00866 
00867 }
00868 
00869 /*
00870  * add an entry to the designated list
00871  */
00872 static PRBool
00873 wallet_WriteToList(
00874     const char* item1,
00875     const char* item2,
00876     nsVoidArray* itemList,
00877     nsVoidArray*& list,
00878     PRBool obscure,
00879     PlacementType placement = DUP_BEFORE) {
00880 
00881   wallet_MapElement * mapElementPtr;
00882   PRBool added_to_list = PR_FALSE;
00883 
00884   wallet_MapElement * mapElement = nsnull;
00885   if (list == wallet_FieldToSchema_list || list == wallet_SchemaStrings_list ||
00886       list == wallet_PositionalSchema_list || list == wallet_StateSchema_list ||
00887       list == wallet_SchemaConcat_list  || list == wallet_DistinguishedSchema_list ||
00888       list == wallet_VcardToSchema_list) {
00889     wallet_AllocateMapElement(mapElement);
00890   } else {
00891     mapElement = new wallet_MapElement;
00892   }
00893   if (!mapElement) {
00894     return PR_FALSE;
00895   }
00896 
00897   nsCAutoString item1UTF8(item1); ToLowerCase(item1UTF8);
00898   mapElement->item1 = ToNewCString(item1UTF8);
00899   mapElement->item2 = PL_strdup(item2);
00900 
00901   if (obscure) {
00902     char * crypt = nsnull;
00903     if (NS_FAILED(EncryptString(mapElement->item2, crypt))) {
00904       delete mapElement;
00905       return PR_FALSE;
00906     }
00907     WALLET_FREEIF(mapElement->item2);
00908     mapElement->item2 = crypt;
00909   }
00910 
00911   /* make sure the list exists */
00912   if(!list) {
00913     list = new nsVoidArray();
00914     if(!list) {
00915       delete mapElement;
00916       return PR_FALSE;
00917     }
00918   }
00919 
00920   mapElement->itemList = itemList;
00921   // note: we didn't want to assign itemList sooner because if we delete mapElement
00922   //       above, we would be wiping out the itemList input parameter
00923 
00924   /*
00925    * Add new entry to the list in alphabetical order by item1.
00926    * If identical value of item1 exists, use "placement" parameter to 
00927    * determine what to do
00928    */
00929   if (AT_END==placement) {
00930     list->AppendElement(mapElement);
00931     return PR_TRUE;
00932   }
00933   PRInt32 count = LIST_COUNT(list);
00934   for (PRInt32 i=0; i<count; i++) {
00935     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, list->ElementAt(i));
00936     if (BY_LENGTH==placement) {
00937       if (LIST_COUNT(mapElementPtr->itemList) < LIST_COUNT(itemList)) {
00938         list->InsertElementAt(mapElement, i);
00939         added_to_list = PR_TRUE;
00940         break;
00941       } else if (LIST_COUNT(mapElementPtr->itemList) == LIST_COUNT(itemList)) {
00942         if (itemList) {
00943           wallet_Sublist * sublistPtr;
00944           wallet_Sublist * sublistPtr2;
00945           sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(0));
00946           sublistPtr2 = NS_STATIC_CAST(wallet_Sublist*, itemList->ElementAt(0));
00947           if(PL_strlen(sublistPtr->item) < PL_strlen(sublistPtr2->item)) {
00948             list->InsertElementAt(mapElement, i);
00949             added_to_list = PR_TRUE;
00950             break;
00951           }
00952         } else if (PL_strlen(mapElementPtr->item2) < PL_strlen(mapElement->item2)) {
00953           list->InsertElementAt(mapElement, i);
00954           added_to_list = PR_TRUE;
00955           break;
00956         }
00957       }
00958     } else if(!PL_strcmp(mapElementPtr->item1, mapElement->item1)) {
00959       if (DUP_OVERWRITE==placement) {
00960         mapElementPtr->item2 = PL_strdup(item2);
00961         mapElementPtr->itemList = itemList;
00962         mapElement->itemList = nsnull; // else delete might delete itemList input parameter
00963         delete mapElement;
00964       } else if (DUP_BEFORE==placement) {
00965         list->InsertElementAt(mapElement, i);
00966       }
00967       if (DUP_AFTER!=placement) {
00968         added_to_list = PR_TRUE;
00969         break;
00970       }
00971     } else if(PL_strcmp(mapElementPtr->item1, mapElement->item1)>=0) {
00972       list->InsertElementAt(mapElement, i);
00973       added_to_list = PR_TRUE;
00974       break;
00975     }
00976   }
00977   if (!added_to_list) {
00978     list->AppendElement(mapElement);
00979   }
00980   return PR_TRUE;
00981 }
00982 
00983 /*
00984  * fetch an entry from the designated list
00985  */
00986 static PRBool
00987 wallet_ReadFromList(
00988   const nsACString& item1,
00989   nsACString& item2,
00990   nsVoidArray*& itemList,
00991   nsVoidArray*& list,
00992   PRBool obscure,
00993   PRInt32& index)
00994 {
00995   if (!list || (index == -1)) {
00996     return PR_FALSE;
00997   }
00998 
00999   /* find item1 in the list */
01000   wallet_MapElement * mapElementPtr;
01001   PRInt32 count = LIST_COUNT(list);
01002   for (PRInt32 i=index; i<count; i++) {
01003     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, list->ElementAt(i));
01004     if(item1.Equals(mapElementPtr->item1,  nsCaseInsensitiveCStringComparator())) {
01005       if (obscure) {
01006         char * plaintext = nsnull;
01007         if (NS_FAILED(DecryptString(mapElementPtr->item2, plaintext))) {
01008           return PR_FALSE;
01009         }
01010         item2 = plaintext;
01011       } else {
01012         item2 = mapElementPtr->item2;
01013       }
01014       itemList = mapElementPtr->itemList;
01015       index = i+1;
01016       if (index == count) {
01017         index = -1;
01018       }
01019       return PR_TRUE;
01020     }
01021   }
01022   index = 0;
01023   return PR_FALSE;
01024 }
01025 
01026 PRBool
01027 wallet_ReadFromList(
01028   const nsACString& item1,
01029   nsACString& item2,
01030   nsVoidArray*& itemList,
01031   nsVoidArray*& list,
01032   PRBool obscure)
01033 {
01034   PRInt32 index = 0;
01035   return wallet_ReadFromList(item1, item2, itemList, list, obscure, index);
01036 }
01037 
01038 
01039 /************************************************************/
01040 /* The following routines are for unlocking the stored data */
01041 /************************************************************/
01042 
01043 char* schemaValueFileName = nsnull;
01044 
01045 static const char URLFileName[] = "URL.tbl";
01046 static const char allFileName[] = "wallet.tbl";
01047 static const char fieldSchemaFileName[] = "FieldSchema.tbl";
01048 static const char vcardSchemaFileName[] = "VcardSchema.tbl";
01049 static const char schemaConcatFileName[] = "SchemaConcat.tbl";
01050 static const char schemaStringsFileName[] = "SchemaStrings.tbl";
01051 static const char positionalSchemaFileName[] = "PositionalSchema.tbl";
01052 static const char stateSchemaFileName[] = "StateSchema.tbl";
01053 static const char distinguishedSchemaFileName[] = "DistinguishedSchema.tbl";
01054 
01055 
01056 /******************************************************/
01057 /* The following routines are for accessing the files */
01058 /******************************************************/
01059 
01060 nsresult Wallet_ProfileDirectory(nsIFile** aFile) {
01061   /* return the profile */
01062   return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aFile);
01063 }
01064 
01065 nsresult Wallet_DefaultsDirectory(nsIFile** aFile) {
01066 
01067   nsresult res;
01068   nsCOMPtr<nsIFile> file;
01069   
01070   res = NS_GetSpecialDirectory(NS_APP_DEFAULTS_50_DIR, getter_AddRefs(file));
01071   if (NS_FAILED(res)) return res;
01072   res = file->AppendNative(NS_LITERAL_CSTRING("wallet"));
01073   if (NS_FAILED(res)) return res;
01074 
01075   NS_ADDREF(*aFile = file);
01076   return NS_OK;
01077 }
01078 
01079 char *
01080 Wallet_RandomName(char* suffix)
01081 {
01082   /* pick the current time as the random number */
01083   time_t curTime = time(NULL);
01084 
01085   /* take 8 least-significant digits + three-digit suffix as the file name */
01086   char name[13];
01087   PR_snprintf(name, 13, "%lu.%s", ((int)curTime%100000000), suffix);
01088   return PL_strdup(name);
01089 }
01090 
01091 /*
01092  * get a line from a file. stream must implement nsILineInputStream.
01093  * return error if end of file reached
01094  * strip carriage returns and line feeds from end of line
01095  * free with nsMemory::Free
01096  */
01097 
01098 nsresult
01099 wallet_GetLine(nsIInputStream* strm, nsACString &line)
01100 {
01101   line.Truncate();
01102   
01103   nsCOMPtr<nsILineInputStream> lis(do_QueryInterface(strm));
01104   NS_ENSURE_TRUE(lis, NS_ERROR_UNEXPECTED);
01105 
01106   PRBool more;
01107   nsresult rv = lis->ReadLine(line, &more);
01108   if (NS_FAILED(rv))
01109     return rv;
01110 
01111   // Assume that we are past EOF if more==FALSE and line is empty
01112   // this may be wrong if the file ends with an empty line, though
01113   if (!more && line.IsEmpty())
01114     return NS_ERROR_FAILURE;
01115 
01116   return NS_OK;
01117 }
01118 
01119 static PRBool
01120 wallet_GetHeader(nsIInputStream* strm)
01121 {
01122   nsCAutoString format;
01123 
01124   /* format revision number */
01125   if (NS_FAILED(wallet_GetLine(strm, format))) {
01126     return PR_FALSE;
01127   }
01128   return format.EqualsLiteral(HEADER_VERSION);
01129 }
01130 
01131 /*
01132  * Write a line-feed to a file
01133  */
01134 static void
01135 wallet_EndLine(nsIOutputStream* strm) {
01136   static const char nl = '\n';
01137   PRUint32 dummy;
01138   strm->Write(&nl, 1, &dummy);
01139 }
01140 
01141 /*
01142  * Write a line to a file
01143  */
01144 void
01145 wallet_PutLine(nsIOutputStream* strm, const char* line) {
01146   PRUint32 dummy;
01147   strm->Write(line, strlen(line), &dummy);
01148   wallet_EndLine(strm);
01149 }
01150 
01151 static void
01152 wallet_PutHeader(nsIOutputStream* strm) {
01153 
01154   /* format revision number */
01155   wallet_PutLine(strm, HEADER_VERSION);
01156 }
01157 
01158 #define WALLET_NULL(_ptr) (!(_ptr) || !(_ptr)[0])
01159 
01160 /*
01161  * write contents of designated list into designated file
01162  */
01163 static void
01164 wallet_WriteToFile(const char * filename, nsVoidArray* list) {
01165   wallet_MapElement * mapElementPtr;
01166 
01167   /* make sure the list exists */
01168   if(!list) {
01169     return;
01170   }
01171 
01172 
01173   /* open output stream */
01174   nsCOMPtr<nsIFile> file;
01175   nsresult rv = Wallet_ProfileDirectory(getter_AddRefs(file));
01176   if (NS_FAILED(rv)) {
01177     return;
01178   }
01179 
01180   file->AppendNative(nsDependentCString(filename));
01181 
01182   nsCOMPtr<nsIOutputStream> fileOutputStream;
01183   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
01184                                        file,
01185                                        -1,
01186                                        0600);
01187   if (NS_FAILED(rv))
01188     return;
01189 
01190   nsCOMPtr<nsIOutputStream> strm;
01191   rv = NS_NewBufferedOutputStream(getter_AddRefs(strm), fileOutputStream, 4096);
01192   if (NS_FAILED(rv))
01193     return;
01194 
01195   /* put out the header */
01196   if (!PL_strcmp(filename, schemaValueFileName)) {
01197     wallet_PutHeader(strm);
01198   }
01199 
01200   /* traverse the list */
01201   PRInt32 count = LIST_COUNT(list);
01202   for (PRInt32 i=0; i<count; i++) {
01203     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, list->ElementAt(i));
01204     wallet_PutLine(strm, (*mapElementPtr).item1);
01205     if (!WALLET_NULL((*mapElementPtr).item2)) {
01206       wallet_PutLine(strm, (*mapElementPtr).item2);
01207     } else {
01208       wallet_Sublist * sublistPtr;
01209       PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
01210       for (PRInt32 j=0; j<count2; j++) {
01211         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j));
01212         wallet_PutLine(strm, (*sublistPtr).item);
01213       }
01214     }
01215     wallet_EndLine(strm);
01216   }
01217 
01218   // All went ok. Maybe except for problems in Write(), but the stream detects
01219   // that for us
01220   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(strm);
01221   NS_ASSERTION(safeStream, "expected a safe output stream!");
01222   if (safeStream) {
01223     rv = safeStream->Finish();
01224     if (NS_FAILED(rv)) {
01225       NS_WARNING("failed to save wallet file! possible dataloss");
01226       return;
01227     }
01228   }
01229 }
01230 
01231 /*
01232  * Read contents of designated file into designated list
01233  */
01234 static void
01235 wallet_ReadFromFile
01236     (const char * filename, nsVoidArray*& list, PRBool localFile, PlacementType placement = AT_END) {
01237 
01238   /* open input stream */
01239   nsCOMPtr<nsIFile> file;
01240   nsresult rv;
01241   if (localFile) {
01242     rv = Wallet_ProfileDirectory(getter_AddRefs(file));
01243   } else {
01244     rv = Wallet_DefaultsDirectory(getter_AddRefs(file));
01245   }
01246   if (NS_FAILED(rv)) {
01247     return;
01248   }
01249   file->AppendNative(nsDependentCString(filename));
01250   nsCOMPtr<nsIInputStream> strm;
01251   rv = NS_NewLocalFileInputStream(getter_AddRefs(strm), file);
01252   if (NS_FAILED(rv))
01253     return;
01254  
01255   /* read in the header */
01256   if (!PL_strcmp(filename, schemaValueFileName)) {
01257     if (!wallet_GetHeader(strm)) {
01258       /* something's wrong -- ignore the file */
01259       return;
01260     }
01261   }
01262 
01263   for (;;) {
01264     if (NS_FAILED(wallet_GetLine(strm, helpMac->item1))) {
01265       /* end of file reached */
01266       break;
01267     }
01268 
01269     /* Distinguished schema list is a list of single entries, not name/value pairs */
01270     if (!PL_strcmp(filename, distinguishedSchemaFileName)) {
01271       nsVoidArray* dummy = NULL;
01272       wallet_WriteToList(helpMac->item1.get(), helpMac->item1.get(), dummy, list, PR_FALSE, placement);
01273       continue;
01274     }
01275 
01276     if (NS_FAILED(wallet_GetLine(strm, helpMac->item2))) {
01277       /* unexpected end of file reached */
01278       break;
01279     }
01280 
01281     if (helpMac->item2.IsEmpty()) {
01282       /* the value must have been deleted */
01283       nsVoidArray* dummy = NULL;
01284       wallet_WriteToList(helpMac->item1.get(), helpMac->item2.get(), dummy, list, PR_FALSE, placement);
01285       continue;
01286     }
01287 
01288     if (NS_FAILED(wallet_GetLine(strm, helpMac->item3))) {
01289       /* end of file reached */
01290       nsVoidArray* dummy = NULL;
01291       wallet_WriteToList(helpMac->item1.get(), helpMac->item2.get(), dummy, list, PR_FALSE, placement);
01292       return;
01293     }
01294 
01295     if (helpMac->item3.IsEmpty()) {
01296       /* just a pair of values, no need for a sublist */
01297       nsVoidArray* dummy = NULL;
01298       wallet_WriteToList(helpMac->item1.get(), helpMac->item2.get(), dummy, list, PR_FALSE, placement);
01299     } else {
01300       /* need to create a sublist and put item2 and item3 onto it */
01301 
01302       nsVoidArray * itemList = new nsVoidArray();
01303       if (!itemList) {
01304         break;
01305       }
01306 
01307       wallet_Sublist * sublist = new wallet_Sublist;
01308       if (!sublist) {
01309         break;
01310       }
01311       sublist->item = ToNewCString(helpMac->item2);
01312       itemList->AppendElement(sublist);
01313       sublist = new wallet_Sublist;
01314       if (!sublist) {
01315         delete itemList;
01316         break;
01317       }
01318       sublist->item = ToNewCString(helpMac->item3);
01319       itemList->AppendElement(sublist);
01320       /* add any following items to sublist up to next blank line */
01321       for (;;) {
01322         /* get next item for sublist */
01323         if (NS_FAILED(wallet_GetLine(strm, helpMac->item3))) {
01324           /* end of file reached */
01325           wallet_WriteToList(helpMac->item1.get(), nsnull, itemList, list, PR_FALSE, placement);
01326           return;
01327         }
01328 
01329         if (helpMac->item3.IsEmpty()) {
01330           /* blank line reached indicating end of sublist */
01331           wallet_WriteToList(helpMac->item1.get(), nsnull, itemList, list, PR_FALSE, placement);
01332           break;
01333         }
01334         /* add item to sublist */
01335         sublist = new wallet_Sublist;
01336         if (!sublist) {
01337           delete itemList;
01338           break;
01339         }
01340         sublist->item = ToNewCString(helpMac->item3);
01341         itemList->AppendElement(sublist);
01342       }
01343     }
01344   }
01345 }
01346 
01347 
01348 /*********************************************************************/
01349 /* The following are utility routines for the main wallet processing */
01350 /*********************************************************************/
01351 
01352 void
01353 Wallet_GiveCaveat(nsIDOMWindowInternal* window, nsIPrompt* dialog) {
01354   /* test for first capturing of data ever and give caveat if so */
01355   if (!SI_GetBoolPref(pref_Caveat, PR_FALSE)) {
01356     SI_SetBoolPref(pref_Caveat, PR_TRUE);
01357     PRUnichar * message = Wallet_Localize("Caveat");
01358     if (window) {
01359       wallet_Alert(message, window);
01360     } else {
01361       wallet_Alert(message, dialog);
01362     }
01363     WALLET_FREE(message);
01364   }
01365 }
01366  
01367 static void
01368 wallet_GetHostFile(nsIURI * url, nsString& outHostFile)
01369 {
01370   outHostFile.Truncate(0);
01371   nsCAutoString host;
01372   nsresult rv = url->GetHost(host);
01373   if (NS_FAILED(rv)) {
01374     return;
01375   }
01376   NS_ConvertUTF8toUCS2 urlName(host);
01377   nsCAutoString file;
01378   rv = url->GetPath(file);
01379   if (NS_FAILED(rv)) {
01380     return;
01381   }
01382   AppendUTF8toUTF16(file, urlName);
01383 
01384   PRInt32 queryPos = urlName.FindChar('?');
01385   PRInt32 stringEnd = (queryPos == kNotFound) ? urlName.Length() : queryPos;
01386   urlName.Left(outHostFile, stringEnd);
01387 }
01388 
01389 static void
01390 Strip(const nsString& textUCS2, nsCString& stripText) {
01391   NS_ConvertUCS2toUTF8 textUTF8(textUCS2);
01392 // above line is equivalen to the following (who would have guessed it?)
01393 //    nsCAutoString textUTF8 = NS_ConvertUCS2toUTF8(textUCS2);
01394   for (PRUint32 i=0; i<textUTF8.Length(); i++) {
01395     char c = textUTF8.CharAt(i);
01396     if (nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) || c>'~') {
01397       stripText += c;
01398     }
01399   }
01400 }
01401 
01402 /*
01403  * given a displayable text, get the schema
01404  */
01405 static void
01406 TextToSchema(
01407     const nsString& text,
01408     nsACString& schema)
01409 {
01410   /* return if no SchemaStrings list exists */
01411   if (!wallet_SchemaStrings_list) {
01412     return;
01413   }
01414 
01415   /* try each schema entry in schemastring table to see if it's acceptable */
01416   wallet_MapElement * mapElementPtr;
01417   PRInt32 count = LIST_COUNT(wallet_SchemaStrings_list);
01418   for (PRInt32 i=0; i<count; i++) {
01419 
01420     /* get each string associated with this schema */
01421     PRBool isSubstring = PR_TRUE;
01422     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, wallet_SchemaStrings_list->ElementAt(i));
01423     wallet_Sublist * sublistPtr;
01424     PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
01425 
01426     if (count2) {
01427       for (PRInt32 i2=0; i2<count2; i2++) {
01428 
01429         /* see if displayable text contains this string */
01430         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(i2));
01431         if (text.Find(sublistPtr->item, PR_TRUE) == -1) {
01432  
01433           /* displayable text does not contain this string, reject this schema */
01434           isSubstring = PR_FALSE;
01435           break;
01436         }
01437       }
01438     } else if (text.Find(mapElementPtr->item2, PR_TRUE) == -1) {
01439  
01440       /* displayable text does not contain this string, reject this schema */
01441       isSubstring = PR_FALSE;
01442     }
01443 
01444     if (isSubstring) {
01445 
01446       /* all strings were contained in the displayable text, accept this schema */
01447       schema.Assign(mapElementPtr->item1);
01448       return;
01449     }
01450   }
01451 }
01452 
01453 /*
01454  * given a field name, get the value
01455  */
01456 static nsresult 
01457 FieldToValue(
01458     const nsString& field,
01459     nsACString& schema,
01460     nsString& valueUCS2,
01461     nsVoidArray*& itemList,
01462     PRInt32& index)
01463 {
01464 
01465   /* return if no SchemaToValue list exists or if all values previous used */
01466   if (!wallet_SchemaToValue_list || index == -1) {
01467     return NS_ERROR_FAILURE;
01468   }
01469 
01470   /* if no schema name is given, fetch schema name from field/schema tables */
01471   nsVoidArray* dummy;
01472   nsCAutoString stripField;
01473   if (schema.IsEmpty()) {
01474     Strip(field, stripField);
01475   }
01476   if (!schema.IsEmpty() ||
01477       wallet_ReadFromList(stripField, schema, dummy, wallet_FieldToSchema_list, PR_FALSE)) {
01478 
01479     /* schema name found, now attempt to fetch value from schema/value table */ 
01480     nsCAutoString valueUTF8;
01481     PRInt32 index2 = index;
01482     if ((index >= 0) &&
01483         wallet_ReadFromList
01484           (schema, valueUTF8, itemList, wallet_SchemaToValue_list, PR_TRUE, index2)) {
01485       /* value found, prefill it into form and return */
01486       CopyUTF8toUTF16(valueUTF8, valueUCS2);
01487       index = index2;
01488       return NS_OK;
01489 
01490     } else {
01491 
01492       /* value not found, see if concatenation rule exists */
01493       nsVoidArray * itemList2;
01494       nsCAutoString valueUTF8b;
01495       if (index > 0) {
01496         index = 0;
01497       }
01498       PRInt32 index0 = index;
01499       PRInt32 index00 = index;
01500       PRInt32 index4 = 0;
01501       while (wallet_ReadFromList(schema, valueUTF8b, itemList2, wallet_SchemaConcat_list, PR_FALSE, index4)) {
01502 
01503         /* concatenation rules exist, generate value as a concatenation */
01504         nsCAutoString concatenatedValueUTF8;
01505         wallet_Sublist * sublistPtr;
01506         concatenatedValueUTF8.SetLength(0);
01507         nsCAutoString valueUTF8c;
01508         PRInt32 index00max = index0;
01509 
01510         if (!valueUTF8b.IsEmpty()) {
01511 
01512           /* single item on rhs of concatenation rule */
01513           PRInt32 index5 = 0;
01514           PRInt32 j;
01515           PRBool failed = PR_FALSE;
01516           for (j=0; j>index0; j -= 2) {
01517             if (!wallet_ReadFromList(valueUTF8b, valueUTF8c, dummy, wallet_SchemaToValue_list, PR_TRUE, index5)) {
01518               failed = PR_TRUE;
01519               break;
01520             }
01521             index00 += 2;
01522           }
01523 
01524           if (!failed && wallet_ReadFromList(valueUTF8b, valueUTF8c, dummy, wallet_SchemaToValue_list, PR_TRUE, index5)) {
01525 
01526             /* found an unused value for the single rhs item */
01527             concatenatedValueUTF8 += valueUTF8c;
01528             index00 += 2;
01529           }
01530           index00max = index00;
01531         }
01532 
01533         /* process each item in a multi-rhs rule */
01534         PRInt32 count = LIST_COUNT(itemList2);
01535         for (PRInt32 i=0; i<count; i++) {
01536           sublistPtr = NS_STATIC_CAST(wallet_Sublist*, itemList2->ElementAt(i));
01537 
01538           /* skip over values found previously */
01539           /*   note: a returned index of -1 means not-found.  So we will use the
01540            *   negative even numbers (-2, -4, -6) to designate found as a concatenation
01541            *   where -2 means first value of each concatenation, -4 means second value, etc.
01542            */
01543           index00 = index0;
01544           PRInt32 index3 = 0;
01545           PRBool failed = PR_FALSE;
01546           nsCAutoString valueUTF8d; valueUTF8d.Assign(sublistPtr->item);
01547           for (PRInt32 j=0; j>index0; j -= 2) {
01548             if (!wallet_ReadFromList(valueUTF8d, valueUTF8, dummy, wallet_SchemaToValue_list, PR_TRUE, index3)) {
01549 
01550               /* all values of next multi-rhs item were used previously */
01551               failed = PR_TRUE;
01552               break;
01553             }
01554             index00 += 2;
01555           }
01556 
01557           if (!failed && wallet_ReadFromList(valueUTF8d, valueUTF8, dummy, wallet_SchemaToValue_list, PR_TRUE, index3)) {
01558             if (!concatenatedValueUTF8.IsEmpty()) {
01559               concatenatedValueUTF8 += " ";
01560             }
01561 
01562             /* found an unused value for the multi-rhs item */
01563             concatenatedValueUTF8 += valueUTF8;
01564             index00 += 2;
01565           }
01566           if (index00 > index00max) {
01567             index00max = index00;
01568           }
01569         }
01570 
01571         itemList = nsnull;
01572         if (!concatenatedValueUTF8.IsEmpty()) {
01573 
01574           /* a new value was found */
01575           index -= 2;
01576           CopyUTF8toUTF16(concatenatedValueUTF8, valueUCS2);
01577           return NS_OK;
01578         }
01579 
01580         /* all values from this concat rule were used, go on to next concat rule */
01581         index0 = index00max;
01582       }
01583 
01584       /* no more concat rules, indicate failure */
01585       index = -1;
01586       return NS_ERROR_FAILURE;
01587     }
01588   } else {
01589     /* schema name not found, use field name as schema name and fetch value */
01590     PRInt32 index2 = index;
01591 
01592     nsAutoString localSchemaUCS2;
01593     wallet_GetHostFile(wallet_lastUrl, localSchemaUCS2);
01594     localSchemaUCS2.AppendLiteral(":");
01595     localSchemaUCS2.Append(field);
01596     NS_ConvertUTF16toUTF8 localSchemaUTF8(localSchemaUCS2);
01597     nsCAutoString valueUTF8;
01598 
01599     if (wallet_ReadFromList
01600         (localSchemaUTF8, valueUTF8, itemList, wallet_SchemaToValue_list, PR_TRUE, index2)) {
01601       /* value found, prefill it into form */
01602       schema = localSchemaUTF8;
01603       index = index2;
01604       CopyUTF8toUTF16(valueUTF8, valueUCS2);
01605       return NS_OK;
01606     }
01607   }
01608   index = -1;
01609   return NS_ERROR_FAILURE;
01610 }
01611 
01612 static nsresult
01613 wallet_GetSelectIndex(
01614   nsIDOMHTMLSelectElement* selectElement,
01615   const nsString& value,
01616   PRInt32& index)
01617 {
01618   PRUint32 length;
01619   selectElement->GetLength(&length);
01620   nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
01621   selectElement->GetOptions(getter_AddRefs(options));
01622   if (options) {
01623     PRUint32 numOptions;
01624     options->GetLength(&numOptions);
01625     for (PRUint32 optionX = 0; optionX < numOptions; optionX++) {
01626       nsCOMPtr<nsIDOMNode> optionNode;
01627       options->Item(optionX, getter_AddRefs(optionNode));
01628 
01629       if (optionNode) {
01630         nsCOMPtr<nsIDOMHTMLOptionElement> optionElement(do_QueryInterface(optionNode));
01631 
01632         if (optionElement) {
01633           nsAutoString optionValue;
01634           nsAutoString optionText;
01635           optionElement->GetValue(optionValue);
01636           optionElement->GetText(optionText);
01637           nsAutoString valueLC( value );
01638           ToLowerCase(valueLC);
01639           ToLowerCase(optionValue);
01640           ToLowerCase(optionText);
01641           optionText.Trim(" \n\t\r");
01642           if (valueLC==optionValue || valueLC==optionText) {
01643             index = optionX;
01644             return NS_OK;
01645           }
01646         }
01647       }
01648     }
01649   }
01650   return NS_ERROR_FAILURE;
01651 }
01652 
01653 void
01654 wallet_StepForwardOrBack
01655     (nsIDOMNode*& elementNode, nsString& text, PRBool& atInputOrSelect, PRBool& atEnd, PRBool goForward) {
01656   nsresult result;
01657   atInputOrSelect = PR_FALSE;
01658   atEnd = PR_FALSE;
01659 
01660  /* try getting next/previous sibling */
01661   nsCOMPtr<nsIDOMNode> sibling;
01662   if (goForward) {
01663     result = elementNode->GetNextSibling(getter_AddRefs(sibling));
01664   } else {
01665     result = elementNode->GetPreviousSibling(getter_AddRefs(sibling));
01666   }
01667   if ((NS_FAILED(result)) || !sibling) {
01668     /* no next/previous siblings, try getting parent */
01669     nsCOMPtr<nsIDOMNode> parent;
01670     result = elementNode->GetParentNode(getter_AddRefs(parent));
01671     if ((NS_FAILED(result)) || !parent) {
01672       /* no parent, we've reached the top of the tree */
01673       atEnd = PR_TRUE;
01674     } else {
01675       /* parent obtained */
01676       elementNode = parent;
01677     }
01678     return;
01679   }
01680   /* sibling obtained */
01681   elementNode = sibling;
01682 
01683   while (PR_TRUE) {
01684 
01685     /* if we've reached a SELECT or non-hidden INPUT tag, we're done */
01686     /*
01687      *    There is a subtle difference here between going forward and going backwards.
01688      *
01689      *    When going forward we are trying to find out how many consecutive <input> elements are not separated
01690      *    by displayed text.  That is important for determing, for example, if we have a three-input phone-number
01691      *    field.  In that case, we want to consider only input tags have type="text" or no type ("text" by default).
01692      *
01693      *    When going backwards we want to find the text between the current <input> element and any preceding
01694      *    visible <input> element.  That would include such things as type="button", type="submit" etc.  The
01695      *    only thing it would exclude is type="hidden".
01696      */
01697     nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(elementNode, &result));
01698     if ((NS_SUCCEEDED(result)) && (inputElement)) {
01699       nsAutoString type;
01700       result = inputElement->GetType(type);
01701       if (goForward) {
01702         if (NS_SUCCEEDED(result) &&
01703             (type.IsEmpty() ||
01704              type.LowerCaseEqualsLiteral("text"))) {
01705           /* at <input> element and it's type is either "text" or is missing ("text" by default) */
01706           atInputOrSelect = PR_TRUE;
01707           return;
01708         }
01709       } else {
01710         if (NS_SUCCEEDED(result) &&
01711             !type.LowerCaseEqualsLiteral("hidden")) {
01712           /* at <input> element and it's type is not "hidden" */
01713           atInputOrSelect = PR_TRUE;
01714           return;
01715         }
01716       }
01717     } else {
01718       nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(elementNode));
01719 
01720       if (selectElement) {
01721         atInputOrSelect = PR_TRUE;
01722         return;
01723       }
01724     }
01725 
01726     /* if we've reached a #text node, append it to accumulated text */
01727     nsAutoString siblingNameUCS2;
01728     result = elementNode->GetNodeName(siblingNameUCS2);
01729     if (siblingNameUCS2.LowerCaseEqualsLiteral("#text")) {
01730       nsAutoString siblingValue;
01731       result = elementNode->GetNodeValue(siblingValue);
01732       text.Append(siblingValue);
01733     }
01734 
01735     /* if we've reached a SCRIPT node, don't fetch its siblings */
01736     if (siblingNameUCS2.LowerCaseEqualsLiteral("script")) {
01737       return;
01738     }
01739 
01740     /* try getting first/last child */
01741     nsCOMPtr<nsIDOMNode> child;
01742     if (goForward) {
01743       result = elementNode->GetFirstChild(getter_AddRefs(child));
01744     } else {
01745       result = elementNode->GetLastChild(getter_AddRefs(child));
01746     }
01747     if ((NS_FAILED(result)) || !child) {
01748       /* no children, we're done with this node */
01749       return;
01750     }
01751     /* child obtained */
01752     elementNode = child;
01753   }
01754 
01755   return;
01756 }
01757 
01758 //#include "nsIUGenCategory.h"
01759 //#include "nsUnicharUtilCIID.h"
01760 //static NS_DEFINE_IID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
01761 
01762 //#include "nsICaseConversion.h"
01763 //static nsICaseConversion* gCaseConv = nsnull;
01764 
01765 static void
01766 wallet_ResolvePositionalSchema(nsIDOMNode* elementNode, nsACString& schema) {
01767   static PRInt32 numerator = 0;
01768   static PRInt32 denominator = 0;
01769   static nsCString lastPositionalSchema;
01770 
01771   /* return if no PositionalSchema list exists */
01772   if (!wallet_PositionalSchema_list) {
01773     schema.SetLength(0);
01774     return;
01775   }
01776 
01777   if (!schema.IsEmpty()) {
01778     numerator = 0;
01779     denominator = 0;
01780     lastPositionalSchema.Assign(schema);
01781   } else if (numerator < denominator) {
01782     schema.Assign(lastPositionalSchema);
01783   } else {
01784     schema.SetLength(0);
01785     return;
01786   }
01787 
01788   /* search PositionalSchema list for our positional schema */
01789   wallet_MapElement * mapElementPtr;
01790   PRInt32 count = LIST_COUNT(wallet_PositionalSchema_list);
01791   for (PRInt32 i=0; i<count; i++) {
01792     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, wallet_PositionalSchema_list->ElementAt(i));
01793     if (schema.Equals(mapElementPtr->item1, nsCaseInsensitiveCStringComparator())) {
01794       /* found our positional schema in the list */
01795 
01796       /* A "position set" is a set of continuous <input> or <select> fields
01797        * with no displayable text between them.  For example: zipcode [     ]-[    ].
01798        * We need to determine how many elements are in the current set (denominator)
01799        * and which of those elements we are currently up to (numerator).  From that
01800        * we can identify our position with the fraction x/y meaning the xth element
01801        * out of a set of y.  We use that fraction when consulting the positionalSchema list
01802        * to determine which schema should be used.
01803        *
01804        * So for example, the positionalSchema list for %zip might be:
01805        *
01806        *    1/1  Home.PostalCode
01807        *    1/2  Home.PostalCode.Prefix
01808        *    2/2  Home.PostalCode.Suffix
01809        *
01810        * The positionalSchema list also contains fractions with no denominators, for example x/.
01811        * That means the xth element out of a set of any length.  These entries come last in
01812        * the positionalSchema list so they can match only if no match for a specific length is
01813        * found.  As an example, the positionalSchema list for %phone might be:
01814        *
01815        *    1/1 Home.Phone
01816        *    1/2 Home.Phone.LocCode
01817        *    2/2 Home.Phone.Number
01818        *    1/  Home.Phone.LocCode
01819        *    2/  Home.Phone.Number.Prefix
01820        *    3/  Home.Phone.Number.Suffix
01821        */
01822 
01823       if (numerator < denominator) {
01824 
01825         /* this is a continuation of previous position set */
01826         numerator++;
01827 
01828       } else {
01829 
01830         /* start a new position set */
01831         numerator = 1; /* start with first element */
01832 
01833         /* determine how many elements in current position set (denominator) */
01834         denominator = 1; /* assume that's the only element */
01835         PRBool atInputOrSelect = PR_FALSE;
01836         PRBool charFound = PR_FALSE;
01837         while (!charFound) {
01838           nsAutoString text;
01839           PRBool atEnd;
01840           wallet_StepForwardOrBack
01841             (elementNode, text, atInputOrSelect, atEnd, PR_TRUE); /* step forward */
01842           if (atEnd) {
01843             break;
01844           }
01845           PRUnichar c;
01846           for (PRUint32 j=0; j<text.Length(); j++) {
01847             c = text.CharAt(j);
01848 
01849             /* break out if an alphanumeric character is found */
01850 
01851 //          nsresult res = CallGetService(kUnicharUtilCID, &gCaseConv);
01852 //
01853 //          nsIUGenCategory* intl = nsnull;
01854 //          nsresult rv = CallGetService(kUnicharUtilCID, &intl);
01855 //          Whaaaaaa, intl is never released here!
01856 //          if (NS_SUCCEEDED(rv) && intl) {
01857 //            PRBool accept;
01858 //            rv = intl->Is(c, intl->kUGenCategory_Number, &accept);
01859 //            if (NS_FAILED(rv) || !accept) {
01860 //              rv = intl->Is(c, intl->kUGenCategory_Letter, &accept);
01861 //            }
01862 //            if (NS_OK(rv) && accept) {
01863 //              charFound = PR_TRUE;
01864 //              break;
01865 //            }
01866 //          } else {
01867 //            /* failed to get the i18n interfaces, so just treat latin characters */
01868               if (nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c)) {
01869                 charFound = PR_TRUE;
01870                 break;
01871 //            }
01872             }
01873           }
01874           if (!charFound && atInputOrSelect) {
01875             /* add one more element to position set */
01876             denominator++;
01877           }
01878         }
01879       }
01880 
01881       nsCAutoString fractionString; /* of form 2/5 meaning 2nd in a 5-element set */
01882       nsCAutoString fractionStringWithoutDenominator; /* of form 2/ meaning 2nd in any-length set */
01883       fractionString.SetLength(0);
01884       fractionString.AppendInt(numerator);
01885       fractionString.Append("/");
01886       fractionStringWithoutDenominator.Assign(fractionString);
01887       fractionString.AppendInt(denominator);
01888 
01889       /* use positionalSchema list to obtain schema */
01890       wallet_Sublist * sublistPtr;
01891       PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
01892       for (PRInt32 j=0; j<count2; j=j+2) {
01893         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j));
01894 
01895         if (!PL_strcmp(sublistPtr->item, fractionString.get()) ||
01896             !PL_strcmp(sublistPtr->item, fractionStringWithoutDenominator.get())) {
01897           sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j+1));
01898           schema.Assign(sublistPtr->item);
01899           return;
01900         }
01901       }
01902     }
01903   }
01904 }
01905 
01906 const char* previousElementState = nsnull;
01907 static nsIDOMNode* previousElementNode;
01908 
01909 static void
01910 wallet_InitializeStateTesting() {
01911   previousElementNode = nsnull;
01912   previousElementState = nsnull;
01913 }
01914 
01915 static void
01916 wallet_ResolveStateSchema(nsIDOMNode* elementNode, nsACString& schema) {
01917 
01918   /* return if no StateSchema list exists */
01919   if (!wallet_StateSchema_list) {
01920     return;
01921   }
01922 
01923   /* search state schema list for our state schema */
01924   wallet_MapElement * mapElementPtr;
01925   PRInt32 count = LIST_COUNT(wallet_StateSchema_list);
01926   for (PRInt32 i=0; i<count; i++) {
01927     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, wallet_StateSchema_list->ElementAt(i));
01928     if (schema.Equals(mapElementPtr->item1, nsCaseInsensitiveCStringComparator())) {
01929       /* found our state schema in the list */
01930 
01931       /* A state-schema entry consists of a set of possible states and the schema associated
01932        * with each state.  For example, for the state-schema $phone we might have
01933        *
01934        *    ship  ShipTo.Phone
01935        *    bill  BillTo.Phone
01936        *    *     Home.Phone
01937        *
01938        * This means that if we are in the "ship" state, the schema is ShipTo.Phone, if in the
01939        * "bill" state it is BillTo.Phone, and if in no identifiable state it is Home.Phone.
01940        *
01941        * So we will start stepping backwards through the dom tree
01942        * obtaining text at each step.  If the text contains a substring for one of
01943        * the states, then that is the state we are in and we take the associated
01944        * schema.  If the text does not contain any of the states, we continue
01945        * stepping back until we get to a preceding node for which we knew the state.
01946        * If none is found, stop when we get to the beginning of the tree.
01947        */
01948 
01949       nsIDOMNode* localElementNode = elementNode;
01950       PRBool atEnd = PR_FALSE;
01951       PRBool atInputOrSelect = PR_FALSE;
01952       while (!atEnd) {
01953 
01954         /* get next text in the dom */
01955         nsAutoString text;
01956         wallet_StepForwardOrBack(localElementNode, text, atInputOrSelect, atEnd, PR_FALSE);
01957 
01958         /* see if it's a node we already saved the state for */
01959         if (localElementNode == previousElementNode) {
01960           previousElementNode = elementNode;
01961 
01962           /* step through the list of states to see if any are the state of the previous Node */
01963           wallet_Sublist * sublistPtr;
01964           PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
01965           PRInt32 j;
01966           for (j=0; j<count2; j=j+2) {
01967             sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j));
01968             if (!PL_strcasecmp(sublistPtr->item, previousElementState)) {
01969               previousElementState = sublistPtr->item;
01970               sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j+1));
01971               schema.Assign(sublistPtr->item);
01972               return;
01973             }
01974 
01975             /* test to see if we obtained the catch-all (*) state.
01976              *   Note: the catch-all must be the last entry in the list
01977              */
01978             if (!PL_strcmp(sublistPtr->item, "*")) {
01979               sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j+1));
01980               schema.Assign(sublistPtr->item);
01981               return;
01982             }
01983           }
01984 
01985           /* no catch-all state specified, return no schema */
01986           return;
01987         }
01988 
01989         /* step through the list of states to see if any are in the text */
01990         wallet_Sublist * sublistPtr;
01991         PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
01992         for (PRInt32 j=0; j<count2; j=j+2) {
01993           sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j));
01994 
01995           /* next state obtained, test to see if it is in the text */
01996           if (text.Find(sublistPtr->item, PR_TRUE) != -1) {
01997             previousElementState = sublistPtr->item;
01998             previousElementNode = elementNode;
01999             sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j+1));
02000             schema.Assign(sublistPtr->item);
02001             return;
02002           }
02003         }
02004       }
02005 
02006       /* state not found, so take the catch-all (*) state */
02007       wallet_Sublist * sublistPtr;
02008       PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
02009       for (PRInt32 j=0; j<count2; j=j+2) {
02010         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j));
02011         if (!PL_strcmp(sublistPtr->item, "*")) {
02012           previousElementNode = localElementNode;
02013           sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(j+1));
02014           schema.Assign(sublistPtr->item);
02015           previousElementNode = elementNode;
02016           return;
02017         }
02018       }
02019 
02020       /* no catch-all state specified, return no schema */
02021       previousElementNode = elementNode;
02022       return;
02023     }
02024   }
02025 
02026   /* This is an error.  It means that a state-schema (entry starting with a $)
02027    * was obtained from the SchemaStrings table or the PositionalSchema table
02028    * but there was no entry for that state-schema in the StateSchema table.
02029    */
02030   NS_ASSERTION(PR_FALSE, "Undefined state in SchemaStrings table");
02031 }
02032 
02033 static void
02034 wallet_GetSchemaFromDisplayableText
02035     (nsIDOMNode* elementNode, nsACString& schema, PRBool skipStateChecking) {
02036 
02037   static nsCString lastSchema;
02038   static nsIDOMNode* lastElementNode;
02039 
02040   /* return if this is the same as the last element node */
02041   if (elementNode == lastElementNode) {
02042     schema.Assign(lastSchema);
02043     return;
02044   }
02045   lastElementNode = elementNode;
02046 
02047   nsIDOMNode* localElementNode = elementNode;
02048   PRBool atInputOrSelect = PR_FALSE;
02049   PRBool atEnd = PR_FALSE;
02050   PRBool someTextFound = PR_FALSE;
02051   while (!atEnd && !atInputOrSelect) {
02052 
02053     /* step back and get text found in a preceding node */
02054     nsAutoString text;
02055     wallet_StepForwardOrBack(localElementNode, text, atInputOrSelect, atEnd, PR_FALSE);
02056 
02057     /* strip off non-alphanumerics */
02058     PRUint32 i;
02059     PRUnichar c;
02060     nsAutoString temp;
02061     for (i=0; i<text.Length(); i++) {
02062       c = text.CharAt(i);
02063       if (nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c)) {
02064         temp.Append(c);
02065       }
02066     }
02067     text = temp;
02068 
02069     /* done if we've obtained enough text from which to determine the schema */
02070     if (!text.IsEmpty()) {
02071       someTextFound = PR_TRUE;
02072 
02073       TextToSchema(text, schema);
02074       if (!schema.IsEmpty()) {
02075 
02076         /* schema found, process positional schema if any */
02077         if (schema.First() == '%') {
02078           wallet_ResolvePositionalSchema(elementNode, schema);
02079         }
02080 
02081         /* process state schema if any */
02082         if (!skipStateChecking && !schema.IsEmpty() && schema.First() == '$') {
02083           wallet_ResolveStateSchema(elementNode, schema);
02084         }
02085         lastSchema.Assign(schema);
02086         return;
02087       }
02088 
02089     }
02090   }
02091 
02092   /* no displayable text found, see if we are inside a position set */
02093   if (!someTextFound) {
02094     wallet_ResolvePositionalSchema(elementNode, schema);
02095   }
02096 
02097   /* process state schema if any */
02098 
02099   /* The current routine is called for each field whose value is to be captured,
02100    * even if there is no value entered for that field.  We do this because we need
02101    * to call ResolvePositionalSchema above even for null values.  If we didn't
02102    * make that call, we would fail to recognize fields in a positional set if any
02103    * preceding fields in that set were blank.  For example:
02104    *
02105    *    name (first, middle, last): [William] [  ] [Clinton] 
02106    *
02107    * With that said, at least we can skip the call to ResolveStateSchema in this
02108    * case.  That call could be very time consuming because it involves looking
02109    * looking backwards through all preceding text (possibly all the way to the
02110    * beginning of the document) just to determine the state.  That is the purpose
02111    * of the skipStateChecking argument.
02112    */
02113 
02114   if (!skipStateChecking && !schema.IsEmpty() && schema.First() == '$') {
02115     wallet_ResolveStateSchema(elementNode, schema);
02116   }
02117 
02118   lastSchema.Assign(schema);
02119   return;
02120 }
02121 
02122 nsresult
02123 wallet_GetPrefills(
02124   nsIDOMNode* elementNode,
02125   nsIDOMHTMLInputElement*& inputElement,  
02126   nsIDOMHTMLSelectElement*& selectElement,
02127   nsACString& schema,
02128   nsString& value,
02129   PRInt32& selectIndex,
02130   PRInt32& index)
02131 {
02132   nsresult result;
02133   nsCAutoString localSchema; localSchema.Assign(schema);
02134 
02135   /* get prefills for input element */
02136   result = elementNode->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement);
02137 
02138   if ((NS_SUCCEEDED(result)) && (nsnull != inputElement)) {
02139     nsAutoString type;
02140     result = inputElement->GetType(type);
02141     if (NS_SUCCEEDED(result) &&
02142         (type.IsEmpty() ||
02143          type.LowerCaseEqualsLiteral("text"))) {
02144       nsAutoString field;
02145       result = inputElement->GetName(field);
02146       if (NS_SUCCEEDED(result)) {
02147         nsVoidArray* itemList;
02148 
02149         /* try to get schema name from vcard attribute if it exists */
02150         if (localSchema.IsEmpty()) {
02151           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(elementNode);
02152           if (element) {
02153             nsAutoString vcard; vcard.AssignLiteral("VCARD_NAME");
02154             nsAutoString vcardValueUCS2;
02155             result = element->GetAttribute(vcard, vcardValueUCS2);
02156             if (NS_OK == result) {
02157               nsVoidArray* dummy;
02158               wallet_ReadFromList(NS_ConvertUCS2toUTF8(vcardValueUCS2), localSchema, dummy,
02159                                   wallet_VcardToSchema_list, PR_FALSE);
02160             }
02161           }
02162         }
02163 
02164         /* try to get schema name from displayable text if possible */
02165         if (localSchema.IsEmpty()) {
02166           wallet_GetSchemaFromDisplayableText(inputElement, localSchema, PR_FALSE);
02167         }
02168 
02169         /*
02170          * if schema name was obtained then get value from schema name,
02171          * otherwise get value from field name by using mapping tables to get schema name
02172          */
02173         if (NS_SUCCEEDED(FieldToValue(field, localSchema, value, itemList, index))) {
02174           if (value.IsEmpty() && nsnull != itemList) {
02175             /* pick first of a set of synonymous values */
02176             const char* encryptedValue = ((wallet_Sublist *)itemList->ElementAt(0))->item;
02177             char* valueCString = nsnull;
02178             if (NS_FAILED(DecryptString(encryptedValue, valueCString))) {
02179               NS_RELEASE(inputElement);
02180               return NS_ERROR_FAILURE;
02181             }
02182             CopyUTF8toUTF16(valueCString, value);
02183           }
02184           selectElement = nsnull;
02185           selectIndex = -1;
02186           schema = localSchema;
02187           return NS_OK;
02188         }
02189       }
02190     }
02191     NS_RELEASE(inputElement);
02192     return NS_ERROR_FAILURE;
02193   }
02194 
02195   /* get prefills for dropdown list */
02196   result = elementNode->QueryInterface(NS_GET_IID(nsIDOMHTMLSelectElement), (void**)&selectElement);
02197   if ((NS_SUCCEEDED(result)) && (nsnull != selectElement)) {
02198     nsAutoString field;
02199     result = selectElement->GetName(field);
02200     if (NS_SUCCEEDED(result)) {
02201 
02202       /* try to get schema name from displayable text if possible */
02203       if (localSchema.IsEmpty()) {
02204         wallet_GetSchemaFromDisplayableText(selectElement, localSchema, PR_FALSE);
02205       }
02206 
02207       nsVoidArray* itemList;
02208       if (NS_SUCCEEDED(FieldToValue(field, localSchema, value, itemList, index))) {
02209         if (!value.IsEmpty()) {
02210           /* no synonym list, just one value to try */
02211           result = wallet_GetSelectIndex(selectElement, value, selectIndex);
02212           if (NS_SUCCEEDED(result)) {
02213             /* value matched one of the values in the drop-down list */
02214 
02215             inputElement = nsnull;
02216             schema = localSchema;
02217             return NS_OK;
02218           }
02219         } else {
02220           /* synonym list exists, try each value */
02221           for (PRInt32 i=0; i<LIST_COUNT(itemList); i++) {
02222             CopyUTF8toUTF16(((wallet_Sublist *)itemList->ElementAt(i))->item, value);
02223             result = wallet_GetSelectIndex(selectElement, value, selectIndex);
02224             if (NS_SUCCEEDED(result)) {
02225               /* value matched one of the values in the drop-down list */
02226 
02227               // No Release() here?
02228 
02229               inputElement = nsnull;
02230               schema = localSchema;
02231               return NS_OK;
02232             }
02233           }
02234         }
02235       }
02236     }
02237     NS_RELEASE(selectElement);
02238   }
02239   return NS_ERROR_FAILURE;
02240 }
02241 
02242 /*
02243  * termination for wallet session
02244  */
02245 void
02246 Wallet_ReleaseAllLists() {
02247     wallet_Clear(&wallet_FieldToSchema_list); /* otherwise we will duplicate the list */
02248     wallet_Clear(&wallet_VcardToSchema_list); /* otherwise we will duplicate the list */
02249     wallet_Clear(&wallet_SchemaConcat_list); /* otherwise we will duplicate the list */
02250     wallet_Clear(&wallet_SchemaStrings_list); /* otherwise we will duplicate the list */
02251     wallet_Clear(&wallet_PositionalSchema_list); /* otherwise we will duplicate the list */
02252     wallet_Clear(&wallet_StateSchema_list); /* otherwise we will duplicate the list */
02253     wallet_Clear(&wallet_DistinguishedSchema_list); /* otherwise we will duplicate the list */
02254     wallet_DeallocateMapElements();
02255     delete helpMac;
02256     helpMac = nsnull;
02257 }
02258 
02259 //#define WALLET_CHECK_FOOTPRINT
02260 #ifdef WALLET_CHECK_FOOTPRINT
02261 PRInt32
02262 wallet_Size(nsVoidArray * list) {
02263   PRInt32 size = 0;
02264   wallet_MapElement * mapElementPtr;
02265   PRInt32 count = LIST_COUNT(list);
02266   for (PRInt32 i=0; i<count; i++) {
02267     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, list->ElementAt(i));
02268     size += sizeof(wallet_MapElement*);
02269     size += sizeof(wallet_MapElement);
02270     size += PL_strlen(mapElementPtr->item1);
02271     size += PL_strlen(mapElementPtr->item2);
02272     wallet_Sublist * sublistPtr;
02273     PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
02274     for (PRInt32 i2=0; i2<count2; i2++) {
02275       sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(i2));
02276       size += sizeof(wallet_Sublist);
02277       size += PL_strlen(sublistPtr->item);
02278     }
02279   }
02280   return size;
02281 }
02282 #endif
02283 
02284 /*
02285  * initialization for wallet session (done only once)
02286  */
02287 
02288 static PRBool wallet_tablesInitialized = PR_FALSE;
02289 static PRBool wallet_ValuesReadIn = PR_FALSE;
02290 static PRBool namesInitialized = PR_FALSE;
02291 static PRBool wallet_URLListInitialized = PR_FALSE;
02292 
02293 static void
02294 wallet_Initialize(PRBool unlockDatabase=PR_TRUE) {
02295 
02296 #ifdef DEBUG_morse
02297 //wallet_ClearStopwatch();
02298 //wallet_ResumeStopwatch();
02299 #endif
02300 
02301   if (!wallet_tablesInitialized) {
02302 #ifdef DEBUG_morse
02303 //wallet_PauseStopwatch();
02304 //wallet_DumpStopwatch();
02305 #endif
02306 //    printf("******** start profile\n");
02307 //             ProfileStart();
02308 
02309     Wallet_ReleaseAllLists();
02310     helpMac = new wallet_HelpMac; /* to speed up startup time on the mac */
02311     wallet_ReadFromFile(distinguishedSchemaFileName, wallet_DistinguishedSchema_list, PR_FALSE);
02312     wallet_ReadFromFile(fieldSchemaFileName, wallet_FieldToSchema_list, PR_FALSE);
02313     wallet_ReadFromFile(vcardSchemaFileName, wallet_VcardToSchema_list, PR_FALSE);
02314     wallet_ReadFromFile(schemaConcatFileName, wallet_SchemaConcat_list, PR_FALSE);
02315     wallet_ReadFromFile(schemaStringsFileName, wallet_SchemaStrings_list, PR_FALSE, BY_LENGTH);
02316     wallet_ReadFromFile(positionalSchemaFileName, wallet_PositionalSchema_list, PR_FALSE);
02317     wallet_ReadFromFile(stateSchemaFileName, wallet_StateSchema_list, PR_FALSE);
02318 
02319 #ifdef WALLET_CHECK_FOOTPRINT
02320     PRInt32 totalSize = 0;
02321     PRInt32 size;
02322     size = wallet_Size(wallet_FieldToSchema_list);
02323     totalSize += size;
02324     printf("FieldToSchema: %d\n", size);
02325     size = wallet_Size(wallet_VcardToSchema_list);
02326     totalSize += size;
02327     printf("VcardToSchema: %d\n", size);
02328     size = wallet_Size(wallet_SchemaConcat_list);
02329     totalSize += size;
02330     printf("SchemaConcat: %d\n", size);
02331     size = wallet_Size(wallet_SchemaStrings_list);
02332     totalSize += size;
02333     printf("SchemaStrings: %d\n", size);
02334     size = wallet_Size(wallet_PositionalSchema_list);
02335     totalSize += size;
02336     printf("PositionalSchema: %d\n", size);
02337     size = wallet_Size(wallet_StateSchema_list);
02338     totalSize += size;
02339     printf("StateSchema: %d\n", size);
02340     size = wallet_Size(wallet_DistinguishedSchema_list);
02341     totalSize += size;
02342     printf("DistinguishedSchema: %d\n", size);
02343     printf("Total size: %d\n", totalSize);
02344 #endif
02345 
02346     /* Note that we sort the SchemaString list by length instead of alphabetically.  To see
02347      * why that's necessary, consider the following example:
02348      *
02349      *    Card.Name: requires "card" and "name" both be present
02350      *    Name: requires "name"
02351      *
02352      * So we want to check for a match on one with more strings (Card.Name in this case) before
02353      * checking for a match with the one containing less strings.
02354      */
02355  
02356 //    ProfileStop();
02357 //   printf("****** end profile\n");
02358     wallet_tablesInitialized = PR_TRUE;
02359   }
02360 
02361   if (!unlockDatabase) {
02362     return;
02363   }
02364 
02365   if (!namesInitialized) {
02366     SI_GetCharPref(pref_WalletSchemaValueFileName, &schemaValueFileName);
02367     if (!schemaValueFileName) {
02368       schemaValueFileName = Wallet_RandomName("w");
02369       SI_SetCharPref(pref_WalletSchemaValueFileName, schemaValueFileName);
02370     }
02371     SI_InitSignonFileName();
02372     namesInitialized = PR_TRUE;
02373   }
02374 
02375   if (!wallet_ValuesReadIn) {
02376     wallet_Clear(&wallet_SchemaToValue_list); /* otherwise we will duplicate the list */
02377     wallet_ReadFromFile(schemaValueFileName, wallet_SchemaToValue_list, PR_TRUE);
02378     wallet_ValuesReadIn = PR_TRUE;
02379   }
02380 
02381 #if DEBUG
02382 //    fprintf(stdout,"Field to Schema table \n");
02383 //    wallet_Dump(wallet_FieldToSchema_list);
02384 
02385 //    fprintf(stdout,"Vcard to Schema table \n");
02386 //    wallet_Dump(wallet_VcardToSchema_list);
02387 
02388 //    fprintf(stdout,"SchemaConcat table \n");
02389 //    wallet_Dump(wallet_SchemaConcat_list);
02390 
02391 //    fprintf(stdout,"SchemaStrings table \n");
02392 //    wallet_Dump(wallet_SchemaStrings_list);
02393 
02394 //    fprintf(stdout,"PositionalSchema table \n");
02395 //    wallet_Dump(wallet_PositionalSchema_list);
02396 
02397 //    fprintf(stdout,"StateSchema table \n");
02398 //    wallet_Dump(wallet_StateSchema_list);
02399 
02400 //    fprintf(stdout,"Schema to Value table \n");
02401 //    wallet_Dump(wallet_SchemaToValue_list);
02402 #endif
02403 
02404 }
02405 
02406 static void
02407 wallet_InitializeURLList() {
02408   if (!wallet_URLListInitialized) {
02409     wallet_Clear(&wallet_URL_list);
02410     wallet_ReadFromFile(URLFileName, wallet_URL_list, PR_TRUE);
02411     wallet_URLListInitialized = PR_TRUE;
02412   }
02413 }
02414 
02415 /*
02416  * initialization for current URL
02417  */
02418 static void
02419 wallet_InitializeCurrentURL(nsIDocument * doc) {
02420 
02421   /* get url */
02422   nsIURI *url = doc->GetDocumentURI();
02423   if (wallet_lastUrl == url) {
02424     return;
02425   } else {
02426     if (wallet_lastUrl) {
02427 //??      NS_RELEASE(lastUrl);
02428     }
02429     wallet_lastUrl = url;
02430   }
02431 
02432 }
02433 
02434 #define SEPARATOR "#*%$"
02435 
02436 static nsresult
02437 wallet_GetNextInString(const nsString& str, nsString& head, nsString& tail) {
02438   PRInt32 separator = str.Find(SEPARATOR);
02439   if (separator == -1) {
02440     return NS_ERROR_FAILURE;
02441   }
02442   str.Left(head, separator);
02443   str.Mid(tail, separator+sizeof(SEPARATOR)-1, str.Length() - (separator+sizeof(SEPARATOR)-1));
02444   return NS_OK;
02445 }
02446 
02447 static void
02448 wallet_ReleasePrefillElementList(nsVoidArray * wallet_PrefillElement_list) {
02449   if (wallet_PrefillElement_list) {
02450     wallet_PrefillElement * prefillElementPtr;
02451     PRInt32 count = LIST_COUNT(wallet_PrefillElement_list);
02452     for (PRInt32 i=count-1; i>=0; i--) {
02453       prefillElementPtr = NS_STATIC_CAST(wallet_PrefillElement*, wallet_PrefillElement_list->ElementAt(i));
02454       delete prefillElementPtr;
02455     }
02456     delete wallet_PrefillElement_list;
02457     wallet_PrefillElement_list = nsnull;
02458   }
02459 }
02460 
02461 #define BREAK PRUnichar('\001')
02462 
02463 nsVoidArray * wallet_list;
02464 PRUnichar * wallet_url;
02465 
02466 void
02467 WLLT_GetPrefillListForViewer(nsAString& aPrefillList)
02468 {
02469   wallet_Initialize(PR_FALSE); /* to initialize helpMac */
02470   wallet_PrefillElement * prefillElementPtr;
02471   nsAutoString buffer;
02472   PRInt32 count = LIST_COUNT(wallet_list);
02473   for (PRInt32 i=0; i<count; i++) {
02474     prefillElementPtr = NS_STATIC_CAST(wallet_PrefillElement*, wallet_list->ElementAt(i));
02475     buffer.Append(BREAK);
02476     buffer.AppendInt(prefillElementPtr->count,10);
02477     buffer.Append(BREAK);
02478     AppendUTF8toUTF16(prefillElementPtr->schema, buffer);
02479     buffer.Append(BREAK);
02480     buffer.Append(prefillElementPtr->value);
02481   }
02482 
02483   buffer.Append(BREAK);
02484   buffer += wallet_url;
02485   aPrefillList = buffer;
02486 }
02487 
02488 static void
02489 wallet_FreeURL(wallet_MapElement *url) {
02490 
02491     if(!url) {
02492         return;
02493     }
02494     wallet_URL_list->RemoveElement(url);
02495     PR_Free(url);
02496 }
02497 
02498 static const char permission_NoCapture_NoPreview[] = "yy";
02499 static const char permission_NoCapture_Preview[] = "yn";
02500 static const char permission_Capture_NoPreview[] = "ny";
02501 static const char permission_Capture_Preview[] = "nn";
02502 
02503 void
02504 Wallet_SignonViewerReturn(const nsAString& results)
02505 {
02506     wallet_MapElement *url;
02507     nsAutoString gone;
02508     char oldPermissionChar;
02509 
02510     /* step through all nopreviews and delete those that are in the sequence */
02511     {
02512       SI_FindValueInArgs(results, NS_LITERAL_STRING("|goneP|"), gone);
02513     }
02514     PRInt32 count = LIST_COUNT(wallet_URL_list);
02515     while (count>0) {
02516       count--;
02517       url = NS_STATIC_CAST(wallet_MapElement*, wallet_URL_list->ElementAt(count));
02518       if (url && SI_InSequence(gone, count)) {
02519         /* clear the NO_PREVIEW indicator */
02520         oldPermissionChar = NO_CAPTURE(url->item2);
02521         WALLET_FREEIF (url->item2);
02522         if (oldPermissionChar == 'y') {
02523           url->item2 = PL_strdup(permission_NoCapture_Preview);
02524         } else {
02525           url->item2 = PL_strdup(permission_Capture_Preview);
02526         }
02527         if (!PL_strcmp(url->item2, permission_Capture_Preview)) {
02528           wallet_FreeURL(url);
02529         }
02530         wallet_WriteToFile(URLFileName, wallet_URL_list);
02531       }
02532     }
02533 
02534     /* step through all nocaptures and delete those that are in the sequence */
02535     {
02536       SI_FindValueInArgs(results, NS_LITERAL_STRING("|goneC|"), gone);
02537     }
02538     PRInt32 count2 = LIST_COUNT(wallet_URL_list);
02539     while (count2>0) {
02540       count2--;
02541       url = NS_STATIC_CAST(wallet_MapElement*, wallet_URL_list->ElementAt(count2));
02542       if (url && SI_InSequence(gone, count2)) {
02543         /* clear the NO_CAPTURE indicator */
02544         oldPermissionChar = NO_PREVIEW(url->item2);
02545         WALLET_FREEIF (url->item2);
02546         if (oldPermissionChar == 'y') {
02547           url->item2 = PL_strdup(permission_Capture_NoPreview);
02548         } else {
02549           url->item2 = PL_strdup(permission_Capture_Preview);
02550         }
02551         if (!PL_strcmp(url->item2, permission_Capture_Preview)) {
02552           wallet_FreeURL(url);
02553         }
02554         wallet_WriteToFile(URLFileName, wallet_URL_list);
02555       }
02556     }
02557 }
02558 
02559 /*
02560  * see if user wants to capture data on current page
02561  */
02562 static PRBool
02563 wallet_OKToCapture(const nsAFlatCString& url, nsIDOMWindowInternal* window) {
02564 
02565   /* exit if pref is not set */
02566   if (!wallet_GetFormsCapturingPref() || !wallet_GetEnabledPref()) {
02567     return PR_FALSE;
02568   }
02569 
02570   /* see if this url is already on list of url's for which we don't want to capture */
02571   wallet_InitializeURLList();
02572   nsVoidArray* dummy;
02573   nsCAutoString urlPermissions;
02574   if (wallet_ReadFromList(url, urlPermissions, dummy, wallet_URL_list, PR_FALSE)) {
02575     if (NO_CAPTURE(urlPermissions) == 'y') {
02576       return PR_FALSE;
02577     }
02578   }
02579 
02580   /* ask user if we should capture the values on this form */
02581   PRUnichar * message = Wallet_Localize("WantToCaptureForm?");
02582 
02583   PRInt32 button = Wallet_3ButtonConfirm(message, window);
02584   if (button == NEVER_BUTTON) {
02585     /* add URL to list with NO_CAPTURE indicator set */
02586     if (NO_PREVIEW(urlPermissions) == 'y') {
02587       urlPermissions = permission_NoCapture_NoPreview;
02588     } else {
02589       urlPermissions = permission_NoCapture_Preview;
02590     }
02591     if (wallet_WriteToList(url.get(), urlPermissions.get(), dummy, wallet_URL_list, PR_FALSE, DUP_OVERWRITE)) {
02592       wallet_WriteToFile(URLFileName, wallet_URL_list);
02593 
02594       /* Notify signon manager dialog to update its display */
02595       nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
02596       if (os) {
02597         os->NotifyObservers(nsnull, "signonChanged", NS_LITERAL_STRING("nocaptures").get());
02598       }
02599     }
02600   }
02601   WALLET_FREE(message);
02602   return (button == YES_BUTTON);
02603 }
02604 
02605 /*
02606  * capture the value of a form element
02607  */
02608 static PRBool
02609 wallet_Capture(nsIDocument* doc, const nsString& field, const nsString& value, nsACString& schema)
02610 {
02611   /* do nothing if there is no value */
02612   if (value.IsEmpty()) {
02613     return PR_FALSE;
02614   }
02615 
02616   /* read in the mappings if they are not already present */
02617   wallet_Initialize();
02618   wallet_InitializeCurrentURL(doc);
02619 
02620   NS_ConvertUTF16toUTF8 valueCString(value);
02621   nsCAutoString oldValue;
02622 
02623   /* is there a mapping from this field name to a schema name */
02624   nsCAutoString localSchema; localSchema.Assign(schema);
02625   nsVoidArray* dummy;
02626   nsCAutoString stripField;
02627   if (localSchema.IsEmpty()) {
02628     Strip(field, stripField);
02629   }
02630   if (!localSchema.IsEmpty() ||
02631       (wallet_ReadFromList(stripField, localSchema, dummy,
02632                            wallet_FieldToSchema_list, PR_FALSE))) {
02633     /* field to schema mapping already exists */
02634 
02635     /* is this a new value for the schema */
02636     PRInt32 index = 0;
02637     PRInt32 lastIndex = index;
02638     while(wallet_ReadFromList(localSchema, oldValue, dummy, wallet_SchemaToValue_list, PR_TRUE, index)) {
02639       PRBool isNewValue = !oldValue.Equals(valueCString.get());
02640       if (!isNewValue) {
02641         /*
02642          * Remove entry from wallet_SchemaToValue_list and then reinsert.  This will
02643          * keep multiple values in that list for the same field ordered with
02644          * most-recently-used first.  That's useful since the first such entry
02645          * is the default value used for pre-filling.
02646          */
02647         wallet_MapElement * mapElement =
02648           (wallet_MapElement *) (wallet_SchemaToValue_list->ElementAt(lastIndex));
02649         wallet_SchemaToValue_list->RemoveElementAt(lastIndex);
02650         wallet_WriteToList(
02651           mapElement->item1,
02652           mapElement->item2,
02653           mapElement->itemList, 
02654           wallet_SchemaToValue_list,
02655           PR_FALSE); /* note: obscure=false, otherwise we will obscure an obscured value */
02656         delete mapElement;
02657         return PR_TRUE;
02658       }
02659       lastIndex = index;
02660     }
02661 
02662     /* this is a new value so store it */
02663     dummy = nsnull;
02664     if (wallet_WriteToList(localSchema.get(), valueCString.get(), dummy, wallet_SchemaToValue_list, PR_TRUE)) {
02665       wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
02666     }
02667 
02668   } else {
02669 
02670     /* no field to schema mapping so assume schema name is same as field name */
02671 
02672     /* is this a new value for the schema */
02673     PRInt32 index = 0;
02674     PRInt32 lastIndex = index;
02675 
02676     nsAutoString concatParamUCS2;
02677     wallet_GetHostFile(wallet_lastUrl, concatParamUCS2);
02678     concatParamUCS2.AppendLiteral(":");
02679     concatParamUCS2.Append(field);
02680     NS_ConvertUTF16toUTF8 concatParamUTF8(concatParamUCS2);
02681     while(wallet_ReadFromList
02682         (concatParamUTF8, oldValue, dummy, wallet_SchemaToValue_list, PR_TRUE, index)) {
02683       PRBool isNewValue = !oldValue.Equals(valueCString.get());
02684       if (!isNewValue) {
02685         /*
02686          * Remove entry from wallet_SchemaToValue_list and then reinsert.  This will
02687          * keep multiple values in that list for the same field ordered with
02688          * most-recently-used first.  That's useful since the first such entry
02689          * is the default value used for pre-filling.
02690          */
02691         wallet_MapElement * mapElement =
02692           (wallet_MapElement *) (wallet_SchemaToValue_list->ElementAt(lastIndex));
02693         wallet_SchemaToValue_list->RemoveElementAt(lastIndex);
02694         wallet_WriteToList(
02695           mapElement->item1,
02696           mapElement->item2,
02697           mapElement->itemList, 
02698           wallet_SchemaToValue_list,
02699           PR_FALSE); /* note: obscure=false, otherwise we will obscure an obscured value */
02700         delete mapElement;
02701         return PR_TRUE;
02702       }
02703       lastIndex = index;
02704 
02705       //??? aren't these next four lines redundant?
02706       wallet_GetHostFile(wallet_lastUrl, concatParamUCS2);
02707       concatParamUCS2.AppendLiteral(":");
02708       concatParamUCS2.Append(field);
02709       CopyUTF16toUTF8(concatParamUCS2, concatParamUTF8);
02710     }
02711 
02712     /* this is a new value so store it */
02713     dummy = nsnull;
02714     nsAutoString hostFileFieldUCS2;
02715     wallet_GetHostFile(wallet_lastUrl, hostFileFieldUCS2);
02716     hostFileFieldUCS2.AppendLiteral(":");
02717     hostFileFieldUCS2.Append(field);
02718 
02719     if (wallet_WriteToList
02720         (NS_ConvertUCS2toUTF8(hostFileFieldUCS2).get(), valueCString.get(), dummy,
02721          wallet_SchemaToValue_list, PR_TRUE)) {
02722       wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
02723     }
02724   }
02725   return PR_TRUE;
02726 }
02727 
02728 /***************************************************************/
02729 /* The following are the interface routines seen by other dlls */
02730 /***************************************************************/
02731 
02732 void
02733 WLLT_GetNopreviewListForViewer(nsAString& aNopreviewList)
02734 {
02735   wallet_Initialize(PR_FALSE); /* to initialize helpMac */
02736   nsAutoString buffer;
02737   wallet_MapElement *url;
02738 
02739   wallet_InitializeURLList();
02740   PRInt32 count = LIST_COUNT(wallet_URL_list);
02741   for (PRInt32 i=0; i<count; i++) {
02742     url = NS_STATIC_CAST(wallet_MapElement*, wallet_URL_list->ElementAt(i));
02743     if (NO_PREVIEW(url->item2) == 'y') {
02744       buffer.Append(BREAK);
02745       AppendUTF8toUTF16(url->item1, buffer);
02746     }
02747   }
02748   aNopreviewList = buffer;
02749 }
02750 
02751 void
02752 WLLT_GetNocaptureListForViewer(nsAString& aNocaptureList)
02753 {
02754   nsAutoString buffer;
02755   wallet_MapElement *url;
02756 
02757   wallet_InitializeURLList();
02758   PRInt32 count = LIST_COUNT(wallet_URL_list);
02759   for (PRInt32 i=0; i<count; i++) {
02760     url = NS_STATIC_CAST(wallet_MapElement*, wallet_URL_list->ElementAt(i));
02761     if (NO_CAPTURE(url->item2) == 'y') {
02762       buffer.Append(BREAK);
02763       AppendUTF8toUTF16(url->item1, buffer);
02764     }
02765   }
02766   aNocaptureList = buffer;
02767 }
02768 
02769 void
02770 WLLT_PostEdit(const nsAString& walletList)
02771 {
02772   nsCOMPtr<nsIFile> file;
02773   nsresult rv = Wallet_ProfileDirectory(getter_AddRefs(file));
02774   if (NS_FAILED(rv)) {
02775     return;
02776   }
02777 
02778   nsAutoString tail( walletList );
02779   nsAutoString head, temp;
02780   PRInt32 separator;
02781 
02782   /* get first item in list */
02783   separator = tail.FindChar(BREAK);
02784   if (-1 == separator) {
02785     return;
02786   }
02787   tail.Left(head, separator);
02788   tail.Mid(temp, separator+1, tail.Length() - (separator+1));
02789   tail = temp;
02790 
02791   /* return if OK button was not pressed */
02792   if (!head.EqualsLiteral("OK")) {
02793     return;
02794   }
02795 
02796   file->AppendNative(nsDependentCString(schemaValueFileName));
02797 
02798   /* open SchemaValue file */
02799   nsCOMPtr<nsIOutputStream> fileOutputStream;
02800   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
02801                                        file,
02802                                        -1,
02803                                        0600);
02804   if (NS_FAILED(rv))
02805     return;
02806 
02807   nsCOMPtr<nsIOutputStream> strm;
02808   rv = NS_NewBufferedOutputStream(getter_AddRefs(strm), fileOutputStream, 4096);
02809   if (NS_FAILED(rv))
02810     return;
02811 
02812   /* write the values in the walletList to the file */
02813   wallet_PutHeader(strm);
02814   for (;;) {
02815     separator = tail.FindChar(BREAK);
02816     if (-1 == separator) {
02817       break;
02818     }
02819     tail.Left(head, separator);
02820     tail.Mid(temp, separator+1, tail.Length() - (separator+1));
02821     tail = temp;
02822 
02823     wallet_PutLine(strm, NS_ConvertUCS2toUTF8(head).get());
02824   }
02825 
02826   /* close the file and read it back into the SchemaToValue list */
02827   // All went ok. Maybe except for problems in Write(), but the stream detects
02828   // that for us
02829   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(strm);
02830   NS_ASSERTION(safeStream, "expected a safe output stream!");
02831   if (safeStream) {
02832     rv = safeStream->Finish();
02833     if (NS_FAILED(rv)) {
02834       NS_WARNING("failed to save wallet file! possible dataloss");
02835       return;
02836     }
02837   }
02838 
02839   strm = nsnull;
02840   fileOutputStream = nsnull;
02841 
02842   wallet_Clear(&wallet_SchemaToValue_list);
02843   wallet_ReadFromFile(schemaValueFileName, wallet_SchemaToValue_list, PR_TRUE);
02844 }
02845 
02846 void
02847 WLLT_PreEdit(nsAString& walletList)
02848 {
02849   wallet_Initialize();
02850   walletList.Assign(BREAK);
02851   wallet_MapElement * mapElementPtr;
02852   PRInt32 count = LIST_COUNT(wallet_SchemaToValue_list);
02853   for (PRInt32 i=0; i<count; i++) {
02854     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, wallet_SchemaToValue_list->ElementAt(i));
02855 
02856     AppendUTF8toUTF16(mapElementPtr->item1, walletList);
02857     walletList.Append(BREAK);
02858     if (!WALLET_NULL(mapElementPtr->item2)) {
02859       AppendUTF8toUTF16(mapElementPtr->item2, walletList);
02860       walletList.Append(BREAK);
02861     } else {
02862       wallet_Sublist * sublistPtr;
02863       PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
02864       for (PRInt32 i2=0; i2<count2; i2++) {
02865         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(i2));
02866         AppendUTF8toUTF16(sublistPtr->item, walletList);
02867         walletList.Append(BREAK);
02868       }
02869     }
02870     walletList.Append(BREAK);
02871   }
02872 }
02873 
02874 void
02875 WLLT_DeleteAll() {
02876   wallet_Initialize();
02877   wallet_Clear(&wallet_SchemaToValue_list);
02878   wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
02879   SI_DeleteAll();
02880 }
02881 
02882 void
02883 WLLT_ClearUserData() {
02884   wallet_ValuesReadIn = PR_FALSE;
02885   namesInitialized = PR_FALSE;
02886   wallet_URLListInitialized = PR_FALSE;
02887 }
02888 
02889 void
02890 WLLT_DeletePersistentUserData() {
02891 
02892   if (schemaValueFileName && schemaValueFileName[0]) {
02893     nsCOMPtr<nsIFile> file;
02894     nsresult rv = Wallet_ProfileDirectory(getter_AddRefs(file));
02895     if (NS_SUCCEEDED(rv)) {
02896       rv = file->AppendNative(nsDependentCString(schemaValueFileName));
02897       if (NS_SUCCEEDED(rv))
02898         file->Remove(PR_FALSE);
02899     }
02900   }
02901 }
02902 
02903 int PR_CALLBACK
02904 wallet_ReencryptAll(const char * newpref, void* window) {
02905   PRUnichar * message;
02906 
02907   /* prevent reentry for the case that the user doesn't supply correct master password */
02908   if (gReencryptionLevel != 0) {
02909     return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */
02910   }
02911   gReencryptionLevel ++;
02912   PRInt32 count = LIST_COUNT(wallet_SchemaToValue_list);
02913   PRInt32 i = 0;
02914   char* plainText = nsnull;
02915 
02916   /* logout first so there is no conversion unless user knows the master password */
02917 if (!changingPassword) {
02918   nsresult rv = wallet_CryptSetup();
02919   if (NS_SUCCEEDED(rv)) {
02920     rv = gSecretDecoderRing->Logout();
02921   }
02922   if (NS_FAILED(rv)) {
02923     goto fail;
02924   }
02925   wallet_Initialize();
02926 }
02927   wallet_MapElement * mapElementPtr;
02928   gEncryptionFailure = PR_FALSE;
02929   for (i=0; i<count && !gEncryptionFailure; i++) {
02930     mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, wallet_SchemaToValue_list->ElementAt(i));
02931     char * crypt = nsnull;
02932     if (!WALLET_NULL(mapElementPtr->item2)) {
02933       if (NS_FAILED(DecryptString(mapElementPtr->item2, plainText))) {
02934         goto fail;
02935       }
02936       if (NS_FAILED(EncryptString(plainText, crypt))) {
02937         goto fail;
02938       }
02939       mapElementPtr->item2 = crypt;
02940     } else {
02941       wallet_Sublist * sublistPtr;
02942       PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList);
02943       for (PRInt32 i2=0; i2<count2; i2++) {
02944         sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(i2));
02945         if (NS_FAILED(DecryptString(sublistPtr->item, plainText))) {
02946           goto fail;
02947         }
02948         if (NS_FAILED(EncryptString(plainText, crypt))) {
02949           goto fail;
02950         }
02951         sublistPtr->item = crypt;
02952       }
02953     }
02954   }
02955   wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
02956   if (!SINGSIGN_ReencryptAll()) {
02957     goto fail;
02958   }
02959 
02960   /* force a rewriting of prefs.js to make sure pref_Crypto got updated
02961    *
02962    *   Note: In the event of a crash after changing this pref (either way), the user
02963    *   could get misled as to what state his storage was in.  If the crash occurred 
02964    *   after changing to encrypted, he could think he was encrypting in the future (because
02965    *   he remembered changed to encypting at one time) but his new values are only being
02966    *   obscurred.  If the crash occurred after changing to obscured, later on he might
02967    *   think his store was encrypted (because he checked the pref panel and that's what
02968    *   it told him) whereas some of the earlier values are actually obscured and so not
02969    *   protected.  For both these reasons, we force this rewriting of the prefs file now.
02970    */
02971   SI_SetBoolPref(pref_Crypto, SI_GetBoolPref(pref_Crypto, PR_TRUE));
02972 
02973 //  message = Wallet_Localize("Converted");
02974 //  wallet_Alert(message, (nsIDOMWindowInternal *)window);
02975 //  WALLET_FREE(message);
02976   gReencryptionLevel--;
02977   return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */
02978 fail:
02979   /* toggle the pref back to its previous value */
02980   SI_SetBoolPref(pref_Crypto, !SI_GetBoolPref(pref_Crypto, PR_TRUE));
02981 
02982   /* alert the user to the failure */
02983   message = Wallet_Localize("NotConverted");
02984   wallet_Alert(message, (nsIDOMWindowInternal *)window);
02985   WALLET_FREE(message);
02986   gReencryptionLevel--;
02987   return 1;
02988 }
02989 
02990 void
02991 WLLT_InitReencryptCallback(nsIDOMWindowInternal* window) {
02992   static PRBool registered = PR_FALSE;
02993   static nsIDOMWindowInternal* lastWindow;
02994   if (registered) {
02995     SI_UnregisterCallback(pref_Crypto, wallet_ReencryptAll, lastWindow);
02996   }
02997   SI_RegisterCallback(pref_Crypto, wallet_ReencryptAll, window);
02998   lastWindow = window;
02999   registered = PR_TRUE;
03000 }
03001 
03002 static void
03003 wallet_DecodeVerticalBars(nsString& s) {
03004   s.ReplaceSubstring(NS_LITERAL_STRING("^2").get(), NS_LITERAL_STRING("|").get());
03005   s.ReplaceSubstring(NS_LITERAL_STRING("^1").get(), NS_LITERAL_STRING("^").get());
03006 }
03007 
03008 /*
03009  * return after previewing a set of prefills
03010  */
03011 void
03012 WLLT_PrefillReturn(const nsAString& results)
03013 {
03014   nsAutoString fillins;
03015   nsAutoString urlName;
03016   nsAutoString skip;
03017   nsAutoString next;
03018 
03019   /* get values that are in environment variables */
03020   SI_FindValueInArgs(results, NS_LITERAL_STRING("|fillins|"), fillins);
03021   SI_FindValueInArgs(results, NS_LITERAL_STRING("|skip|"), skip);
03022   SI_FindValueInArgs(results, NS_LITERAL_STRING("|url|"), urlName);
03023   wallet_DecodeVerticalBars(fillins);
03024   wallet_DecodeVerticalBars(urlName);
03025 
03026   /* add url to url list if user doesn't want to preview this page in the future */
03027   if (skip.EqualsLiteral("true")) {
03028     NS_ConvertUTF16toUTF8 url(urlName);
03029     nsVoidArray* dummy;
03030     nsCAutoString urlPermissions("nn");
03031     wallet_ReadFromList(url, urlPermissions, dummy, wallet_URL_list, PR_FALSE);
03032     /* add URL to list with NO_PREVIEW indicator set */
03033     if (NO_CAPTURE(urlPermissions) == 'y') {
03034       urlPermissions = permission_NoCapture_NoPreview;
03035     } else {
03036       urlPermissions = permission_Capture_NoPreview;
03037     }
03038     if (wallet_WriteToList(url.get(), urlPermissions.get(), dummy, wallet_URL_list, PR_FALSE, DUP_OVERWRITE)) {
03039       wallet_WriteToFile(URLFileName, wallet_URL_list);
03040 
03041       /* Notify signon manager dialog to update its display */
03042       nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
03043       if (os) {
03044         os->NotifyObservers(nsnull, "signonChanged", NS_LITERAL_STRING("nopreviews").get());
03045       }
03046     }
03047   }
03048 
03049   /* process the list, doing the fillins */
03050   if (fillins.Length() == 0) { /* user pressed CANCEL */
03051     wallet_ReleasePrefillElementList(wallet_list);
03052     wallet_list = nsnull;
03053     nsMemory::Free(wallet_url);
03054     wallet_url = nsnull;
03055     return;
03056   }
03057 
03058   /*
03059    * note: there are two lists involved here and we are stepping through both of them.
03060    * One is the pre-fill list that was generated when we walked through the html content.
03061    * For each pre-fillable item, it contains n entries, one for each possible value that
03062    * can be prefilled for that field.  The first entry for each field can be identified
03063    * because it has a non-zero count field (in fact, the count is the number of entries
03064    * for that field), all subsequent entries for the same field have a zero count field.
03065    * The other is the fillin list which was generated by the html dialog that just
03066    * finished.  It contains one entry for each pre-fillable item specificying that
03067    * particular value that should be prefilled for that item.
03068    */
03069 
03070   wallet_PrefillElement * mapElementPtr;
03071   /* step through pre-fill list */
03072   PRInt32 count = LIST_COUNT(wallet_list);
03073   for (PRInt32 i=0; i<count; i++) {
03074     mapElementPtr = NS_STATIC_CAST(wallet_PrefillElement*, wallet_list->ElementAt(i));
03075 
03076     /* advance in fillins list each time a new schema name in pre-fill list is encountered */
03077     if (mapElementPtr->count != 0) {
03078       /* count != 0 indicates a new schema name */
03079       nsAutoString tail;
03080       if (NS_FAILED(wallet_GetNextInString(fillins, next, tail))) {
03081         break;
03082       }
03083       fillins = tail;
03084       if (PL_strcmp(NS_ConvertUCS2toUTF8(next).get(), mapElementPtr->schema)) {
03085         break; /* something's wrong so stop prefilling */
03086       }
03087       wallet_GetNextInString(fillins, next, tail);
03088       fillins = tail;
03089     }
03090     if (next == mapElementPtr->value) {
03091       /*
03092        * Remove entry from wallet_SchemaToValue_list and then reinsert.  This will
03093        * keep multiple values in that list for the same field ordered with
03094        * most-recently-used first.  That's useful since the first such entry
03095        * is the default value used for pre-filling.
03096        */
03097       /*
03098        * Test for mapElementPtr->count being zero is an optimization that avoids us from doing a
03099        * reordering if the current entry already was first
03100        */
03101       if (mapElementPtr->count == 0) {
03102         nsCAutoString oldvalueUTF8;
03103         PRInt32 index = 0;
03104         PRInt32 lastIndex = index;
03105         nsVoidArray* dummy;
03106         while(wallet_ReadFromList(nsDependentCString(mapElementPtr->schema),
03107                                   oldvalueUTF8,
03108                                   dummy,
03109                                   wallet_SchemaToValue_list,
03110                                   PR_TRUE,
03111                                   index)) {
03112           if (oldvalueUTF8.Equals(NS_ConvertUCS2toUTF8(mapElementPtr->value).get())) {
03113             wallet_MapElement * mapElement =
03114               (wallet_MapElement *) (wallet_SchemaToValue_list->ElementAt(lastIndex));
03115             wallet_SchemaToValue_list->RemoveElementAt(lastIndex);
03116             wallet_WriteToList(
03117               mapElement->item1,
03118               mapElement->item2,
03119               mapElement->itemList,
03120               wallet_SchemaToValue_list,
03121               PR_FALSE); /* note: obscure=false, otherwise we will obscure an obscured value */
03122             delete mapElement;
03123             break;
03124           }
03125           lastIndex = index;
03126         }
03127       }
03128     }
03129 
03130     /* Change the value */
03131 
03132     if (!next.IsEmpty()) {
03133       if (mapElementPtr->inputElement) {
03134         mapElementPtr->inputElement->SetValue(next);
03135       } else {
03136         nsresult result;
03137         result = wallet_GetSelectIndex(mapElementPtr->selectElement, next, mapElementPtr->selectIndex);
03138         if (NS_SUCCEEDED(result)) {
03139           mapElementPtr->selectElement->SetSelectedIndex(mapElementPtr->selectIndex);
03140         } else {
03141           mapElementPtr->selectElement->SetSelectedIndex(0);
03142         }
03143       }
03144     }
03145   }
03146 
03147   /* Release the prefill list that was generated when we walked thru the html content */
03148   wallet_ReleasePrefillElementList(wallet_list);
03149   wallet_list = nsnull;
03150   nsMemory::Free(wallet_url);
03151   wallet_url = nsnull;
03152 }
03153 
03154 /*
03155  * get the form elements on the current page and prefill them if possible
03156  */
03157 static void
03158 wallet_TraversalForPrefill
03159     (nsIDOMWindow* win, nsVoidArray* wallet_PrefillElement_list, nsString& urlName) {
03160 
03161   nsresult result;
03162   if (nsnull != win) {
03163     nsCOMPtr<nsIDOMDocument> domdoc;
03164     result = win->GetDocument(getter_AddRefs(domdoc));
03165     if (NS_SUCCEEDED(result)) {
03166       nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
03167       if (doc) {
03168         nsIURI *url = doc->GetDocumentURI();
03169         if (url) {
03170           wallet_GetHostFile(url, urlName);
03171         }
03172         wallet_Initialize();
03173         wallet_InitializeCurrentURL(doc);
03174 
03175         nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(doc);
03176         if (htmldoc) {
03177           nsCOMPtr<nsIDOMHTMLCollection> forms;
03178           htmldoc->GetForms(getter_AddRefs(forms));
03179           if (forms) {
03180             wallet_InitializeStateTesting();
03181             PRUint32 numForms;
03182             forms->GetLength(&numForms);
03183             for (PRUint32 formX = 0; (formX < numForms) && !gEncryptionFailure; formX++) {
03184               nsCOMPtr<nsIDOMNode> formNode;
03185               forms->Item(formX, getter_AddRefs(formNode));
03186               if (formNode) {
03187                 nsCOMPtr<nsIDOMHTMLFormElement> formElement = do_QueryInterface(formNode);
03188                 if (formElement) {
03189                   nsCOMPtr<nsIDOMHTMLCollection> elements;
03190                   result = formElement->GetElements(getter_AddRefs(elements));
03191                   if (elements) {
03192                     /* got to the form elements at long last */
03193                     PRUint32 numElements;
03194                     elements->GetLength(&numElements);
03195                     for (PRUint32 elementX = 0; (elementX < numElements) && !gEncryptionFailure; elementX++) {
03196                       nsCOMPtr<nsIDOMNode> elementNode;
03197                       elements->Item(elementX, getter_AddRefs(elementNode));
03198                       if (elementNode) {
03199                         wallet_PrefillElement * prefillElement;
03200                         PRInt32 index = 0;
03201                         wallet_PrefillElement * firstElement = nsnull;
03202                         PRUint32 numberOfElements = 0;
03203                         for (; !gEncryptionFailure;) {
03204                           /* loop to allow for multiple values */
03205                           /* first element in multiple-value group will have its count
03206                            * field set to the number of elements in group.  All other
03207                            * elements in group will have count field set to 0
03208                            */
03209                           prefillElement = new wallet_PrefillElement;
03210                           nsCAutoString schemaUTF8;
03211                           if (NS_SUCCEEDED(wallet_GetPrefills
03212                               (elementNode,
03213                               prefillElement->inputElement,
03214                               prefillElement->selectElement,
03215                               schemaUTF8,
03216                               prefillElement->value,
03217                               prefillElement->selectIndex,
03218                               index))) {
03219                             /* another value found */
03220                             prefillElement->schema = ToNewCString(schemaUTF8);
03221                             if (nsnull == firstElement) {
03222                               firstElement = prefillElement;
03223                             }
03224                             numberOfElements++;
03225                             prefillElement->count = 0;
03226                             wallet_PrefillElement_list->AppendElement(prefillElement);
03227                           } else {
03228                             /* value not found, stop looking for more values */
03229                             delete prefillElement;
03230                             break;
03231                           }
03232                         } // for
03233                         if (numberOfElements>0) {
03234                           firstElement->count = numberOfElements;
03235                         }
03236                       }
03237                     } // for
03238                   }
03239                 }
03240               }
03241             }
03242           }
03243         }
03244       }
03245     }
03246   }
03247 
03248   nsCOMPtr<nsIDOMWindowCollection> frames;
03249   win->GetFrames(getter_AddRefs(frames));
03250   if (frames) {
03251     PRUint32 numFrames;
03252     frames->GetLength(&numFrames);
03253     for (PRUint32 frameX = 0; (frameX < numFrames) && !gEncryptionFailure; frameX++) {
03254       nsCOMPtr<nsIDOMWindow> frameNode;
03255       frames->Item(frameX, getter_AddRefs(frameNode));
03256       if (frameNode) {
03257         wallet_TraversalForPrefill(frameNode, wallet_PrefillElement_list, urlName);
03258       }
03259     }
03260   }
03261 }
03262 
03263 nsresult
03264 WLLT_PrefillOneElement
03265   (nsIDOMWindowInternal* win, nsIDOMNode* elementNode, nsAString& compositeValue)
03266 {
03267   nsIDOMHTMLInputElement* inputElement;
03268   nsIDOMHTMLSelectElement* selectElement;
03269   nsCAutoString schema;
03270   nsString value;
03271   PRInt32 selectIndex = 0;
03272   PRInt32 index = 0;
03273 
03274   if (nsnull != win) {
03275     nsCOMPtr<nsIDOMDocument> domdoc;
03276     nsresult result = win->GetDocument(getter_AddRefs(domdoc));
03277     if (NS_SUCCEEDED(result)) {
03278       nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
03279       if (doc) {
03280         wallet_Initialize(PR_TRUE);
03281         wallet_InitializeCurrentURL(doc);
03282         wallet_InitializeStateTesting();
03283         while (NS_SUCCEEDED(wallet_GetPrefills
03284             (elementNode,
03285             inputElement,
03286             selectElement,
03287             schema,
03288             value,
03289             selectIndex,
03290             index))) {
03291           compositeValue.Append(BREAK);
03292           compositeValue.Append(value);
03293         }
03294       }
03295     }
03296   }
03297   return NS_OK;
03298 }
03299 
03300 nsresult
03301 WLLT_Prefill(nsIPresShell* shell, PRBool quick, nsIDOMWindowInternal* win)
03302 {
03303   /* do not prefill if preview window is open in some other browser window */
03304   if (wallet_list) {
03305     return NS_ERROR_FAILURE;
03306   }
03307 
03308   /* create list of elements that can be prefilled */
03309   nsVoidArray *wallet_PrefillElement_list=new nsVoidArray();
03310   if (!wallet_PrefillElement_list) {
03311     return NS_ERROR_FAILURE;
03312   }
03313 
03314   nsAutoString urlName;
03315   gEncryptionFailure = PR_FALSE;
03316   wallet_TraversalForPrefill(win, wallet_PrefillElement_list, urlName);
03317 
03318   /* return if no elements were put into the list */
03319   if (LIST_COUNT(wallet_PrefillElement_list) == 0) {
03320     if (!gEncryptionFailure) {
03321       PRUnichar * message = Wallet_Localize("noPrefills");
03322       wallet_Alert(message, win);
03323       WALLET_FREE(message);
03324     }
03325 
03326     // Shouldn't wallet_PrefillElement_list be deleted here?
03327 
03328     return NS_ERROR_FAILURE; // indicates to caller not to display preview screen
03329   }
03330 
03331   /* prefill each element using the list */
03332 
03333   /* determine if url is on list of urls that should not be previewed */
03334   PRBool noPreview = PR_FALSE;
03335   if (!quick) {
03336     wallet_InitializeURLList();
03337     nsVoidArray* dummy;
03338     nsCAutoString urlPermissions;
03339     if (!urlName.IsEmpty()) {
03340       wallet_ReadFromList
03341         (NS_ConvertUCS2toUTF8(urlName), urlPermissions, dummy, wallet_URL_list, PR_FALSE);
03342       noPreview = (NO_PREVIEW(urlPermissions) == 'y');
03343     }
03344   }
03345 
03346   /* determine if preview is necessary */
03347   if (noPreview || quick) {
03348     /* prefill each element without any preview for user verification */
03349     wallet_PrefillElement * mapElementPtr;
03350     PRInt32 count = LIST_COUNT(wallet_PrefillElement_list);
03351     for (PRInt32 i=0; i<count; i++) {
03352       mapElementPtr = NS_STATIC_CAST(wallet_PrefillElement*, wallet_PrefillElement_list->ElementAt(i));
03353       if (mapElementPtr->count) {
03354         if (mapElementPtr->inputElement) {
03355           mapElementPtr->inputElement->SetValue(mapElementPtr->value);
03356         } else {
03357           mapElementPtr->selectElement->SetSelectedIndex(mapElementPtr->selectIndex);
03358         }
03359       }
03360     }
03361     /* go thru list just generated and release everything */
03362     wallet_ReleasePrefillElementList(wallet_PrefillElement_list);
03363     return NS_ERROR_FAILURE; // indicates to caller not to display preview screen
03364   } else {
03365     /* let user preview and verify the prefills first */
03366     wallet_list = wallet_PrefillElement_list;
03367     nsMemory::Free(wallet_url); 
03368     wallet_url = ToNewUnicode(urlName);
03369 #ifdef DEBUG_morse
03370 
03371 
03372 //wallet_DumpTiming();
03373 //wallet_ClearTiming();
03374 #endif
03375     return NS_OK; // indicates that caller is to display preview screen
03376   }
03377 }
03378 
03379 static PRBool
03380 wallet_CaptureInputElement(nsIDOMNode* elementNode, nsIDocument* doc) {
03381   nsresult result;
03382   PRBool captured = PR_FALSE;
03383   nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(elementNode);
03384   if (inputElement) {
03385     /* it's an input element */
03386     nsAutoString type;
03387     result = inputElement->GetType(type);
03388     if (NS_SUCCEEDED(result) &&
03389         (type.IsEmpty() ||
03390          type.LowerCaseEqualsLiteral("text"))) {
03391       nsAutoString field;
03392       result = inputElement->GetName(field);
03393       if (NS_SUCCEEDED(result)) {
03394         nsAutoString value;
03395         result = inputElement->GetValue(value);
03396         if (NS_SUCCEEDED(result)) {
03397           /* get schema name from vcard attribute if it exists */
03398           nsCAutoString schema;
03399           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(elementNode);
03400           if (element) {
03401             nsAutoString vcardName; vcardName.AssignLiteral("VCARD_NAME");
03402             nsAutoString vcardValueUCS2;
03403             result = element->GetAttribute(vcardName, vcardValueUCS2);
03404             if (NS_OK == result) {
03405               nsVoidArray* dummy;
03406               wallet_ReadFromList(NS_ConvertUCS2toUTF8(vcardValueUCS2), schema, dummy,
03407                                   wallet_VcardToSchema_list, PR_FALSE);
03408             }
03409           }
03410           if (schema.IsEmpty()) {
03411             /* get schema from displayable text if possible */
03412             wallet_GetSchemaFromDisplayableText(inputElement, schema, value.IsEmpty());
03413           }
03414           if (wallet_Capture(doc, field, value, schema)) {
03415             captured = PR_TRUE;
03416           }
03417         }
03418       }
03419     }
03420   }
03421   return captured;
03422 }
03423 
03424 static PRBool
03425 wallet_CaptureSelectElement(nsIDOMNode* elementNode, nsIDocument* doc) {
03426   nsresult result;
03427   PRBool captured = PR_FALSE;
03428   nsCOMPtr<nsIDOMHTMLSelectElement> selectElement = do_QueryInterface(elementNode);
03429   if (selectElement) {
03430     /* it's a dropdown list */
03431     nsAutoString field;
03432     result = selectElement->GetName(field);
03433 
03434     if (NS_SUCCEEDED(result)) {
03435       PRUint32 length;
03436       selectElement->GetLength(&length);
03437 
03438       nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
03439       selectElement->GetOptions(getter_AddRefs(options));
03440 
03441       if (options) {
03442         PRInt32 selectedIndex;
03443         result = selectElement->GetSelectedIndex(&selectedIndex);
03444 
03445         if (NS_SUCCEEDED(result)) {
03446           nsCOMPtr<nsIDOMNode> optionNode;
03447 
03448           options->Item(selectedIndex, getter_AddRefs(optionNode));
03449 
03450           if (optionNode) {
03451             nsCOMPtr<nsIDOMHTMLOptionElement> optionElement(do_QueryInterface(optionNode));
03452 
03453             if (optionElement) {
03454               nsAutoString optionValue;
03455               nsAutoString optionText;
03456 
03457               PRBool valueOK = NS_SUCCEEDED(optionElement->GetValue(optionValue))
03458                                && optionValue.Length();
03459               PRBool textOK = NS_SUCCEEDED(optionElement->GetText(optionText))
03460                               && optionText.Length();
03461               if (valueOK || textOK) {
03462                 /* get schema name from vcard attribute if it exists */
03463                 nsCAutoString schema;
03464                 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(elementNode);
03465                 if (element) {
03466                   nsAutoString vcardName; vcardName.AssignLiteral("VCARD_NAME");
03467                   nsAutoString vcardValueUCS2;
03468                   result = element->GetAttribute(vcardName, vcardValueUCS2);
03469                   if (NS_OK == result) {
03470                     nsVoidArray* dummy;
03471                     wallet_ReadFromList(NS_ConvertUCS2toUTF8(vcardValueUCS2), schema, dummy,
03472                                         wallet_VcardToSchema_list, PR_FALSE);
03473                   }
03474                 }
03475                 if (schema.IsEmpty()) {
03476                   /* get schema from displayable text if possible */
03477                   wallet_GetSchemaFromDisplayableText(selectElement, schema, (!valueOK && !textOK));
03478                 }
03479                 if (valueOK && wallet_Capture(doc, field, optionValue, schema)) {
03480                   captured = PR_TRUE;
03481                 }
03482                 optionText.Trim(" \n\t\r");
03483                 if (textOK && wallet_Capture(doc, field, optionText, schema)) {
03484                   captured = PR_TRUE;
03485                 }
03486               }
03487             }
03488           }
03489         }
03490       }
03491     }
03492   }
03493   return captured;
03494 }
03495 
03496 static void
03497 wallet_TraversalForRequestToCapture(nsIDOMWindow* win, PRInt32& captureCount) {
03498 
03499   nsresult result;
03500   if (nsnull != win) {
03501     nsCOMPtr<nsIDOMDocument> domdoc;
03502     result = win->GetDocument(getter_AddRefs(domdoc));
03503     if (NS_SUCCEEDED(result)) {
03504       nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
03505       if (doc) {
03506         wallet_Initialize();
03507         wallet_InitializeCurrentURL(doc);
03508         nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(doc);
03509         if (htmldoc) {
03510           nsCOMPtr<nsIDOMHTMLCollection> forms;
03511           htmldoc->GetForms(getter_AddRefs(forms));
03512           if (forms) {
03513           wallet_InitializeStateTesting();
03514             PRUint32 numForms;
03515             forms->GetLength(&numForms);
03516             for (PRUint32 formX = 0; (formX < numForms) && !gEncryptionFailure; formX++) {
03517               nsCOMPtr<nsIDOMNode> formNode;
03518               forms->Item(formX, getter_AddRefs(formNode));
03519               if (formNode) {
03520                 nsCOMPtr<nsIDOMHTMLFormElement> formElement = do_QueryInterface(formNode);
03521                 if (formElement) {
03522                   nsCOMPtr<nsIDOMHTMLCollection> elements;
03523                   result = formElement->GetElements(getter_AddRefs(elements));
03524                   if (elements) {
03525                     /* got to the form elements at long last */
03526                     /* now find out how many text fields are on the form */
03527                     PRUint32 numElements;
03528                     elements->GetLength(&numElements);
03529                     for (PRUint32 elementY = 0; (elementY < numElements) && !gEncryptionFailure; elementY++) {
03530                       nsCOMPtr<nsIDOMNode> elementNode;
03531                       elements->Item(elementY, getter_AddRefs(elementNode));
03532                       if (elementNode) {
03533                         if (wallet_CaptureInputElement(elementNode, doc)) {
03534                           captureCount++;
03535                         }
03536                         if (wallet_CaptureSelectElement(elementNode, doc)) {
03537                           captureCount++;
03538                         }
03539                       }
03540                     }
03541                   }
03542                 }
03543               }
03544             }
03545           }
03546         }
03547       }
03548     }
03549   }
03550 
03551   nsCOMPtr<nsIDOMWindowCollection> frames;
03552   win->GetFrames(getter_AddRefs(frames));
03553   if (frames) {
03554     PRUint32 numFrames;
03555     frames->GetLength(&numFrames);
03556     for (PRUint32 frameX = 0; (frameX < numFrames) && !gEncryptionFailure; frameX++)
03557     {
03558       nsCOMPtr<nsIDOMWindow> frameNode;
03559       frames->Item(frameX, getter_AddRefs(frameNode));
03560       if (frameNode) {
03561         wallet_TraversalForRequestToCapture(frameNode, captureCount);
03562       }
03563     }
03564   }
03565 }
03566 
03567 void
03568 WLLT_RequestToCapture(nsIPresShell* shell, nsIDOMWindowInternal* win, PRUint32* status) {
03569 
03570   PRInt32 captureCount = 0;
03571   gEncryptionFailure = PR_FALSE;
03572   wallet_TraversalForRequestToCapture(win, captureCount);
03573 
03574   PRUnichar * message;
03575   if (gEncryptionFailure) {
03576     message = Wallet_Localize("UnableToCapture");
03577     *status = 0;
03578   } else if (captureCount) {
03579     /* give caveat if this is the first time data is being captured */
03580     Wallet_GiveCaveat(win, nsnull);
03581     message = Wallet_Localize("Captured");
03582     *status = 0;
03583   } else {
03584     message = Wallet_Localize("NotCaptured");
03585     *status = +1;
03586   }
03587   wallet_Alert(message, win);
03588   WALLET_FREE(message);
03589 }
03590 
03591 static PRBool
03592 wallet_IsNewValue(nsIDOMNode* elementNode, nsString valueOnForm) {
03593   if (valueOnForm.Equals(EmptyString())) {
03594     return PR_FALSE;
03595   }
03596   nsIDOMHTMLInputElement* inputElement;
03597   nsIDOMHTMLSelectElement* selectElement;
03598   nsCAutoString schema;
03599   nsAutoString valueSaved;
03600   PRInt32 selectIndex = 0;
03601   PRInt32 index = 0;
03602   while (NS_SUCCEEDED(wallet_GetPrefills
03603       (elementNode, inputElement, selectElement, schema, valueSaved, selectIndex, index))) {
03604     if (valueOnForm.Equals(valueSaved)) {
03605       return PR_FALSE;
03606     }
03607   }
03608   return PR_TRUE;
03609 }
03610 
03611 void
03612 WLLT_OnSubmit(nsIContent* currentForm, nsIDOMWindowInternal* window) {
03613 
03614   nsCOMPtr<nsIDOMHTMLFormElement> currentFormNode(do_QueryInterface(currentForm));
03615 
03616   /* get url name as ascii string */
03617   nsAutoString strippedURLNameUCS2;
03618   nsCOMPtr<nsIDocument> doc = currentForm->GetDocument();
03619   if (!doc) {
03620     return;
03621   }
03622   nsIURI *docURL = doc->GetDocumentURI();
03623   if (!docURL) {
03624     return;
03625   }
03626   wallet_GetHostFile(docURL, strippedURLNameUCS2);
03627   NS_ConvertUTF16toUTF8 strippedURLNameUTF8(strippedURLNameUCS2);
03628 
03629   /* get to the form elements */
03630   nsCOMPtr<nsIDOMHTMLDocument> htmldoc(do_QueryInterface(doc));
03631   if (htmldoc == nsnull) {
03632     return;
03633   }
03634 
03635   nsCOMPtr<nsIDOMHTMLCollection> forms;
03636   nsresult rv = htmldoc->GetForms(getter_AddRefs(forms));
03637   if (NS_FAILED(rv) || (forms == nsnull)) {
03638     return;
03639   }
03640 
03641   PRUint32 numForms;
03642   forms->GetLength(&numForms);
03643   for (PRUint32 formX = 0; formX < numForms; formX++) {
03644     nsCOMPtr<nsIDOMNode> formNode;
03645     forms->Item(formX, getter_AddRefs(formNode));
03646     if (nsnull != formNode) {
03647       nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(formNode));
03648       if ((nsnull != formElement)) {
03649         nsCOMPtr<nsIDOMHTMLCollection> elements;
03650         rv = formElement->GetElements(getter_AddRefs(elements));
03651         if ((NS_SUCCEEDED(rv)) && (nsnull != elements)) {
03652           /* got to the form elements at long last */ 
03653           nsVoidArray * signonData = new nsVoidArray();
03654           si_SignonDataStruct * data;
03655           PRUint32 numElements;
03656           elements->GetLength(&numElements);
03657           PRBool OKToPrompt = PR_FALSE;
03658           PRInt32 passwordcount = 0;
03659           PRInt32 hits = 0;
03660           wallet_Initialize(PR_FALSE);
03661           wallet_InitializeCurrentURL(doc);
03662           wallet_InitializeStateTesting();
03663           PRBool newValueFound = PR_FALSE;
03664           for (PRUint32 elementX = 0; elementX < numElements; elementX++) {
03665             nsCOMPtr<nsIDOMNode> elementNode;
03666             elements->Item(elementX, getter_AddRefs(elementNode));
03667             if (nsnull != elementNode) {
03668               nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(elementNode));
03669               if ((NS_SUCCEEDED(rv)) && (nsnull != selectElement)) {
03670                 if (passwordcount == 0 && !newValueFound && !OKToPrompt) {
03671                   nsAutoString valueOnForm;
03672                   rv = selectElement->GetValue(valueOnForm);
03673                   if (NS_SUCCEEDED(rv) && wallet_IsNewValue (elementNode, valueOnForm)) {
03674                     newValueFound = PR_TRUE;
03675                     if (hits > 1) {
03676                       OKToPrompt = PR_TRUE;
03677                     }
03678                   }
03679                 }
03680               }
03681               nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(elementNode));
03682               if ((NS_SUCCEEDED(rv)) && (nsnull != inputElement)) {
03683                 nsAutoString type;
03684                 rv = inputElement->GetType(type);
03685                 if (NS_SUCCEEDED(rv)) {
03686 
03687                   PRBool isText = (type.IsEmpty() || type.LowerCaseEqualsLiteral("text"));
03688                   PRBool isPassword = type.LowerCaseEqualsLiteral("password");
03689 
03690                   // don't save password if field was left blank
03691                   if (isPassword) {
03692                     nsAutoString val;
03693                     (void) inputElement->GetValue(val);
03694                     if (val.IsEmpty()) {
03695                       isPassword = PR_FALSE;
03696                     }
03697                   }
03698 
03699                   // Do not store this 'password' form element if the 'autocomplete = off'
03700                   // attribute is present, unless the 'wallet.crypto.autocompleteoverride'
03701                   // preference is enabled. (The "autocomplete" property is a Microsoft
03702                   // extension to HTML.)
03703                   if (isPassword && !SI_GetBoolPref(pref_AutoCompleteOverride, PR_FALSE)) {
03704                     nsAutoString val;
03705                     (void) inputElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), val);
03706                     if (val.LowerCaseEqualsLiteral("off")) {
03707                       isPassword = PR_FALSE;
03708                     } else {
03709                       (void) formElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), val);
03710                       if (val.LowerCaseEqualsLiteral("off")) {
03711                         isPassword = PR_FALSE;
03712                       }
03713                     }
03714                   }
03715 
03716                   if (isPassword) {
03717                     passwordcount++;
03718                     OKToPrompt = PR_FALSE;
03719                   }
03720 
03721                   if (isText) {
03722                     if (passwordcount == 0 && !newValueFound && !OKToPrompt) {
03723                       nsAutoString valueOnForm;
03724                       rv = inputElement->GetValue(valueOnForm);
03725                       if (NS_SUCCEEDED(rv) && wallet_IsNewValue (elementNode, valueOnForm)) {
03726                         newValueFound = PR_TRUE;
03727                         if (hits > 1) {
03728                           OKToPrompt = PR_TRUE;
03729                         }
03730                       }
03731                     }
03732                   }
03733 
03734                   if (isText || isPassword) {
03735                     nsAutoString value;
03736                     rv = inputElement->GetValue(value);
03737                     if (NS_SUCCEEDED(rv)) {
03738                       nsAutoString field;
03739                       rv = inputElement->GetName(field);
03740                       if (NS_SUCCEEDED(rv)) {
03741                         data = new si_SignonDataStruct;
03742                         data->value = value;
03743                         if (!field.IsEmpty() && field.CharAt(0) == '\\') {
03744                           /*
03745                            * Note that data saved for browser-generated logins (e.g. http
03746                            * authentication) use artificial field names starting with
03747                            * \= (see USERNAMEFIELD and PASSWORDFIELD in singsign.cpp).  To
03748                            * avoid mistakes whereby saved logins for http authentication is
03749                            * then prefilled into a field on the html form at the same URL,
03750                            * we will prevent html field names from starting with \=.  We
03751                            * do that by doubling up a backslash if it appears in the first
03752                            * character position
03753                            */
03754                           data->name = nsAutoString('\\');
03755                           data->name.Append(field);
03756 
03757                         } else {
03758                           data->name = field;
03759                         }
03760                         data->isPassword = isPassword;
03761                         signonData->AppendElement(data);
03762                         if (passwordcount == 0 && !OKToPrompt) {
03763                           /* get schema from field */
03764                           nsCAutoString schema;
03765                           nsVoidArray* dummy;
03766                           nsCAutoString stripField;
03767 
03768                           /* try to get schema from displayable text */
03769                           if (schema.IsEmpty()) {
03770                             wallet_GetSchemaFromDisplayableText(inputElement, schema, PR_FALSE);
03771                           }
03772 
03773                           /* no schema found, so try to get it from field name */
03774                           if (schema.IsEmpty()) {
03775                             Strip(field, stripField);
03776                             wallet_ReadFromList
03777                               (stripField, schema, 
03778                                dummy, wallet_FieldToSchema_list, PR_FALSE);
03779                           }
03780 
03781                           /* if schema found, see if it is in distinguished schema list */
03782                           if (!schema.IsEmpty()) {
03783                             /* see if schema is in distinguished list */
03784                             wallet_MapElement * mapElementPtr;
03785                             PRInt32 count = LIST_COUNT(wallet_DistinguishedSchema_list);
03786                             /* test for at least two distinguished schemas and no passwords */
03787                             for (PRInt32 i=0; i<count; i++) {
03788                               mapElementPtr = NS_STATIC_CAST
03789                                 (wallet_MapElement*, wallet_DistinguishedSchema_list->ElementAt(i));
03790                                   if (schema.Equals(mapElementPtr->item1, nsCaseInsensitiveCStringComparator()) && !value.IsEmpty()) {
03791                                 hits++;
03792                                 if (hits > 1 && newValueFound) {
03793                                   OKToPrompt = PR_TRUE;
03794                                   break;
03795                                 }
03796                               }
03797                             }
03798                           }
03799                         }
03800                       }
03801                     }
03802                   }
03803                 }
03804               }
03805             }
03806           }
03807 
03808           /* save login if appropriate */
03809           if (currentFormNode == formNode) {
03810             nsCOMPtr<nsIPrompt> dialog;
03811             nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
03812             if (wwatch)
03813               wwatch->GetNewPrompter(0, getter_AddRefs(dialog));
03814 
03815             if (dialog) {
03816               SINGSIGN_RememberSignonData(dialog, docURL, signonData, window);
03817             }
03818           }
03819           PRInt32 count2 = signonData->Count();
03820           for (PRInt32 i=count2-1; i>=0; i--) {
03821             data = NS_STATIC_CAST(si_SignonDataStruct*, signonData->ElementAt(i));
03822             delete data;
03823           }
03824           delete signonData;
03825 
03826           /* save form if it meets all necessary conditions */
03827           if (wallet_GetFormsCapturingPref() &&
03828               (OKToPrompt) && wallet_OKToCapture(strippedURLNameUTF8, window)) {
03829 
03830             /* give caveat if this is the first time data is being captured */
03831             Wallet_GiveCaveat(window, nsnull);
03832   
03833             /* conditions all met, now save it */
03834             for (PRUint32 elementY = 0; elementY < numElements; elementY++) {
03835               nsIDOMNode* elementNode = nsnull;
03836               elements->Item(elementY, &elementNode);
03837               if (nsnull != elementNode) {
03838                 wallet_CaptureInputElement(elementNode, doc);
03839                 wallet_CaptureSelectElement(elementNode, doc);
03840               }
03841             }
03842           }
03843         }
03844       }
03845     }
03846   }
03847 }