extra: import at 3.0.1 beta 1
[mozilla-extra.git] / extensions / wallet / src / wallet.cpp
blobb5461967ef8b40d3cbab75f847752a763bd64c65
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
13 * License.
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.
22 * Contributor(s):
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 ***** */
39 wallet.cpp
42 #include "wallet.h"
43 #include "singsign.h"
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"
59 #include "nsIURL.h"
60 #include "nsIDOMWindowCollection.h"
61 #include "nsIPrompt.h"
62 #include "nsIWindowWatcher.h"
64 #include "nsAppDirectoryServiceDefs.h"
66 #include "nsIStringBundle.h"
67 #include "prmem.h"
68 #include "prprf.h"
69 #include "nsIContent.h"
70 #include "nsIObserverService.h"
72 #include "nsIWalletService.h"
74 #include <time.h>
76 #include "prlong.h"
77 #include "prinrval.h"
79 #include "prlog.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;
100 static void
101 wallet_SetFormsCapturingPref(PRBool x)
103 /* do nothing if new value of pref is same as current value */
104 if (x == wallet_captureForms) {
105 return;
108 /* change the pref */
109 wallet_captureForms = x;
112 int PR_CALLBACK
113 wallet_FormsCapturingPrefChanged(const char * newpref, void * data)
115 PRBool x;
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 */
121 static void
122 wallet_RegisterCapturePrefCallbacks(void)
124 PRBool x;
125 static PRBool first_time = PR_TRUE;
127 if(first_time)
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);
136 static PRBool
137 wallet_GetFormsCapturingPref(void)
139 wallet_RegisterCapturePrefCallbacks();
140 return wallet_captureForms;
143 static PRBool
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;
149 if (first_time) {
150 first_time = PR_FALSE;
151 PRBool x = SI_GetBoolPref(pref_enabled, PR_TRUE);
152 enabled = x;
154 return enabled;
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 {
169 public:
170 wallet_Sublist()
172 MOZ_COUNT_CTOR(wallet_Sublist);
174 ~wallet_Sublist()
176 WALLET_FREEIF(item);
177 MOZ_COUNT_DTOR(wallet_Sublist);
179 const char* item;
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
188 * item1 and item2.
191 class wallet_MapElement {
192 public:
193 wallet_MapElement() : itemList(nsnull)
195 MOZ_COUNT_CTOR(wallet_MapElement);
197 ~wallet_MapElement()
199 WALLET_FREEIF(item1);
200 WALLET_FREEIF(item2);
201 if (itemList) {
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));
206 delete sublistPtr;
208 delete itemList;
210 MOZ_COUNT_DTOR(wallet_MapElement);
212 const char* item1;
213 const char* item2;
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 {
225 public:
226 wallet_HelpMac() {
227 MOZ_COUNT_CTOR(wallet_HelpMac);
229 ~wallet_HelpMac() {
230 MOZ_COUNT_DTOR(wallet_HelpMac);
232 nsCString item1;
233 nsCString item2;
234 nsCString item3;
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 {
252 public:
253 wallet_PrefillElement() : inputElement(nsnull), selectElement(nsnull)
255 schema = 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;
267 char* schema;
268 nsString value;
269 PRInt32 selectIndex;
270 PRUint32 count;
273 nsIURI * wallet_lastUrl = NULL;
275 /***********************************************************/
276 /* The following routines are for diagnostic purposes only */
277 /***********************************************************/
279 #ifdef DEBUG_morse
281 static void
282 wallet_Pause(){
283 fprintf(stdout,"%cpress y to continue\n", '\007');
284 char c;
285 for (;;) {
286 c = getchar();
287 if (tolower(c) == 'y') {
288 fprintf(stdout,"OK\n");
289 break;
292 while (c != '\n') {
293 c = getchar();
297 static void
298 wallet_DumpAutoString(const nsString& as){
299 fprintf(stdout, "%s\n", NS_LossyConvertUTF16toASCII(as).get());
302 static void
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));
316 wallet_Pause();
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;
332 static void
333 wallet_ClearTiming() {
334 timing_index = 0;
335 LL_I2L(timings[timing_index++], PR_IntervalNow());
338 static void
339 wallet_DumpTiming() {
340 PRInt32 i, r4;
341 PRInt64 r1, r2, r3;
342 for (i=1; i<timing_index; i++) {
343 LL_SUB(r1, timings[i], timings[i-1]);
344 LL_I2L(r2, 100);
345 LL_DIV(r3, r1, r2);
346 LL_L2I(r4, r3);
347 fprintf(stdout, "time %c = %ld\n", timingID[i], (long)r4);
348 if (i%20 == 0) {
349 wallet_Pause();
352 wallet_Pause();
355 static void
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());
364 static void
365 wallet_ClearStopwatch() {
366 stopwatch = LL_Zero();
367 stopwatchRunning = PR_FALSE;
370 static void
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;
379 static void
380 wallet_PauseStopwatch() {
381 PRInt64 r1, r2;
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;
391 static void
392 wallet_DumpStopwatch() {
393 PRInt64 r1, r2;
394 PRInt32 r3;
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());
402 LL_I2L(r1, 100);
403 LL_DIV(r2, stopwatch, r1);
404 LL_L2I(r3, r2);
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"
416 PRUnichar *
417 Wallet_Localize(const char* genericString) {
418 nsresult ret;
419 nsAutoString v;
421 /* create a bundle for the localization */
422 nsCOMPtr<nsIStringBundleService> pStringService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &ret);
423 if (NS_FAILED(ret)) {
424 #ifdef DEBUG
425 printf("cannot get string service\n");
426 #endif
427 return ToNewUnicode(v);
429 nsCOMPtr<nsIStringBundle> bundle;
430 ret = pStringService->CreateBundle(PROPERTIES_URL, getter_AddRefs(bundle));
431 if (NS_FAILED(ret)) {
432 #ifdef DEBUG
433 printf("cannot create instance\n");
434 #endif
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)) {
443 #ifdef DEBUG
444 printf("cannot get string from name\n");
445 #endif
446 return ToNewUnicode(v);
448 v = ptrv;
449 nsCRT::free(ptrv);
451 /* convert # to newlines */
452 PRUint32 i;
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 /**********************/
467 PRBool
468 Wallet_Confirm(PRUnichar * szMessage, nsIDOMWindowInternal* window)
470 PRBool retval = PR_TRUE; /* default value */
472 nsresult res;
473 nsCOMPtr<nsIPrompt> dialog;
474 window->GetPrompter(getter_AddRefs(dialog));
475 if (!dialog) {
476 return retval;
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);
482 return retval;
485 PRBool
486 Wallet_ConfirmYN(PRUnichar * szMessage, nsIDOMWindowInternal* window) {
487 nsresult res;
488 nsCOMPtr<nsIPrompt> dialog;
489 window->GetPrompter(getter_AddRefs(dialog));
490 if (!dialog) {
491 return PR_FALSE;
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);
504 PRInt32
505 Wallet_3ButtonConfirm(PRUnichar * szMessage, nsIDOMWindowInternal* window)
507 nsresult res;
508 nsCOMPtr<nsIPrompt> dialog;
509 window->GetPrompter(getter_AddRefs(dialog));
510 if (!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;
530 static void
531 wallet_Alert(PRUnichar * szMessage, nsIDOMWindowInternal* window)
533 nsresult res;
534 nsCOMPtr<nsIPrompt> dialog;
535 window->GetPrompter(getter_AddRefs(dialog));
536 if (!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());
543 WALLET_FREE(title);
544 return; // XXX should return the error
547 static void
548 wallet_Alert(PRUnichar * szMessage, nsIPrompt* dialog)
550 nsresult res;
551 const nsAutoString message( szMessage );
552 PRUnichar * title = Wallet_Localize("CaveatTitle");
553 res = dialog->Alert(title, message.get());
554 WALLET_FREE(title);
555 return; // XXX should return the error
558 PRBool
559 Wallet_CheckConfirmYN
560 (PRUnichar * szMessage, PRUnichar * szCheckMessage, PRBool* checkValue,
561 nsIDOMWindowInternal* window) {
562 nsresult res;
563 nsCOMPtr<nsIPrompt> dialog;
564 window->GetPrompter(getter_AddRefs(dialog));
565 if (!dialog) {
566 return PR_FALSE;
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)) {
576 *checkValue = 0;
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;
596 static nsresult
597 wallet_CryptSetup() {
598 if (!gSecretDecoderRing)
600 /* Get a secret decoder ring */
601 nsresult rv = NS_OK;
602 nsCOMPtr<nsISecretDecoderRing> secretDecoderRing
603 = do_CreateInstance("@mozilla.org/security/sdr;1", &rv);
604 if (NS_FAILED(rv)) {
605 return NS_ERROR_FAILURE;
607 gSecretDecoderRing = secretDecoderRing.get();
608 NS_ADDREF(gSecretDecoderRing);
610 return NS_OK;
613 #define PREFIX "~"
614 #include "plbase64.h"
616 static nsresult EncryptString (const char * text, char *& crypt) {
618 /* use SecretDecoderRing if encryption pref is set */
619 nsresult rv;
620 if (SI_GetBoolPref(pref_Crypto, PR_FALSE)) {
621 rv = wallet_CryptSetup();
622 if (NS_SUCCEEDED(rv)) {
623 rv = gSecretDecoderRing->EncryptString(text, &crypt);
625 if (NS_FAILED(rv)) {
626 gEncryptionFailure = PR_TRUE;
628 return rv;
631 /* otherwise do our own obscuring using Base64 encoding */
632 char * crypt0 = PL_Base64Encode(text, 0, NULL);
633 if (!crypt0) {
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);
639 PRUint32 i;
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';
647 WALLET_FREE(crypt0);
649 return NS_OK;
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);
657 text[0] = '\0';
658 return NS_OK;
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);
682 if (NS_FAILED(rv)) {
683 gEncryptionFailure = PR_TRUE;
685 return rv;
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);
693 text[0] = '\0';
694 return NS_OK;
696 text = PL_Base64Decode(&crypt[PREFIX_len], 0, NULL);
697 if (!text) {
698 return NS_ERROR_FAILURE;
700 return NS_OK;
703 void
704 WLLT_ExpirePassword(PRBool* status) {
705 if (gSecretDecoderRing) {
706 gSecretDecoderRing->LogoutAndTeardown();
708 *status = PR_TRUE;
711 void
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;
722 void
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);
733 nsresult
734 wallet_Encrypt(const nsCString& text, nsCString& crypt) {
736 /* encrypt text to crypt */
737 char * cryptCString = nsnull;
738 nsresult rv = EncryptString(text.get(), cryptCString);
739 if (NS_FAILED(rv)) {
740 return rv;
742 crypt = cryptCString;
743 WALLET_FREE(cryptCString);
744 return NS_OK;
747 nsresult
748 wallet_Decrypt(const nsCString& crypt, nsCString& text) {
750 /* decrypt crypt to text */
751 char * textCString = nsnull;
752 nsresult rv = DecryptString(crypt.get(), textCString);
753 if (NS_FAILED(rv)) {
754 return rv;
757 text = textCString;
758 WALLET_FREE(textCString);
759 return NS_OK;
762 nsresult
763 Wallet_Encrypt (const nsAString& textUCS2, nsAString& cryptUCS2) {
764 nsCAutoString cryptUTF8;
765 nsresult rv = wallet_Encrypt(NS_ConvertUTF16toUTF8(textUCS2), cryptUTF8);
766 CopyUTF8toUTF16(cryptUTF8, cryptUCS2);
767 return rv;
770 nsresult
771 Wallet_Decrypt(const nsAString& cryptUCS2, nsAString& textUCS2) {
772 nsCAutoString textUTF8;
773 nsresult rv = wallet_Decrypt(NS_ConvertUTF16toUTF8(cryptUCS2), textUTF8);
774 CopyUTF8toUTF16(textUTF8, textUCS2);
775 return rv;
779 /**********************************************************/
780 /* The following routines are for accessing the data base */
781 /**********************************************************/
784 * clear out the designated list
786 static void
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;
797 delete (*list);
798 *list = nsnull;
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;
811 static nsresult
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++];
828 return NS_OK;
831 static void
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++) {
838 mapElementPtr =
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--) {
847 mapElementPtr =
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
860 static PRBool
861 wallet_WriteToList(
862 const char* item1,
863 const char* item2,
864 nsVoidArray* itemList,
865 nsVoidArray*& list,
866 PRBool obscure,
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);
878 } else {
879 mapElement = new wallet_MapElement;
881 if (!mapElement) {
882 return PR_FALSE;
885 nsCAutoString item1UTF8(item1); ToLowerCase(item1UTF8);
886 mapElement->item1 = ToNewCString(item1UTF8);
887 mapElement->item2 = PL_strdup(item2);
889 if (obscure) {
890 char * crypt = nsnull;
891 if (NS_FAILED(EncryptString(mapElement->item2, crypt))) {
892 delete mapElement;
893 return PR_FALSE;
895 WALLET_FREEIF(mapElement->item2);
896 mapElement->item2 = crypt;
899 /* make sure the list exists */
900 if(!list) {
901 list = new nsVoidArray();
902 if(!list) {
903 delete mapElement;
904 return PR_FALSE;
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);
919 return PR_TRUE;
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;
928 break;
929 } else if (LIST_COUNT(mapElementPtr->itemList) == LIST_COUNT(itemList)) {
930 if (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;
938 break;
940 } else if (PL_strlen(mapElementPtr->item2) < PL_strlen(mapElement->item2)) {
941 list->InsertElementAt(mapElement, i);
942 added_to_list = PR_TRUE;
943 break;
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
951 delete mapElement;
952 } else if (DUP_BEFORE==placement) {
953 list->InsertElementAt(mapElement, i);
955 if (DUP_AFTER!=placement) {
956 added_to_list = PR_TRUE;
957 break;
959 } else if(PL_strcmp(mapElementPtr->item1, mapElement->item1)>=0) {
960 list->InsertElementAt(mapElement, i);
961 added_to_list = PR_TRUE;
962 break;
965 if (!added_to_list) {
966 list->AppendElement(mapElement);
968 return PR_TRUE;
972 * fetch an entry from the designated list
974 static PRBool
975 wallet_ReadFromList(
976 const nsACString& item1,
977 nsACString& item2,
978 nsVoidArray*& itemList,
979 nsVoidArray*& list,
980 PRBool obscure,
981 PRInt32& index)
983 if (!list || (index == -1)) {
984 return PR_FALSE;
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())) {
993 if (obscure) {
994 char * plaintext = nsnull;
995 if (NS_FAILED(DecryptString(mapElementPtr->item2, plaintext))) {
996 return PR_FALSE;
998 item2 = plaintext;
999 } else {
1000 item2 = mapElementPtr->item2;
1002 itemList = mapElementPtr->itemList;
1003 index = i+1;
1004 if (index == count) {
1005 index = -1;
1007 return PR_TRUE;
1010 index = 0;
1011 return PR_FALSE;
1014 PRBool
1015 wallet_ReadFromList(
1016 const nsACString& item1,
1017 nsACString& item2,
1018 nsVoidArray*& itemList,
1019 nsVoidArray*& list,
1020 PRBool obscure)
1022 PRInt32 index = 0;
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) {
1055 nsresult res;
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);
1064 return NS_OK;
1067 char *
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 */
1074 char name[13];
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
1086 nsresult
1087 wallet_GetLine(nsIInputStream* strm, nsACString &line)
1089 line.Truncate();
1091 nsCOMPtr<nsILineInputStream> lis(do_QueryInterface(strm));
1092 NS_ENSURE_TRUE(lis, NS_ERROR_UNEXPECTED);
1094 PRBool more;
1095 nsresult rv = lis->ReadLine(line, &more);
1096 if (NS_FAILED(rv))
1097 return rv;
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;
1104 return NS_OK;
1107 static PRBool
1108 wallet_GetHeader(nsIInputStream* strm)
1110 nsCAutoString format;
1112 /* format revision number */
1113 if (NS_FAILED(wallet_GetLine(strm, format))) {
1114 return PR_FALSE;
1116 return format.EqualsLiteral(HEADER_VERSION);
1120 * Write a line-feed to a file
1122 static void
1123 wallet_EndLine(nsIOutputStream* strm) {
1124 static const char nl = '\n';
1125 PRUint32 dummy;
1126 strm->Write(&nl, 1, &dummy);
1130 * Write a line to a file
1132 void
1133 wallet_PutLine(nsIOutputStream* strm, const char* line) {
1134 PRUint32 dummy;
1135 strm->Write(line, strlen(line), &dummy);
1136 wallet_EndLine(strm);
1139 static void
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
1151 static void
1152 wallet_WriteToFile(const char * filename, nsVoidArray* list) {
1153 wallet_MapElement * mapElementPtr;
1155 /* make sure the list exists */
1156 if(!list) {
1157 return;
1161 /* open output stream */
1162 nsCOMPtr<nsIFile> file;
1163 nsresult rv = Wallet_ProfileDirectory(getter_AddRefs(file));
1164 if (NS_FAILED(rv)) {
1165 return;
1168 file->AppendNative(nsDependentCString(filename));
1170 nsCOMPtr<nsIOutputStream> fileOutputStream;
1171 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
1172 file,
1174 0600);
1175 if (NS_FAILED(rv))
1176 return;
1178 nsCOMPtr<nsIOutputStream> strm;
1179 rv = NS_NewBufferedOutputStream(getter_AddRefs(strm), fileOutputStream, 4096);
1180 if (NS_FAILED(rv))
1181 return;
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);
1195 } else {
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
1207 // that for us
1208 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(strm);
1209 NS_ASSERTION(safeStream, "expected a safe output stream!");
1210 if (safeStream) {
1211 rv = safeStream->Finish();
1212 if (NS_FAILED(rv)) {
1213 NS_WARNING("failed to save wallet file! possible dataloss");
1214 return;
1220 * Read contents of designated file into designated list
1222 static void
1223 wallet_ReadFromFile
1224 (const char * filename, nsVoidArray*& list, PRBool localFile, PlacementType placement = AT_END) {
1226 /* open input stream */
1227 nsCOMPtr<nsIFile> file;
1228 nsresult rv;
1229 if (localFile) {
1230 rv = Wallet_ProfileDirectory(getter_AddRefs(file));
1231 } else {
1232 rv = Wallet_DefaultsDirectory(getter_AddRefs(file));
1234 if (NS_FAILED(rv)) {
1235 return;
1237 file->AppendNative(nsDependentCString(filename));
1238 nsCOMPtr<nsIInputStream> strm;
1239 rv = NS_NewLocalFileInputStream(getter_AddRefs(strm), file);
1240 if (NS_FAILED(rv))
1241 return;
1243 /* read in the header */
1244 if (!PL_strcmp(filename, schemaValueFileName)) {
1245 if (!wallet_GetHeader(strm)) {
1246 /* something's wrong -- ignore the file */
1247 return;
1251 for (;;) {
1252 if (NS_FAILED(wallet_GetLine(strm, helpMac->item1))) {
1253 /* end of file reached */
1254 break;
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);
1261 continue;
1264 if (NS_FAILED(wallet_GetLine(strm, helpMac->item2))) {
1265 /* unexpected end of file reached */
1266 break;
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);
1273 continue;
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);
1280 return;
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);
1287 } else {
1288 /* need to create a sublist and put item2 and item3 onto it */
1290 nsVoidArray * itemList = new nsVoidArray();
1291 if (!itemList) {
1292 break;
1295 wallet_Sublist * sublist = new wallet_Sublist;
1296 if (!sublist) {
1297 break;
1299 sublist->item = ToNewCString(helpMac->item2);
1300 itemList->AppendElement(sublist);
1301 sublist = new wallet_Sublist;
1302 if (!sublist) {
1303 delete itemList;
1304 break;
1306 sublist->item = ToNewCString(helpMac->item3);
1307 itemList->AppendElement(sublist);
1308 /* add any following items to sublist up to next blank line */
1309 for (;;) {
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);
1314 return;
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);
1320 break;
1322 /* add item to sublist */
1323 sublist = new wallet_Sublist;
1324 if (!sublist) {
1325 delete itemList;
1326 break;
1328 sublist->item = ToNewCString(helpMac->item3);
1329 itemList->AppendElement(sublist);
1336 /*********************************************************************/
1337 /* The following are utility routines for the main wallet processing */
1338 /*********************************************************************/
1340 void
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");
1346 if (window) {
1347 wallet_Alert(message, window);
1348 } else {
1349 wallet_Alert(message, dialog);
1351 WALLET_FREE(message);
1355 static void
1356 wallet_GetHostFile(nsIURI * url, nsString& outHostFile)
1358 outHostFile.Truncate(0);
1359 nsCAutoString host;
1360 nsresult rv = url->GetHost(host);
1361 if (NS_FAILED(rv)) {
1362 return;
1364 NS_ConvertUTF8toUTF16 urlName(host);
1365 nsCAutoString file;
1366 rv = url->GetPath(file);
1367 if (NS_FAILED(rv)) {
1368 return;
1370 AppendUTF8toUTF16(file, urlName);
1372 PRInt32 queryPos = urlName.FindChar('?');
1373 PRInt32 stringEnd = (queryPos == kNotFound) ? urlName.Length() : queryPos;
1374 urlName.Left(outHostFile, stringEnd);
1377 static void
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>'~') {
1385 stripText += c;
1391 * given a displayable text, get the schema
1393 static void
1394 TextToSchema(
1395 const nsString& text,
1396 nsACString& schema)
1398 /* return if no SchemaStrings list exists */
1399 if (!wallet_SchemaStrings_list) {
1400 return;
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);
1414 if (count2) {
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;
1423 break;
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;
1432 if (isSubstring) {
1434 /* all strings were contained in the displayable text, accept this schema */
1435 schema.Assign(mapElementPtr->item1);
1436 return;
1442 * given a field name, get the value
1444 static nsresult
1445 FieldToValue(
1446 const nsString& field,
1447 nsACString& schema,
1448 nsString& valueUCS2,
1449 nsVoidArray*& itemList,
1450 PRInt32& index)
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 */
1459 nsVoidArray* dummy;
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;
1470 if ((index >= 0) &&
1471 wallet_ReadFromList
1472 (schema, valueUTF8, itemList, wallet_SchemaToValue_list, PR_TRUE, index2)) {
1473 /* value found, prefill it into form and return */
1474 CopyUTF8toUTF16(valueUTF8, valueUCS2);
1475 index = index2;
1476 return NS_OK;
1478 } else {
1480 /* value not found, see if concatenation rule exists */
1481 nsVoidArray * itemList2;
1482 nsCAutoString valueUTF8b;
1483 if (index > 0) {
1484 index = 0;
1486 PRInt32 index0 = index;
1487 PRInt32 index00 = index;
1488 PRInt32 index4 = 0;
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 */
1501 PRInt32 index5 = 0;
1502 PRInt32 j;
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)) {
1506 failed = PR_TRUE;
1507 break;
1509 index00 += 2;
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;
1516 index00 += 2;
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.
1531 index00 = index0;
1532 PRInt32 index3 = 0;
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 */
1539 failed = PR_TRUE;
1540 break;
1542 index00 += 2;
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;
1552 index00 += 2;
1554 if (index00 > index00max) {
1555 index00max = index00;
1559 itemList = nsnull;
1560 if (!concatenatedValueUTF8.IsEmpty()) {
1562 /* a new value was found */
1563 index -= 2;
1564 CopyUTF8toUTF16(concatenatedValueUTF8, valueUCS2);
1565 return NS_OK;
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 */
1573 index = -1;
1574 return NS_ERROR_FAILURE;
1576 } else {
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;
1591 index = index2;
1592 CopyUTF8toUTF16(valueUTF8, valueUCS2);
1593 return NS_OK;
1596 index = -1;
1597 return NS_ERROR_FAILURE;
1600 static nsresult
1601 wallet_GetSelectIndex(
1602 nsIDOMHTMLSelectElement* selectElement,
1603 const nsString& value,
1604 PRInt32& index)
1606 PRUint32 length;
1607 selectElement->GetLength(&length);
1608 nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
1609 selectElement->GetOptions(getter_AddRefs(options));
1610 if (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));
1617 if (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) {
1631 index = optionX;
1632 return NS_OK;
1638 return NS_ERROR_FAILURE;
1641 void
1642 wallet_StepForwardOrBack
1643 (nsIDOMNode*& elementNode, nsString& text, PRBool& atInputOrSelect, PRBool& atEnd, PRBool goForward) {
1644 nsresult result;
1645 atInputOrSelect = PR_FALSE;
1646 atEnd = PR_FALSE;
1648 /* try getting next/previous sibling */
1649 nsCOMPtr<nsIDOMNode> sibling;
1650 if (goForward) {
1651 result = elementNode->GetNextSibling(getter_AddRefs(sibling));
1652 } else {
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 */
1661 atEnd = PR_TRUE;
1662 } else {
1663 /* parent obtained */
1664 elementNode = parent;
1666 return;
1668 /* sibling obtained */
1669 elementNode = sibling;
1671 while (PR_TRUE) {
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)) {
1687 nsAutoString type;
1688 result = inputElement->GetType(type);
1689 if (goForward) {
1690 if (NS_SUCCEEDED(result) &&
1691 (type.IsEmpty() ||
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;
1695 return;
1697 } else {
1698 if (NS_SUCCEEDED(result) &&
1699 !type.LowerCaseEqualsLiteral("hidden")) {
1700 /* at <input> element and it's type is not "hidden" */
1701 atInputOrSelect = PR_TRUE;
1702 return;
1705 } else {
1706 nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(elementNode));
1708 if (selectElement) {
1709 atInputOrSelect = PR_TRUE;
1710 return;
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")) {
1725 return;
1728 /* try getting first/last child */
1729 nsCOMPtr<nsIDOMNode> child;
1730 if (goForward) {
1731 result = elementNode->GetFirstChild(getter_AddRefs(child));
1732 } else {
1733 result = elementNode->GetLastChild(getter_AddRefs(child));
1735 if ((NS_FAILED(result)) || !child) {
1736 /* no children, we're done with this node */
1737 return;
1739 /* child obtained */
1740 elementNode = child;
1743 return;
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;
1753 static void
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);
1762 return;
1765 if (!schema.IsEmpty()) {
1766 numerator = 0;
1767 denominator = 0;
1768 lastPositionalSchema.Assign(schema);
1769 } else if (numerator < denominator) {
1770 schema.Assign(lastPositionalSchema);
1771 } else {
1772 schema.SetLength(0);
1773 return;
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:
1803 * 1/1 Home.Phone
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 */
1814 numerator++;
1816 } else {
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) {
1826 nsAutoString text;
1827 PRBool atEnd;
1828 wallet_StepForwardOrBack
1829 (elementNode, text, atInputOrSelect, atEnd, PR_TRUE); /* step forward */
1830 if (atEnd) {
1831 break;
1833 PRUnichar c;
1834 for (PRUint32 j=0; j<text.Length(); j++) {
1835 c = text.CharAt(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) {
1845 // PRBool accept;
1846 // rv = intl->Is(c, intl->kUGenCategory_Number, &accept);
1847 // if (NS_FAILED(rv) || !accept) {
1848 // rv = intl->Is(c, intl->kUGenCategory_Letter, &accept);
1849 // }
1850 // if (NS_OK(rv) && accept) {
1851 // charFound = PR_TRUE;
1852 // break;
1853 // }
1854 // } else {
1855 // /* failed to get the i18n interfaces, so just treat latin characters */
1856 if (nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c)) {
1857 charFound = PR_TRUE;
1858 break;
1859 // }
1862 if (!charFound && atInputOrSelect) {
1863 /* add one more element to position set */
1864 denominator++;
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);
1887 return;
1894 const char* previousElementState = nsnull;
1895 static nsIDOMNode* previousElementNode;
1897 static void
1898 wallet_InitializeStateTesting() {
1899 previousElementNode = nsnull;
1900 previousElementState = nsnull;
1903 static void
1904 wallet_ResolveStateSchema(nsIDOMNode* elementNode, nsACString& schema) {
1906 /* return if no StateSchema list exists */
1907 if (!wallet_StateSchema_list) {
1908 return;
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
1922 * ship ShipTo.Phone
1923 * bill BillTo.Phone
1924 * * Home.Phone
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;
1940 while (!atEnd) {
1942 /* get next text in the dom */
1943 nsAutoString text;
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);
1953 PRInt32 j;
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);
1960 return;
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);
1969 return;
1973 /* no catch-all state specified, return no schema */
1974 return;
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);
1989 return;
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;
2004 return;
2008 /* no catch-all state specified, return no schema */
2009 previousElementNode = elementNode;
2010 return;
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");
2021 static void
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);
2031 return;
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 */
2042 nsAutoString text;
2043 wallet_StepForwardOrBack(localElementNode, text, atInputOrSelect, atEnd, PR_FALSE);
2045 /* strip off non-alphanumerics */
2046 PRUint32 i;
2047 PRUnichar c;
2048 nsAutoString temp;
2049 for (i=0; i<text.Length(); i++) {
2050 c = text.CharAt(i);
2051 if (nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c)) {
2052 temp.Append(c);
2055 text = temp;
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);
2074 return;
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);
2107 return;
2110 nsresult
2111 wallet_GetPrefills(
2112 nsIDOMNode* elementNode,
2113 nsIDOMHTMLInputElement*& inputElement,
2114 nsIDOMHTMLSelectElement*& selectElement,
2115 nsACString& schema,
2116 nsString& value,
2117 PRInt32& selectIndex,
2118 PRInt32& index)
2120 nsresult result;
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)) {
2127 nsAutoString type;
2128 result = inputElement->GetType(type);
2129 if (NS_SUCCEEDED(result) &&
2130 (type.IsEmpty() ||
2131 type.LowerCaseEqualsLiteral("text"))) {
2132 nsAutoString field;
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);
2140 if (element) {
2141 nsAutoString vcard; vcard.AssignLiteral("VCARD_NAME");
2142 nsAutoString vcardValueUCS2;
2143 result = element->GetAttribute(vcard, vcardValueUCS2);
2144 if (NS_OK == result) {
2145 nsVoidArray* dummy;
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;
2173 selectIndex = -1;
2174 schema = localSchema;
2175 return NS_OK;
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)) {
2186 nsAutoString field;
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;
2205 return NS_OK;
2207 } else {
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;
2219 return NS_OK;
2225 NS_RELEASE(selectElement);
2227 return NS_ERROR_FAILURE;
2231 * termination for wallet session
2233 void
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();
2243 delete helpMac;
2244 helpMac = nsnull;
2247 //#define WALLET_CHECK_FOOTPRINT
2248 #ifdef WALLET_CHECK_FOOTPRINT
2249 PRInt32
2250 wallet_Size(nsVoidArray * list) {
2251 PRInt32 size = 0;
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);
2268 return size;
2270 #endif
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;
2281 static void
2282 wallet_Initialize(PRBool unlockDatabase=PR_TRUE) {
2284 #ifdef DEBUG_morse
2285 //wallet_ClearStopwatch();
2286 //wallet_ResumeStopwatch();
2287 #endif
2289 if (!wallet_tablesInitialized) {
2290 #ifdef DEBUG_morse
2291 //wallet_PauseStopwatch();
2292 //wallet_DumpStopwatch();
2293 #endif
2294 // printf("******** start profile\n");
2295 // ProfileStart();
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;
2309 PRInt32 size;
2310 size = wallet_Size(wallet_FieldToSchema_list);
2311 totalSize += size;
2312 printf("FieldToSchema: %d\n", size);
2313 size = wallet_Size(wallet_VcardToSchema_list);
2314 totalSize += size;
2315 printf("VcardToSchema: %d\n", size);
2316 size = wallet_Size(wallet_SchemaConcat_list);
2317 totalSize += size;
2318 printf("SchemaConcat: %d\n", size);
2319 size = wallet_Size(wallet_SchemaStrings_list);
2320 totalSize += size;
2321 printf("SchemaStrings: %d\n", size);
2322 size = wallet_Size(wallet_PositionalSchema_list);
2323 totalSize += size;
2324 printf("PositionalSchema: %d\n", size);
2325 size = wallet_Size(wallet_StateSchema_list);
2326 totalSize += size;
2327 printf("StateSchema: %d\n", size);
2328 size = wallet_Size(wallet_DistinguishedSchema_list);
2329 totalSize += size;
2330 printf("DistinguishedSchema: %d\n", size);
2331 printf("Total size: %d\n", totalSize);
2332 #endif
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.
2344 // ProfileStop();
2345 // printf("****** end profile\n");
2346 wallet_tablesInitialized = PR_TRUE;
2349 if (!unlockDatabase) {
2350 return;
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;
2369 #if DEBUG
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);
2390 #endif
2394 static void
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
2406 static void
2407 wallet_InitializeCurrentURL(nsIDocument * doc) {
2409 /* get url */
2410 nsIURI *url = doc->GetDocumentURI();
2411 if (wallet_lastUrl == url) {
2412 return;
2413 } else {
2414 if (wallet_lastUrl) {
2415 //?? NS_RELEASE(lastUrl);
2417 wallet_lastUrl = url;
2422 #define SEPARATOR "#*%$"
2424 static nsresult
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));
2432 return NS_OK;
2435 static void
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;
2454 void
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;
2476 static void
2477 wallet_FreeURL(wallet_MapElement *url) {
2479 if(!url) {
2480 return;
2482 wallet_URL_list->RemoveElement(url);
2483 PR_Free(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";
2491 void
2492 Wallet_SignonViewerReturn(const nsAString& results)
2494 wallet_MapElement *url;
2495 nsAutoString gone;
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);
2503 while (count>0) {
2504 count--;
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);
2512 } else {
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);
2527 while (count2>0) {
2528 count2--;
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);
2536 } else {
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
2550 static PRBool
2551 wallet_OKToCapture(const nsAFlatCString& url, nsIDOMWindowInternal* window) {
2553 /* exit if pref is not set */
2554 if (!wallet_GetFormsCapturingPref() || !wallet_GetEnabledPref()) {
2555 return PR_FALSE;
2558 /* see if this url is already on list of url's for which we don't want to capture */
2559 wallet_InitializeURLList();
2560 nsVoidArray* dummy;
2561 nsCAutoString urlPermissions;
2562 if (wallet_ReadFromList(url, urlPermissions, dummy, wallet_URL_list, PR_FALSE)) {
2563 if (NO_CAPTURE(urlPermissions) == 'y') {
2564 return PR_FALSE;
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;
2576 } else {
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"));
2584 if (os) {
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
2596 static PRBool
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()) {
2601 return PR_FALSE;
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);
2613 nsVoidArray* dummy;
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 */
2624 PRInt32 index = 0;
2625 PRInt32 lastIndex = index;
2626 while(wallet_ReadFromList(localSchema, oldValue, dummy, wallet_SchemaToValue_list, PR_TRUE, index)) {
2627 PRBool isNewValue = !oldValue.Equals(valueCString.get());
2628 if (!isNewValue) {
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);
2638 wallet_WriteToList(
2639 mapElement->item1,
2640 mapElement->item2,
2641 mapElement->itemList,
2642 wallet_SchemaToValue_list,
2643 PR_FALSE); /* note: obscure=false, otherwise we will obscure an obscured value */
2644 delete mapElement;
2645 return PR_TRUE;
2647 lastIndex = index;
2650 /* this is a new value so store it */
2651 dummy = nsnull;
2652 if (wallet_WriteToList(localSchema.get(), valueCString.get(), dummy, wallet_SchemaToValue_list, PR_TRUE)) {
2653 wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
2656 } else {
2658 /* no field to schema mapping so assume schema name is same as field name */
2660 /* is this a new value for the schema */
2661 PRInt32 index = 0;
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());
2672 if (!isNewValue) {
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);
2682 wallet_WriteToList(
2683 mapElement->item1,
2684 mapElement->item2,
2685 mapElement->itemList,
2686 wallet_SchemaToValue_list,
2687 PR_FALSE); /* note: obscure=false, otherwise we will obscure an obscured value */
2688 delete mapElement;
2689 return PR_TRUE;
2691 lastIndex = index;
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 */
2701 dummy = nsnull;
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);
2713 return PR_TRUE;
2716 /***************************************************************/
2717 /* The following are the interface routines seen by other dlls */
2718 /***************************************************************/
2720 void
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;
2739 void
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;
2757 void
2758 WLLT_PostEdit(const nsAString& walletList)
2760 nsCOMPtr<nsIFile> file;
2761 nsresult rv = Wallet_ProfileDirectory(getter_AddRefs(file));
2762 if (NS_FAILED(rv)) {
2763 return;
2766 nsAutoString tail( walletList );
2767 nsAutoString head, temp;
2768 PRInt32 separator;
2770 /* get first item in list */
2771 separator = tail.FindChar(BREAK);
2772 if (-1 == separator) {
2773 return;
2775 tail.Left(head, separator);
2776 tail.Mid(temp, separator+1, tail.Length() - (separator+1));
2777 tail = temp;
2779 /* return if OK button was not pressed */
2780 if (!head.EqualsLiteral("OK")) {
2781 return;
2784 file->AppendNative(nsDependentCString(schemaValueFileName));
2786 /* open SchemaValue file */
2787 nsCOMPtr<nsIOutputStream> fileOutputStream;
2788 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
2789 file,
2791 0600);
2792 if (NS_FAILED(rv))
2793 return;
2795 nsCOMPtr<nsIOutputStream> strm;
2796 rv = NS_NewBufferedOutputStream(getter_AddRefs(strm), fileOutputStream, 4096);
2797 if (NS_FAILED(rv))
2798 return;
2800 /* write the values in the walletList to the file */
2801 wallet_PutHeader(strm);
2802 for (;;) {
2803 separator = tail.FindChar(BREAK);
2804 if (-1 == separator) {
2805 break;
2807 tail.Left(head, separator);
2808 tail.Mid(temp, separator+1, tail.Length() - (separator+1));
2809 tail = temp;
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
2816 // that for us
2817 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(strm);
2818 NS_ASSERTION(safeStream, "expected a safe output stream!");
2819 if (safeStream) {
2820 rv = safeStream->Finish();
2821 if (NS_FAILED(rv)) {
2822 NS_WARNING("failed to save wallet file! possible dataloss");
2823 return;
2827 strm = nsnull;
2828 fileOutputStream = nsnull;
2830 wallet_Clear(&wallet_SchemaToValue_list);
2831 wallet_ReadFromFile(schemaValueFileName, wallet_SchemaToValue_list, PR_TRUE);
2834 void
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);
2849 } else {
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);
2862 void
2863 WLLT_DeleteAll() {
2864 wallet_Initialize();
2865 wallet_Clear(&wallet_SchemaToValue_list);
2866 wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
2867 SI_DeleteAll();
2870 void
2871 WLLT_ClearUserData() {
2872 wallet_ValuesReadIn = PR_FALSE;
2873 namesInitialized = PR_FALSE;
2874 wallet_URLListInitialized = PR_FALSE;
2877 void
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);
2891 int PR_CALLBACK
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);
2901 PRInt32 i = 0;
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)) {
2911 goto fail;
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))) {
2922 goto fail;
2924 if (NS_FAILED(EncryptString(plainText, crypt))) {
2925 goto fail;
2927 mapElementPtr->item2 = crypt;
2928 } else {
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))) {
2934 goto fail;
2936 if (NS_FAILED(EncryptString(plainText, crypt))) {
2937 goto fail;
2939 sublistPtr->item = crypt;
2943 wallet_WriteToFile(schemaValueFileName, wallet_SchemaToValue_list);
2944 if (!SINGSIGN_ReencryptAll()) {
2945 goto fail;
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 */
2966 fail:
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--;
2975 return 1;
2978 void
2979 WLLT_InitReencryptCallback(nsIDOMWindowInternal* window) {
2980 static PRBool registered = PR_FALSE;
2981 static nsIDOMWindowInternal* lastWindow;
2982 if (registered) {
2983 SI_UnregisterCallback(pref_Crypto, wallet_ReencryptAll, lastWindow);
2985 SI_RegisterCallback(pref_Crypto, wallet_ReencryptAll, window);
2986 lastWindow = window;
2987 registered = PR_TRUE;
2990 static void
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
2999 void
3000 WLLT_PrefillReturn(const nsAString& results)
3002 nsAutoString fillins;
3003 nsAutoString urlName;
3004 nsAutoString skip;
3005 nsAutoString next;
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);
3017 nsVoidArray* dummy;
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;
3023 } else {
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"));
3031 if (os) {
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;
3043 return;
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 */
3067 nsAutoString tail;
3068 if (NS_FAILED(wallet_GetNextInString(fillins, next, tail))) {
3069 break;
3071 fillins = 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);
3076 fillins = 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;
3091 PRInt32 index = 0;
3092 PRInt32 lastIndex = index;
3093 nsVoidArray* dummy;
3094 while(wallet_ReadFromList(nsDependentCString(mapElementPtr->schema),
3095 oldvalueUTF8,
3096 dummy,
3097 wallet_SchemaToValue_list,
3098 PR_TRUE,
3099 index)) {
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);
3104 wallet_WriteToList(
3105 mapElement->item1,
3106 mapElement->item2,
3107 mapElement->itemList,
3108 wallet_SchemaToValue_list,
3109 PR_FALSE); /* note: obscure=false, otherwise we will obscure an obscured value */
3110 delete mapElement;
3111 break;
3113 lastIndex = index;
3118 /* Change the value */
3120 if (!next.IsEmpty()) {
3121 if (mapElementPtr->inputElement) {
3122 mapElementPtr->inputElement->SetValue(next);
3123 } else {
3124 nsresult result;
3125 result = wallet_GetSelectIndex(mapElementPtr->selectElement, next, mapElementPtr->selectIndex);
3126 if (NS_SUCCEEDED(result)) {
3127 mapElementPtr->selectElement->SetSelectedIndex(mapElementPtr->selectIndex);
3128 } else {
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
3145 static void
3146 wallet_TraversalForPrefill
3147 (nsIDOMWindow* win, nsVoidArray* wallet_PrefillElement_list, nsString& urlName) {
3149 nsresult result;
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);
3155 if (doc) {
3156 nsIURI *url = doc->GetDocumentURI();
3157 if (url) {
3158 wallet_GetHostFile(url, urlName);
3160 wallet_Initialize();
3161 wallet_InitializeCurrentURL(doc);
3163 nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(doc);
3164 if (htmldoc) {
3165 nsCOMPtr<nsIDOMHTMLCollection> forms;
3166 htmldoc->GetForms(getter_AddRefs(forms));
3167 if (forms) {
3168 wallet_InitializeStateTesting();
3169 PRUint32 numForms;
3170 forms->GetLength(&numForms);
3171 for (PRUint32 formX = 0; (formX < numForms) && !gEncryptionFailure; formX++) {
3172 nsCOMPtr<nsIDOMNode> formNode;
3173 forms->Item(formX, getter_AddRefs(formNode));
3174 if (formNode) {
3175 nsCOMPtr<nsIDOMHTMLFormElement> formElement = do_QueryInterface(formNode);
3176 if (formElement) {
3177 nsCOMPtr<nsIDOMHTMLCollection> elements;
3178 result = formElement->GetElements(getter_AddRefs(elements));
3179 if (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));
3186 if (elementNode) {
3187 wallet_PrefillElement * prefillElement;
3188 PRInt32 index = 0;
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
3200 (elementNode,
3201 prefillElement->inputElement,
3202 prefillElement->selectElement,
3203 schemaUTF8,
3204 prefillElement->value,
3205 prefillElement->selectIndex,
3206 index))) {
3207 /* another value found */
3208 prefillElement->schema = ToNewCString(schemaUTF8);
3209 if (nsnull == firstElement) {
3210 firstElement = prefillElement;
3212 numberOfElements++;
3213 prefillElement->count = 0;
3214 wallet_PrefillElement_list->AppendElement(prefillElement);
3215 } else {
3216 /* value not found, stop looking for more values */
3217 delete prefillElement;
3218 break;
3220 } // for
3221 if (numberOfElements>0) {
3222 firstElement->count = numberOfElements;
3225 } // for
3236 nsCOMPtr<nsIDOMWindowCollection> frames;
3237 win->GetFrames(getter_AddRefs(frames));
3238 if (frames) {
3239 PRUint32 numFrames;
3240 frames->GetLength(&numFrames);
3241 for (PRUint32 frameX = 0; (frameX < numFrames) && !gEncryptionFailure; frameX++) {
3242 nsCOMPtr<nsIDOMWindow> frameNode;
3243 frames->Item(frameX, getter_AddRefs(frameNode));
3244 if (frameNode) {
3245 wallet_TraversalForPrefill(frameNode, wallet_PrefillElement_list, urlName);
3251 nsresult
3252 WLLT_PrefillOneElement
3253 (nsIDOMWindowInternal* win, nsIDOMNode* elementNode, nsAString& compositeValue)
3255 nsIDOMHTMLInputElement* inputElement;
3256 nsIDOMHTMLSelectElement* selectElement;
3257 nsCAutoString schema;
3258 nsString value;
3259 PRInt32 selectIndex = 0;
3260 PRInt32 index = 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);
3267 if (doc) {
3268 wallet_Initialize(PR_TRUE);
3269 wallet_InitializeCurrentURL(doc);
3270 wallet_InitializeStateTesting();
3271 while (NS_SUCCEEDED(wallet_GetPrefills
3272 (elementNode,
3273 inputElement,
3274 selectElement,
3275 schema,
3276 value,
3277 selectIndex,
3278 index))) {
3279 compositeValue.Append(BREAK);
3280 compositeValue.Append(value);
3285 return NS_OK;
3288 nsresult
3289 WLLT_Prefill(nsIPresShell* shell, PRBool quick, nsIDOMWindowInternal* win)
3291 /* do not prefill if preview window is open in some other browser window */
3292 if (wallet_list) {
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;
3323 if (!quick) {
3324 wallet_InitializeURLList();
3325 nsVoidArray* dummy;
3326 nsCAutoString urlPermissions;
3327 if (!urlName.IsEmpty()) {
3328 wallet_ReadFromList
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);
3344 } else {
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
3352 } else {
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);
3357 #ifdef DEBUG_morse
3358 ////wallet_DumpStopwatch();
3359 ////wallet_ClearStopwatch();
3360 //wallet_DumpTiming();
3361 //wallet_ClearTiming();
3362 #endif
3363 return NS_OK; // indicates that caller is to display preview screen
3367 static PRBool
3368 wallet_CaptureInputElement(nsIDOMNode* elementNode, nsIDocument* doc) {
3369 nsresult result;
3370 PRBool captured = PR_FALSE;
3371 nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(elementNode);
3372 if (inputElement) {
3373 /* it's an input element */
3374 nsAutoString type;
3375 result = inputElement->GetType(type);
3376 if (NS_SUCCEEDED(result) &&
3377 (type.IsEmpty() ||
3378 type.LowerCaseEqualsLiteral("text"))) {
3379 nsAutoString field;
3380 result = inputElement->GetName(field);
3381 if (NS_SUCCEEDED(result)) {
3382 nsAutoString value;
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);
3388 if (element) {
3389 nsAutoString vcardName; vcardName.AssignLiteral("VCARD_NAME");
3390 nsAutoString vcardValueUCS2;
3391 result = element->GetAttribute(vcardName, vcardValueUCS2);
3392 if (NS_OK == result) {
3393 nsVoidArray* dummy;
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)) {
3403 captured = PR_TRUE;
3409 return captured;
3412 static PRBool
3413 wallet_CaptureSelectElement(nsIDOMNode* elementNode, nsIDocument* doc) {
3414 nsresult result;
3415 PRBool captured = PR_FALSE;
3416 nsCOMPtr<nsIDOMHTMLSelectElement> selectElement = do_QueryInterface(elementNode);
3417 if (selectElement) {
3418 /* it's a dropdown list */
3419 nsAutoString field;
3420 result = selectElement->GetName(field);
3422 if (NS_SUCCEEDED(result)) {
3423 PRUint32 length;
3424 selectElement->GetLength(&length);
3426 nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
3427 selectElement->GetOptions(getter_AddRefs(options));
3429 if (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));
3438 if (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);
3453 if (element) {
3454 nsAutoString vcardName; vcardName.AssignLiteral("VCARD_NAME");
3455 nsAutoString vcardValueUCS2;
3456 result = element->GetAttribute(vcardName, vcardValueUCS2);
3457 if (NS_OK == result) {
3458 nsVoidArray* dummy;
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)) {
3468 captured = PR_TRUE;
3470 optionText.Trim(" \n\t\r");
3471 if (textOK && wallet_Capture(doc, field, optionText, schema)) {
3472 captured = PR_TRUE;
3481 return captured;
3484 static void
3485 wallet_TraversalForRequestToCapture(nsIDOMWindow* win, PRInt32& captureCount) {
3487 nsresult result;
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);
3493 if (doc) {
3494 wallet_Initialize();
3495 wallet_InitializeCurrentURL(doc);
3496 nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(doc);
3497 if (htmldoc) {
3498 nsCOMPtr<nsIDOMHTMLCollection> forms;
3499 htmldoc->GetForms(getter_AddRefs(forms));
3500 if (forms) {
3501 wallet_InitializeStateTesting();
3502 PRUint32 numForms;
3503 forms->GetLength(&numForms);
3504 for (PRUint32 formX = 0; (formX < numForms) && !gEncryptionFailure; formX++) {
3505 nsCOMPtr<nsIDOMNode> formNode;
3506 forms->Item(formX, getter_AddRefs(formNode));
3507 if (formNode) {
3508 nsCOMPtr<nsIDOMHTMLFormElement> formElement = do_QueryInterface(formNode);
3509 if (formElement) {
3510 nsCOMPtr<nsIDOMHTMLCollection> elements;
3511 result = formElement->GetElements(getter_AddRefs(elements));
3512 if (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));
3520 if (elementNode) {
3521 if (wallet_CaptureInputElement(elementNode, doc)) {
3522 captureCount++;
3524 if (wallet_CaptureSelectElement(elementNode, doc)) {
3525 captureCount++;
3539 nsCOMPtr<nsIDOMWindowCollection> frames;
3540 win->GetFrames(getter_AddRefs(frames));
3541 if (frames) {
3542 PRUint32 numFrames;
3543 frames->GetLength(&numFrames);
3544 for (PRUint32 frameX = 0; (frameX < numFrames) && !gEncryptionFailure; frameX++)
3546 nsCOMPtr<nsIDOMWindow> frameNode;
3547 frames->Item(frameX, getter_AddRefs(frameNode));
3548 if (frameNode) {
3549 wallet_TraversalForRequestToCapture(frameNode, captureCount);
3555 void
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");
3565 *status = 0;
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");
3570 *status = 0;
3571 } else {
3572 message = Wallet_Localize("NotCaptured");
3573 *status = +1;
3575 wallet_Alert(message, win);
3576 WALLET_FREE(message);
3579 static PRBool
3580 wallet_IsNewValue(nsIDOMNode* elementNode, nsString valueOnForm) {
3581 if (valueOnForm.Equals(EmptyString())) {
3582 return PR_FALSE;
3584 nsIDOMHTMLInputElement* inputElement;
3585 nsIDOMHTMLSelectElement* selectElement;
3586 nsCAutoString schema;
3587 nsAutoString valueSaved;
3588 PRInt32 selectIndex = 0;
3589 PRInt32 index = 0;
3590 while (NS_SUCCEEDED(wallet_GetPrefills
3591 (elementNode, inputElement, selectElement, schema, valueSaved, selectIndex, index))) {
3592 if (valueOnForm.Equals(valueSaved)) {
3593 return PR_FALSE;
3596 return PR_TRUE;
3599 void
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();
3607 if (!doc) {
3608 return;
3610 nsIURI *docURL = doc->GetDocumentURI();
3611 if (!docURL) {
3612 return;
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) {
3620 return;
3623 nsCOMPtr<nsIDOMHTMLCollection> forms;
3624 nsresult rv = htmldoc->GetForms(getter_AddRefs(forms));
3625 if (NS_FAILED(rv) || (forms == nsnull)) {
3626 return;
3629 PRUint32 numForms;
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;
3647 PRInt32 hits = 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;
3663 if (hits > 1) {
3664 OKToPrompt = PR_TRUE;
3669 nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(elementNode));
3670 if ((NS_SUCCEEDED(rv)) && (nsnull != inputElement)) {
3671 nsAutoString type;
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
3679 if (isPassword) {
3680 nsAutoString val;
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)) {
3692 nsAutoString val;
3693 (void) inputElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), val);
3694 if (val.LowerCaseEqualsLiteral("off")) {
3695 isPassword = PR_FALSE;
3696 } else {
3697 (void) formElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), val);
3698 if (val.LowerCaseEqualsLiteral("off")) {
3699 isPassword = PR_FALSE;
3704 if (isPassword) {
3705 passwordcount++;
3706 OKToPrompt = PR_FALSE;
3709 if (isText) {
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;
3715 if (hits > 1) {
3716 OKToPrompt = PR_TRUE;
3722 if (isText || isPassword) {
3723 nsAutoString value;
3724 rv = inputElement->GetValue(value);
3725 if (NS_SUCCEEDED(rv)) {
3726 nsAutoString field;
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);
3745 } else {
3746 data->name = field;
3748 data->isPassword = isPassword;
3749 signonData->AppendElement(data);
3750 if (passwordcount == 0 && !OKToPrompt) {
3751 /* get schema from field */
3752 nsCAutoString schema;
3753 nsVoidArray* dummy;
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);
3764 wallet_ReadFromList
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()) {
3779 hits++;
3780 if (hits > 1 && newValueFound) {
3781 OKToPrompt = PR_TRUE;
3782 break;
3796 /* save login if appropriate */
3797 if (currentFormNode == formNode) {
3798 nsCOMPtr<nsIPrompt> dialog;
3799 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
3800 if (wwatch)
3801 wwatch->GetNewPrompter(0, getter_AddRefs(dialog));
3803 if (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));
3810 delete data;
3812 delete signonData;
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);