/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* wallet.cpp */ #define AutoCapture //#define IgnoreFieldNames #include "wallet.h" #include "singsign.h" #include "nsNetUtil.h" #include "nsIServiceManager.h" #include "nsIDocument.h" #include "nsIDOMHTMLDocument.h" #include "nsIDOMNSHTMLOptionCollection.h" #include "nsIDOMHTMLFormElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLSelectElement.h" #include "nsIDOMHTMLOptionElement.h" #include "nsIURL.h" #include "nsIDOMWindowCollection.h" #include "nsFileStream.h" #include "nsAppDirectoryServiceDefs.h" #include "nsINetSupportDialogService.h" #include "nsIStringBundle.h" #include "nsILocale.h" #include "nsIFileSpec.h" #include "prmem.h" #include "prprf.h" #include "nsIProfile.h" #include "nsIContent.h" #include "nsISecurityManagerComponent.h" #include "nsIWalletService.h" #ifdef DEBUG_morse #define morseAssert NS_ASSERTION #else #define morseAssert(x,y) 0 #endif static NS_DEFINE_IID(kIDOMHTMLDocumentIID, NS_IDOMHTMLDOCUMENT_IID); static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID); static NS_DEFINE_CID(kProfileCID, NS_PROFILE_CID); static NS_DEFINE_IID(kIStringBundleServiceIID, NS_ISTRINGBUNDLESERVICE_IID); static NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID); #include "prlong.h" #include "prinrval.h" #include "prlog.h" // // To enable logging (see prlog.h for full details): // // set NSPR_LOG_MODULES=nsWallet:5 // set NSPR_LOG_FILE=nspr.log // PRLogModuleInfo* gWalletLog = nsnull; /********************************************************/ /* The following data and procedures are for preference */ /********************************************************/ static const char *pref_WalletExtractTables = "wallet.extractTables"; static const char *pref_Caveat = "wallet.caveat"; #ifdef AutoCapture static const char *pref_captureForms = "wallet.captureForms"; static const char *pref_enabled = "wallet.enabled"; #else static const char *pref_WalletNotified = "wallet.Notified"; #endif /* AutoCapture */ static const char *pref_WalletSchemaValueFileName = "wallet.SchemaValueFileName"; static const char *pref_WalletServer = "wallet.Server"; static const char *pref_WalletVersion = "wallet.version"; static const char *pref_WalletLastModified = "wallet.lastModified"; #ifdef AutoCapture PRIVATE PRBool wallet_captureForms = PR_FALSE; #else PRIVATE PRBool wallet_Notified = PR_FALSE; #endif PRIVATE char * wallet_Server = nsnull; #ifdef AutoCapture PRIVATE void wallet_SetFormsCapturingPref(PRBool x) { /* do nothing if new value of pref is same as current value */ if (x == wallet_captureForms) { return; } /* change the pref */ wallet_captureForms = x; } MODULE_PRIVATE int PR_CALLBACK wallet_FormsCapturingPrefChanged(const char * newpref, void * data) { PRBool x; x = SI_GetBoolPref(pref_captureForms, PR_TRUE); wallet_SetFormsCapturingPref(x); return 0; /* this is PREF_NOERROR but we no longer include prefapi.h */ } static void wallet_RegisterCapturePrefCallbacks(void) { PRBool x; static PRBool first_time = PR_TRUE; if(first_time) { first_time = PR_FALSE; x = SI_GetBoolPref(pref_captureForms, PR_TRUE); wallet_SetFormsCapturingPref(x); SI_RegisterCallback(pref_captureForms, wallet_FormsCapturingPrefChanged, NULL); } } PRIVATE PRBool wallet_GetFormsCapturingPref(void) { wallet_RegisterCapturePrefCallbacks(); return wallet_captureForms; } PRIVATE PRBool wallet_GetEnabledPref(void) { /* This pref is not in the prefs panel. It's purpose is to remove wallet from all UI */ static PRBool first_time = PR_TRUE; static PRBool enabled = PR_TRUE; if (first_time) { first_time = PR_FALSE; PRBool x = SI_GetBoolPref(pref_enabled, PR_TRUE); enabled = x; } return enabled; } #else PRIVATE void wallet_SetWalletNotificationPref(PRBool x) { SI_SetBoolPref(pref_WalletNotified, x); wallet_Notified = x; } PRIVATE PRBool wallet_GetWalletNotificationPref(void) { static PRBool first_time = PR_TRUE; if (first_time) { PRBool x = SI_GetBoolPref(pref_WalletNotified, PR_FALSE); wallet_Notified = x; } return wallet_Notified; } #endif /* ! AutoCapture */ /***************************************************/ /* The following declarations define the data base */ /***************************************************/ enum PlacementType {DUP_IGNORE, DUP_OVERWRITE, DUP_BEFORE, DUP_AFTER, AT_END, BY_LENGTH}; #define LIST_COUNT(list) ((list) ? (list)->Count() : 0) MOZ_DECL_CTOR_COUNTER(wallet_Sublist) class wallet_Sublist { public: wallet_Sublist() { MOZ_COUNT_CTOR(wallet_Sublist); } ~wallet_Sublist() { MOZ_COUNT_DTOR(wallet_Sublist); } nsString item; }; /* * The data structure below consists of mapping tables that map one item into another. * The actual interpretation of the items depend on which table we are in. For * example, if in the field-to-schema table, item1 is a field name and item2 is a * schema name. Whereas in the schema-to-value table, item1 is a schema name and * item2 is a value. Therefore this generic data structure refers to them simply as * item1 and item2. */ MOZ_DECL_CTOR_COUNTER(wallet_MapElement) class wallet_MapElement { public: wallet_MapElement() : itemList(nsnull) { MOZ_COUNT_CTOR(wallet_MapElement); } ~wallet_MapElement() { if (itemList) { PRInt32 count = LIST_COUNT(itemList); wallet_Sublist * sublistPtr; for (PRInt32 i=0; iElementAt(i)); delete sublistPtr; } delete itemList; } MOZ_COUNT_DTOR(wallet_MapElement); } nsString item1; nsString item2; nsVoidArray * itemList; }; /* Purpose of this class is to speed up startup time on the mac * * These strings are used over and over again inside an inner loop. Rather * then allocating them and then deallocating them, they will be allocated * only once and left sitting on the heap */ MOZ_DECL_CTOR_COUNTER(wallet_HelpMac) class wallet_HelpMac { public: wallet_HelpMac() { MOZ_COUNT_CTOR(wallet_HelpMac); } ~wallet_HelpMac() { MOZ_COUNT_DTOR(wallet_HelpMac); } nsAutoString item1; nsAutoString item2; nsAutoString item3; nsAutoString dummy; }; wallet_HelpMac * helpMac; PRIVATE nsVoidArray * wallet_FieldToSchema_list=0; PRIVATE nsVoidArray * wallet_VcardToSchema_list=0; PRIVATE nsVoidArray * wallet_SchemaToValue_list=0; PRIVATE nsVoidArray * wallet_SchemaConcat_list=0; PRIVATE nsVoidArray * wallet_SchemaStrings_list=0; PRIVATE nsVoidArray * wallet_PositionalSchema_list=0; PRIVATE nsVoidArray * wallet_StateSchema_list=0; PRIVATE nsVoidArray * wallet_URL_list=0; #ifdef AutoCapture PRIVATE nsVoidArray * wallet_DistinguishedSchema_list=0; #endif #define NO_CAPTURE 0 #define NO_PREVIEW 1 MOZ_DECL_CTOR_COUNTER(wallet_PrefillElement) class wallet_PrefillElement { public: wallet_PrefillElement() : inputElement(nsnull), selectElement(nsnull) { MOZ_COUNT_CTOR(wallet_PrefillElement); } ~wallet_PrefillElement() { NS_IF_RELEASE(inputElement); NS_IF_RELEASE(selectElement); MOZ_COUNT_DTOR(wallet_PrefillElement); } nsIDOMHTMLInputElement* inputElement; nsIDOMHTMLSelectElement* selectElement; nsString schema; nsString value; PRInt32 selectIndex; PRUint32 count; }; nsIURI * wallet_lastUrl = NULL; /***********************************************************/ /* The following routines are for diagnostic purposes only */ /***********************************************************/ #ifdef DEBUG static void wallet_Pause(){ fprintf(stdout,"%cpress y to continue\n", '\007'); char c; for (;;) { c = getchar(); if (tolower(c) == 'y') { fprintf(stdout,"OK\n"); break; } } while (c != '\n') { c = getchar(); } } static void wallet_DumpAutoString(const nsString& as){ char s[100]; as.ToCString(s, sizeof(s)); fprintf(stdout, "%s\n", s); } static void wallet_Dump(nsVoidArray * list) { wallet_MapElement * mapElementPtr; char item1[100]; char item2[100]; char item[100]; PRInt32 count = LIST_COUNT(list); for (PRInt32 i=0; iElementAt(i)); mapElementPtr->item1.ToCString(item1, sizeof(item1)); mapElementPtr->item2.ToCString(item2, sizeof(item2)); fprintf(stdout, "%s %s \n", item1, item2); wallet_Sublist * sublistPtr; PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList); for (PRInt32 i2=0; i2itemList->ElementAt(i2)); sublistPtr->item.ToCString(item, sizeof(item)); fprintf(stdout, " %s \n", item); } } wallet_Pause(); } /******************************************************************/ /* The following diagnostic routines are for timing purposes only */ /******************************************************************/ const PRInt32 timing_max = 1000; PRInt64 timings [timing_max]; char timingID [timing_max]; PRInt32 timing_index = 0; PRInt64 stopwatch = LL_Zero(); PRInt64 stopwatchBase; PRBool stopwatchRunning = PR_FALSE; static void wallet_ClearTiming() { timing_index = 0; LL_I2L(timings[timing_index++], PR_IntervalNow()); } static void wallet_DumpTiming() { PRInt32 i, r4; PRInt64 r1, r2, r3; for (i=1; i pStringService = do_GetService(kStringBundleServiceCID, &ret); if (NS_FAILED(ret)) { #ifdef DEBUG printf("cannot get string service\n"); #endif return v.ToNewUnicode(); } nsCOMPtr locale; nsCOMPtr bundle; ret = pStringService->CreateBundle(PROPERTIES_URL, locale, getter_AddRefs(bundle)); if (NS_FAILED(ret)) { #ifdef DEBUG printf("cannot create instance\n"); #endif return v.ToNewUnicode(); } /* localize the given string */ nsAutoString strtmp; strtmp.AssignWithConversion(genericString); const PRUnichar *ptrtmp = strtmp.GetUnicode(); PRUnichar *ptrv = nsnull; ret = bundle->GetStringFromName(ptrtmp, &ptrv); if (NS_FAILED(ret)) { #ifdef DEBUG printf("cannot get string from name\n"); #endif return v.ToNewUnicode(); } v = ptrv; nsCRT::free(ptrv); /* convert # to newlines */ PRUint32 i; for (i=0; i dialog; window->GetPrompter(getter_AddRefs(dialog)); if (!dialog) { return retval; } const nsAutoString message( szMessage ); retval = PR_FALSE; /* in case user exits dialog by clicking X */ res = dialog->Confirm(nsnull, message.GetUnicode(), &retval); return retval; } PUBLIC PRBool Wallet_ConfirmYN(PRUnichar * szMessage, nsIDOMWindowInternal* window) { nsresult res; nsCOMPtr dialog; window->GetPrompter(getter_AddRefs(dialog)); if (!dialog) { return PR_FALSE; } PRInt32 buttonPressed = 1; /* in case user exits dialog by clickin X */ PRUnichar * yes_string = Wallet_Localize("Yes"); PRUnichar * no_string = Wallet_Localize("No"); PRUnichar * confirm_string = Wallet_Localize("Confirm"); res = dialog->UniversalDialog( NULL, /* title message */ confirm_string, /* title text in top line of window */ szMessage, /* this is the main message */ NULL, /* This is the checkbox message */ yes_string, /* first button text */ no_string, /* second button text */ NULL, /* third button text */ NULL, /* fourth button text */ NULL, /* first edit field label */ NULL, /* second edit field label */ NULL, /* first edit field initial and final value */ NULL, /* second edit field initial and final value */ NULL, /* icon: question mark by default */ NULL, /* initial and final value of checkbox */ 2, /* number of buttons */ 0, /* number of edit fields */ 0, /* is first edit field a password field */ &buttonPressed); Recycle(yes_string); Recycle(no_string); Recycle(confirm_string); return (buttonPressed == 0); } PUBLIC PRInt32 Wallet_3ButtonConfirm(PRUnichar * szMessage, nsIDOMWindowInternal* window) { nsresult res; nsCOMPtr dialog; window->GetPrompter(getter_AddRefs(dialog)); if (!dialog) { return 0; /* default value is NO */ } PRInt32 buttonPressed = 1; /* default of NO if user exits dialog by clickin X */ PRUnichar * yes_string = Wallet_Localize("Yes"); PRUnichar * no_string = Wallet_Localize("No"); PRUnichar * never_string = Wallet_Localize("Never"); PRUnichar * confirm_string = Wallet_Localize("Confirm"); res = dialog->UniversalDialog( NULL, /* title message */ confirm_string, /* title text in top line of window */ szMessage, /* this is the main message */ NULL, /* This is the checkbox message */ yes_string, /* first button text */ no_string, /* second button text */ never_string, /* third button text */ NULL, /* fourth button text */ /* note: buttons are laid out as FIRST, THIRD, FOURTH, SECOND */ NULL, /* first edit field label */ NULL, /* second edit field label */ NULL, /* first edit field initial and final value */ NULL, /* second edit field initial and final value */ NULL, /* icon: question mark by default */ NULL, /* initial and final value of checkbox */ 3, /* number of buttons */ 0, /* number of edit fields */ 0, /* is first edit field a password field */ &buttonPressed); Recycle(yes_string); Recycle(no_string); Recycle(never_string); Recycle(confirm_string); return buttonPressed; } PRIVATE void wallet_Alert(PRUnichar * szMessage, nsIDOMWindowInternal* window) { nsresult res; nsCOMPtr dialog; window->GetPrompter(getter_AddRefs(dialog)); if (!dialog) { return; // XXX should return the error } const nsAutoString message( szMessage ); PRUnichar * title = Wallet_Localize("CaveatTitle"); res = dialog->Alert(title, message.GetUnicode()); Recycle(title); return; // XXX should return the error } PRIVATE void wallet_Alert(PRUnichar * szMessage, nsIPrompt* dialog) { nsresult res; const nsAutoString message( szMessage ); PRUnichar * title = Wallet_Localize("CaveatTitle"); res = dialog->Alert(title, message.GetUnicode()); Recycle(title); return; // XXX should return the error } PUBLIC PRBool Wallet_CheckConfirmYN (PRUnichar * szMessage, PRUnichar * szCheckMessage, PRBool* checkValue, nsIDOMWindowInternal* window) { nsresult res; nsCOMPtr dialog; window->GetPrompter(getter_AddRefs(dialog)); if (!dialog) { return PR_FALSE; } PRInt32 buttonPressed = 1; /* in case user exits dialog by clickin X */ PRUnichar * yes_string = Wallet_Localize("Yes"); PRUnichar * no_string = Wallet_Localize("No"); PRUnichar * confirm_string = Wallet_Localize("Confirm"); res = dialog->UniversalDialog( NULL, /* title message */ confirm_string, /* title text in top line of window */ szMessage, /* this is the main message */ szCheckMessage, /* This is the checkbox message */ yes_string, /* first button text */ no_string, /* second button text */ NULL, /* third button text */ NULL, /* fourth button text */ NULL, /* first edit field label */ NULL, /* second edit field label */ NULL, /* first edit field initial and final value */ NULL, /* second edit field initial and final value */ NULL, /* icon: question mark by default */ checkValue, /* initial and final value of checkbox */ 2, /* number of buttons */ 0, /* number of edit fields */ 0, /* is first edit field a password field */ &buttonPressed); if (NS_FAILED(res)) { *checkValue = 0; } if (*checkValue!=0 && *checkValue!=1) { *checkValue = 0; /* this should never happen but it is happening!!! */ } Recycle(yes_string); Recycle(no_string); Recycle(confirm_string); return (buttonPressed == 0); } /*******************************************************/ /* The following routines are for Encyption/Decryption */ /*******************************************************/ #include "nsISecretDecoderRing.h" nsISecretDecoderRing* gSecretDecoderRing; PRBool gEncryptionFailure = PR_FALSE; PRIVATE nsresult wallet_CryptSetup() { if (!gSecretDecoderRing) { /* Get a secret decoder ring */ nsresult rv = NS_OK; nsCOMPtr secretDecoderRing = do_CreateInstance("@mozilla.org/security/sdr;1", &rv); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } gSecretDecoderRing = secretDecoderRing.get(); NS_ADDREF(gSecretDecoderRing); } return NS_OK; } #define PREFIX "~" #include "plbase64.h" PRIVATE nsresult EncryptString (const char * text, char *& crypt) { /* use SecretDecoderRing if encryption pref is set */ nsresult rv; if (SI_GetBoolPref(pref_Crypto, PR_FALSE)) { rv = wallet_CryptSetup(); if (NS_SUCCEEDED(rv)) { rv = gSecretDecoderRing->EncryptString(text, &crypt); } if (NS_FAILED(rv)) { gEncryptionFailure = PR_TRUE; } return rv; } /* otherwise do our own obscuring using Base64 encoding */ char * crypt0 = PL_Base64Encode((const char *)text, 0, NULL); if (!crypt0) { return NS_ERROR_FAILURE; } crypt = (char *)PR_Malloc(PL_strlen(PREFIX) + PL_strlen(crypt0) + 1); PRUint32 i; for (i=0; iDecryptString(crypt, &text); } if (NS_FAILED(rv)) { gEncryptionFailure = PR_TRUE; } return rv; } /* otherwise do our own de-obscuring */ if (PL_strlen(crypt) == PL_strlen(PREFIX)) { text = (char *)PR_Malloc(1); text[0] = '\0'; return NS_OK; } text = PL_Base64Decode(&crypt[PL_strlen(PREFIX)], 0, NULL); if (!text) { return NS_ERROR_FAILURE; } return NS_OK; } PUBLIC void WLLT_ExpirePassword(PRBool* status) { nsresult rv = wallet_CryptSetup(); if (NS_SUCCEEDED(rv)) { rv = gSecretDecoderRing->Logout(); } *status = NS_SUCCEEDED(rv); } PRBool changingPassword = PR_FALSE; PUBLIC void WLLT_ChangePassword(PRBool* status) { nsresult rv = wallet_CryptSetup(); if (NS_SUCCEEDED(rv)) { changingPassword = PR_TRUE; rv = gSecretDecoderRing->ChangePassword(); changingPassword = PR_FALSE; } *status = NS_SUCCEEDED(rv); } PUBLIC nsresult Wallet_Encrypt (const nsString& text, nsString& crypt) { /* convert text from unichar to UTF8 */ nsAutoString UTF8text; PRUnichar c; for (PRUint32 i=0; i>6) & 0x1F)); UTF8text += PRUnichar((0x80) | (c & 0x3F)); } else { UTF8text += PRUnichar((0xE0) | ((c>>12) & 0xF)); UTF8text += PRUnichar((0x80) | ((c>>6) & 0x3F)); UTF8text += PRUnichar((0x80) | (c & 0x3F)); } } /* encrypt text to crypt */ char * cryptCString = nsnull; char * UTF8textCString = UTF8text.ToNewCString(); nsresult rv = EncryptString(UTF8textCString, cryptCString); Recycle (UTF8textCString); if NS_FAILED(rv) { return rv; } crypt.AssignWithConversion(cryptCString); Recycle (cryptCString); return NS_OK; } PUBLIC nsresult Wallet_Decrypt(const nsString& crypt, nsString& text) { /* decrypt crypt to text */ char * cryptCString = crypt.ToNewCString(); char * UTF8textCString = nsnull; nsresult rv = DecryptString(cryptCString, UTF8textCString); Recycle(cryptCString); if NS_FAILED(rv) { return rv; } /* convert text from UTF8 to unichar */ PRUnichar c1, c2, c3; text.Truncate(0); text.SetCapacity(2 * crypt.Length()); for (PRUint32 i=0; i=0; i--) { mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, (*list)->ElementAt(i)); delete mapElementPtr; } } delete (*list); *list = 0; } /* * allocate another mapElement * We are going to buffer up allocations because it was found that alocating one * element at a time was very inefficient on the mac */ PRIVATE nsVoidArray * wallet_MapElementAllocations_list=0; const PRInt32 kAllocBlockElems = 500; static PRInt32 wallet_NextAllocSlot = kAllocBlockElems; static wallet_MapElement * wallet_AllocateMapElement() { static wallet_MapElement* mapElementTable; if (wallet_NextAllocSlot >= kAllocBlockElems) { mapElementTable = new wallet_MapElement[kAllocBlockElems]; if (!mapElementTable) { return nsnull; } if(!wallet_MapElementAllocations_list) { wallet_MapElementAllocations_list = new nsVoidArray(); } if(wallet_MapElementAllocations_list) { wallet_MapElementAllocations_list->AppendElement(mapElementTable); } wallet_NextAllocSlot = 0; } return &mapElementTable[wallet_NextAllocSlot++]; } static void wallet_DeallocateMapElements() { wallet_MapElement * mapElementPtr; PRInt32 count = LIST_COUNT(wallet_MapElementAllocations_list); for (PRInt32 i=count-1; i>=0; i--) { mapElementPtr = NS_STATIC_CAST(wallet_MapElement*, (wallet_MapElementAllocations_list)->ElementAt(i)); delete [] mapElementPtr; } delete wallet_MapElementAllocations_list; wallet_MapElementAllocations_list = 0; wallet_NextAllocSlot = kAllocBlockElems; } /* * add an entry to the designated list */ static PRBool wallet_WriteToList( nsString item1, // not ref. Locally modified nsString item2, // not ref. Locally modified nsVoidArray* itemList, nsVoidArray*& list, PRBool obscure, PlacementType placement = DUP_BEFORE) { wallet_MapElement * mapElementPtr; PRBool added_to_list = PR_FALSE; wallet_MapElement * mapElement; if (list == wallet_FieldToSchema_list || list == wallet_SchemaStrings_list || list == wallet_PositionalSchema_list || list == wallet_StateSchema_list || list == wallet_SchemaConcat_list || list == wallet_DistinguishedSchema_list || list == wallet_VcardToSchema_list) { mapElement = wallet_AllocateMapElement(); } else { mapElement = new wallet_MapElement; } if (!mapElement) { return PR_FALSE; } item1.ToLowerCase(); if (obscure) { nsAutoString crypt; if (NS_FAILED(Wallet_Encrypt(item2, crypt))) { return PR_FALSE; } item2 = crypt; } mapElement->item1 = item1; mapElement->item2 = item2; mapElement->itemList = itemList; /* make sure the list exists */ if(!list) { list = new nsVoidArray(); if(!list) { return PR_FALSE; } } /* * Add new entry to the list in alphabetical order by item1. * If identical value of item1 exists, use "placement" parameter to * determine what to do */ if (AT_END==placement) { list->AppendElement(mapElement); return PR_TRUE; } PRInt32 count = LIST_COUNT(list); for (PRInt32 i=0; iElementAt(i)); if (BY_LENGTH==placement) { if (LIST_COUNT(mapElementPtr->itemList) < LIST_COUNT(itemList)) { list->InsertElementAt(mapElement, i); added_to_list = PR_TRUE; break; } else if (LIST_COUNT(mapElementPtr->itemList) == LIST_COUNT(itemList)) { if (itemList) { wallet_Sublist * sublistPtr; wallet_Sublist * sublistPtr2; sublistPtr = NS_STATIC_CAST(wallet_Sublist*, mapElementPtr->itemList->ElementAt(0)); sublistPtr2 = NS_STATIC_CAST(wallet_Sublist*, itemList->ElementAt(0)); if(sublistPtr->item.Length() < sublistPtr2->item.Length()) { list->InsertElementAt(mapElement, i); added_to_list = PR_TRUE; break; } } else if (mapElementPtr->item2.Length() < item2.Length()) { list->InsertElementAt(mapElement, i); added_to_list = PR_TRUE; break; } } } else if((mapElementPtr->item1.Compare(item1))==0) { if (DUP_OVERWRITE==placement) { delete mapElement; mapElementPtr->item1 = item1; mapElementPtr->item2 = item2; mapElementPtr->itemList = itemList; } else if (DUP_BEFORE==placement) { list->InsertElementAt(mapElement, i); } if (DUP_AFTER!=placement) { added_to_list = PR_TRUE; break; } } else if((mapElementPtr->item1.Compare(item1))>=0) { list->InsertElementAt(mapElement, i); added_to_list = PR_TRUE; break; } } if (!added_to_list) { list->AppendElement(mapElement); } return PR_TRUE; } /* * fetch an entry from the designated list */ static PRBool wallet_ReadFromList( nsString item1, nsString& item2, nsVoidArray*& itemList, nsVoidArray*& list, PRBool obscure, PRInt32& index) { if (!list || (index == -1)) { return PR_FALSE; } /* find item1 in the list */ wallet_MapElement * mapElementPtr; item1.ToLowerCase(); PRInt32 count = LIST_COUNT(list); for (PRInt32 i=index; iElementAt(i)); if((mapElementPtr->item1.Compare(item1))==0) { if (obscure) { if (NS_FAILED(Wallet_Decrypt(mapElementPtr->item2, item2))) { return PR_FALSE; } } else { item2 = nsAutoString(mapElementPtr->item2); } itemList = mapElementPtr->itemList; index = i+1; if (index == count) { index = -1; } return PR_TRUE; } } index = 0; return PR_FALSE; } PRBool wallet_ReadFromList( nsString item1, nsString& item2, nsVoidArray*& itemList, nsVoidArray*& list, PRBool obscure) { PRInt32 index = 0; return wallet_ReadFromList(item1, item2, itemList, list, obscure, index); } /*************************************************************/ /* The following routines are for reading/writing utf8 files */ /*************************************************************/ /* * For purposed of internationalization, characters are represented in memory as 16-bit * values (unicode, aka UCS-2) rather than 7 bit values (ascii). For simplicity, the * unicode representation of an ascii character has the upper 9 bits of zero and the * lower 7 bits equal to the 7-bit ascii value. * * These 16-bit unicode values could be stored directly in files. However such files would * not be readable by ascii editors even if they contained all ascii values. To solve * this problem, the 16-bit unicode values are first encoded into a sequence of 8-bit * characters before being written to the file -- the encoding is such that unicode * characters which have the upper 9 bits of zero are encoded into a single 8-bit character * of the same value whereas the remaining unicode characters are encoded into a sequence of * more than one 8-bit character. * * There is a standard 8-bit-encoding of bit strings and it is called UTF-8. The format of * UTF-8 is as follows: * * Up to 7 bits: 0xxxxxxx * Up to 11 bits: 110xxxxx 10xxxxxx * Up to 16 bits: 1110xxxx 10xxxxxx 10xxxxxx * Up to 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx * Up to 26 bits: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx * Up to 31 bits: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx * * Since we are converting unicode (16-bit) values, we need only be concerned with the * first three lines above. * * There are conversion routines provided in intl/uconv which convert between unicode and * UTF-8. However these routines are extremely cumbersome to use. So I have a very simple * pair of encoding/decoding routines for converting between unicode characters and UTF-8 * sequences. Here are the encoding/decoding algorithms that I use: * * encoding 16-bit unicode to 8-bit utf8 stream: * if (unicodeChar <= 0x7F) { // up to 7 bits * utf8Char1 = 0xxxxxxx + lower 7 bits of unicodeChar * } else if (unicodeChar <= 0x7FF) { // up to 11 bits * utf8Char1 = 110xxxxx + upper 5 bits of unicodeChar * utf8Char2 = 10xxxxxx + lower 6 bits of unicodeChar * } else { // up to 16 bits * utf8Char1 = 1110xxxx + upper 4 bits of unicodeChar * utf8Char2 = 10xxxxxx + next 6 bits of unicodeChar * utf8Char3 = 10xxxxxx + lower 6 bits of unicodeChar * } * * decoding 8-bit utf8 stream to 16-bit unicode: * if (utf8Char1 starts with 0) { * unicodeChar = utf8Char1; * } else if (utf8Char1 starts with 110) { * unicodeChar = (lower 5 bits of utf8Char1)<<6 * + (lower 6 bits of utf8Char2); * } else if (utf8Char1 starts with 1110) { * unicodeChar = (lower 4 bits of utf8Char1)<<12 * + (lower 6 bits of utf8Char2)<<6 * + (lower 6 bits of utf8Char3); * } else { * error; * } * */ PUBLIC void Wallet_UTF8Put(nsOutputFileStream& strm, PRUnichar c) { if (c <= 0x7F) { strm.put((char)c); } else if (c <= 0x7FF) { strm.put(((PRUnichar)0xC0) | ((c>>6) & 0x1F)); strm.put(((PRUnichar)0x80) | (c & 0x3F)); } else { strm.put(((PRUnichar)0xE0) | ((c>>12) & 0xF)); strm.put(((PRUnichar)0x80) | ((c>>6) & 0x3F)); strm.put(((PRUnichar)0x80) | (c & 0x3F)); } } static PRUnichar wallet_Get(nsInputFileStream& strm) { const PRUint32 buflen = 1000; static char buf[buflen+1]; static PRUint32 last = 0; static PRUint32 next = 0; if (next >= last) { next = 0; last = strm.read(buf, buflen); if (last <= 0 || strm.eof()) { /* note that eof is not set until we read past the end of the file */ return 0; } } return (buf[next++] & 0xFF); } PUBLIC PRUnichar Wallet_UTF8Get(nsInputFileStream& strm) { PRUnichar c = wallet_Get(strm); if ((c & 0x80) == 0x00) { return c; } else if ((c & 0xE0) == 0xC0) { return (((c & 0x1F)<<6) + (wallet_Get(strm) & 0x3F)); } else if ((c & 0xF0) == 0xE0) { return (((c & 0x0F)<<12) + ((wallet_Get(strm) & 0x3F)<<6) + (wallet_Get(strm) & 0x3F)); } else { return 0; /* this is an error, input was not utf8 */ } }/* * I have an even a simpler set of routines if you are not concerned about UTF-8. The * algorithms for those routines are as follows: * * encoding 16-bit unicode to 8-bit simple stream: * if (unicodeChar < 0xFF) { * simpleChar1 = unicodeChar * } else { * simpleChar1 = 0xFF * simpleChar2 = upper 8 bits of unicodeChar * simpleChar3 = lower 8 bits of unicodeChar * } * * decoding 8-bit simple stream to 16-bit unicode: * if (simpleChar1 < 0xFF) { * unicodeChar = simpleChar1; * } else { * unicodeChar = 256*simpleChar2 + simpleChar3; * } * */ PUBLIC void Wallet_SimplePut(nsOutputFileStream& strm, PRUnichar c) { if (c < 0xFF) { strm.put((char)c); } else { strm.put((PRUnichar)0xFF); strm.put((c>>8) & 0xFF); strm.put(c & 0xFF); } } PUBLIC PRUnichar Wallet_SimpleGet(nsInputFileStream& strm) { PRUnichar c = (strm.get() & 0xFF); if (c != 0xFF) { return c; } else { return ((strm.get() & 0xFF)<<8) + (strm.get() & 0xFF); } } /************************************************************/ /* The following routines are for unlocking the stored data */ /************************************************************/ char* schemaValueFileName = nsnull; const char URLFileName[] = "URL.tbl"; const char allFileName[] = "wallet.tbl"; const char fieldSchemaFileName[] = "FieldSchema.tbl"; const char vcardSchemaFileName[] = "VcardSchema.tbl"; const char schemaConcatFileName[] = "SchemaConcat.tbl"; const char schemaStringsFileName[] = "SchemaStrings.tbl"; const char positionalSchemaFileName[] = "PositionalSchema.tbl"; const char stateSchemaFileName[] = "StateSchema.tbl"; #ifdef AutoCapture const char distinguishedSchemaFileName[] = "DistinguishedSchema.tbl"; #endif /******************************************************/ /* The following routines are for accessing the files */ /******************************************************/ PUBLIC nsresult Wallet_ProfileDirectory(nsFileSpec& dirSpec) { /* return the profile */ nsresult res; nsCOMPtr aFile; nsXPIDLCString pathBuf; nsCOMPtr tempSpec; res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(aFile)); if (NS_FAILED(res)) return res; res = aFile->GetPath(getter_Copies(pathBuf)); if (NS_FAILED(res)) return res; // TODO: Change the function to return an nsIFile // and not do this conversion res = NS_NewFileSpec(getter_AddRefs(tempSpec)); if (NS_FAILED(res)) return res; res = tempSpec->SetNativePath(pathBuf); if (NS_FAILED(res)) return res; res = tempSpec->GetFileSpec(&dirSpec); return res; } PUBLIC nsresult Wallet_DefaultsDirectory(nsFileSpec& dirSpec) { nsresult res; nsCOMPtr aFile; nsXPIDLCString pathBuf; nsCOMPtr tempSpec; res = NS_GetSpecialDirectory(NS_APP_DEFAULTS_50_DIR, getter_AddRefs(aFile)); if (NS_FAILED(res)) return res; res = aFile->Append("wallet"); if (NS_FAILED(res)) return res; res = aFile->GetPath(getter_Copies(pathBuf)); if (NS_FAILED(res)) return res; // TODO: Change the function to return an nsIFile // and not do this conversion res = NS_NewFileSpec(getter_AddRefs(tempSpec)); if (NS_FAILED(res)) return res; res = tempSpec->SetNativePath(pathBuf); if (NS_FAILED(res)) return res; res = tempSpec->GetFileSpec(&dirSpec); return res; } PUBLIC char * Wallet_RandomName(char* suffix) { /* pick the current time as the random number */ time_t curTime = time(NULL); /* take 8 least-significant digits + three-digit suffix as the file name */ char name[13]; PR_snprintf(name, 13, "%lu.%s", ((int)curTime%100000000), suffix); return PL_strdup(name); } /* * get a line from a file * return -1 if end of file reached * strip carriage returns and line feeds from end of line */ static PRInt32 wallet_GetLine(nsInputFileStream& strm, nsString& line) { const PRUint32 kInitialStringCapacity = 64; /* read the line */ line.Truncate(0); PRInt32 stringLen = 0; PRInt32 stringCap = kInitialStringCapacity; line.SetCapacity(stringCap); PRUnichar c; static PRUnichar lastC = '\0'; for (;;) { c = Wallet_UTF8Get(strm); /* check for eof */ if (c == 0) { return -1; } /* check for line terminator (mac=CR, unix=LF, win32=CR+LF */ if (c == '\n' && lastC == '\r') { continue; /* ignore LF if preceded by a CR */ } lastC = c; if (c == '\n' || c == '\r') { break; } stringLen ++; // buffer string grows if (stringLen == stringCap) { stringCap += stringCap; // double buffer len line.SetCapacity(stringCap); } line += c; } return NS_OK; } static PRBool wallet_GetHeader(nsInputFileStream& strm) { nsAutoString format; nsAutoString buffer; /* format revision number */ if (NS_FAILED(wallet_GetLine(strm, format))) { return PR_FALSE; } if (!format.EqualsWithConversion(HEADER_VERSION)) { /* something's wrong */ return PR_FALSE; } return PR_TRUE; } /* * Write a line to a file */ static void wallet_PutLine(nsOutputFileStream& strm, const nsString& line) { for (PRUint32 i=0; iElementAt(i)); wallet_PutLine(strm, (*mapElementPtr).item1); if (!(*mapElementPtr).item2.IsEmpty()) { wallet_PutLine(strm, (*mapElementPtr).item2); } else { wallet_Sublist * sublistPtr; PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList); for (PRInt32 j=0; jitemList->ElementAt(j)); wallet_PutLine(strm, (*sublistPtr).item); } } wallet_PutLine(strm, nsAutoString()); } /* close the stream */ strm.flush(); strm.close(); } /* * Read contents of designated file into designated list */ static void wallet_ReadFromFile (const char * filename, nsVoidArray*& list, PRBool localFile, PlacementType placement = AT_END) { /* open input stream */ nsFileSpec dirSpec; nsresult rv; if (localFile) { rv = Wallet_ProfileDirectory(dirSpec); } else { rv = Wallet_DefaultsDirectory(dirSpec); } if (NS_FAILED(rv)) { return; } nsInputFileStream strm(dirSpec + filename); if (!strm.is_open()) { return; } /* read in the header */ if (filename == schemaValueFileName) { if (!wallet_GetHeader(strm)) { /* something's wrong -- ignore the file */ strm.close(); return; } } for (;;) { if (NS_FAILED(wallet_GetLine(strm, helpMac->item1))) { /* end of file reached */ break; } #ifdef AutoCapture /* Distinguished schema list is a list of single entries, not name/value pairs */ if (PL_strcmp(filename, distinguishedSchemaFileName) == 0) { nsVoidArray* dummy = NULL; wallet_WriteToList(helpMac->item1, helpMac->item1, dummy, list, PR_FALSE, placement); continue; } #endif if (NS_FAILED(wallet_GetLine(strm, helpMac->item2))) { /* unexpected end of file reached */ break; } if (helpMac->item2.Length()==0) { /* the value must have been deleted */ nsVoidArray* dummy = NULL; wallet_WriteToList(helpMac->item1, helpMac->item2, dummy, list, PR_FALSE, placement); continue; } if (NS_FAILED(wallet_GetLine(strm, helpMac->item3))) { /* end of file reached */ nsVoidArray* dummy = NULL; wallet_WriteToList(helpMac->item1, helpMac->item2, dummy, list, PR_FALSE, placement); strm.close(); return; } if (helpMac->item3.Length()==0) { /* just a pair of values, no need for a sublist */ nsVoidArray* dummy = NULL; wallet_WriteToList(helpMac->item1, helpMac->item2, dummy, list, PR_FALSE, placement); } else { /* need to create a sublist and put item2 and item3 onto it */ nsVoidArray * itemList = new nsVoidArray(); if (!itemList) { break; } wallet_Sublist * sublist = new wallet_Sublist; if (!sublist) { break; } sublist->item = helpMac->item2; itemList->AppendElement(sublist); sublist = new wallet_Sublist; if (!sublist) { break; } sublist->item = helpMac->item3; itemList->AppendElement(sublist); /* add any following items to sublist up to next blank line */ helpMac->dummy.Truncate(0); for (;;) { /* get next item for sublist */ if (NS_FAILED(wallet_GetLine(strm, helpMac->item3))) { /* end of file reached */ wallet_WriteToList(helpMac->item1, helpMac->dummy, itemList, list, PR_FALSE, placement); strm.close(); return; } if (helpMac->item3.Length()==0) { /* blank line reached indicating end of sublist */ wallet_WriteToList(helpMac->item1, helpMac->dummy, itemList, list, PR_FALSE, placement); break; } /* add item to sublist */ sublist = new wallet_Sublist; if (!sublist) { break; } sublist->item = helpMac->item3; itemList->AppendElement(sublist); } } } strm.close(); } /*********************************************************************/ /* The following are utility routines for the main wallet processing */ /*********************************************************************/ PUBLIC void Wallet_GiveCaveat(nsIDOMWindowInternal* window, nsIPrompt* dialog) { /* test for first capturing of data ever and give caveat if so */ if (!SI_GetBoolPref(pref_Caveat, PR_FALSE)) { SI_SetBoolPref(pref_Caveat, PR_TRUE); PRUnichar * message = Wallet_Localize("Caveat"); if (window) { wallet_Alert(message, window); } else { wallet_Alert(message, dialog); } Recycle(message); } } static void wallet_GetHostFile(nsIURI * url, nsString& outHostFile) { outHostFile.Truncate(0); nsAutoString urlName; char* host; nsresult rv = url->GetHost(&host); if (NS_FAILED(rv)) { return; } urlName.AppendWithConversion(host); nsCRT::free(host); char* file; rv = url->GetPath(&file); if (NS_FAILED(rv)) { return; } urlName.AppendWithConversion(file); nsCRT::free(file); PRInt32 queryPos = urlName.FindChar('?'); PRInt32 stringEnd = (queryPos == kNotFound) ? urlName.Length() : queryPos; urlName.Left(outHostFile, stringEnd); } static nsString& Strip(const nsString& text, nsString& stripText) { for (PRUint32 i=0; i'~') { stripText += c; } } return stripText; } /* * given a displayable text, get the schema */ static void TextToSchema( const nsString& text, nsString& schema) { /* return if no SchemaStrings list exists */ if (!wallet_SchemaStrings_list) { return; } /* try each schema entry in schemastring table to see if it's acceptable */ wallet_MapElement * mapElementPtr; PRInt32 count = LIST_COUNT(wallet_SchemaStrings_list); for (PRInt32 i=0; iElementAt(i)); wallet_Sublist * sublistPtr; PRInt32 count2 = LIST_COUNT(mapElementPtr->itemList); if (count2) { for (PRInt32 i2=0; i2itemList->ElementAt(i2)); if (text.Find(sublistPtr->item, PR_TRUE) == -1) { /* displayable text does not contain this string, reject this schema */ isSubstring = PR_FALSE; break; } } } else if (text.Find(mapElementPtr->item2, PR_TRUE) == -1) { /* displayable text does not contain this string, reject this schema */ isSubstring = PR_FALSE; } if (isSubstring) { /* all strings were contained in the displayable text, accept this schema */ schema = mapElementPtr->item1; return; } } } /* * given a field name, get the value */ static PRInt32 FieldToValue( const nsString& field, nsString& schema, nsString& value, nsVoidArray*& itemList, PRInt32& index) { /* return if no SchemaToValue list exists or if all values previous used */ if (!wallet_SchemaToValue_list || index == -1) { return -1; } /* if no schema name is given, fetch schema name from field/schema tables */ nsVoidArray* dummy; nsString stripField; if ((schema.Length() > 0) || wallet_ReadFromList(Strip(field, stripField), schema, dummy, wallet_FieldToSchema_list, PR_FALSE)) { /* schema name found, now attempt to fetch value from schema/value table */ PRInt32 index2 = index; if ((index >= 0) && wallet_ReadFromList(schema, value, itemList, wallet_SchemaToValue_list, PR_TRUE, index2)) { /* value found, prefill it into form and return */ index = index2; return 0; } else { /* value not found, see if concatenation rule exists */ nsVoidArray * itemList2; nsAutoString dummy2; if (index > 0) { index = 0; } PRInt32 index0 = index; PRInt32 index00 = index; PRInt32 index4 = 0; while (wallet_ReadFromList(schema, dummy2, itemList2, wallet_SchemaConcat_list, PR_FALSE, index4)) { /* concatenation rules exist, generate value as a concatenation */ wallet_Sublist * sublistPtr; value.SetLength(0); nsAutoString value2; PRInt32 index00max = index0; if (dummy2.Length() > 0) { /* single item on rhs of concatenation rule */ PRInt32 index5 = 0; PRInt32 j; PRBool failed = PR_FALSE; for (j=0; j>index0; j -= 2) { if (!wallet_ReadFromList(dummy2, value2, dummy, wallet_SchemaToValue_list, PR_TRUE, index5)) { failed = PR_TRUE; break; } index00 += 2; } if (!failed && wallet_ReadFromList(dummy2, value2, dummy, wallet_SchemaToValue_list, PR_TRUE, index5)) { /* found an unused value for the single rhs item */ value += value2; index00 += 2; } index00max = index00; } /* process each item in a multi-rhs rule */ PRInt32 count = LIST_COUNT(itemList2); for (PRInt32 i=0; iElementAt(i)); /* skip over values found previously */ /* note: a returned index of -1 means not-found. So we will use the * negative even numbers (-2, -4, -6) to designate found as a concatenation * where -2 means first value of each concatenation, -4 means second value, etc. */ index00 = index0; PRInt32 index3 = 0; PRBool failed = PR_FALSE; for (PRInt32 j=0; j>index0; j -= 2) { if (!wallet_ReadFromList(sublistPtr->item, value2, dummy, wallet_SchemaToValue_list, PR_TRUE, index3)) { /* all values of next multi-rhs item were used previously */ failed = PR_TRUE; break; } index00 += 2; } if (!failed && wallet_ReadFromList(sublistPtr->item, value2, dummy, wallet_SchemaToValue_list, PR_TRUE, index3)) { if (value.Length()>0) { value.AppendWithConversion(" "); } /* found an unused value for the multi-rhs item */ value += value2; index00 += 2; } if (index00 > index00max) { index00max = index00; } } itemList = nsnull; if (value.Length()>0) { /* a new value was found */ index -= 2; return 0; } /* all values from this concat rule were used, go on to next concat rule */ index0 = index00max; } /* no more concat rules, indicate failure */ index = -1; return -1; } } else { /* schema name not found, use field name as schema name and fetch value */ PRInt32 index2 = index; nsAutoString temp; wallet_GetHostFile(wallet_lastUrl, temp); temp.AppendWithConversion(":"); temp.Append(field); if (wallet_ReadFromList(temp, value, itemList, wallet_SchemaToValue_list, PR_TRUE, index2)) { /* value found, prefill it into form */ schema = temp; index = index2; return 0; } } index = -1; return -1; } static PRInt32 wallet_GetSelectIndex( nsIDOMHTMLSelectElement* selectElement, const nsString& value, PRInt32& index) { nsresult result; PRUint32 length; selectElement->GetLength(&length); nsIDOMNSHTMLOptionCollection * options; result = selectElement->GetOptions(&options); if ((NS_SUCCEEDED(result)) && (nsnull != options)) { PRUint32 numOptions; options->GetLength(&numOptions); for (PRUint32 optionX = 0; optionX < numOptions; optionX++) { nsIDOMNode* optionNode = nsnull; options->Item(optionX, &optionNode); if (nsnull != optionNode) { nsIDOMHTMLOptionElement* optionElement = nsnull; result = optionNode->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&optionElement); if ((NS_SUCCEEDED(result)) && (nsnull != optionElement)) { nsAutoString optionValue; nsAutoString optionText; optionElement->GetValue(optionValue); optionElement->GetText(optionText); nsAutoString valueLC( value ); valueLC.ToLowerCase(); optionValue.ToLowerCase(); optionText.ToLowerCase(); if (valueLC==optionValue || valueLC==optionText) { index = optionX; return 0; } NS_RELEASE(optionElement); } NS_RELEASE(optionNode); } } NS_RELEASE(options); } return -1; } void wallet_StepForwardOrBack (nsIDOMNode*& elementNode, nsString& text, PRBool& atInputOrSelect, PRBool& atEnd, PRBool goForward) { nsresult result; atInputOrSelect = PR_FALSE; atEnd = PR_FALSE; /* try getting next/previous sibling */ nsCOMPtr sibling; if (goForward) { result = elementNode->GetNextSibling(getter_AddRefs(sibling)); } else { result = elementNode->GetPreviousSibling(getter_AddRefs(sibling)); } if ((NS_FAILED(result)) || !sibling) { /* no next/previous siblings, try getting parent */ nsCOMPtr parent; result = elementNode->GetParentNode(getter_AddRefs(parent)); if ((NS_FAILED(result)) || !parent) { /* no parent, we've reached the top of the tree */ atEnd = PR_TRUE; } else { /* parent obtained */ elementNode = parent; } return; } /* sibling obtained */ elementNode = sibling; while (PR_TRUE) { /* if we've reached a SELECT or non-hidden INPUT tag, we're done */ /* * There is a subtle difference here between going forward and going backwards. * * When going forward we are trying to find out how many consecutive elements are not separated * by displayed text. That is important for determing, for example, if we have a three-input phone-number * field. In that case, we want to consider only input tags have type="text" or no type ("text" by default). * * When going backwards we want to find the text between the current element and any preceding * visible element. That would include such things as type="button", type="submit" etc. The * only thing it would exclude is type="hidden". */ nsIDOMHTMLInputElement* inputElement; result = elementNode->QueryInterface(kIDOMHTMLInputElementIID, (void**)&inputElement); if ((NS_SUCCEEDED(result)) && (inputElement)) { nsAutoString type; result = inputElement->GetType(type); if (goForward) { if (NS_SUCCEEDED(result) && ((type.CompareWithConversion("text", PR_TRUE) == 0) || type.IsEmpty())) { /* at element and it's type is either "text" or is missing ("text" by default) */ atInputOrSelect = PR_TRUE; return; } } else { if (NS_SUCCEEDED(result) && (type.CompareWithConversion("hidden", PR_TRUE) != 0)) { /* at element and it's type is not "hidden" */ atInputOrSelect = PR_TRUE; return; } } } else { nsIDOMHTMLSelectElement* selectElement; result = elementNode->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&selectElement); if ((NS_SUCCEEDED(result)) && (selectElement)) { atInputOrSelect = PR_TRUE; return; } } /* if we've reached a #text node, append it to accumulated text */ nsAutoString siblingName; result = elementNode->GetNodeName(siblingName); nsCAutoString siblingCName; siblingCName.AssignWithConversion(siblingName); // if (siblingName.EqualsIgnoreCase(NS_LITERAL_STRING("#text")) { if (siblingCName.EqualsIgnoreCase("#text")) { nsAutoString siblingValue; result = elementNode->GetNodeValue(siblingValue); text.Append(siblingValue); } /* if we've reached a SCRIPT node, don't fetch its siblings */ // if (siblingName.EqualsIgnoreCase(NS_LITERAL_STRING("SCRIPT")) { if (siblingCName.EqualsIgnoreCase("SCRIPT")) { return; } /* try getting first/last child */ nsCOMPtr child; if (goForward) { result = elementNode->GetFirstChild(getter_AddRefs(child)); } else { result = elementNode->GetLastChild(getter_AddRefs(child)); } if ((NS_FAILED(result)) || !child) { /* no children, we're done with this node */ return; } /* child obtained */ elementNode = child; } return; } //#include "nsIUGenCategory.h" //#include "nsUnicharUtilCIID.h" //static NS_DEFINE_IID(kUnicharUtilCID, NS_UNICHARUTIL_CID); //static NS_DEFINE_IID(kIUGenCategoryIID, NS_IUGENCATEGORY_IID); //#include "nsICaseConversion.h" //static NS_DEFINE_IID(kICaseConversionIID, NS_ICASECONVERSION_IID); //static nsICaseConversion* gCaseConv = nsnull; static void wallet_ResolvePositionalSchema(nsIDOMNode* elementNode, nsString& schema) { static PRInt32 numerator = 0; static PRInt32 denominator = 0; static nsString lastPositionalSchema; /* return if no PositionalSchema list exists */ if (!wallet_PositionalSchema_list) { schema.SetLength(0); return; } if (schema.Length()) { numerator = 0; denominator = 0; lastPositionalSchema = schema; } else if (numerator < denominator) { schema = lastPositionalSchema; } else { schema.SetLength(0); return; } /* search PositionalSchema list for our positional schema */ wallet_MapElement * mapElementPtr; PRInt32 count = LIST_COUNT(wallet_PositionalSchema_list); for (PRInt32 i=0; iElementAt(i)); if (mapElementPtr->item1.EqualsIgnoreCase(schema)) { /* found our positional schema in the list */ /* A "position set" is a set of continuous or