1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
45 #include "nsNetUtil.h"
46 #include "nsILineInputStream.h"
47 #include "nsReadableUtils.h"
48 #include "nsUnicharUtils.h"
49 #include "nsILocalFile.h"
51 #include "nsIServiceManager.h"
52 #include "nsIDocument.h"
53 #include "nsIDOMHTMLDocument.h"
54 #include "nsIDOMHTMLCollection.h"
55 #include "nsIDOMHTMLFormElement.h"
56 #include "nsIDOMHTMLInputElement.h"
57 #include "nsIDOMHTMLSelectElement.h"
58 #include "nsIDOMHTMLOptionElement.h"
60 #include "nsIDOMWindowCollection.h"
61 #include "nsIPrompt.h"
62 #include "nsIWindowWatcher.h"
64 #include "nsAppDirectoryServiceDefs.h"
66 #include "nsIStringBundle.h"
69 #include "nsIContent.h"
70 #include "nsIObserverService.h"
72 #include "nsIWalletService.h"
81 // To enable logging (see prlog.h for full details):
83 // set NSPR_LOG_MODULES=nsWallet:5
84 // set NSPR_LOG_FILE=nspr.log
86 PRLogModuleInfo
* gWalletLog
= nsnull
;
89 /********************************************************/
90 /* The following data and procedures are for preference */
91 /********************************************************/
93 static const char pref_Caveat
[] = "wallet.caveat";
94 static const char pref_captureForms
[] = "wallet.captureForms";
95 static const char pref_enabled
[] = "wallet.enabled";
96 static const char pref_WalletSchemaValueFileName
[] = "wallet.SchemaValueFileName";
98 static PRBool wallet_captureForms
= PR_FALSE
;
101 wallet_SetFormsCapturingPref(PRBool x
)
103 /* do nothing if new value of pref is same as current value */
104 if (x
== wallet_captureForms
) {
108 /* change the pref */
109 wallet_captureForms
= x
;
113 wallet_FormsCapturingPrefChanged(const char * newpref
, void * data
)
116 x
= SI_GetBoolPref(pref_captureForms
, PR_TRUE
);
117 wallet_SetFormsCapturingPref(x
);
118 return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */
122 wallet_RegisterCapturePrefCallbacks(void)
125 static PRBool first_time
= PR_TRUE
;
129 first_time
= PR_FALSE
;
130 x
= SI_GetBoolPref(pref_captureForms
, PR_TRUE
);
131 wallet_SetFormsCapturingPref(x
);
132 SI_RegisterCallback(pref_captureForms
, wallet_FormsCapturingPrefChanged
, NULL
);
137 wallet_GetFormsCapturingPref(void)
139 wallet_RegisterCapturePrefCallbacks();
140 return wallet_captureForms
;
144 wallet_GetEnabledPref(void)
146 /* This pref is not in the prefs panel. It's purpose is to remove wallet from all UI */
147 static PRBool first_time
= PR_TRUE
;
148 static PRBool enabled
= PR_TRUE
;
150 first_time
= PR_FALSE
;
151 PRBool x
= SI_GetBoolPref(pref_enabled
, PR_TRUE
);
158 /***************************************************/
159 /* The following declarations define the data base */
160 /***************************************************/
162 #define WALLET_FREE(_ptr) { nsMemory::Free((void*)_ptr); (_ptr) = nsnull; }
163 #define WALLET_FREEIF(_ptr) if (_ptr) WALLET_FREE(_ptr)
165 enum PlacementType
{DUP_IGNORE
, DUP_OVERWRITE
, DUP_BEFORE
, DUP_AFTER
, AT_END
, BY_LENGTH
};
166 #define LIST_COUNT(list) ((list) ? (list)->Count() : 0)
168 class wallet_Sublist
{
172 MOZ_COUNT_CTOR(wallet_Sublist
);
177 MOZ_COUNT_DTOR(wallet_Sublist
);
183 * The data structure below consists of mapping tables that map one item into another.
184 * The actual interpretation of the items depend on which table we are in. For
185 * example, if in the field-to-schema table, item1 is a field name and item2 is a
186 * schema name. Whereas in the schema-to-value table, item1 is a schema name and
187 * item2 is a value. Therefore this generic data structure refers to them simply as
191 class wallet_MapElement
{
193 wallet_MapElement() : itemList(nsnull
)
195 MOZ_COUNT_CTOR(wallet_MapElement
);
199 WALLET_FREEIF(item1
);
200 WALLET_FREEIF(item2
);
202 PRInt32 count
= LIST_COUNT(itemList
);
203 wallet_Sublist
* sublistPtr
;
204 for (PRInt32 i
=0; i
<count
; i
++) {
205 sublistPtr
= static_cast<wallet_Sublist
*>(itemList
->ElementAt(i
));
210 MOZ_COUNT_DTOR(wallet_MapElement
);
214 nsVoidArray
* itemList
;
217 /* Purpose of this class is to speed up startup time on the mac
219 * These strings are used over and over again inside an inner loop. Rather
220 * then allocating them and then deallocating them, they will be allocated
221 * only once and left sitting on the heap
224 class wallet_HelpMac
{
227 MOZ_COUNT_CTOR(wallet_HelpMac
);
230 MOZ_COUNT_DTOR(wallet_HelpMac
);
236 wallet_HelpMac
* helpMac
;
238 static nsVoidArray
* wallet_FieldToSchema_list
= 0;
239 static nsVoidArray
* wallet_VcardToSchema_list
= 0;
240 static nsVoidArray
* wallet_SchemaToValue_list
= 0;
241 static nsVoidArray
* wallet_SchemaConcat_list
= 0;
242 static nsVoidArray
* wallet_SchemaStrings_list
= 0;
243 static nsVoidArray
* wallet_PositionalSchema_list
= 0;
244 static nsVoidArray
* wallet_StateSchema_list
= 0;
245 static nsVoidArray
* wallet_URL_list
= 0;
246 static nsVoidArray
* wallet_DistinguishedSchema_list
= 0;
248 #define NO_CAPTURE(x) x[0]
249 #define NO_PREVIEW(x) x[1]
251 class wallet_PrefillElement
{
253 wallet_PrefillElement() : inputElement(nsnull
), selectElement(nsnull
)
256 MOZ_COUNT_CTOR(wallet_PrefillElement
);
258 ~wallet_PrefillElement()
260 WALLET_FREEIF(schema
);
261 NS_IF_RELEASE(inputElement
);
262 NS_IF_RELEASE(selectElement
);
263 MOZ_COUNT_DTOR(wallet_PrefillElement
);
265 nsIDOMHTMLInputElement
* inputElement
;
266 nsIDOMHTMLSelectElement
* selectElement
;
273 nsIURI
* wallet_lastUrl
= NULL
;
275 /***********************************************************/
276 /* The following routines are for diagnostic purposes only */
277 /***********************************************************/
283 fprintf(stdout
,"%cpress y to continue\n", '\007');
287 if (tolower(c
) == 'y') {
288 fprintf(stdout
,"OK\n");
298 wallet_DumpAutoString(const nsString
& as
){
299 fprintf(stdout
, "%s\n", NS_LossyConvertUTF16toASCII(as
).get());
303 wallet_Dump(nsVoidArray
* list
) {
304 wallet_MapElement
* mapElementPtr
;
305 PRInt32 count
= LIST_COUNT(list
);
306 for (PRInt32 i
=0; i
<count
; i
++) {
307 mapElementPtr
= static_cast<wallet_MapElement
*>(list
->ElementAt(i
));
308 fprintf(stdout
, "%s %s \n", (mapElementPtr
->item1
), (mapElementPtr
->item2
));
309 wallet_Sublist
* sublistPtr
;
310 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
311 for (PRInt32 i2
=0; i2
<count2
; i2
++) {
312 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(i2
));
313 fprintf(stdout
, " %s \n", (sublistPtr
->item
));
319 /******************************************************************/
320 /* The following diagnostic routines are for timing purposes only */
321 /******************************************************************/
323 const PRInt32 timing_max
= 1000;
324 PRInt64 timings
[timing_max
];
325 char timingID
[timing_max
];
326 PRInt32 timing_index
= 0;
328 PRInt64 stopwatch
= LL_Zero();
329 PRInt64 stopwatchBase
;
330 PRBool stopwatchRunning
= PR_FALSE
;
333 wallet_ClearTiming() {
335 LL_I2L(timings
[timing_index
++], PR_IntervalNow());
339 wallet_DumpTiming() {
342 for (i
=1; i
<timing_index
; i
++) {
343 LL_SUB(r1
, timings
[i
], timings
[i
-1]);
347 fprintf(stdout
, "time %c = %ld\n", timingID
[i
], (long)r4
);
356 wallet_AddTiming(char c
) {
357 if (timing_index
<timing_max
) {
358 timingID
[timing_index
] = c
;
359 // note: PR_IntervalNow returns a 32 bit value!
360 LL_I2L(timings
[timing_index
++], PR_IntervalNow());
365 wallet_ClearStopwatch() {
366 stopwatch
= LL_Zero();
367 stopwatchRunning
= PR_FALSE
;
371 wallet_ResumeStopwatch() {
372 if (!stopwatchRunning
) {
373 // note: PR_IntervalNow returns a 32 bit value!
374 LL_I2L(stopwatchBase
, PR_IntervalNow());
375 stopwatchRunning
= PR_TRUE
;
380 wallet_PauseStopwatch() {
382 if (stopwatchRunning
) {
383 // note: PR_IntervalNow returns a 32 bit value!
384 LL_I2L(r1
, PR_IntervalNow());
385 LL_SUB(r2
, r1
, stopwatchBase
);
386 LL_ADD(stopwatch
, stopwatch
, r2
);
387 stopwatchRunning
= PR_FALSE
;
392 wallet_DumpStopwatch() {
395 if (stopwatchRunning
) {
396 // note: PR_IntervalNow returns a 32 bit value!
397 LL_I2L(r1
, PR_IntervalNow());
398 LL_SUB(r2
, r1
, stopwatchBase
);
399 LL_ADD(stopwatch
, stopwatch
, r2
);
400 LL_I2L(stopwatchBase
, PR_IntervalNow());
403 LL_DIV(r2
, stopwatch
, r1
);
405 fprintf(stdout
, "stopwatch = %ld\n", (long)r3
);
407 #endif /* DEBUG_morse */
410 /*************************************************************************/
411 /* The following routines are used for accessing strings to be localized */
412 /*************************************************************************/
414 #define PROPERTIES_URL "chrome://communicator/locale/wallet/wallet.properties"
417 Wallet_Localize(const char* genericString
) {
421 /* create a bundle for the localization */
422 nsCOMPtr
<nsIStringBundleService
> pStringService
= do_GetService(NS_STRINGBUNDLE_CONTRACTID
, &ret
);
423 if (NS_FAILED(ret
)) {
425 printf("cannot get string service\n");
427 return ToNewUnicode(v
);
429 nsCOMPtr
<nsIStringBundle
> bundle
;
430 ret
= pStringService
->CreateBundle(PROPERTIES_URL
, getter_AddRefs(bundle
));
431 if (NS_FAILED(ret
)) {
433 printf("cannot create instance\n");
435 return ToNewUnicode(v
);
438 /* localize the given string */
439 NS_ConvertASCIItoUTF16
strtmp(genericString
);
440 PRUnichar
*ptrv
= nsnull
;
441 ret
= bundle
->GetStringFromName(strtmp
.get(), &ptrv
);
442 if (NS_FAILED(ret
)) {
444 printf("cannot get string from name\n");
446 return ToNewUnicode(v
);
451 /* convert # to newlines */
453 for (i
=0; i
<v
.Length(); i
++) {
454 if (v
.CharAt(i
) == '#') {
455 v
.SetCharAt('\n', i
);
459 return ToNewUnicode(v
);
463 /**********************/
464 /* Modal dialog boxes */
465 /**********************/
468 Wallet_Confirm(PRUnichar
* szMessage
, nsIDOMWindowInternal
* window
)
470 PRBool retval
= PR_TRUE
; /* default value */
473 nsCOMPtr
<nsIPrompt
> dialog
;
474 window
->GetPrompter(getter_AddRefs(dialog
));
479 const nsAutoString
message( szMessage
);
480 retval
= PR_FALSE
; /* in case user exits dialog by clicking X */
481 res
= dialog
->Confirm(nsnull
, message
.get(), &retval
);
486 Wallet_ConfirmYN(PRUnichar
* szMessage
, nsIDOMWindowInternal
* window
) {
488 nsCOMPtr
<nsIPrompt
> dialog
;
489 window
->GetPrompter(getter_AddRefs(dialog
));
494 PRInt32 buttonPressed
= 1; /* in case user exits dialog by clickin X */
495 PRUnichar
* confirm_string
= Wallet_Localize("Confirm");
497 res
= dialog
->ConfirmEx(confirm_string
, szMessage
, nsIPrompt::STD_YES_NO_BUTTONS
,
498 nsnull
, nsnull
, nsnull
, nsnull
, nsnull
, &buttonPressed
);
500 WALLET_FREE(confirm_string
);
501 return (buttonPressed
== 0);
505 Wallet_3ButtonConfirm(PRUnichar
* szMessage
, nsIDOMWindowInternal
* window
)
508 nsCOMPtr
<nsIPrompt
> dialog
;
509 window
->GetPrompter(getter_AddRefs(dialog
));
511 return 0; /* default value is NO */
514 PRInt32 buttonPressed
= 1; /* default of NO if user exits dialog by clickin X */
515 PRUnichar
* never_string
= Wallet_Localize("Never");
516 PRUnichar
* confirm_string
= Wallet_Localize("Confirm");
518 res
= dialog
->ConfirmEx(confirm_string
, szMessage
,
519 nsIPrompt::BUTTON_POS_1_DEFAULT
+
520 nsIPrompt::STD_YES_NO_BUTTONS
+
521 (nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_2
),
522 nsnull
, nsnull
, never_string
, nsnull
, nsnull
, &buttonPressed
);
524 WALLET_FREE(never_string
);
525 WALLET_FREE(confirm_string
);
527 return buttonPressed
;
531 wallet_Alert(PRUnichar
* szMessage
, nsIDOMWindowInternal
* window
)
534 nsCOMPtr
<nsIPrompt
> dialog
;
535 window
->GetPrompter(getter_AddRefs(dialog
));
537 return; // XXX should return the error
540 const nsAutoString
message( szMessage
);
541 PRUnichar
* title
= Wallet_Localize("CaveatTitle");
542 res
= dialog
->Alert(title
, message
.get());
544 return; // XXX should return the error
548 wallet_Alert(PRUnichar
* szMessage
, nsIPrompt
* dialog
)
551 const nsAutoString
message( szMessage
);
552 PRUnichar
* title
= Wallet_Localize("CaveatTitle");
553 res
= dialog
->Alert(title
, message
.get());
555 return; // XXX should return the error
559 Wallet_CheckConfirmYN
560 (PRUnichar
* szMessage
, PRUnichar
* szCheckMessage
, PRBool
* checkValue
,
561 nsIDOMWindowInternal
* window
) {
563 nsCOMPtr
<nsIPrompt
> dialog
;
564 window
->GetPrompter(getter_AddRefs(dialog
));
569 PRInt32 buttonPressed
= 1; /* in case user exits dialog by clickin X */
570 PRUnichar
* confirm_string
= Wallet_Localize("Confirm");
572 res
= dialog
->ConfirmEx(confirm_string
, szMessage
, nsIPrompt::STD_YES_NO_BUTTONS
,
573 nsnull
, nsnull
, nsnull
, szCheckMessage
, checkValue
, &buttonPressed
);
575 if (NS_FAILED(res
)) {
578 if (*checkValue
!=0 && *checkValue
!=1) {
579 NS_ASSERTION(PR_FALSE
, "Bad result from checkbox");
580 *checkValue
= 0; /* this should never happen but it is happening!!! */
582 WALLET_FREE(confirm_string
);
583 return (buttonPressed
== 0);
587 /*******************************************************/
588 /* The following routines are for Encyption/Decryption */
589 /*******************************************************/
591 #include "nsISecretDecoderRing.h"
592 nsISecretDecoderRing
* gSecretDecoderRing
= nsnull
;
593 PRBool gEncryptionFailure
= PR_FALSE
;
594 PRInt32 gReencryptionLevel
= 0;
597 wallet_CryptSetup() {
598 if (!gSecretDecoderRing
)
600 /* Get a secret decoder ring */
602 nsCOMPtr
<nsISecretDecoderRing
> secretDecoderRing
603 = do_CreateInstance("@mozilla.org/security/sdr;1", &rv
);
605 return NS_ERROR_FAILURE
;
607 gSecretDecoderRing
= secretDecoderRing
.get();
608 NS_ADDREF(gSecretDecoderRing
);
614 #include "plbase64.h"
616 static nsresult
EncryptString (const char * text
, char *& crypt
) {
618 /* use SecretDecoderRing if encryption pref is set */
620 if (SI_GetBoolPref(pref_Crypto
, PR_FALSE
)) {
621 rv
= wallet_CryptSetup();
622 if (NS_SUCCEEDED(rv
)) {
623 rv
= gSecretDecoderRing
->EncryptString(text
, &crypt
);
626 gEncryptionFailure
= PR_TRUE
;
631 /* otherwise do our own obscuring using Base64 encoding */
632 char * crypt0
= PL_Base64Encode(text
, 0, NULL
);
634 return NS_ERROR_FAILURE
;
636 PRUint32 PREFIX_len
= sizeof (PREFIX
) - 1;
637 PRUint32 crypt0_len
= PL_strlen(crypt0
);
638 crypt
= (char *)PR_Malloc(PREFIX_len
+ crypt0_len
+ 1);
640 for (i
=0; i
<PREFIX_len
; i
++) {
641 crypt
[i
] = PREFIX
[i
];
643 for (i
=0; i
<crypt0_len
; i
++) {
644 crypt
[PREFIX_len
+i
] = crypt0
[i
];
646 crypt
[PREFIX_len
+ crypt0_len
] = '\0';
652 static nsresult
DecryptString (const char * crypt
, char *& text
) {
654 /* treat zero-length crypt string as a special case */
655 if (crypt
[0] == '\0') {
656 text
= (char *)PR_Malloc(1);
661 /* use SecretDecoderRing if crypt doesn't starts with prefix */
662 if (crypt
[0] != PREFIX
[0]) {
663 if ((gReencryptionLevel
== 0) && !SI_GetBoolPref(pref_Crypto
, PR_FALSE
)) {
665 * User's data is encrypted but pref says it's not.
666 * This should never occur but it has been observed.
667 * Consequence of it happening is that user will be asked for master password
668 * when doing such mundane things as opening edit menu or context menu.
670 * Note that we do not want to make this test if we are in the middle of
671 * reencypting the entire database (i.e., while execute wallet_ReencryptAll).
672 * In that case the pref has already been changed and this test will always
673 * fail. That is why we test the gReencryptionLevel indicator.
675 NS_ASSERTION(PR_FALSE
, "wallet.crypto pref is set incorrectly");
676 return NS_ERROR_FAILURE
;
678 nsresult rv
= wallet_CryptSetup();
679 if (NS_SUCCEEDED(rv
)) {
680 rv
= gSecretDecoderRing
->DecryptString(crypt
, &text
);
683 gEncryptionFailure
= PR_TRUE
;
688 /* otherwise do our own de-obscuring */
690 PRUint32 PREFIX_len
= sizeof(PREFIX
) - 1;
691 if (PL_strlen(crypt
) == PREFIX_len
) {
692 text
= (char *)PR_Malloc(1);
696 text
= PL_Base64Decode(&crypt
[PREFIX_len
], 0, NULL
);
698 return NS_ERROR_FAILURE
;
704 WLLT_ExpirePassword(PRBool
* status
) {
705 if (gSecretDecoderRing
) {
706 gSecretDecoderRing
->LogoutAndTeardown();
712 WLLT_ExpirePasswordOnly(PRBool
* status
) {
713 nsresult rv
= wallet_CryptSetup();
714 if (NS_SUCCEEDED(rv
)) {
715 rv
= gSecretDecoderRing
->Logout();
717 *status
= NS_SUCCEEDED(rv
);
720 PRBool changingPassword
= PR_FALSE
;
723 WLLT_ChangePassword(PRBool
* status
) {
724 nsresult rv
= wallet_CryptSetup();
725 if (NS_SUCCEEDED(rv
)) {
726 changingPassword
= PR_TRUE
;
727 rv
= gSecretDecoderRing
->ChangePassword();
728 changingPassword
= PR_FALSE
;
730 *status
= NS_SUCCEEDED(rv
);
734 wallet_Encrypt(const nsCString
& text
, nsCString
& crypt
) {
736 /* encrypt text to crypt */
737 char * cryptCString
= nsnull
;
738 nsresult rv
= EncryptString(text
.get(), cryptCString
);
742 crypt
= cryptCString
;
743 WALLET_FREE(cryptCString
);
748 wallet_Decrypt(const nsCString
& crypt
, nsCString
& text
) {
750 /* decrypt crypt to text */
751 char * textCString
= nsnull
;
752 nsresult rv
= DecryptString(crypt
.get(), textCString
);
758 WALLET_FREE(textCString
);
763 Wallet_Encrypt (const nsAString
& textUCS2
, nsAString
& cryptUCS2
) {
764 nsCAutoString cryptUTF8
;
765 nsresult rv
= wallet_Encrypt(NS_ConvertUTF16toUTF8(textUCS2
), cryptUTF8
);
766 CopyUTF8toUTF16(cryptUTF8
, cryptUCS2
);
771 Wallet_Decrypt(const nsAString
& cryptUCS2
, nsAString
& textUCS2
) {
772 nsCAutoString textUTF8
;
773 nsresult rv
= wallet_Decrypt(NS_ConvertUTF16toUTF8(cryptUCS2
), textUTF8
);
774 CopyUTF8toUTF16(textUTF8
, textUCS2
);
779 /**********************************************************/
780 /* The following routines are for accessing the data base */
781 /**********************************************************/
784 * clear out the designated list
787 wallet_Clear(nsVoidArray
** list
) {
788 if (*list
== wallet_SchemaToValue_list
|| *list
== wallet_URL_list
) {
789 /* the other lists were allocated in blocks and need to be deallocated the same way */
790 wallet_MapElement
* mapElementPtr
;
791 PRInt32 count
= LIST_COUNT((*list
));
792 for (PRInt32 i
=count
-1; i
>=0; i
--) {
793 mapElementPtr
= static_cast<wallet_MapElement
*>((*list
)->ElementAt(i
));
794 delete mapElementPtr
;
802 * allocate another mapElement
803 * We are going to buffer up allocations because it was found that alocating one
804 * element at a time was very inefficient on the mac
807 static nsVoidArray
* wallet_MapElementAllocations_list
= 0;
808 const PRInt32 kAllocBlockElems
= 500;
809 static PRInt32 wallet_NextAllocSlot
= kAllocBlockElems
;
812 wallet_AllocateMapElement(wallet_MapElement
*& mapElement
) {
813 static wallet_MapElement
* mapElementTable
;
814 if (wallet_NextAllocSlot
>= kAllocBlockElems
) {
815 mapElementTable
= new wallet_MapElement
[kAllocBlockElems
];
816 if (!mapElementTable
) {
817 return NS_ERROR_OUT_OF_MEMORY
;
819 if(!wallet_MapElementAllocations_list
) {
820 wallet_MapElementAllocations_list
= new nsVoidArray();
822 if(wallet_MapElementAllocations_list
) {
823 wallet_MapElementAllocations_list
->AppendElement(mapElementTable
);
825 wallet_NextAllocSlot
= 0;
827 mapElement
= &mapElementTable
[wallet_NextAllocSlot
++];
832 wallet_DeallocateMapElements() {
833 wallet_MapElement
* mapElementPtr
;
834 PRInt32 count
= LIST_COUNT(wallet_MapElementAllocations_list
);
836 // initialize remainder of last allocated block so we don't crash on []delete
837 for (PRInt32 j
=wallet_NextAllocSlot
; j
<kAllocBlockElems
; j
++) {
839 static_cast<wallet_MapElement
*>
840 ((wallet_MapElementAllocations_list
)->ElementAt(count
-1));
841 mapElementPtr
[j
].item1
= nsnull
;
842 mapElementPtr
[j
].item2
= nsnull
;
843 mapElementPtr
[j
].itemList
= nsnull
;
846 for (PRInt32 i
=count
-1; i
>=0; i
--) {
848 static_cast<wallet_MapElement
*>((wallet_MapElementAllocations_list
)->ElementAt(i
));
849 delete [] mapElementPtr
;
851 delete wallet_MapElementAllocations_list
;
852 wallet_MapElementAllocations_list
= nsnull
;
853 wallet_NextAllocSlot
= kAllocBlockElems
;
858 * add an entry to the designated list
864 nsVoidArray
* itemList
,
867 PlacementType placement
= DUP_BEFORE
) {
869 wallet_MapElement
* mapElementPtr
;
870 PRBool added_to_list
= PR_FALSE
;
872 wallet_MapElement
* mapElement
= nsnull
;
873 if (list
== wallet_FieldToSchema_list
|| list
== wallet_SchemaStrings_list
||
874 list
== wallet_PositionalSchema_list
|| list
== wallet_StateSchema_list
||
875 list
== wallet_SchemaConcat_list
|| list
== wallet_DistinguishedSchema_list
||
876 list
== wallet_VcardToSchema_list
) {
877 wallet_AllocateMapElement(mapElement
);
879 mapElement
= new wallet_MapElement
;
885 nsCAutoString
item1UTF8(item1
); ToLowerCase(item1UTF8
);
886 mapElement
->item1
= ToNewCString(item1UTF8
);
887 mapElement
->item2
= PL_strdup(item2
);
890 char * crypt
= nsnull
;
891 if (NS_FAILED(EncryptString(mapElement
->item2
, crypt
))) {
895 WALLET_FREEIF(mapElement
->item2
);
896 mapElement
->item2
= crypt
;
899 /* make sure the list exists */
901 list
= new nsVoidArray();
908 mapElement
->itemList
= itemList
;
909 // note: we didn't want to assign itemList sooner because if we delete mapElement
910 // above, we would be wiping out the itemList input parameter
913 * Add new entry to the list in alphabetical order by item1.
914 * If identical value of item1 exists, use "placement" parameter to
915 * determine what to do
917 if (AT_END
==placement
) {
918 list
->AppendElement(mapElement
);
921 PRInt32 count
= LIST_COUNT(list
);
922 for (PRInt32 i
=0; i
<count
; i
++) {
923 mapElementPtr
= static_cast<wallet_MapElement
*>(list
->ElementAt(i
));
924 if (BY_LENGTH
==placement
) {
925 if (LIST_COUNT(mapElementPtr
->itemList
) < LIST_COUNT(itemList
)) {
926 list
->InsertElementAt(mapElement
, i
);
927 added_to_list
= PR_TRUE
;
929 } else if (LIST_COUNT(mapElementPtr
->itemList
) == LIST_COUNT(itemList
)) {
931 wallet_Sublist
* sublistPtr
;
932 wallet_Sublist
* sublistPtr2
;
933 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(0));
934 sublistPtr2
= static_cast<wallet_Sublist
*>(itemList
->ElementAt(0));
935 if(PL_strlen(sublistPtr
->item
) < PL_strlen(sublistPtr2
->item
)) {
936 list
->InsertElementAt(mapElement
, i
);
937 added_to_list
= PR_TRUE
;
940 } else if (PL_strlen(mapElementPtr
->item2
) < PL_strlen(mapElement
->item2
)) {
941 list
->InsertElementAt(mapElement
, i
);
942 added_to_list
= PR_TRUE
;
946 } else if(!PL_strcmp(mapElementPtr
->item1
, mapElement
->item1
)) {
947 if (DUP_OVERWRITE
==placement
) {
948 mapElementPtr
->item2
= PL_strdup(item2
);
949 mapElementPtr
->itemList
= itemList
;
950 mapElement
->itemList
= nsnull
; // else delete might delete itemList input parameter
952 } else if (DUP_BEFORE
==placement
) {
953 list
->InsertElementAt(mapElement
, i
);
955 if (DUP_AFTER
!=placement
) {
956 added_to_list
= PR_TRUE
;
959 } else if(PL_strcmp(mapElementPtr
->item1
, mapElement
->item1
)>=0) {
960 list
->InsertElementAt(mapElement
, i
);
961 added_to_list
= PR_TRUE
;
965 if (!added_to_list
) {
966 list
->AppendElement(mapElement
);
972 * fetch an entry from the designated list
976 const nsACString
& item1
,
978 nsVoidArray
*& itemList
,
983 if (!list
|| (index
== -1)) {
987 /* find item1 in the list */
988 wallet_MapElement
* mapElementPtr
;
989 PRInt32 count
= LIST_COUNT(list
);
990 for (PRInt32 i
=index
; i
<count
; i
++) {
991 mapElementPtr
= static_cast<wallet_MapElement
*>(list
->ElementAt(i
));
992 if(item1
.Equals(mapElementPtr
->item1
, nsCaseInsensitiveCStringComparator())) {
994 char * plaintext
= nsnull
;
995 if (NS_FAILED(DecryptString(mapElementPtr
->item2
, plaintext
))) {
1000 item2
= mapElementPtr
->item2
;
1002 itemList
= mapElementPtr
->itemList
;
1004 if (index
== count
) {
1015 wallet_ReadFromList(
1016 const nsACString
& item1
,
1018 nsVoidArray
*& itemList
,
1023 return wallet_ReadFromList(item1
, item2
, itemList
, list
, obscure
, index
);
1027 /************************************************************/
1028 /* The following routines are for unlocking the stored data */
1029 /************************************************************/
1031 char* schemaValueFileName
= nsnull
;
1033 static const char URLFileName
[] = "URL.tbl";
1034 static const char allFileName
[] = "wallet.tbl";
1035 static const char fieldSchemaFileName
[] = "FieldSchema.tbl";
1036 static const char vcardSchemaFileName
[] = "VcardSchema.tbl";
1037 static const char schemaConcatFileName
[] = "SchemaConcat.tbl";
1038 static const char schemaStringsFileName
[] = "SchemaStrings.tbl";
1039 static const char positionalSchemaFileName
[] = "PositionalSchema.tbl";
1040 static const char stateSchemaFileName
[] = "StateSchema.tbl";
1041 static const char distinguishedSchemaFileName
[] = "DistinguishedSchema.tbl";
1044 /******************************************************/
1045 /* The following routines are for accessing the files */
1046 /******************************************************/
1048 nsresult
Wallet_ProfileDirectory(nsIFile
** aFile
) {
1049 /* return the profile */
1050 return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
, aFile
);
1053 nsresult
Wallet_DefaultsDirectory(nsIFile
** aFile
) {
1056 nsCOMPtr
<nsIFile
> file
;
1058 res
= NS_GetSpecialDirectory(NS_APP_DEFAULTS_50_DIR
, getter_AddRefs(file
));
1059 if (NS_FAILED(res
)) return res
;
1060 res
= file
->AppendNative(NS_LITERAL_CSTRING("wallet"));
1061 if (NS_FAILED(res
)) return res
;
1063 NS_ADDREF(*aFile
= file
);
1068 Wallet_RandomName(char* suffix
)
1070 /* pick the current time as the random number */
1071 time_t curTime
= time(NULL
);
1073 /* take 8 least-significant digits + three-digit suffix as the file name */
1075 PR_snprintf(name
, 13, "%lu.%s", ((int)curTime
%100000000), suffix
);
1076 return PL_strdup(name
);
1080 * get a line from a file. stream must implement nsILineInputStream.
1081 * return error if end of file reached
1082 * strip carriage returns and line feeds from end of line
1083 * free with nsMemory::Free
1087 wallet_GetLine(nsIInputStream
* strm
, nsACString
&line
)
1091 nsCOMPtr
<nsILineInputStream
> lis(do_QueryInterface(strm
));
1092 NS_ENSURE_TRUE(lis
, NS_ERROR_UNEXPECTED
);
1095 nsresult rv
= lis
->ReadLine(line
, &more
);
1099 // Assume that we are past EOF if more==FALSE and line is empty
1100 // this may be wrong if the file ends with an empty line, though
1101 if (!more
&& line
.IsEmpty())
1102 return NS_ERROR_FAILURE
;
1108 wallet_GetHeader(nsIInputStream
* strm
)
1110 nsCAutoString format
;
1112 /* format revision number */
1113 if (NS_FAILED(wallet_GetLine(strm
, format
))) {
1116 return format
.EqualsLiteral(HEADER_VERSION
);
1120 * Write a line-feed to a file
1123 wallet_EndLine(nsIOutputStream
* strm
) {
1124 static const char nl
= '\n';
1126 strm
->Write(&nl
, 1, &dummy
);
1130 * Write a line to a file
1133 wallet_PutLine(nsIOutputStream
* strm
, const char* line
) {
1135 strm
->Write(line
, strlen(line
), &dummy
);
1136 wallet_EndLine(strm
);
1140 wallet_PutHeader(nsIOutputStream
* strm
) {
1142 /* format revision number */
1143 wallet_PutLine(strm
, HEADER_VERSION
);
1146 #define WALLET_NULL(_ptr) (!(_ptr) || !(_ptr)[0])
1149 * write contents of designated list into designated file
1152 wallet_WriteToFile(const char * filename
, nsVoidArray
* list
) {
1153 wallet_MapElement
* mapElementPtr
;
1155 /* make sure the list exists */
1161 /* open output stream */
1162 nsCOMPtr
<nsIFile
> file
;
1163 nsresult rv
= Wallet_ProfileDirectory(getter_AddRefs(file
));
1164 if (NS_FAILED(rv
)) {
1168 file
->AppendNative(nsDependentCString(filename
));
1170 nsCOMPtr
<nsIOutputStream
> fileOutputStream
;
1171 rv
= NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream
),
1178 nsCOMPtr
<nsIOutputStream
> strm
;
1179 rv
= NS_NewBufferedOutputStream(getter_AddRefs(strm
), fileOutputStream
, 4096);
1183 /* put out the header */
1184 if (!PL_strcmp(filename
, schemaValueFileName
)) {
1185 wallet_PutHeader(strm
);
1188 /* traverse the list */
1189 PRInt32 count
= LIST_COUNT(list
);
1190 for (PRInt32 i
=0; i
<count
; i
++) {
1191 mapElementPtr
= static_cast<wallet_MapElement
*>(list
->ElementAt(i
));
1192 wallet_PutLine(strm
, (*mapElementPtr
).item1
);
1193 if (!WALLET_NULL((*mapElementPtr
).item2
)) {
1194 wallet_PutLine(strm
, (*mapElementPtr
).item2
);
1196 wallet_Sublist
* sublistPtr
;
1197 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
1198 for (PRInt32 j
=0; j
<count2
; j
++) {
1199 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
));
1200 wallet_PutLine(strm
, (*sublistPtr
).item
);
1203 wallet_EndLine(strm
);
1206 // All went ok. Maybe except for problems in Write(), but the stream detects
1208 nsCOMPtr
<nsISafeOutputStream
> safeStream
= do_QueryInterface(strm
);
1209 NS_ASSERTION(safeStream
, "expected a safe output stream!");
1211 rv
= safeStream
->Finish();
1212 if (NS_FAILED(rv
)) {
1213 NS_WARNING("failed to save wallet file! possible dataloss");
1220 * Read contents of designated file into designated list
1224 (const char * filename
, nsVoidArray
*& list
, PRBool localFile
, PlacementType placement
= AT_END
) {
1226 /* open input stream */
1227 nsCOMPtr
<nsIFile
> file
;
1230 rv
= Wallet_ProfileDirectory(getter_AddRefs(file
));
1232 rv
= Wallet_DefaultsDirectory(getter_AddRefs(file
));
1234 if (NS_FAILED(rv
)) {
1237 file
->AppendNative(nsDependentCString(filename
));
1238 nsCOMPtr
<nsIInputStream
> strm
;
1239 rv
= NS_NewLocalFileInputStream(getter_AddRefs(strm
), file
);
1243 /* read in the header */
1244 if (!PL_strcmp(filename
, schemaValueFileName
)) {
1245 if (!wallet_GetHeader(strm
)) {
1246 /* something's wrong -- ignore the file */
1252 if (NS_FAILED(wallet_GetLine(strm
, helpMac
->item1
))) {
1253 /* end of file reached */
1257 /* Distinguished schema list is a list of single entries, not name/value pairs */
1258 if (!PL_strcmp(filename
, distinguishedSchemaFileName
)) {
1259 nsVoidArray
* dummy
= NULL
;
1260 wallet_WriteToList(helpMac
->item1
.get(), helpMac
->item1
.get(), dummy
, list
, PR_FALSE
, placement
);
1264 if (NS_FAILED(wallet_GetLine(strm
, helpMac
->item2
))) {
1265 /* unexpected end of file reached */
1269 if (helpMac
->item2
.IsEmpty()) {
1270 /* the value must have been deleted */
1271 nsVoidArray
* dummy
= NULL
;
1272 wallet_WriteToList(helpMac
->item1
.get(), helpMac
->item2
.get(), dummy
, list
, PR_FALSE
, placement
);
1276 if (NS_FAILED(wallet_GetLine(strm
, helpMac
->item3
))) {
1277 /* end of file reached */
1278 nsVoidArray
* dummy
= NULL
;
1279 wallet_WriteToList(helpMac
->item1
.get(), helpMac
->item2
.get(), dummy
, list
, PR_FALSE
, placement
);
1283 if (helpMac
->item3
.IsEmpty()) {
1284 /* just a pair of values, no need for a sublist */
1285 nsVoidArray
* dummy
= NULL
;
1286 wallet_WriteToList(helpMac
->item1
.get(), helpMac
->item2
.get(), dummy
, list
, PR_FALSE
, placement
);
1288 /* need to create a sublist and put item2 and item3 onto it */
1290 nsVoidArray
* itemList
= new nsVoidArray();
1295 wallet_Sublist
* sublist
= new wallet_Sublist
;
1299 sublist
->item
= ToNewCString(helpMac
->item2
);
1300 itemList
->AppendElement(sublist
);
1301 sublist
= new wallet_Sublist
;
1306 sublist
->item
= ToNewCString(helpMac
->item3
);
1307 itemList
->AppendElement(sublist
);
1308 /* add any following items to sublist up to next blank line */
1310 /* get next item for sublist */
1311 if (NS_FAILED(wallet_GetLine(strm
, helpMac
->item3
))) {
1312 /* end of file reached */
1313 wallet_WriteToList(helpMac
->item1
.get(), nsnull
, itemList
, list
, PR_FALSE
, placement
);
1317 if (helpMac
->item3
.IsEmpty()) {
1318 /* blank line reached indicating end of sublist */
1319 wallet_WriteToList(helpMac
->item1
.get(), nsnull
, itemList
, list
, PR_FALSE
, placement
);
1322 /* add item to sublist */
1323 sublist
= new wallet_Sublist
;
1328 sublist
->item
= ToNewCString(helpMac
->item3
);
1329 itemList
->AppendElement(sublist
);
1336 /*********************************************************************/
1337 /* The following are utility routines for the main wallet processing */
1338 /*********************************************************************/
1341 Wallet_GiveCaveat(nsIDOMWindowInternal
* window
, nsIPrompt
* dialog
) {
1342 /* test for first capturing of data ever and give caveat if so */
1343 if (!SI_GetBoolPref(pref_Caveat
, PR_FALSE
)) {
1344 SI_SetBoolPref(pref_Caveat
, PR_TRUE
);
1345 PRUnichar
* message
= Wallet_Localize("Caveat");
1347 wallet_Alert(message
, window
);
1349 wallet_Alert(message
, dialog
);
1351 WALLET_FREE(message
);
1356 wallet_GetHostFile(nsIURI
* url
, nsString
& outHostFile
)
1358 outHostFile
.Truncate(0);
1360 nsresult rv
= url
->GetHost(host
);
1361 if (NS_FAILED(rv
)) {
1364 NS_ConvertUTF8toUTF16
urlName(host
);
1366 rv
= url
->GetPath(file
);
1367 if (NS_FAILED(rv
)) {
1370 AppendUTF8toUTF16(file
, urlName
);
1372 PRInt32 queryPos
= urlName
.FindChar('?');
1373 PRInt32 stringEnd
= (queryPos
== kNotFound
) ? urlName
.Length() : queryPos
;
1374 urlName
.Left(outHostFile
, stringEnd
);
1378 Strip(const nsString
& textUCS2
, nsCString
& stripText
) {
1379 NS_ConvertUTF16toUTF8
textUTF8(textUCS2
);
1380 // above line is equivalen to the following (who would have guessed it?)
1381 // nsCAutoString textUTF8 = NS_ConvertUTF16toUTF8(textUCS2);
1382 for (PRUint32 i
=0; i
<textUTF8
.Length(); i
++) {
1383 char c
= textUTF8
.CharAt(i
);
1384 if (nsCRT::IsAsciiAlpha(c
) || nsCRT::IsAsciiDigit(c
) || c
>'~') {
1391 * given a displayable text, get the schema
1395 const nsString
& text
,
1398 /* return if no SchemaStrings list exists */
1399 if (!wallet_SchemaStrings_list
) {
1403 /* try each schema entry in schemastring table to see if it's acceptable */
1404 wallet_MapElement
* mapElementPtr
;
1405 PRInt32 count
= LIST_COUNT(wallet_SchemaStrings_list
);
1406 for (PRInt32 i
=0; i
<count
; i
++) {
1408 /* get each string associated with this schema */
1409 PRBool isSubstring
= PR_TRUE
;
1410 mapElementPtr
= static_cast<wallet_MapElement
*>(wallet_SchemaStrings_list
->ElementAt(i
));
1411 wallet_Sublist
* sublistPtr
;
1412 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
1415 for (PRInt32 i2
=0; i2
<count2
; i2
++) {
1417 /* see if displayable text contains this string */
1418 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(i2
));
1419 if (text
.Find(sublistPtr
->item
, PR_TRUE
) == -1) {
1421 /* displayable text does not contain this string, reject this schema */
1422 isSubstring
= PR_FALSE
;
1426 } else if (text
.Find(mapElementPtr
->item2
, PR_TRUE
) == -1) {
1428 /* displayable text does not contain this string, reject this schema */
1429 isSubstring
= PR_FALSE
;
1434 /* all strings were contained in the displayable text, accept this schema */
1435 schema
.Assign(mapElementPtr
->item1
);
1442 * given a field name, get the value
1446 const nsString
& field
,
1448 nsString
& valueUCS2
,
1449 nsVoidArray
*& itemList
,
1453 /* return if no SchemaToValue list exists or if all values previous used */
1454 if (!wallet_SchemaToValue_list
|| index
== -1) {
1455 return NS_ERROR_FAILURE
;
1458 /* if no schema name is given, fetch schema name from field/schema tables */
1460 nsCAutoString stripField
;
1461 if (schema
.IsEmpty()) {
1462 Strip(field
, stripField
);
1464 if (!schema
.IsEmpty() ||
1465 wallet_ReadFromList(stripField
, schema
, dummy
, wallet_FieldToSchema_list
, PR_FALSE
)) {
1467 /* schema name found, now attempt to fetch value from schema/value table */
1468 nsCAutoString valueUTF8
;
1469 PRInt32 index2
= index
;
1472 (schema
, valueUTF8
, itemList
, wallet_SchemaToValue_list
, PR_TRUE
, index2
)) {
1473 /* value found, prefill it into form and return */
1474 CopyUTF8toUTF16(valueUTF8
, valueUCS2
);
1480 /* value not found, see if concatenation rule exists */
1481 nsVoidArray
* itemList2
;
1482 nsCAutoString valueUTF8b
;
1486 PRInt32 index0
= index
;
1487 PRInt32 index00
= index
;
1489 while (wallet_ReadFromList(schema
, valueUTF8b
, itemList2
, wallet_SchemaConcat_list
, PR_FALSE
, index4
)) {
1491 /* concatenation rules exist, generate value as a concatenation */
1492 nsCAutoString concatenatedValueUTF8
;
1493 wallet_Sublist
* sublistPtr
;
1494 concatenatedValueUTF8
.SetLength(0);
1495 nsCAutoString valueUTF8c
;
1496 PRInt32 index00max
= index0
;
1498 if (!valueUTF8b
.IsEmpty()) {
1500 /* single item on rhs of concatenation rule */
1503 PRBool failed
= PR_FALSE
;
1504 for (j
=0; j
>index0
; j
-= 2) {
1505 if (!wallet_ReadFromList(valueUTF8b
, valueUTF8c
, dummy
, wallet_SchemaToValue_list
, PR_TRUE
, index5
)) {
1512 if (!failed
&& wallet_ReadFromList(valueUTF8b
, valueUTF8c
, dummy
, wallet_SchemaToValue_list
, PR_TRUE
, index5
)) {
1514 /* found an unused value for the single rhs item */
1515 concatenatedValueUTF8
+= valueUTF8c
;
1518 index00max
= index00
;
1521 /* process each item in a multi-rhs rule */
1522 PRInt32 count
= LIST_COUNT(itemList2
);
1523 for (PRInt32 i
=0; i
<count
; i
++) {
1524 sublistPtr
= static_cast<wallet_Sublist
*>(itemList2
->ElementAt(i
));
1526 /* skip over values found previously */
1527 /* note: a returned index of -1 means not-found. So we will use the
1528 * negative even numbers (-2, -4, -6) to designate found as a concatenation
1529 * where -2 means first value of each concatenation, -4 means second value, etc.
1533 PRBool failed
= PR_FALSE
;
1534 nsCAutoString valueUTF8d
; valueUTF8d
.Assign(sublistPtr
->item
);
1535 for (PRInt32 j
=0; j
>index0
; j
-= 2) {
1536 if (!wallet_ReadFromList(valueUTF8d
, valueUTF8
, dummy
, wallet_SchemaToValue_list
, PR_TRUE
, index3
)) {
1538 /* all values of next multi-rhs item were used previously */
1545 if (!failed
&& wallet_ReadFromList(valueUTF8d
, valueUTF8
, dummy
, wallet_SchemaToValue_list
, PR_TRUE
, index3
)) {
1546 if (!concatenatedValueUTF8
.IsEmpty()) {
1547 concatenatedValueUTF8
+= " ";
1550 /* found an unused value for the multi-rhs item */
1551 concatenatedValueUTF8
+= valueUTF8
;
1554 if (index00
> index00max
) {
1555 index00max
= index00
;
1560 if (!concatenatedValueUTF8
.IsEmpty()) {
1562 /* a new value was found */
1564 CopyUTF8toUTF16(concatenatedValueUTF8
, valueUCS2
);
1568 /* all values from this concat rule were used, go on to next concat rule */
1569 index0
= index00max
;
1572 /* no more concat rules, indicate failure */
1574 return NS_ERROR_FAILURE
;
1577 /* schema name not found, use field name as schema name and fetch value */
1578 PRInt32 index2
= index
;
1580 nsAutoString localSchemaUCS2
;
1581 wallet_GetHostFile(wallet_lastUrl
, localSchemaUCS2
);
1582 localSchemaUCS2
.AppendLiteral(":");
1583 localSchemaUCS2
.Append(field
);
1584 NS_ConvertUTF16toUTF8
localSchemaUTF8(localSchemaUCS2
);
1585 nsCAutoString valueUTF8
;
1587 if (wallet_ReadFromList
1588 (localSchemaUTF8
, valueUTF8
, itemList
, wallet_SchemaToValue_list
, PR_TRUE
, index2
)) {
1589 /* value found, prefill it into form */
1590 schema
= localSchemaUTF8
;
1592 CopyUTF8toUTF16(valueUTF8
, valueUCS2
);
1597 return NS_ERROR_FAILURE
;
1601 wallet_GetSelectIndex(
1602 nsIDOMHTMLSelectElement
* selectElement
,
1603 const nsString
& value
,
1607 selectElement
->GetLength(&length
);
1608 nsCOMPtr
<nsIDOMHTMLOptionsCollection
> options
;
1609 selectElement
->GetOptions(getter_AddRefs(options
));
1611 PRUint32 numOptions
;
1612 options
->GetLength(&numOptions
);
1613 for (PRUint32 optionX
= 0; optionX
< numOptions
; optionX
++) {
1614 nsCOMPtr
<nsIDOMNode
> optionNode
;
1615 options
->Item(optionX
, getter_AddRefs(optionNode
));
1618 nsCOMPtr
<nsIDOMHTMLOptionElement
> optionElement(do_QueryInterface(optionNode
));
1620 if (optionElement
) {
1621 nsAutoString optionValue
;
1622 nsAutoString optionText
;
1623 optionElement
->GetValue(optionValue
);
1624 optionElement
->GetText(optionText
);
1625 nsAutoString
valueLC( value
);
1626 ToLowerCase(valueLC
);
1627 ToLowerCase(optionValue
);
1628 ToLowerCase(optionText
);
1629 optionText
.Trim(" \n\t\r");
1630 if (valueLC
==optionValue
|| valueLC
==optionText
) {
1638 return NS_ERROR_FAILURE
;
1642 wallet_StepForwardOrBack
1643 (nsIDOMNode
*& elementNode
, nsString
& text
, PRBool
& atInputOrSelect
, PRBool
& atEnd
, PRBool goForward
) {
1645 atInputOrSelect
= PR_FALSE
;
1648 /* try getting next/previous sibling */
1649 nsCOMPtr
<nsIDOMNode
> sibling
;
1651 result
= elementNode
->GetNextSibling(getter_AddRefs(sibling
));
1653 result
= elementNode
->GetPreviousSibling(getter_AddRefs(sibling
));
1655 if ((NS_FAILED(result
)) || !sibling
) {
1656 /* no next/previous siblings, try getting parent */
1657 nsCOMPtr
<nsIDOMNode
> parent
;
1658 result
= elementNode
->GetParentNode(getter_AddRefs(parent
));
1659 if ((NS_FAILED(result
)) || !parent
) {
1660 /* no parent, we've reached the top of the tree */
1663 /* parent obtained */
1664 elementNode
= parent
;
1668 /* sibling obtained */
1669 elementNode
= sibling
;
1673 /* if we've reached a SELECT or non-hidden INPUT tag, we're done */
1675 * There is a subtle difference here between going forward and going backwards.
1677 * When going forward we are trying to find out how many consecutive <input> elements are not separated
1678 * by displayed text. That is important for determing, for example, if we have a three-input phone-number
1679 * field. In that case, we want to consider only input tags have type="text" or no type ("text" by default).
1681 * When going backwards we want to find the text between the current <input> element and any preceding
1682 * visible <input> element. That would include such things as type="button", type="submit" etc. The
1683 * only thing it would exclude is type="hidden".
1685 nsCOMPtr
<nsIDOMHTMLInputElement
> inputElement(do_QueryInterface(elementNode
, &result
));
1686 if ((NS_SUCCEEDED(result
)) && (inputElement
)) {
1688 result
= inputElement
->GetType(type
);
1690 if (NS_SUCCEEDED(result
) &&
1692 type
.LowerCaseEqualsLiteral("text"))) {
1693 /* at <input> element and it's type is either "text" or is missing ("text" by default) */
1694 atInputOrSelect
= PR_TRUE
;
1698 if (NS_SUCCEEDED(result
) &&
1699 !type
.LowerCaseEqualsLiteral("hidden")) {
1700 /* at <input> element and it's type is not "hidden" */
1701 atInputOrSelect
= PR_TRUE
;
1706 nsCOMPtr
<nsIDOMHTMLSelectElement
> selectElement(do_QueryInterface(elementNode
));
1708 if (selectElement
) {
1709 atInputOrSelect
= PR_TRUE
;
1714 /* if we've reached a #text node, append it to accumulated text */
1715 nsAutoString siblingNameUCS2
;
1716 result
= elementNode
->GetNodeName(siblingNameUCS2
);
1717 if (siblingNameUCS2
.LowerCaseEqualsLiteral("#text")) {
1718 nsAutoString siblingValue
;
1719 result
= elementNode
->GetNodeValue(siblingValue
);
1720 text
.Append(siblingValue
);
1723 /* if we've reached a SCRIPT node, don't fetch its siblings */
1724 if (siblingNameUCS2
.LowerCaseEqualsLiteral("script")) {
1728 /* try getting first/last child */
1729 nsCOMPtr
<nsIDOMNode
> child
;
1731 result
= elementNode
->GetFirstChild(getter_AddRefs(child
));
1733 result
= elementNode
->GetLastChild(getter_AddRefs(child
));
1735 if ((NS_FAILED(result
)) || !child
) {
1736 /* no children, we're done with this node */
1739 /* child obtained */
1740 elementNode
= child
;
1746 //#include "nsIUGenCategory.h"
1747 //#include "nsUnicharUtilCIID.h"
1748 //static NS_DEFINE_IID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
1750 //#include "nsICaseConversion.h"
1751 //static nsICaseConversion* gCaseConv = nsnull;
1754 wallet_ResolvePositionalSchema(nsIDOMNode
* elementNode
, nsACString
& schema
) {
1755 static PRInt32 numerator
= 0;
1756 static PRInt32 denominator
= 0;
1757 static nsCString lastPositionalSchema
;
1759 /* return if no PositionalSchema list exists */
1760 if (!wallet_PositionalSchema_list
) {
1761 schema
.SetLength(0);
1765 if (!schema
.IsEmpty()) {
1768 lastPositionalSchema
.Assign(schema
);
1769 } else if (numerator
< denominator
) {
1770 schema
.Assign(lastPositionalSchema
);
1772 schema
.SetLength(0);
1776 /* search PositionalSchema list for our positional schema */
1777 wallet_MapElement
* mapElementPtr
;
1778 PRInt32 count
= LIST_COUNT(wallet_PositionalSchema_list
);
1779 for (PRInt32 i
=0; i
<count
; i
++) {
1780 mapElementPtr
= static_cast<wallet_MapElement
*>(wallet_PositionalSchema_list
->ElementAt(i
));
1781 if (schema
.Equals(mapElementPtr
->item1
, nsCaseInsensitiveCStringComparator())) {
1782 /* found our positional schema in the list */
1784 /* A "position set" is a set of continuous <input> or <select> fields
1785 * with no displayable text between them. For example: zipcode [ ]-[ ].
1786 * We need to determine how many elements are in the current set (denominator)
1787 * and which of those elements we are currently up to (numerator). From that
1788 * we can identify our position with the fraction x/y meaning the xth element
1789 * out of a set of y. We use that fraction when consulting the positionalSchema list
1790 * to determine which schema should be used.
1792 * So for example, the positionalSchema list for %zip might be:
1794 * 1/1 Home.PostalCode
1795 * 1/2 Home.PostalCode.Prefix
1796 * 2/2 Home.PostalCode.Suffix
1798 * The positionalSchema list also contains fractions with no denominators, for example x/.
1799 * That means the xth element out of a set of any length. These entries come last in
1800 * the positionalSchema list so they can match only if no match for a specific length is
1801 * found. As an example, the positionalSchema list for %phone might be:
1804 * 1/2 Home.Phone.LocCode
1805 * 2/2 Home.Phone.Number
1806 * 1/ Home.Phone.LocCode
1807 * 2/ Home.Phone.Number.Prefix
1808 * 3/ Home.Phone.Number.Suffix
1811 if (numerator
< denominator
) {
1813 /* this is a continuation of previous position set */
1818 /* start a new position set */
1819 numerator
= 1; /* start with first element */
1821 /* determine how many elements in current position set (denominator) */
1822 denominator
= 1; /* assume that's the only element */
1823 PRBool atInputOrSelect
= PR_FALSE
;
1824 PRBool charFound
= PR_FALSE
;
1825 while (!charFound
) {
1828 wallet_StepForwardOrBack
1829 (elementNode
, text
, atInputOrSelect
, atEnd
, PR_TRUE
); /* step forward */
1834 for (PRUint32 j
=0; j
<text
.Length(); j
++) {
1837 /* break out if an alphanumeric character is found */
1839 // nsresult res = CallGetService(kUnicharUtilCID, &gCaseConv);
1841 // nsIUGenCategory* intl = nsnull;
1842 // nsresult rv = CallGetService(kUnicharUtilCID, &intl);
1843 // Whaaaaaa, intl is never released here!
1844 // if (NS_SUCCEEDED(rv) && intl) {
1846 // rv = intl->Is(c, intl->kUGenCategory_Number, &accept);
1847 // if (NS_FAILED(rv) || !accept) {
1848 // rv = intl->Is(c, intl->kUGenCategory_Letter, &accept);
1850 // if (NS_OK(rv) && accept) {
1851 // charFound = PR_TRUE;
1855 // /* failed to get the i18n interfaces, so just treat latin characters */
1856 if (nsCRT::IsAsciiAlpha(c
) || nsCRT::IsAsciiDigit(c
)) {
1857 charFound
= PR_TRUE
;
1862 if (!charFound
&& atInputOrSelect
) {
1863 /* add one more element to position set */
1869 nsCAutoString fractionString
; /* of form 2/5 meaning 2nd in a 5-element set */
1870 nsCAutoString fractionStringWithoutDenominator
; /* of form 2/ meaning 2nd in any-length set */
1871 fractionString
.SetLength(0);
1872 fractionString
.AppendInt(numerator
);
1873 fractionString
.Append("/");
1874 fractionStringWithoutDenominator
.Assign(fractionString
);
1875 fractionString
.AppendInt(denominator
);
1877 /* use positionalSchema list to obtain schema */
1878 wallet_Sublist
* sublistPtr
;
1879 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
1880 for (PRInt32 j
=0; j
<count2
; j
=j
+2) {
1881 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
));
1883 if (!PL_strcmp(sublistPtr
->item
, fractionString
.get()) ||
1884 !PL_strcmp(sublistPtr
->item
, fractionStringWithoutDenominator
.get())) {
1885 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
+1));
1886 schema
.Assign(sublistPtr
->item
);
1894 const char* previousElementState
= nsnull
;
1895 static nsIDOMNode
* previousElementNode
;
1898 wallet_InitializeStateTesting() {
1899 previousElementNode
= nsnull
;
1900 previousElementState
= nsnull
;
1904 wallet_ResolveStateSchema(nsIDOMNode
* elementNode
, nsACString
& schema
) {
1906 /* return if no StateSchema list exists */
1907 if (!wallet_StateSchema_list
) {
1911 /* search state schema list for our state schema */
1912 wallet_MapElement
* mapElementPtr
;
1913 PRInt32 count
= LIST_COUNT(wallet_StateSchema_list
);
1914 for (PRInt32 i
=0; i
<count
; i
++) {
1915 mapElementPtr
= static_cast<wallet_MapElement
*>(wallet_StateSchema_list
->ElementAt(i
));
1916 if (schema
.Equals(mapElementPtr
->item1
, nsCaseInsensitiveCStringComparator())) {
1917 /* found our state schema in the list */
1919 /* A state-schema entry consists of a set of possible states and the schema associated
1920 * with each state. For example, for the state-schema $phone we might have
1926 * This means that if we are in the "ship" state, the schema is ShipTo.Phone, if in the
1927 * "bill" state it is BillTo.Phone, and if in no identifiable state it is Home.Phone.
1929 * So we will start stepping backwards through the dom tree
1930 * obtaining text at each step. If the text contains a substring for one of
1931 * the states, then that is the state we are in and we take the associated
1932 * schema. If the text does not contain any of the states, we continue
1933 * stepping back until we get to a preceding node for which we knew the state.
1934 * If none is found, stop when we get to the beginning of the tree.
1937 nsIDOMNode
* localElementNode
= elementNode
;
1938 PRBool atEnd
= PR_FALSE
;
1939 PRBool atInputOrSelect
= PR_FALSE
;
1942 /* get next text in the dom */
1944 wallet_StepForwardOrBack(localElementNode
, text
, atInputOrSelect
, atEnd
, PR_FALSE
);
1946 /* see if it's a node we already saved the state for */
1947 if (localElementNode
== previousElementNode
) {
1948 previousElementNode
= elementNode
;
1950 /* step through the list of states to see if any are the state of the previous Node */
1951 wallet_Sublist
* sublistPtr
;
1952 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
1954 for (j
=0; j
<count2
; j
=j
+2) {
1955 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
));
1956 if (!PL_strcasecmp(sublistPtr
->item
, previousElementState
)) {
1957 previousElementState
= sublistPtr
->item
;
1958 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
+1));
1959 schema
.Assign(sublistPtr
->item
);
1963 /* test to see if we obtained the catch-all (*) state.
1964 * Note: the catch-all must be the last entry in the list
1966 if (!PL_strcmp(sublistPtr
->item
, "*")) {
1967 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
+1));
1968 schema
.Assign(sublistPtr
->item
);
1973 /* no catch-all state specified, return no schema */
1977 /* step through the list of states to see if any are in the text */
1978 wallet_Sublist
* sublistPtr
;
1979 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
1980 for (PRInt32 j
=0; j
<count2
; j
=j
+2) {
1981 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
));
1983 /* next state obtained, test to see if it is in the text */
1984 if (text
.Find(sublistPtr
->item
, PR_TRUE
) != -1) {
1985 previousElementState
= sublistPtr
->item
;
1986 previousElementNode
= elementNode
;
1987 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
+1));
1988 schema
.Assign(sublistPtr
->item
);
1994 /* state not found, so take the catch-all (*) state */
1995 wallet_Sublist
* sublistPtr
;
1996 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
1997 for (PRInt32 j
=0; j
<count2
; j
=j
+2) {
1998 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
));
1999 if (!PL_strcmp(sublistPtr
->item
, "*")) {
2000 previousElementNode
= localElementNode
;
2001 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(j
+1));
2002 schema
.Assign(sublistPtr
->item
);
2003 previousElementNode
= elementNode
;
2008 /* no catch-all state specified, return no schema */
2009 previousElementNode
= elementNode
;
2014 /* This is an error. It means that a state-schema (entry starting with a $)
2015 * was obtained from the SchemaStrings table or the PositionalSchema table
2016 * but there was no entry for that state-schema in the StateSchema table.
2018 NS_ASSERTION(PR_FALSE
, "Undefined state in SchemaStrings table");
2022 wallet_GetSchemaFromDisplayableText
2023 (nsIDOMNode
* elementNode
, nsACString
& schema
, PRBool skipStateChecking
) {
2025 static nsCString lastSchema
;
2026 static nsIDOMNode
* lastElementNode
;
2028 /* return if this is the same as the last element node */
2029 if (elementNode
== lastElementNode
) {
2030 schema
.Assign(lastSchema
);
2033 lastElementNode
= elementNode
;
2035 nsIDOMNode
* localElementNode
= elementNode
;
2036 PRBool atInputOrSelect
= PR_FALSE
;
2037 PRBool atEnd
= PR_FALSE
;
2038 PRBool someTextFound
= PR_FALSE
;
2039 while (!atEnd
&& !atInputOrSelect
) {
2041 /* step back and get text found in a preceding node */
2043 wallet_StepForwardOrBack(localElementNode
, text
, atInputOrSelect
, atEnd
, PR_FALSE
);
2045 /* strip off non-alphanumerics */
2049 for (i
=0; i
<text
.Length(); i
++) {
2051 if (nsCRT::IsAsciiAlpha(c
) || nsCRT::IsAsciiDigit(c
)) {
2057 /* done if we've obtained enough text from which to determine the schema */
2058 if (!text
.IsEmpty()) {
2059 someTextFound
= PR_TRUE
;
2061 TextToSchema(text
, schema
);
2062 if (!schema
.IsEmpty()) {
2064 /* schema found, process positional schema if any */
2065 if (schema
.First() == '%') {
2066 wallet_ResolvePositionalSchema(elementNode
, schema
);
2069 /* process state schema if any */
2070 if (!skipStateChecking
&& !schema
.IsEmpty() && schema
.First() == '$') {
2071 wallet_ResolveStateSchema(elementNode
, schema
);
2073 lastSchema
.Assign(schema
);
2080 /* no displayable text found, see if we are inside a position set */
2081 if (!someTextFound
) {
2082 wallet_ResolvePositionalSchema(elementNode
, schema
);
2085 /* process state schema if any */
2087 /* The current routine is called for each field whose value is to be captured,
2088 * even if there is no value entered for that field. We do this because we need
2089 * to call ResolvePositionalSchema above even for null values. If we didn't
2090 * make that call, we would fail to recognize fields in a positional set if any
2091 * preceding fields in that set were blank. For example:
2093 * name (first, middle, last): [William] [ ] [Clinton]
2095 * With that said, at least we can skip the call to ResolveStateSchema in this
2096 * case. That call could be very time consuming because it involves looking
2097 * looking backwards through all preceding text (possibly all the way to the
2098 * beginning of the document) just to determine the state. That is the purpose
2099 * of the skipStateChecking argument.
2102 if (!skipStateChecking
&& !schema
.IsEmpty() && schema
.First() == '$') {
2103 wallet_ResolveStateSchema(elementNode
, schema
);
2106 lastSchema
.Assign(schema
);
2112 nsIDOMNode
* elementNode
,
2113 nsIDOMHTMLInputElement
*& inputElement
,
2114 nsIDOMHTMLSelectElement
*& selectElement
,
2117 PRInt32
& selectIndex
,
2121 nsCAutoString localSchema
; localSchema
.Assign(schema
);
2123 /* get prefills for input element */
2124 result
= elementNode
->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement
), (void**)&inputElement
);
2126 if ((NS_SUCCEEDED(result
)) && (nsnull
!= inputElement
)) {
2128 result
= inputElement
->GetType(type
);
2129 if (NS_SUCCEEDED(result
) &&
2131 type
.LowerCaseEqualsLiteral("text"))) {
2133 result
= inputElement
->GetName(field
);
2134 if (NS_SUCCEEDED(result
)) {
2135 nsVoidArray
* itemList
;
2137 /* try to get schema name from vcard attribute if it exists */
2138 if (localSchema
.IsEmpty()) {
2139 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(elementNode
);
2141 nsAutoString vcard
; vcard
.AssignLiteral("VCARD_NAME");
2142 nsAutoString vcardValueUCS2
;
2143 result
= element
->GetAttribute(vcard
, vcardValueUCS2
);
2144 if (NS_OK
== result
) {
2146 wallet_ReadFromList(NS_ConvertUTF16toUTF8(vcardValueUCS2
), localSchema
, dummy
,
2147 wallet_VcardToSchema_list
, PR_FALSE
);
2152 /* try to get schema name from displayable text if possible */
2153 if (localSchema
.IsEmpty()) {
2154 wallet_GetSchemaFromDisplayableText(inputElement
, localSchema
, PR_FALSE
);
2158 * if schema name was obtained then get value from schema name,
2159 * otherwise get value from field name by using mapping tables to get schema name
2161 if (NS_SUCCEEDED(FieldToValue(field
, localSchema
, value
, itemList
, index
))) {
2162 if (value
.IsEmpty() && nsnull
!= itemList
) {
2163 /* pick first of a set of synonymous values */
2164 const char* encryptedValue
= ((wallet_Sublist
*)itemList
->ElementAt(0))->item
;
2165 char* valueCString
= nsnull
;
2166 if (NS_FAILED(DecryptString(encryptedValue
, valueCString
))) {
2167 NS_RELEASE(inputElement
);
2168 return NS_ERROR_FAILURE
;
2170 CopyUTF8toUTF16(valueCString
, value
);
2172 selectElement
= nsnull
;
2174 schema
= localSchema
;
2179 NS_RELEASE(inputElement
);
2180 return NS_ERROR_FAILURE
;
2183 /* get prefills for dropdown list */
2184 result
= elementNode
->QueryInterface(NS_GET_IID(nsIDOMHTMLSelectElement
), (void**)&selectElement
);
2185 if ((NS_SUCCEEDED(result
)) && (nsnull
!= selectElement
)) {
2187 result
= selectElement
->GetName(field
);
2188 if (NS_SUCCEEDED(result
)) {
2190 /* try to get schema name from displayable text if possible */
2191 if (localSchema
.IsEmpty()) {
2192 wallet_GetSchemaFromDisplayableText(selectElement
, localSchema
, PR_FALSE
);
2195 nsVoidArray
* itemList
;
2196 if (NS_SUCCEEDED(FieldToValue(field
, localSchema
, value
, itemList
, index
))) {
2197 if (!value
.IsEmpty()) {
2198 /* no synonym list, just one value to try */
2199 result
= wallet_GetSelectIndex(selectElement
, value
, selectIndex
);
2200 if (NS_SUCCEEDED(result
)) {
2201 /* value matched one of the values in the drop-down list */
2203 inputElement
= nsnull
;
2204 schema
= localSchema
;
2208 /* synonym list exists, try each value */
2209 for (PRInt32 i
=0; i
<LIST_COUNT(itemList
); i
++) {
2210 CopyUTF8toUTF16(((wallet_Sublist
*)itemList
->ElementAt(i
))->item
, value
);
2211 result
= wallet_GetSelectIndex(selectElement
, value
, selectIndex
);
2212 if (NS_SUCCEEDED(result
)) {
2213 /* value matched one of the values in the drop-down list */
2215 // No Release() here?
2217 inputElement
= nsnull
;
2218 schema
= localSchema
;
2225 NS_RELEASE(selectElement
);
2227 return NS_ERROR_FAILURE
;
2231 * termination for wallet session
2234 Wallet_ReleaseAllLists() {
2235 wallet_Clear(&wallet_FieldToSchema_list
); /* otherwise we will duplicate the list */
2236 wallet_Clear(&wallet_VcardToSchema_list
); /* otherwise we will duplicate the list */
2237 wallet_Clear(&wallet_SchemaConcat_list
); /* otherwise we will duplicate the list */
2238 wallet_Clear(&wallet_SchemaStrings_list
); /* otherwise we will duplicate the list */
2239 wallet_Clear(&wallet_PositionalSchema_list
); /* otherwise we will duplicate the list */
2240 wallet_Clear(&wallet_StateSchema_list
); /* otherwise we will duplicate the list */
2241 wallet_Clear(&wallet_DistinguishedSchema_list
); /* otherwise we will duplicate the list */
2242 wallet_DeallocateMapElements();
2247 //#define WALLET_CHECK_FOOTPRINT
2248 #ifdef WALLET_CHECK_FOOTPRINT
2250 wallet_Size(nsVoidArray
* list
) {
2252 wallet_MapElement
* mapElementPtr
;
2253 PRInt32 count
= LIST_COUNT(list
);
2254 for (PRInt32 i
=0; i
<count
; i
++) {
2255 mapElementPtr
= static_cast<wallet_MapElement
*>(list
->ElementAt(i
));
2256 size
+= sizeof(wallet_MapElement
*);
2257 size
+= sizeof(wallet_MapElement
);
2258 size
+= PL_strlen(mapElementPtr
->item1
);
2259 size
+= PL_strlen(mapElementPtr
->item2
);
2260 wallet_Sublist
* sublistPtr
;
2261 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
2262 for (PRInt32 i2
=0; i2
<count2
; i2
++) {
2263 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(i2
));
2264 size
+= sizeof(wallet_Sublist
);
2265 size
+= PL_strlen(sublistPtr
->item
);
2273 * initialization for wallet session (done only once)
2276 static PRBool wallet_tablesInitialized
= PR_FALSE
;
2277 static PRBool wallet_ValuesReadIn
= PR_FALSE
;
2278 static PRBool namesInitialized
= PR_FALSE
;
2279 static PRBool wallet_URLListInitialized
= PR_FALSE
;
2282 wallet_Initialize(PRBool unlockDatabase
=PR_TRUE
) {
2285 //wallet_ClearStopwatch();
2286 //wallet_ResumeStopwatch();
2289 if (!wallet_tablesInitialized
) {
2291 //wallet_PauseStopwatch();
2292 //wallet_DumpStopwatch();
2294 // printf("******** start profile\n");
2297 Wallet_ReleaseAllLists();
2298 helpMac
= new wallet_HelpMac
; /* to speed up startup time on the mac */
2299 wallet_ReadFromFile(distinguishedSchemaFileName
, wallet_DistinguishedSchema_list
, PR_FALSE
);
2300 wallet_ReadFromFile(fieldSchemaFileName
, wallet_FieldToSchema_list
, PR_FALSE
);
2301 wallet_ReadFromFile(vcardSchemaFileName
, wallet_VcardToSchema_list
, PR_FALSE
);
2302 wallet_ReadFromFile(schemaConcatFileName
, wallet_SchemaConcat_list
, PR_FALSE
);
2303 wallet_ReadFromFile(schemaStringsFileName
, wallet_SchemaStrings_list
, PR_FALSE
, BY_LENGTH
);
2304 wallet_ReadFromFile(positionalSchemaFileName
, wallet_PositionalSchema_list
, PR_FALSE
);
2305 wallet_ReadFromFile(stateSchemaFileName
, wallet_StateSchema_list
, PR_FALSE
);
2307 #ifdef WALLET_CHECK_FOOTPRINT
2308 PRInt32 totalSize
= 0;
2310 size
= wallet_Size(wallet_FieldToSchema_list
);
2312 printf("FieldToSchema: %d\n", size
);
2313 size
= wallet_Size(wallet_VcardToSchema_list
);
2315 printf("VcardToSchema: %d\n", size
);
2316 size
= wallet_Size(wallet_SchemaConcat_list
);
2318 printf("SchemaConcat: %d\n", size
);
2319 size
= wallet_Size(wallet_SchemaStrings_list
);
2321 printf("SchemaStrings: %d\n", size
);
2322 size
= wallet_Size(wallet_PositionalSchema_list
);
2324 printf("PositionalSchema: %d\n", size
);
2325 size
= wallet_Size(wallet_StateSchema_list
);
2327 printf("StateSchema: %d\n", size
);
2328 size
= wallet_Size(wallet_DistinguishedSchema_list
);
2330 printf("DistinguishedSchema: %d\n", size
);
2331 printf("Total size: %d\n", totalSize
);
2334 /* Note that we sort the SchemaString list by length instead of alphabetically. To see
2335 * why that's necessary, consider the following example:
2337 * Card.Name: requires "card" and "name" both be present
2338 * Name: requires "name"
2340 * So we want to check for a match on one with more strings (Card.Name in this case) before
2341 * checking for a match with the one containing less strings.
2345 // printf("****** end profile\n");
2346 wallet_tablesInitialized
= PR_TRUE
;
2349 if (!unlockDatabase
) {
2353 if (!namesInitialized
) {
2354 SI_GetCharPref(pref_WalletSchemaValueFileName
, &schemaValueFileName
);
2355 if (!schemaValueFileName
) {
2356 schemaValueFileName
= Wallet_RandomName("w");
2357 SI_SetCharPref(pref_WalletSchemaValueFileName
, schemaValueFileName
);
2359 SI_InitSignonFileName();
2360 namesInitialized
= PR_TRUE
;
2363 if (!wallet_ValuesReadIn
) {
2364 wallet_Clear(&wallet_SchemaToValue_list
); /* otherwise we will duplicate the list */
2365 wallet_ReadFromFile(schemaValueFileName
, wallet_SchemaToValue_list
, PR_TRUE
);
2366 wallet_ValuesReadIn
= PR_TRUE
;
2370 // fprintf(stdout,"Field to Schema table \n");
2371 // wallet_Dump(wallet_FieldToSchema_list);
2373 // fprintf(stdout,"Vcard to Schema table \n");
2374 // wallet_Dump(wallet_VcardToSchema_list);
2376 // fprintf(stdout,"SchemaConcat table \n");
2377 // wallet_Dump(wallet_SchemaConcat_list);
2379 // fprintf(stdout,"SchemaStrings table \n");
2380 // wallet_Dump(wallet_SchemaStrings_list);
2382 // fprintf(stdout,"PositionalSchema table \n");
2383 // wallet_Dump(wallet_PositionalSchema_list);
2385 // fprintf(stdout,"StateSchema table \n");
2386 // wallet_Dump(wallet_StateSchema_list);
2388 // fprintf(stdout,"Schema to Value table \n");
2389 // wallet_Dump(wallet_SchemaToValue_list);
2395 wallet_InitializeURLList() {
2396 if (!wallet_URLListInitialized
) {
2397 wallet_Clear(&wallet_URL_list
);
2398 wallet_ReadFromFile(URLFileName
, wallet_URL_list
, PR_TRUE
);
2399 wallet_URLListInitialized
= PR_TRUE
;
2404 * initialization for current URL
2407 wallet_InitializeCurrentURL(nsIDocument
* doc
) {
2410 nsIURI
*url
= doc
->GetDocumentURI();
2411 if (wallet_lastUrl
== url
) {
2414 if (wallet_lastUrl
) {
2415 //?? NS_RELEASE(lastUrl);
2417 wallet_lastUrl
= url
;
2422 #define SEPARATOR "#*%$"
2425 wallet_GetNextInString(const nsString
& str
, nsString
& head
, nsString
& tail
) {
2426 PRInt32 separator
= str
.Find(SEPARATOR
);
2427 if (separator
== -1) {
2428 return NS_ERROR_FAILURE
;
2430 str
.Left(head
, separator
);
2431 str
.Mid(tail
, separator
+sizeof(SEPARATOR
)-1, str
.Length() - (separator
+sizeof(SEPARATOR
)-1));
2436 wallet_ReleasePrefillElementList(nsVoidArray
* wallet_PrefillElement_list
) {
2437 if (wallet_PrefillElement_list
) {
2438 wallet_PrefillElement
* prefillElementPtr
;
2439 PRInt32 count
= LIST_COUNT(wallet_PrefillElement_list
);
2440 for (PRInt32 i
=count
-1; i
>=0; i
--) {
2441 prefillElementPtr
= static_cast<wallet_PrefillElement
*>(wallet_PrefillElement_list
->ElementAt(i
));
2442 delete prefillElementPtr
;
2444 delete wallet_PrefillElement_list
;
2445 wallet_PrefillElement_list
= nsnull
;
2449 #define BREAK PRUnichar('\001')
2451 nsVoidArray
* wallet_list
;
2452 PRUnichar
* wallet_url
;
2455 WLLT_GetPrefillListForViewer(nsAString
& aPrefillList
)
2457 wallet_Initialize(PR_FALSE
); /* to initialize helpMac */
2458 wallet_PrefillElement
* prefillElementPtr
;
2459 nsAutoString buffer
;
2460 PRInt32 count
= LIST_COUNT(wallet_list
);
2461 for (PRInt32 i
=0; i
<count
; i
++) {
2462 prefillElementPtr
= static_cast<wallet_PrefillElement
*>(wallet_list
->ElementAt(i
));
2463 buffer
.Append(BREAK
);
2464 buffer
.AppendInt(prefillElementPtr
->count
,10);
2465 buffer
.Append(BREAK
);
2466 AppendUTF8toUTF16(prefillElementPtr
->schema
, buffer
);
2467 buffer
.Append(BREAK
);
2468 buffer
.Append(prefillElementPtr
->value
);
2471 buffer
.Append(BREAK
);
2472 buffer
+= wallet_url
;
2473 aPrefillList
= buffer
;
2477 wallet_FreeURL(wallet_MapElement
*url
) {
2482 wallet_URL_list
->RemoveElement(url
);
2486 static const char permission_NoCapture_NoPreview
[] = "yy";
2487 static const char permission_NoCapture_Preview
[] = "yn";
2488 static const char permission_Capture_NoPreview
[] = "ny";
2489 static const char permission_Capture_Preview
[] = "nn";
2492 Wallet_SignonViewerReturn(const nsAString
& results
)
2494 wallet_MapElement
*url
;
2496 char oldPermissionChar
;
2498 /* step through all nopreviews and delete those that are in the sequence */
2500 SI_FindValueInArgs(results
, NS_LITERAL_STRING("|goneP|"), gone
);
2502 PRInt32 count
= LIST_COUNT(wallet_URL_list
);
2505 url
= static_cast<wallet_MapElement
*>(wallet_URL_list
->ElementAt(count
));
2506 if (url
&& SI_InSequence(gone
, count
)) {
2507 /* clear the NO_PREVIEW indicator */
2508 oldPermissionChar
= NO_CAPTURE(url
->item2
);
2509 WALLET_FREEIF (url
->item2
);
2510 if (oldPermissionChar
== 'y') {
2511 url
->item2
= PL_strdup(permission_NoCapture_Preview
);
2513 url
->item2
= PL_strdup(permission_Capture_Preview
);
2515 if (!PL_strcmp(url
->item2
, permission_Capture_Preview
)) {
2516 wallet_FreeURL(url
);
2518 wallet_WriteToFile(URLFileName
, wallet_URL_list
);
2522 /* step through all nocaptures and delete those that are in the sequence */
2524 SI_FindValueInArgs(results
, NS_LITERAL_STRING("|goneC|"), gone
);
2526 PRInt32 count2
= LIST_COUNT(wallet_URL_list
);
2529 url
= static_cast<wallet_MapElement
*>(wallet_URL_list
->ElementAt(count2
));
2530 if (url
&& SI_InSequence(gone
, count2
)) {
2531 /* clear the NO_CAPTURE indicator */
2532 oldPermissionChar
= NO_PREVIEW(url
->item2
);
2533 WALLET_FREEIF (url
->item2
);
2534 if (oldPermissionChar
== 'y') {
2535 url
->item2
= PL_strdup(permission_Capture_NoPreview
);
2537 url
->item2
= PL_strdup(permission_Capture_Preview
);
2539 if (!PL_strcmp(url
->item2
, permission_Capture_Preview
)) {
2540 wallet_FreeURL(url
);
2542 wallet_WriteToFile(URLFileName
, wallet_URL_list
);
2548 * see if user wants to capture data on current page
2551 wallet_OKToCapture(const nsAFlatCString
& url
, nsIDOMWindowInternal
* window
) {
2553 /* exit if pref is not set */
2554 if (!wallet_GetFormsCapturingPref() || !wallet_GetEnabledPref()) {
2558 /* see if this url is already on list of url's for which we don't want to capture */
2559 wallet_InitializeURLList();
2561 nsCAutoString urlPermissions
;
2562 if (wallet_ReadFromList(url
, urlPermissions
, dummy
, wallet_URL_list
, PR_FALSE
)) {
2563 if (NO_CAPTURE(urlPermissions
) == 'y') {
2568 /* ask user if we should capture the values on this form */
2569 PRUnichar
* message
= Wallet_Localize("WantToCaptureForm?");
2571 PRInt32 button
= Wallet_3ButtonConfirm(message
, window
);
2572 if (button
== NEVER_BUTTON
) {
2573 /* add URL to list with NO_CAPTURE indicator set */
2574 if (NO_PREVIEW(urlPermissions
) == 'y') {
2575 urlPermissions
= permission_NoCapture_NoPreview
;
2577 urlPermissions
= permission_NoCapture_Preview
;
2579 if (wallet_WriteToList(url
.get(), urlPermissions
.get(), dummy
, wallet_URL_list
, PR_FALSE
, DUP_OVERWRITE
)) {
2580 wallet_WriteToFile(URLFileName
, wallet_URL_list
);
2582 /* Notify signon manager dialog to update its display */
2583 nsCOMPtr
<nsIObserverService
> os(do_GetService("@mozilla.org/observer-service;1"));
2585 os
->NotifyObservers(nsnull
, "signonChanged", NS_LITERAL_STRING("nocaptures").get());
2589 WALLET_FREE(message
);
2590 return (button
== YES_BUTTON
);
2594 * capture the value of a form element
2597 wallet_Capture(nsIDocument
* doc
, const nsString
& field
, const nsString
& value
, nsACString
& schema
)
2599 /* do nothing if there is no value */
2600 if (value
.IsEmpty()) {
2604 /* read in the mappings if they are not already present */
2605 wallet_Initialize();
2606 wallet_InitializeCurrentURL(doc
);
2608 NS_ConvertUTF16toUTF8
valueCString(value
);
2609 nsCAutoString oldValue
;
2611 /* is there a mapping from this field name to a schema name */
2612 nsCAutoString localSchema
; localSchema
.Assign(schema
);
2614 nsCAutoString stripField
;
2615 if (localSchema
.IsEmpty()) {
2616 Strip(field
, stripField
);
2618 if (!localSchema
.IsEmpty() ||
2619 (wallet_ReadFromList(stripField
, localSchema
, dummy
,
2620 wallet_FieldToSchema_list
, PR_FALSE
))) {
2621 /* field to schema mapping already exists */
2623 /* is this a new value for the schema */
2625 PRInt32 lastIndex
= index
;
2626 while(wallet_ReadFromList(localSchema
, oldValue
, dummy
, wallet_SchemaToValue_list
, PR_TRUE
, index
)) {
2627 PRBool isNewValue
= !oldValue
.Equals(valueCString
.get());
2630 * Remove entry from wallet_SchemaToValue_list and then reinsert. This will
2631 * keep multiple values in that list for the same field ordered with
2632 * most-recently-used first. That's useful since the first such entry
2633 * is the default value used for pre-filling.
2635 wallet_MapElement
* mapElement
=
2636 (wallet_MapElement
*) (wallet_SchemaToValue_list
->ElementAt(lastIndex
));
2637 wallet_SchemaToValue_list
->RemoveElementAt(lastIndex
);
2641 mapElement
->itemList
,
2642 wallet_SchemaToValue_list
,
2643 PR_FALSE
); /* note: obscure=false, otherwise we will obscure an obscured value */
2650 /* this is a new value so store it */
2652 if (wallet_WriteToList(localSchema
.get(), valueCString
.get(), dummy
, wallet_SchemaToValue_list
, PR_TRUE
)) {
2653 wallet_WriteToFile(schemaValueFileName
, wallet_SchemaToValue_list
);
2658 /* no field to schema mapping so assume schema name is same as field name */
2660 /* is this a new value for the schema */
2662 PRInt32 lastIndex
= index
;
2664 nsAutoString concatParamUCS2
;
2665 wallet_GetHostFile(wallet_lastUrl
, concatParamUCS2
);
2666 concatParamUCS2
.AppendLiteral(":");
2667 concatParamUCS2
.Append(field
);
2668 NS_ConvertUTF16toUTF8
concatParamUTF8(concatParamUCS2
);
2669 while(wallet_ReadFromList
2670 (concatParamUTF8
, oldValue
, dummy
, wallet_SchemaToValue_list
, PR_TRUE
, index
)) {
2671 PRBool isNewValue
= !oldValue
.Equals(valueCString
.get());
2674 * Remove entry from wallet_SchemaToValue_list and then reinsert. This will
2675 * keep multiple values in that list for the same field ordered with
2676 * most-recently-used first. That's useful since the first such entry
2677 * is the default value used for pre-filling.
2679 wallet_MapElement
* mapElement
=
2680 (wallet_MapElement
*) (wallet_SchemaToValue_list
->ElementAt(lastIndex
));
2681 wallet_SchemaToValue_list
->RemoveElementAt(lastIndex
);
2685 mapElement
->itemList
,
2686 wallet_SchemaToValue_list
,
2687 PR_FALSE
); /* note: obscure=false, otherwise we will obscure an obscured value */
2693 //??? aren't these next four lines redundant?
2694 wallet_GetHostFile(wallet_lastUrl
, concatParamUCS2
);
2695 concatParamUCS2
.AppendLiteral(":");
2696 concatParamUCS2
.Append(field
);
2697 CopyUTF16toUTF8(concatParamUCS2
, concatParamUTF8
);
2700 /* this is a new value so store it */
2702 nsAutoString hostFileFieldUCS2
;
2703 wallet_GetHostFile(wallet_lastUrl
, hostFileFieldUCS2
);
2704 hostFileFieldUCS2
.AppendLiteral(":");
2705 hostFileFieldUCS2
.Append(field
);
2707 if (wallet_WriteToList
2708 (NS_ConvertUTF16toUTF8(hostFileFieldUCS2
).get(), valueCString
.get(), dummy
,
2709 wallet_SchemaToValue_list
, PR_TRUE
)) {
2710 wallet_WriteToFile(schemaValueFileName
, wallet_SchemaToValue_list
);
2716 /***************************************************************/
2717 /* The following are the interface routines seen by other dlls */
2718 /***************************************************************/
2721 WLLT_GetNopreviewListForViewer(nsAString
& aNopreviewList
)
2723 wallet_Initialize(PR_FALSE
); /* to initialize helpMac */
2724 nsAutoString buffer
;
2725 wallet_MapElement
*url
;
2727 wallet_InitializeURLList();
2728 PRInt32 count
= LIST_COUNT(wallet_URL_list
);
2729 for (PRInt32 i
=0; i
<count
; i
++) {
2730 url
= static_cast<wallet_MapElement
*>(wallet_URL_list
->ElementAt(i
));
2731 if (NO_PREVIEW(url
->item2
) == 'y') {
2732 buffer
.Append(BREAK
);
2733 AppendUTF8toUTF16(url
->item1
, buffer
);
2736 aNopreviewList
= buffer
;
2740 WLLT_GetNocaptureListForViewer(nsAString
& aNocaptureList
)
2742 nsAutoString buffer
;
2743 wallet_MapElement
*url
;
2745 wallet_InitializeURLList();
2746 PRInt32 count
= LIST_COUNT(wallet_URL_list
);
2747 for (PRInt32 i
=0; i
<count
; i
++) {
2748 url
= static_cast<wallet_MapElement
*>(wallet_URL_list
->ElementAt(i
));
2749 if (NO_CAPTURE(url
->item2
) == 'y') {
2750 buffer
.Append(BREAK
);
2751 AppendUTF8toUTF16(url
->item1
, buffer
);
2754 aNocaptureList
= buffer
;
2758 WLLT_PostEdit(const nsAString
& walletList
)
2760 nsCOMPtr
<nsIFile
> file
;
2761 nsresult rv
= Wallet_ProfileDirectory(getter_AddRefs(file
));
2762 if (NS_FAILED(rv
)) {
2766 nsAutoString
tail( walletList
);
2767 nsAutoString head
, temp
;
2770 /* get first item in list */
2771 separator
= tail
.FindChar(BREAK
);
2772 if (-1 == separator
) {
2775 tail
.Left(head
, separator
);
2776 tail
.Mid(temp
, separator
+1, tail
.Length() - (separator
+1));
2779 /* return if OK button was not pressed */
2780 if (!head
.EqualsLiteral("OK")) {
2784 file
->AppendNative(nsDependentCString(schemaValueFileName
));
2786 /* open SchemaValue file */
2787 nsCOMPtr
<nsIOutputStream
> fileOutputStream
;
2788 rv
= NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream
),
2795 nsCOMPtr
<nsIOutputStream
> strm
;
2796 rv
= NS_NewBufferedOutputStream(getter_AddRefs(strm
), fileOutputStream
, 4096);
2800 /* write the values in the walletList to the file */
2801 wallet_PutHeader(strm
);
2803 separator
= tail
.FindChar(BREAK
);
2804 if (-1 == separator
) {
2807 tail
.Left(head
, separator
);
2808 tail
.Mid(temp
, separator
+1, tail
.Length() - (separator
+1));
2811 wallet_PutLine(strm
, NS_ConvertUTF16toUTF8(head
).get());
2814 /* close the file and read it back into the SchemaToValue list */
2815 // All went ok. Maybe except for problems in Write(), but the stream detects
2817 nsCOMPtr
<nsISafeOutputStream
> safeStream
= do_QueryInterface(strm
);
2818 NS_ASSERTION(safeStream
, "expected a safe output stream!");
2820 rv
= safeStream
->Finish();
2821 if (NS_FAILED(rv
)) {
2822 NS_WARNING("failed to save wallet file! possible dataloss");
2828 fileOutputStream
= nsnull
;
2830 wallet_Clear(&wallet_SchemaToValue_list
);
2831 wallet_ReadFromFile(schemaValueFileName
, wallet_SchemaToValue_list
, PR_TRUE
);
2835 WLLT_PreEdit(nsAString
& walletList
)
2837 wallet_Initialize();
2838 walletList
.Assign(BREAK
);
2839 wallet_MapElement
* mapElementPtr
;
2840 PRInt32 count
= LIST_COUNT(wallet_SchemaToValue_list
);
2841 for (PRInt32 i
=0; i
<count
; i
++) {
2842 mapElementPtr
= static_cast<wallet_MapElement
*>(wallet_SchemaToValue_list
->ElementAt(i
));
2844 AppendUTF8toUTF16(mapElementPtr
->item1
, walletList
);
2845 walletList
.Append(BREAK
);
2846 if (!WALLET_NULL(mapElementPtr
->item2
)) {
2847 AppendUTF8toUTF16(mapElementPtr
->item2
, walletList
);
2848 walletList
.Append(BREAK
);
2850 wallet_Sublist
* sublistPtr
;
2851 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
2852 for (PRInt32 i2
=0; i2
<count2
; i2
++) {
2853 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(i2
));
2854 AppendUTF8toUTF16(sublistPtr
->item
, walletList
);
2855 walletList
.Append(BREAK
);
2858 walletList
.Append(BREAK
);
2864 wallet_Initialize();
2865 wallet_Clear(&wallet_SchemaToValue_list
);
2866 wallet_WriteToFile(schemaValueFileName
, wallet_SchemaToValue_list
);
2871 WLLT_ClearUserData() {
2872 wallet_ValuesReadIn
= PR_FALSE
;
2873 namesInitialized
= PR_FALSE
;
2874 wallet_URLListInitialized
= PR_FALSE
;
2878 WLLT_DeletePersistentUserData() {
2880 if (schemaValueFileName
&& schemaValueFileName
[0]) {
2881 nsCOMPtr
<nsIFile
> file
;
2882 nsresult rv
= Wallet_ProfileDirectory(getter_AddRefs(file
));
2883 if (NS_SUCCEEDED(rv
)) {
2884 rv
= file
->AppendNative(nsDependentCString(schemaValueFileName
));
2885 if (NS_SUCCEEDED(rv
))
2886 file
->Remove(PR_FALSE
);
2892 wallet_ReencryptAll(const char * newpref
, void* window
) {
2893 PRUnichar
* message
;
2895 /* prevent reentry for the case that the user doesn't supply correct master password */
2896 if (gReencryptionLevel
!= 0) {
2897 return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */
2899 gReencryptionLevel
++;
2900 PRInt32 count
= LIST_COUNT(wallet_SchemaToValue_list
);
2902 char* plainText
= nsnull
;
2904 /* logout first so there is no conversion unless user knows the master password */
2905 if (!changingPassword
) {
2906 nsresult rv
= wallet_CryptSetup();
2907 if (NS_SUCCEEDED(rv
)) {
2908 rv
= gSecretDecoderRing
->Logout();
2910 if (NS_FAILED(rv
)) {
2913 wallet_Initialize();
2915 wallet_MapElement
* mapElementPtr
;
2916 gEncryptionFailure
= PR_FALSE
;
2917 for (i
=0; i
<count
&& !gEncryptionFailure
; i
++) {
2918 mapElementPtr
= static_cast<wallet_MapElement
*>(wallet_SchemaToValue_list
->ElementAt(i
));
2919 char * crypt
= nsnull
;
2920 if (!WALLET_NULL(mapElementPtr
->item2
)) {
2921 if (NS_FAILED(DecryptString(mapElementPtr
->item2
, plainText
))) {
2924 if (NS_FAILED(EncryptString(plainText
, crypt
))) {
2927 mapElementPtr
->item2
= crypt
;
2929 wallet_Sublist
* sublistPtr
;
2930 PRInt32 count2
= LIST_COUNT(mapElementPtr
->itemList
);
2931 for (PRInt32 i2
=0; i2
<count2
; i2
++) {
2932 sublistPtr
= static_cast<wallet_Sublist
*>(mapElementPtr
->itemList
->ElementAt(i2
));
2933 if (NS_FAILED(DecryptString(sublistPtr
->item
, plainText
))) {
2936 if (NS_FAILED(EncryptString(plainText
, crypt
))) {
2939 sublistPtr
->item
= crypt
;
2943 wallet_WriteToFile(schemaValueFileName
, wallet_SchemaToValue_list
);
2944 if (!SINGSIGN_ReencryptAll()) {
2948 /* force a rewriting of prefs.js to make sure pref_Crypto got updated
2950 * Note: In the event of a crash after changing this pref (either way), the user
2951 * could get misled as to what state his storage was in. If the crash occurred
2952 * after changing to encrypted, he could think he was encrypting in the future (because
2953 * he remembered changed to encypting at one time) but his new values are only being
2954 * obscurred. If the crash occurred after changing to obscured, later on he might
2955 * think his store was encrypted (because he checked the pref panel and that's what
2956 * it told him) whereas some of the earlier values are actually obscured and so not
2957 * protected. For both these reasons, we force this rewriting of the prefs file now.
2959 SI_SetBoolPref(pref_Crypto
, SI_GetBoolPref(pref_Crypto
, PR_TRUE
));
2961 // message = Wallet_Localize("Converted");
2962 // wallet_Alert(message, (nsIDOMWindowInternal *)window);
2963 // WALLET_FREE(message);
2964 gReencryptionLevel
--;
2965 return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */
2967 /* toggle the pref back to its previous value */
2968 SI_SetBoolPref(pref_Crypto
, !SI_GetBoolPref(pref_Crypto
, PR_TRUE
));
2970 /* alert the user to the failure */
2971 message
= Wallet_Localize("NotConverted");
2972 wallet_Alert(message
, (nsIDOMWindowInternal
*)window
);
2973 WALLET_FREE(message
);
2974 gReencryptionLevel
--;
2979 WLLT_InitReencryptCallback(nsIDOMWindowInternal
* window
) {
2980 static PRBool registered
= PR_FALSE
;
2981 static nsIDOMWindowInternal
* lastWindow
;
2983 SI_UnregisterCallback(pref_Crypto
, wallet_ReencryptAll
, lastWindow
);
2985 SI_RegisterCallback(pref_Crypto
, wallet_ReencryptAll
, window
);
2986 lastWindow
= window
;
2987 registered
= PR_TRUE
;
2991 wallet_DecodeVerticalBars(nsString
& s
) {
2992 s
.ReplaceSubstring(NS_LITERAL_STRING("^2").get(), NS_LITERAL_STRING("|").get());
2993 s
.ReplaceSubstring(NS_LITERAL_STRING("^1").get(), NS_LITERAL_STRING("^").get());
2997 * return after previewing a set of prefills
3000 WLLT_PrefillReturn(const nsAString
& results
)
3002 nsAutoString fillins
;
3003 nsAutoString urlName
;
3007 /* get values that are in environment variables */
3008 SI_FindValueInArgs(results
, NS_LITERAL_STRING("|fillins|"), fillins
);
3009 SI_FindValueInArgs(results
, NS_LITERAL_STRING("|skip|"), skip
);
3010 SI_FindValueInArgs(results
, NS_LITERAL_STRING("|url|"), urlName
);
3011 wallet_DecodeVerticalBars(fillins
);
3012 wallet_DecodeVerticalBars(urlName
);
3014 /* add url to url list if user doesn't want to preview this page in the future */
3015 if (skip
.EqualsLiteral("true")) {
3016 NS_ConvertUTF16toUTF8
url(urlName
);
3018 nsCAutoString
urlPermissions("nn");
3019 wallet_ReadFromList(url
, urlPermissions
, dummy
, wallet_URL_list
, PR_FALSE
);
3020 /* add URL to list with NO_PREVIEW indicator set */
3021 if (NO_CAPTURE(urlPermissions
) == 'y') {
3022 urlPermissions
= permission_NoCapture_NoPreview
;
3024 urlPermissions
= permission_Capture_NoPreview
;
3026 if (wallet_WriteToList(url
.get(), urlPermissions
.get(), dummy
, wallet_URL_list
, PR_FALSE
, DUP_OVERWRITE
)) {
3027 wallet_WriteToFile(URLFileName
, wallet_URL_list
);
3029 /* Notify signon manager dialog to update its display */
3030 nsCOMPtr
<nsIObserverService
> os(do_GetService("@mozilla.org/observer-service;1"));
3032 os
->NotifyObservers(nsnull
, "signonChanged", NS_LITERAL_STRING("nopreviews").get());
3037 /* process the list, doing the fillins */
3038 if (fillins
.Length() == 0) { /* user pressed CANCEL */
3039 wallet_ReleasePrefillElementList(wallet_list
);
3040 wallet_list
= nsnull
;
3041 nsMemory::Free(wallet_url
);
3042 wallet_url
= nsnull
;
3047 * note: there are two lists involved here and we are stepping through both of them.
3048 * One is the pre-fill list that was generated when we walked through the html content.
3049 * For each pre-fillable item, it contains n entries, one for each possible value that
3050 * can be prefilled for that field. The first entry for each field can be identified
3051 * because it has a non-zero count field (in fact, the count is the number of entries
3052 * for that field), all subsequent entries for the same field have a zero count field.
3053 * The other is the fillin list which was generated by the html dialog that just
3054 * finished. It contains one entry for each pre-fillable item specificying that
3055 * particular value that should be prefilled for that item.
3058 wallet_PrefillElement
* mapElementPtr
;
3059 /* step through pre-fill list */
3060 PRInt32 count
= LIST_COUNT(wallet_list
);
3061 for (PRInt32 i
=0; i
<count
; i
++) {
3062 mapElementPtr
= static_cast<wallet_PrefillElement
*>(wallet_list
->ElementAt(i
));
3064 /* advance in fillins list each time a new schema name in pre-fill list is encountered */
3065 if (mapElementPtr
->count
!= 0) {
3066 /* count != 0 indicates a new schema name */
3068 if (NS_FAILED(wallet_GetNextInString(fillins
, next
, tail
))) {
3072 if (PL_strcmp(NS_ConvertUTF16toUTF8(next
).get(), mapElementPtr
->schema
)) {
3073 break; /* something's wrong so stop prefilling */
3075 wallet_GetNextInString(fillins
, next
, tail
);
3078 if (next
== mapElementPtr
->value
) {
3080 * Remove entry from wallet_SchemaToValue_list and then reinsert. This will
3081 * keep multiple values in that list for the same field ordered with
3082 * most-recently-used first. That's useful since the first such entry
3083 * is the default value used for pre-filling.
3086 * Test for mapElementPtr->count being zero is an optimization that avoids us from doing a
3087 * reordering if the current entry already was first
3089 if (mapElementPtr
->count
== 0) {
3090 nsCAutoString oldvalueUTF8
;
3092 PRInt32 lastIndex
= index
;
3094 while(wallet_ReadFromList(nsDependentCString(mapElementPtr
->schema
),
3097 wallet_SchemaToValue_list
,
3100 if (oldvalueUTF8
.Equals(NS_ConvertUTF16toUTF8(mapElementPtr
->value
).get())) {
3101 wallet_MapElement
* mapElement
=
3102 (wallet_MapElement
*) (wallet_SchemaToValue_list
->ElementAt(lastIndex
));
3103 wallet_SchemaToValue_list
->RemoveElementAt(lastIndex
);
3107 mapElement
->itemList
,
3108 wallet_SchemaToValue_list
,
3109 PR_FALSE
); /* note: obscure=false, otherwise we will obscure an obscured value */
3118 /* Change the value */
3120 if (!next
.IsEmpty()) {
3121 if (mapElementPtr
->inputElement
) {
3122 mapElementPtr
->inputElement
->SetValue(next
);
3125 result
= wallet_GetSelectIndex(mapElementPtr
->selectElement
, next
, mapElementPtr
->selectIndex
);
3126 if (NS_SUCCEEDED(result
)) {
3127 mapElementPtr
->selectElement
->SetSelectedIndex(mapElementPtr
->selectIndex
);
3129 mapElementPtr
->selectElement
->SetSelectedIndex(0);
3135 /* Release the prefill list that was generated when we walked thru the html content */
3136 wallet_ReleasePrefillElementList(wallet_list
);
3137 wallet_list
= nsnull
;
3138 nsMemory::Free(wallet_url
);
3139 wallet_url
= nsnull
;
3143 * get the form elements on the current page and prefill them if possible
3146 wallet_TraversalForPrefill
3147 (nsIDOMWindow
* win
, nsVoidArray
* wallet_PrefillElement_list
, nsString
& urlName
) {
3150 if (nsnull
!= win
) {
3151 nsCOMPtr
<nsIDOMDocument
> domdoc
;
3152 result
= win
->GetDocument(getter_AddRefs(domdoc
));
3153 if (NS_SUCCEEDED(result
)) {
3154 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domdoc
);
3156 nsIURI
*url
= doc
->GetDocumentURI();
3158 wallet_GetHostFile(url
, urlName
);
3160 wallet_Initialize();
3161 wallet_InitializeCurrentURL(doc
);
3163 nsCOMPtr
<nsIDOMHTMLDocument
> htmldoc
= do_QueryInterface(doc
);
3165 nsCOMPtr
<nsIDOMHTMLCollection
> forms
;
3166 htmldoc
->GetForms(getter_AddRefs(forms
));
3168 wallet_InitializeStateTesting();
3170 forms
->GetLength(&numForms
);
3171 for (PRUint32 formX
= 0; (formX
< numForms
) && !gEncryptionFailure
; formX
++) {
3172 nsCOMPtr
<nsIDOMNode
> formNode
;
3173 forms
->Item(formX
, getter_AddRefs(formNode
));
3175 nsCOMPtr
<nsIDOMHTMLFormElement
> formElement
= do_QueryInterface(formNode
);
3177 nsCOMPtr
<nsIDOMHTMLCollection
> elements
;
3178 result
= formElement
->GetElements(getter_AddRefs(elements
));
3180 /* got to the form elements at long last */
3181 PRUint32 numElements
;
3182 elements
->GetLength(&numElements
);
3183 for (PRUint32 elementX
= 0; (elementX
< numElements
) && !gEncryptionFailure
; elementX
++) {
3184 nsCOMPtr
<nsIDOMNode
> elementNode
;
3185 elements
->Item(elementX
, getter_AddRefs(elementNode
));
3187 wallet_PrefillElement
* prefillElement
;
3189 wallet_PrefillElement
* firstElement
= nsnull
;
3190 PRUint32 numberOfElements
= 0;
3191 for (; !gEncryptionFailure
;) {
3192 /* loop to allow for multiple values */
3193 /* first element in multiple-value group will have its count
3194 * field set to the number of elements in group. All other
3195 * elements in group will have count field set to 0
3197 prefillElement
= new wallet_PrefillElement
;
3198 nsCAutoString schemaUTF8
;
3199 if (NS_SUCCEEDED(wallet_GetPrefills
3201 prefillElement
->inputElement
,
3202 prefillElement
->selectElement
,
3204 prefillElement
->value
,
3205 prefillElement
->selectIndex
,
3207 /* another value found */
3208 prefillElement
->schema
= ToNewCString(schemaUTF8
);
3209 if (nsnull
== firstElement
) {
3210 firstElement
= prefillElement
;
3213 prefillElement
->count
= 0;
3214 wallet_PrefillElement_list
->AppendElement(prefillElement
);
3216 /* value not found, stop looking for more values */
3217 delete prefillElement
;
3221 if (numberOfElements
>0) {
3222 firstElement
->count
= numberOfElements
;
3236 nsCOMPtr
<nsIDOMWindowCollection
> frames
;
3237 win
->GetFrames(getter_AddRefs(frames
));
3240 frames
->GetLength(&numFrames
);
3241 for (PRUint32 frameX
= 0; (frameX
< numFrames
) && !gEncryptionFailure
; frameX
++) {
3242 nsCOMPtr
<nsIDOMWindow
> frameNode
;
3243 frames
->Item(frameX
, getter_AddRefs(frameNode
));
3245 wallet_TraversalForPrefill(frameNode
, wallet_PrefillElement_list
, urlName
);
3252 WLLT_PrefillOneElement
3253 (nsIDOMWindowInternal
* win
, nsIDOMNode
* elementNode
, nsAString
& compositeValue
)
3255 nsIDOMHTMLInputElement
* inputElement
;
3256 nsIDOMHTMLSelectElement
* selectElement
;
3257 nsCAutoString schema
;
3259 PRInt32 selectIndex
= 0;
3262 if (nsnull
!= win
) {
3263 nsCOMPtr
<nsIDOMDocument
> domdoc
;
3264 nsresult result
= win
->GetDocument(getter_AddRefs(domdoc
));
3265 if (NS_SUCCEEDED(result
)) {
3266 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domdoc
);
3268 wallet_Initialize(PR_TRUE
);
3269 wallet_InitializeCurrentURL(doc
);
3270 wallet_InitializeStateTesting();
3271 while (NS_SUCCEEDED(wallet_GetPrefills
3279 compositeValue
.Append(BREAK
);
3280 compositeValue
.Append(value
);
3289 WLLT_Prefill(nsIPresShell
* shell
, PRBool quick
, nsIDOMWindowInternal
* win
)
3291 /* do not prefill if preview window is open in some other browser window */
3293 return NS_ERROR_FAILURE
;
3296 /* create list of elements that can be prefilled */
3297 nsVoidArray
*wallet_PrefillElement_list
=new nsVoidArray();
3298 if (!wallet_PrefillElement_list
) {
3299 return NS_ERROR_FAILURE
;
3302 nsAutoString urlName
;
3303 gEncryptionFailure
= PR_FALSE
;
3304 wallet_TraversalForPrefill(win
, wallet_PrefillElement_list
, urlName
);
3306 /* return if no elements were put into the list */
3307 if (LIST_COUNT(wallet_PrefillElement_list
) == 0) {
3308 if (!gEncryptionFailure
) {
3309 PRUnichar
* message
= Wallet_Localize("noPrefills");
3310 wallet_Alert(message
, win
);
3311 WALLET_FREE(message
);
3314 // Shouldn't wallet_PrefillElement_list be deleted here?
3316 return NS_ERROR_FAILURE
; // indicates to caller not to display preview screen
3319 /* prefill each element using the list */
3321 /* determine if url is on list of urls that should not be previewed */
3322 PRBool noPreview
= PR_FALSE
;
3324 wallet_InitializeURLList();
3326 nsCAutoString urlPermissions
;
3327 if (!urlName
.IsEmpty()) {
3329 (NS_ConvertUTF16toUTF8(urlName
), urlPermissions
, dummy
, wallet_URL_list
, PR_FALSE
);
3330 noPreview
= (NO_PREVIEW(urlPermissions
) == 'y');
3334 /* determine if preview is necessary */
3335 if (noPreview
|| quick
) {
3336 /* prefill each element without any preview for user verification */
3337 wallet_PrefillElement
* mapElementPtr
;
3338 PRInt32 count
= LIST_COUNT(wallet_PrefillElement_list
);
3339 for (PRInt32 i
=0; i
<count
; i
++) {
3340 mapElementPtr
= static_cast<wallet_PrefillElement
*>(wallet_PrefillElement_list
->ElementAt(i
));
3341 if (mapElementPtr
->count
) {
3342 if (mapElementPtr
->inputElement
) {
3343 mapElementPtr
->inputElement
->SetValue(mapElementPtr
->value
);
3345 mapElementPtr
->selectElement
->SetSelectedIndex(mapElementPtr
->selectIndex
);
3349 /* go thru list just generated and release everything */
3350 wallet_ReleasePrefillElementList(wallet_PrefillElement_list
);
3351 return NS_ERROR_FAILURE
; // indicates to caller not to display preview screen
3353 /* let user preview and verify the prefills first */
3354 wallet_list
= wallet_PrefillElement_list
;
3355 nsMemory::Free(wallet_url
);
3356 wallet_url
= ToNewUnicode(urlName
);
3358 ////wallet_DumpStopwatch();
3359 ////wallet_ClearStopwatch();
3360 //wallet_DumpTiming();
3361 //wallet_ClearTiming();
3363 return NS_OK
; // indicates that caller is to display preview screen
3368 wallet_CaptureInputElement(nsIDOMNode
* elementNode
, nsIDocument
* doc
) {
3370 PRBool captured
= PR_FALSE
;
3371 nsCOMPtr
<nsIDOMHTMLInputElement
> inputElement
= do_QueryInterface(elementNode
);
3373 /* it's an input element */
3375 result
= inputElement
->GetType(type
);
3376 if (NS_SUCCEEDED(result
) &&
3378 type
.LowerCaseEqualsLiteral("text"))) {
3380 result
= inputElement
->GetName(field
);
3381 if (NS_SUCCEEDED(result
)) {
3383 result
= inputElement
->GetValue(value
);
3384 if (NS_SUCCEEDED(result
)) {
3385 /* get schema name from vcard attribute if it exists */
3386 nsCAutoString schema
;
3387 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(elementNode
);
3389 nsAutoString vcardName
; vcardName
.AssignLiteral("VCARD_NAME");
3390 nsAutoString vcardValueUCS2
;
3391 result
= element
->GetAttribute(vcardName
, vcardValueUCS2
);
3392 if (NS_OK
== result
) {
3394 wallet_ReadFromList(NS_ConvertUTF16toUTF8(vcardValueUCS2
), schema
, dummy
,
3395 wallet_VcardToSchema_list
, PR_FALSE
);
3398 if (schema
.IsEmpty()) {
3399 /* get schema from displayable text if possible */
3400 wallet_GetSchemaFromDisplayableText(inputElement
, schema
, value
.IsEmpty());
3402 if (wallet_Capture(doc
, field
, value
, schema
)) {
3413 wallet_CaptureSelectElement(nsIDOMNode
* elementNode
, nsIDocument
* doc
) {
3415 PRBool captured
= PR_FALSE
;
3416 nsCOMPtr
<nsIDOMHTMLSelectElement
> selectElement
= do_QueryInterface(elementNode
);
3417 if (selectElement
) {
3418 /* it's a dropdown list */
3420 result
= selectElement
->GetName(field
);
3422 if (NS_SUCCEEDED(result
)) {
3424 selectElement
->GetLength(&length
);
3426 nsCOMPtr
<nsIDOMHTMLOptionsCollection
> options
;
3427 selectElement
->GetOptions(getter_AddRefs(options
));
3430 PRInt32 selectedIndex
;
3431 result
= selectElement
->GetSelectedIndex(&selectedIndex
);
3433 if (NS_SUCCEEDED(result
)) {
3434 nsCOMPtr
<nsIDOMNode
> optionNode
;
3436 options
->Item(selectedIndex
, getter_AddRefs(optionNode
));
3439 nsCOMPtr
<nsIDOMHTMLOptionElement
> optionElement(do_QueryInterface(optionNode
));
3441 if (optionElement
) {
3442 nsAutoString optionValue
;
3443 nsAutoString optionText
;
3445 PRBool valueOK
= NS_SUCCEEDED(optionElement
->GetValue(optionValue
))
3446 && optionValue
.Length();
3447 PRBool textOK
= NS_SUCCEEDED(optionElement
->GetText(optionText
))
3448 && optionText
.Length();
3449 if (valueOK
|| textOK
) {
3450 /* get schema name from vcard attribute if it exists */
3451 nsCAutoString schema
;
3452 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(elementNode
);
3454 nsAutoString vcardName
; vcardName
.AssignLiteral("VCARD_NAME");
3455 nsAutoString vcardValueUCS2
;
3456 result
= element
->GetAttribute(vcardName
, vcardValueUCS2
);
3457 if (NS_OK
== result
) {
3459 wallet_ReadFromList(NS_ConvertUTF16toUTF8(vcardValueUCS2
), schema
, dummy
,
3460 wallet_VcardToSchema_list
, PR_FALSE
);
3463 if (schema
.IsEmpty()) {
3464 /* get schema from displayable text if possible */
3465 wallet_GetSchemaFromDisplayableText(selectElement
, schema
, (!valueOK
&& !textOK
));
3467 if (valueOK
&& wallet_Capture(doc
, field
, optionValue
, schema
)) {
3470 optionText
.Trim(" \n\t\r");
3471 if (textOK
&& wallet_Capture(doc
, field
, optionText
, schema
)) {
3485 wallet_TraversalForRequestToCapture(nsIDOMWindow
* win
, PRInt32
& captureCount
) {
3488 if (nsnull
!= win
) {
3489 nsCOMPtr
<nsIDOMDocument
> domdoc
;
3490 result
= win
->GetDocument(getter_AddRefs(domdoc
));
3491 if (NS_SUCCEEDED(result
)) {
3492 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domdoc
);
3494 wallet_Initialize();
3495 wallet_InitializeCurrentURL(doc
);
3496 nsCOMPtr
<nsIDOMHTMLDocument
> htmldoc
= do_QueryInterface(doc
);
3498 nsCOMPtr
<nsIDOMHTMLCollection
> forms
;
3499 htmldoc
->GetForms(getter_AddRefs(forms
));
3501 wallet_InitializeStateTesting();
3503 forms
->GetLength(&numForms
);
3504 for (PRUint32 formX
= 0; (formX
< numForms
) && !gEncryptionFailure
; formX
++) {
3505 nsCOMPtr
<nsIDOMNode
> formNode
;
3506 forms
->Item(formX
, getter_AddRefs(formNode
));
3508 nsCOMPtr
<nsIDOMHTMLFormElement
> formElement
= do_QueryInterface(formNode
);
3510 nsCOMPtr
<nsIDOMHTMLCollection
> elements
;
3511 result
= formElement
->GetElements(getter_AddRefs(elements
));
3513 /* got to the form elements at long last */
3514 /* now find out how many text fields are on the form */
3515 PRUint32 numElements
;
3516 elements
->GetLength(&numElements
);
3517 for (PRUint32 elementY
= 0; (elementY
< numElements
) && !gEncryptionFailure
; elementY
++) {
3518 nsCOMPtr
<nsIDOMNode
> elementNode
;
3519 elements
->Item(elementY
, getter_AddRefs(elementNode
));
3521 if (wallet_CaptureInputElement(elementNode
, doc
)) {
3524 if (wallet_CaptureSelectElement(elementNode
, doc
)) {
3539 nsCOMPtr
<nsIDOMWindowCollection
> frames
;
3540 win
->GetFrames(getter_AddRefs(frames
));
3543 frames
->GetLength(&numFrames
);
3544 for (PRUint32 frameX
= 0; (frameX
< numFrames
) && !gEncryptionFailure
; frameX
++)
3546 nsCOMPtr
<nsIDOMWindow
> frameNode
;
3547 frames
->Item(frameX
, getter_AddRefs(frameNode
));
3549 wallet_TraversalForRequestToCapture(frameNode
, captureCount
);
3556 WLLT_RequestToCapture(nsIPresShell
* shell
, nsIDOMWindowInternal
* win
, PRUint32
* status
) {
3558 PRInt32 captureCount
= 0;
3559 gEncryptionFailure
= PR_FALSE
;
3560 wallet_TraversalForRequestToCapture(win
, captureCount
);
3562 PRUnichar
* message
;
3563 if (gEncryptionFailure
) {
3564 message
= Wallet_Localize("UnableToCapture");
3566 } else if (captureCount
) {
3567 /* give caveat if this is the first time data is being captured */
3568 Wallet_GiveCaveat(win
, nsnull
);
3569 message
= Wallet_Localize("Captured");
3572 message
= Wallet_Localize("NotCaptured");
3575 wallet_Alert(message
, win
);
3576 WALLET_FREE(message
);
3580 wallet_IsNewValue(nsIDOMNode
* elementNode
, nsString valueOnForm
) {
3581 if (valueOnForm
.Equals(EmptyString())) {
3584 nsIDOMHTMLInputElement
* inputElement
;
3585 nsIDOMHTMLSelectElement
* selectElement
;
3586 nsCAutoString schema
;
3587 nsAutoString valueSaved
;
3588 PRInt32 selectIndex
= 0;
3590 while (NS_SUCCEEDED(wallet_GetPrefills
3591 (elementNode
, inputElement
, selectElement
, schema
, valueSaved
, selectIndex
, index
))) {
3592 if (valueOnForm
.Equals(valueSaved
)) {
3600 WLLT_OnSubmit(nsIDOMHTMLFormElement
* currentFormNode
, nsIDOMWindowInternal
* window
) {
3602 nsCOMPtr
<nsIContent
> currentForm
= do_QueryInterface(currentFormNode
);
3604 /* get url name as ascii string */
3605 nsAutoString strippedURLNameUCS2
;
3606 nsCOMPtr
<nsIDocument
> doc
= currentForm
->GetDocument();
3610 nsIURI
*docURL
= doc
->GetDocumentURI();
3614 wallet_GetHostFile(docURL
, strippedURLNameUCS2
);
3615 NS_ConvertUTF16toUTF8
strippedURLNameUTF8(strippedURLNameUCS2
);
3617 /* get to the form elements */
3618 nsCOMPtr
<nsIDOMHTMLDocument
> htmldoc(do_QueryInterface(doc
));
3619 if (htmldoc
== nsnull
) {
3623 nsCOMPtr
<nsIDOMHTMLCollection
> forms
;
3624 nsresult rv
= htmldoc
->GetForms(getter_AddRefs(forms
));
3625 if (NS_FAILED(rv
) || (forms
== nsnull
)) {
3630 forms
->GetLength(&numForms
);
3631 for (PRUint32 formX
= 0; formX
< numForms
; formX
++) {
3632 nsCOMPtr
<nsIDOMNode
> formNode
;
3633 forms
->Item(formX
, getter_AddRefs(formNode
));
3634 if (nsnull
!= formNode
) {
3635 nsCOMPtr
<nsIDOMHTMLFormElement
> formElement(do_QueryInterface(formNode
));
3636 if ((nsnull
!= formElement
)) {
3637 nsCOMPtr
<nsIDOMHTMLCollection
> elements
;
3638 rv
= formElement
->GetElements(getter_AddRefs(elements
));
3639 if ((NS_SUCCEEDED(rv
)) && (nsnull
!= elements
)) {
3640 /* got to the form elements at long last */
3641 nsVoidArray
* signonData
= new nsVoidArray();
3642 si_SignonDataStruct
* data
;
3643 PRUint32 numElements
;
3644 elements
->GetLength(&numElements
);
3645 PRBool OKToPrompt
= PR_FALSE
;
3646 PRInt32 passwordcount
= 0;
3648 wallet_Initialize(PR_FALSE
);
3649 wallet_InitializeCurrentURL(doc
);
3650 wallet_InitializeStateTesting();
3651 PRBool newValueFound
= PR_FALSE
;
3652 for (PRUint32 elementX
= 0; elementX
< numElements
; elementX
++) {
3653 nsCOMPtr
<nsIDOMNode
> elementNode
;
3654 elements
->Item(elementX
, getter_AddRefs(elementNode
));
3655 if (nsnull
!= elementNode
) {
3656 nsCOMPtr
<nsIDOMHTMLSelectElement
> selectElement(do_QueryInterface(elementNode
));
3657 if ((NS_SUCCEEDED(rv
)) && (nsnull
!= selectElement
)) {
3658 if (passwordcount
== 0 && !newValueFound
&& !OKToPrompt
) {
3659 nsAutoString valueOnForm
;
3660 rv
= selectElement
->GetValue(valueOnForm
);
3661 if (NS_SUCCEEDED(rv
) && wallet_IsNewValue (elementNode
, valueOnForm
)) {
3662 newValueFound
= PR_TRUE
;
3664 OKToPrompt
= PR_TRUE
;
3669 nsCOMPtr
<nsIDOMHTMLInputElement
> inputElement(do_QueryInterface(elementNode
));
3670 if ((NS_SUCCEEDED(rv
)) && (nsnull
!= inputElement
)) {
3672 rv
= inputElement
->GetType(type
);
3673 if (NS_SUCCEEDED(rv
)) {
3675 PRBool isText
= (type
.IsEmpty() || type
.LowerCaseEqualsLiteral("text"));
3676 PRBool isPassword
= type
.LowerCaseEqualsLiteral("password");
3678 // don't save password if field was left blank
3681 (void) inputElement
->GetValue(val
);
3682 if (val
.IsEmpty()) {
3683 isPassword
= PR_FALSE
;
3687 // Do not store this 'password' form element if the 'autocomplete = off'
3688 // attribute is present, unless the 'wallet.crypto.autocompleteoverride'
3689 // preference is enabled. (The "autocomplete" property is a Microsoft
3690 // extension to HTML.)
3691 if (isPassword
&& !SI_GetBoolPref(pref_AutoCompleteOverride
, PR_FALSE
)) {
3693 (void) inputElement
->GetAttribute(NS_LITERAL_STRING("autocomplete"), val
);
3694 if (val
.LowerCaseEqualsLiteral("off")) {
3695 isPassword
= PR_FALSE
;
3697 (void) formElement
->GetAttribute(NS_LITERAL_STRING("autocomplete"), val
);
3698 if (val
.LowerCaseEqualsLiteral("off")) {
3699 isPassword
= PR_FALSE
;
3706 OKToPrompt
= PR_FALSE
;
3710 if (passwordcount
== 0 && !newValueFound
&& !OKToPrompt
) {
3711 nsAutoString valueOnForm
;
3712 rv
= inputElement
->GetValue(valueOnForm
);
3713 if (NS_SUCCEEDED(rv
) && wallet_IsNewValue (elementNode
, valueOnForm
)) {
3714 newValueFound
= PR_TRUE
;
3716 OKToPrompt
= PR_TRUE
;
3722 if (isText
|| isPassword
) {
3724 rv
= inputElement
->GetValue(value
);
3725 if (NS_SUCCEEDED(rv
)) {
3727 rv
= inputElement
->GetName(field
);
3728 if (NS_SUCCEEDED(rv
)) {
3729 data
= new si_SignonDataStruct
;
3730 data
->value
= value
;
3731 if (!field
.IsEmpty() && field
.CharAt(0) == '\\') {
3733 * Note that data saved for browser-generated logins (e.g. http
3734 * authentication) use artificial field names starting with
3735 * \= (see USERNAMEFIELD and PASSWORDFIELD in singsign.cpp). To
3736 * avoid mistakes whereby saved logins for http authentication is
3737 * then prefilled into a field on the html form at the same URL,
3738 * we will prevent html field names from starting with \=. We
3739 * do that by doubling up a backslash if it appears in the first
3740 * character position
3742 data
->name
= nsAutoString('\\');
3743 data
->name
.Append(field
);
3748 data
->isPassword
= isPassword
;
3749 signonData
->AppendElement(data
);
3750 if (passwordcount
== 0 && !OKToPrompt
) {
3751 /* get schema from field */
3752 nsCAutoString schema
;
3754 nsCAutoString stripField
;
3756 /* try to get schema from displayable text */
3757 if (schema
.IsEmpty()) {
3758 wallet_GetSchemaFromDisplayableText(inputElement
, schema
, PR_FALSE
);
3761 /* no schema found, so try to get it from field name */
3762 if (schema
.IsEmpty()) {
3763 Strip(field
, stripField
);
3765 (stripField
, schema
,
3766 dummy
, wallet_FieldToSchema_list
, PR_FALSE
);
3769 /* if schema found, see if it is in distinguished schema list */
3770 if (!schema
.IsEmpty()) {
3771 /* see if schema is in distinguished list */
3772 wallet_MapElement
* mapElementPtr
;
3773 PRInt32 count
= LIST_COUNT(wallet_DistinguishedSchema_list
);
3774 /* test for at least two distinguished schemas and no passwords */
3775 for (PRInt32 i
=0; i
<count
; i
++) {
3776 mapElementPtr
= static_cast<wallet_MapElement
*>
3777 (wallet_DistinguishedSchema_list
->ElementAt(i
));
3778 if (schema
.Equals(mapElementPtr
->item1
, nsCaseInsensitiveCStringComparator()) && !value
.IsEmpty()) {
3780 if (hits
> 1 && newValueFound
) {
3781 OKToPrompt
= PR_TRUE
;
3796 /* save login if appropriate */
3797 if (currentFormNode
== formNode
) {
3798 nsCOMPtr
<nsIPrompt
> dialog
;
3799 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
3801 wwatch
->GetNewPrompter(0, getter_AddRefs(dialog
));
3804 SINGSIGN_RememberSignonData(dialog
, docURL
, signonData
, window
);
3807 PRInt32 count2
= signonData
->Count();
3808 for (PRInt32 i
=count2
-1; i
>=0; i
--) {
3809 data
= static_cast<si_SignonDataStruct
*>(signonData
->ElementAt(i
));
3814 /* save form if it meets all necessary conditions */
3815 if (wallet_GetFormsCapturingPref() &&
3816 (OKToPrompt
) && wallet_OKToCapture(strippedURLNameUTF8
, window
)) {
3818 /* give caveat if this is the first time data is being captured */
3819 Wallet_GiveCaveat(window
, nsnull
);
3821 /* conditions all met, now save it */
3822 for (PRUint32 elementY
= 0; elementY
< numElements
; elementY
++) {
3823 nsIDOMNode
* elementNode
= nsnull
;
3824 elements
->Item(elementY
, &elementNode
);
3825 if (nsnull
!= elementNode
) {
3826 wallet_CaptureInputElement(elementNode
, doc
);
3827 wallet_CaptureSelectElement(elementNode
, doc
);