diff --git a/mozilla/extensions/makefile.win b/mozilla/extensions/makefile.win new file mode 100644 index 00000000000..805e692ffcf --- /dev/null +++ b/mozilla/extensions/makefile.win @@ -0,0 +1,22 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=.. + +DIRS=wallet + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/extensions/wallet/makefile.win b/mozilla/extensions/wallet/makefile.win new file mode 100644 index 00000000000..07b85964841 --- /dev/null +++ b/mozilla/extensions/wallet/makefile.win @@ -0,0 +1,22 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=..\.. + +DIRS=public src module + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/extensions/wallet/module/MANIFEST b/mozilla/extensions/wallet/module/MANIFEST new file mode 100644 index 00000000000..fa47047bc53 --- /dev/null +++ b/mozilla/extensions/wallet/module/MANIFEST @@ -0,0 +1,5 @@ +# +# This is a list of local files which get copied to the mozilla:dist:privacy:module directory +# + +nsIWallet.h diff --git a/mozilla/extensions/wallet/module/makefile.win b/mozilla/extensions/wallet/module/makefile.win new file mode 100644 index 00000000000..e69de29bb2d diff --git a/mozilla/extensions/wallet/module/nsIWalletService.h b/mozilla/extensions/wallet/module/nsIWalletService.h new file mode 100644 index 00000000000..af1823ae7b4 --- /dev/null +++ b/mozilla/extensions/wallet/module/nsIWalletService.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsIWalletService_h___ +#define nsIWalletService_h___ + +//#include "nscore.h" +#include "nsISupports.h" +#include "nsString.h" +#include "nsIPresShell.h" +#include "lo_ele.h" +#include "nsIURL.h" + +// {738CFD51-ABCF-11d2-AB4B-0080C787AD96} +#define NS_IWALLETSERVICE_IID \ +{ 0x738cfd51, 0xabcf, 0x11d2, { 0xab, 0x4b, 0x0, 0x80, 0xc7, 0x87, 0xad, 0x96 } }; + + +// {738CFD52-ABCF-11d2-AB4B-0080C787AD96} +#define NS_WALLETSERVICE_CID \ +{ 0x738cfd52, 0xabcf, 0x11d2, { 0xab, 0x4b, 0x0, 0x80, 0xc7, 0x87, 0xad, 0x96 } }; + +/** + * The nsIWalletService interface provides an API to the wallet service. + * This is a preliminary interface which will change over time! + * + */ +struct nsIWalletService : public nsISupports +{ + NS_IMETHOD WALLET_PreEdit(nsIURL* url) = 0; + NS_IMETHOD WALLET_Prefill(nsIPresShell* shell, PRBool quick) = 0; + NS_IMETHOD WALLET_Capture(nsIDocument* doc, nsString name, nsString value) = 0; + NS_IMETHOD WALLET_OKToCapture(PRBool* result, PRInt32 count, char* URLName) = 0; +#ifdef junk + NS_IMETHOD SI_DisplaySignonInfoAsHTML()=0; + NS_IMETHOD SI_RememberSignonData + (char* URLName, LO_FormSubmitData *submit)=0; + NS_IMETHOD SI_RestoreSignonData + (char* URLNAME, char* name, char** value)=0; +#endif +}; + +#endif /* nsIWalletService_h___ */ diff --git a/mozilla/extensions/wallet/module/nsWalletBuiltInDataSources.h b/mozilla/extensions/wallet/module/nsWalletBuiltInDataSources.h new file mode 100644 index 00000000000..5d8a76f1c76 --- /dev/null +++ b/mozilla/extensions/wallet/module/nsWalletBuiltInDataSources.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +// This header file just contains prototypes for the factory methods +// for "builtin" data sources that are included in walletlib.dll. Each of +// these data sources is exposed to the external world via its CID in +// ../include/nsIWalletService.h. + +#ifndef nsBuiltinDataSources_h__ +#define nsBuiltinDataSources_h__ + +//#include "nsError.h" + +//class nsIWalletDataSource; +//class nsIWalletDataBase; + +nsresult NS_NewWalletService(nsIWalletServiceDataSource** result); + +#endif // nsBuiltinDataSources_h__ diff --git a/mozilla/extensions/wallet/module/nsWalletFactory.cpp b/mozilla/extensions/wallet/module/nsWalletFactory.cpp new file mode 100644 index 00000000000..6a2ea3afde2 --- /dev/null +++ b/mozilla/extensions/wallet/module/nsWalletFactory.cpp @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsIWalletService.h" +//#include "nsIServiceManager.h" +//#include "nsRepository.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); +static NS_DEFINE_CID(kWalletServiceCID, NS_WALLETSERVICE_CID); + +//#if defined(HAS_C_PLUS_PLUS_CASTS) +//#define NS_STATIC_CAST(__type, __ptr) static_cast<__type>(__ptr) +//#else +//#define NS_STATIC_CAST(__type, __ptr) ((__type)(__ptr)) +//#endif + +// factory functions +nsresult NS_NewWalletService(nsIWalletService** result); + +class WalletFactoryImpl : public nsIFactory +{ +public: + WalletFactoryImpl(const nsCID &aClass); + + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + +protected: + virtual ~WalletFactoryImpl(); + +private: + nsCID mClassID; +}; + +//////////////////////////////////////////////////////////////////////// + +WalletFactoryImpl::WalletFactoryImpl(const nsCID &aClass) +{ + NS_INIT_REFCNT(); + mClassID = aClass; +} + +WalletFactoryImpl::~WalletFactoryImpl() +{ + NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction"); +} + +NS_IMETHODIMP +WalletFactoryImpl::QueryInterface(const nsIID &aIID, + void **aResult) +{ + if (! aResult) + return NS_ERROR_NULL_POINTER; + + // Always NULL result, in case of failure + *aResult = nsnull; + + if (aIID.Equals(kISupportsIID)) { + *aResult = NS_STATIC_CAST(nsISupports*, this); + AddRef(); + return NS_OK; + } else if (aIID.Equals(kIFactoryIID)) { + *aResult = NS_STATIC_CAST(nsIFactory*, this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(WalletFactoryImpl); +NS_IMPL_RELEASE(WalletFactoryImpl); + +NS_IMETHODIMP +WalletFactoryImpl::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + *aResult = nsnull; + + nsresult rv; + PRBool wasRefCounted = PR_TRUE; + nsISupports *inst = nsnull; + if (mClassID.Equals(kWalletServiceCID)) { + if (NS_FAILED(rv = NS_NewWalletService((nsIWalletService**) &inst))) + return rv; + } + else { + return NS_ERROR_NO_INTERFACE; + } + + if (! inst) + return NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv = inst->QueryInterface(aIID, aResult))) + // We didn't get the right interface, so clean up + delete inst; + + if (wasRefCounted) + NS_IF_RELEASE(inst); + + return rv; +} + +nsresult WalletFactoryImpl::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////// + + + +// return the proper factory to the caller +extern "C" PR_IMPLEMENT(nsresult) +NSGetFactory(nsISupports* serviceMgr, + const nsCID &aClass, + const char *aClassName, + const char *aProgID, + nsIFactory **aFactory) +{ + if (! aFactory) + return NS_ERROR_NULL_POINTER; + + WalletFactoryImpl* factory = new WalletFactoryImpl(aClass); + if (factory == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(factory); + *aFactory = factory; + return NS_OK; +} diff --git a/mozilla/extensions/wallet/module/nsWalletService.cpp b/mozilla/extensions/wallet/module/nsWalletService.cpp new file mode 100644 index 00000000000..b7646cbf869 --- /dev/null +++ b/mozilla/extensions/wallet/module/nsWalletService.cpp @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (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. + */ + +//#include "nsRepository.h" +#include "nsWalletService.h" +//#include "nsINetService.h" +#include "nsIServiceManager.h" +//static NS_DEFINE_IID(kINetServiceIID, NS_INETSERVICE_IID); +//static NS_DEFINE_IID(kNetServiceCID, NS_NETSERVICE_CID); + +//#include "nsIWebShell.h" +//static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID); +//static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID); + +static NS_DEFINE_IID(kIWalletServiceIID, NS_IWALLETSERVICE_IID); + +#include "wallet.h" + +//#if defined(HAS_C_PLUS_PLUS_CASTS) +//#define NS_STATIC_CAST(__type, __ptr) static_cast<__type>(__ptr) +//#else +//#define NS_STATIC_CAST(__type, __ptr) ((__type)(__ptr)) +//#endif + +nsWalletlibService::nsWalletlibService() +{ + NS_INIT_REFCNT(); +} + +nsWalletlibService::~nsWalletlibService() +{ +} + +/* calls into the wallet module */ + +NS_IMETHODIMP +nsWalletlibService::QueryInterface(REFNSIID iid, void** result) +{ + if (! result) + return NS_ERROR_NULL_POINTER; + + *result = nsnull; + if (iid.Equals(kIWalletServiceIID)) { + *result = NS_STATIC_CAST(nsIWalletService*, this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsWalletlibService); +NS_IMPL_RELEASE(nsWalletlibService); + +NS_IMETHODIMP nsWalletlibService::WALLET_PreEdit(nsIURL* url) { + ::WLLT_PreEdit(url); + return NS_OK; +} + +NS_IMETHODIMP nsWalletlibService::WALLET_Prefill(nsIPresShell* shell, PRBool quick) { + ::WLLT_Prefill(shell, quick); + return NS_OK; +} + +NS_IMETHODIMP nsWalletlibService::WALLET_OKToCapture + (PRBool* result, PRInt32 count, char* URLName) { + ::WLLT_OKToCapture(result, count, URLName); + return NS_OK; +} + +NS_IMETHODIMP nsWalletlibService::WALLET_Capture( + nsIDocument* doc, + nsString name, + nsString value) { + ::WLLT_Capture(doc, name, value); + return NS_OK; +} + +#ifdef junk +NS_IMETHODIMP +nsWalletlibService::SI_DisplaySignonInfoAsHTML(){ + ::SI_DisplaySignonInfoAsHTML(); + return NS_OK; +} + +NS_IMETHODIMP +nsWalletlibService::SI_RememberSignonData + (char* URLName, LO_FormSubmitData *submit) { + ::SI_RememberSignonData(URLName, submit); + return NS_OK; +} + +NS_IMETHODIMP +nsWalletlibService::SI_RestoreSignonData + (char* URLName, char* name, char** value) { + ::SI_RestoreSignonData(URLName, name, value); + return NS_OK; +} +#endif + +/* call to create the wallet object */ + +nsresult +NS_NewWalletService(nsIWalletService** result) +{ + nsIWalletService* wallet = new nsWalletlibService(); + if (! wallet) + return NS_ERROR_NULL_POINTER; + + *result = wallet; + NS_ADDREF(*result); + return NS_OK; +} diff --git a/mozilla/extensions/wallet/module/nsWalletService.h b/mozilla/extensions/wallet/module/nsWalletService.h new file mode 100644 index 00000000000..e29b14c89e4 --- /dev/null +++ b/mozilla/extensions/wallet/module/nsWalletService.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (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. + */ + +#ifndef nsWalletService_h___ +#define nsWalletService_h___ + +#include "nsIWalletService.h" + +class nsWalletlibService : public nsIWalletService { + +public: + NS_DECL_ISUPPORTS + nsWalletlibService(); + + /* Implementation of the nsIWalletService interface */ + NS_IMETHOD WALLET_PreEdit(nsIURL* url); + NS_IMETHOD WALLET_Prefill(nsIPresShell* shell, PRBool quick); + NS_IMETHOD WALLET_Capture(nsIDocument* doc, nsString name, nsString value); + NS_IMETHOD WALLET_OKToCapture(PRBool* result, PRInt32 count, char* URLName); +#ifdef junk + NS_IMETHOD SI_DisplaySignonInfoAsHTML(); + NS_IMETHOD SI_RememberSignonData + (char* URLName, LO_FormSubmitData *submit); + NS_IMETHOD SI_RestoreSignonData + (char* URLNAME, char* name, char** value); +#endif + +protected: + virtual ~nsWalletlibService(); + +private: +}; + + +#endif /* nsWalletService_h___ */ diff --git a/mozilla/extensions/wallet/module/wallet.def b/mozilla/extensions/wallet/module/wallet.def new file mode 100644 index 00000000000..485cdf2f9fe --- /dev/null +++ b/mozilla/extensions/wallet/module/wallet.def @@ -0,0 +1,19 @@ +; The contents of this file are subject to the Netscape Public License +; Version 1.0 (the "NPL"); you may not use this file except in +; compliance with the NPL. You may obtain a copy of the NPL at +; http://www.mozilla.org/NPL/ +; +; Software distributed under the NPL is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +; for the specific language governing rights and limitations under the +; NPL. +; +; The Initial Developer of this code under the NPL is Netscape +; Communications Corporation. Portions created by Netscape are +; Copyright (C) 1998 Netscape Communications Corporation. All Rights +; Reserved. + +LIBRARY wallet.dll + +EXPORTS + WALLET_Prefill diff --git a/mozilla/extensions/wallet/public/MANIFEST b/mozilla/extensions/wallet/public/MANIFEST new file mode 100644 index 00000000000..29a6f7431f8 --- /dev/null +++ b/mozilla/extensions/wallet/public/MANIFEST @@ -0,0 +1,5 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +wallet.h diff --git a/mozilla/extensions/wallet/public/makefile.win b/mozilla/extensions/wallet/public/makefile.win new file mode 100644 index 00000000000..0324cb282f4 --- /dev/null +++ b/mozilla/extensions/wallet/public/makefile.win @@ -0,0 +1,29 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +IGNORE_MANIFEST=1 + +DEPTH=..\..\.. + +EXPORTS = \ + singsign.h \ + wallet.h \ + $(NULL) + +MODULE = wallet + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/extensions/wallet/public/singsign.h b/mozilla/extensions/wallet/public/singsign.h new file mode 100644 index 00000000000..3d816bc9e64 --- /dev/null +++ b/mozilla/extensions/wallet/public/singsign.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (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. + */ + + +/* + singsign.h --- prototypes for wallet functions. +*/ + + +#ifndef _SINGSIGN_H +#define _SINGSIGNT_H + +#include "ntypes.h" + +XP_BEGIN_PROTOS + +extern void +SI_DisplaySignonInfoAsHTML(); + +extern void +SI_RememberSignonData(char* URLName, LO_FormSubmitData *submit); + +extern void +SI_RestoreSignonData(char* URLName, char* name, char** value); + +XP_END_PROTOS + +#endif /* !_SINGSIGN_H */ diff --git a/mozilla/extensions/wallet/public/wallet.h b/mozilla/extensions/wallet/public/wallet.h new file mode 100644 index 00000000000..a09f74798cd --- /dev/null +++ b/mozilla/extensions/wallet/public/wallet.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (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. + */ + + +/* + wallet.h --- prototypes for wallet functions. +*/ + + +#ifndef _WALLET_H +#define _WALLET_H + +#include "ntypes.h" +#include "nsIPresShell.h" +#include "nsString.h" +#include "nsIURL.h" + +XP_BEGIN_PROTOS + +extern void +WLLT_PreEdit(nsIURL* url); + +extern void +WLLT_Prefill(nsIPresShell* shell, PRBool quick); + +extern void +WLLT_OKToCapture(PRBool * result, PRInt32 count, char* URLName); + +extern void +WLLT_Capture(nsIDocument* doc, nsString name, nsString value); + +XP_END_PROTOS + +#endif /* !_WALLET_H */ diff --git a/mozilla/extensions/wallet/src/htmldlgs.h b/mozilla/extensions/wallet/src/htmldlgs.h new file mode 100644 index 00000000000..bba52947238 --- /dev/null +++ b/mozilla/extensions/wallet/src/htmldlgs.h @@ -0,0 +1,321 @@ +#include "xp_mcom.h" + +#include "xp_file.h" + +#include "plarenas.h" +#include "jsotypes.h" +#include "plstr.h" +#include "seccomon.h" +#include "xpgetstr.h" + +#define HTML_DLGS_URL "file:///y|/htmldlgs.html" +#define XP_DIALOG_CANCEL_BUTTON (1<<0) +#define XP_DIALOG_OK_BUTTON (1<<2) +#define XP_STRINGS_CHUNKSIZE 512 +typedef struct _XPDialogState XPDialogState; +typedef struct _XPDialogInfo XPDialogInfo; +typedef struct _XPDialogStrings XPDialogStrings; +typedef PRBool (* XP_HTMLDialogHandler) + (XPDialogState *state, char **argv, int argc, unsigned int button); + +/* SACopy and SACat should really be defined elsewhere */ +#include "plstr.h" +#include "prmem.h" +#define LocalStrAllocCopy(dest, src) Local_SACopy (&(dest), src) +#define LocalStrAllocCat(dest, src) Local_SACat (&(dest), src) +char * +Local_SACopy(char **destination, const char *source) +{ + if(*destination) { + PL_strfree(*destination); + *destination = 0; + } + *destination = PL_strdup(source); + return *destination; +} + +char * +Local_SACat(char **destination, const char *source) +{ + if (source && *source) { + if (*destination) { + int length = PL_strlen (*destination); + *destination = (char *) PR_Realloc(*destination, length + PL_strlen(source) + 1); + if (*destination == NULL) { + return(NULL); + } + PL_strcpy (*destination + length, source); + } else { + *destination = PL_strdup(source); + } + } + return *destination; +} + +struct _XPDialogState { + PRArenaPool *arena; + void *window; + void *proto_win; + XPDialogInfo *dialogInfo; + void *arg; + void (* deleteCallback)(void *arg); + void *cbarg; + PRBool deleted; +}; +struct _XPDialogInfo { + unsigned int buttonFlags; + XP_HTMLDialogHandler handler; + int width; + int height; +}; +struct _XPDialogStrings +{ + PRArenaPool *arena; + int basestringnum; + int nargs; + char **args; + char *contents; +}; + +XPDialogState * +XP_MakeHTMLDialog( + void *proto_win, + XPDialogInfo *dialogInfo, + int titlenum, + XPDialogStrings *strings, + void *arg, + PRBool utf8CharSet) +{ + /* write out html dialog to /htmldlgs.htm */ + XP_File f = fopen("/htmldlgs.htm","w"); + for (int i=0; inargs; i++) { + if (strings->args[i]) { + fprintf(f, "%s", (char *)(strings->args[i])); + } + } + fclose(f); + fflush(f); + + /* write out dialog info to /index.htm */ + f = fopen("/index.htm","w"); + fprintf(f, " \n"); + fprintf(f, " \n", + dialogInfo->width, dialogInfo->height); + fprintf(f, " \n"); + fprintf(f, " \n"); + fclose(f); + fflush(f); + + return NULL; +} + +void +XP_MakeHTMLDialog2(XPDialogInfo *dialogInfo) { + char* argv[] = {NULL, NULL, NULL, NULL, NULL, NULL}; + int argc = 0; + char* button = NULL; + + nsAutoString * nsCookie = new nsAutoString(""); + nsIURL* url; + char* separator; + + nsINetService *netservice; + nsresult res; + res = nsServiceManager::GetService(kNetServiceCID, + kINetServiceIID, + (nsISupports **)&netservice); + if ((NS_OK == res) && (nsnull != netservice)) { + const nsAutoString html_dlgs = nsAutoString(HTML_DLGS_URL); + if (!NS_FAILED(NS_NewURL(&url, html_dlgs))) { + res = netservice->GetCookieString(url, *nsCookie); + } + + /* convert cookie to a C string */ + + char *cookies = nsCookie->ToNewCString(); + char *cookie = PL_strstr(cookies, "htmldlgs=|"); /* get to htmldlgs=| */ + cookie = cookie + PL_strlen("htmldlgs=|"); /* get passed htmldlgs=| */ + + /* button name is first item in cookie (up to next verical bar) */ + + separator = strchr(cookie, '|'); + *separator = '\0'; + LocalStrAllocCopy(button, cookie); + cookie = separator+1; + *separator = '|'; + + /* remainder of cookie string are the args, separated by vertical bars */ + for (int i=0; ((*cookie != '\0') && (*cookie != ';')); i++) { + separator = strchr(cookie, '|'); + *separator = '\0'; + LocalStrAllocCopy(argv[i], cookie); + cookie = separator+1; + *separator = '|'; + argc++; + } + + /* call the callback routine */ + if (!PORT_Strcmp(button,"OK")) { + (dialogInfo->handler)(NULL, argv, argc, XP_DIALOG_OK_BUTTON); + } else { + (dialogInfo->handler)(NULL, argv, argc, XP_DIALOG_CANCEL_BUTTON); + } + + /* free up the allocated strings */ + XP_FREE(button); + for (int j=0; jarena = arena; + header->basestringnum = stringnum; + + src = XP_GetString(stringnum); + len = PORT_Strlen(src); + size = len + 1; + dst = header->contents = + (char *)PORT_ArenaAlloc(arena, sizeof(char) * size); + if (dst == NULL) { + goto loser; + } + + while (!done) { /* Concatenate pieces to form message */ + PORT_Memcpy(dst, src, len+1); + done = 1; + if (XP_STRSTR(src, "%-cont-%")) { /* Continuation */ + src = XP_GetString(++stringnum); + len = PORT_Strlen(src); + header->contents = + (char *)PORT_ArenaGrow(arena, + header->contents, size, size + len); + if (header->contents == NULL) { + goto loser; + } + dst = header->contents + size - 1; + size += len; + done = 0; + } + } + + /* At this point we should have the complete message in + header->contents, including like %-cont-%, which will be + ignored later. */ + + /* Count the arguments in the message */ + header->nargs = -1; /* Support %0% as lowest token */ + src = header->contents; + while ((src = PORT_Strchr(src, '%'))) { + src++; + n = (int)XP_STRTOUL(src, &dst, 10); + if (dst == src) { /* Integer not found... */ + src = PORT_Strchr(src, '%') + 1; /* so skip this %..% */ + PORT_Assert(NULL != src-1); /* Unclosed %..% ? */ + continue; + } + + if (header->nargs < n) { + header->nargs = n; + } + src = dst + 1; + } + + if (++(header->nargs) > 0) { /* Allocate space for arguments */ + header->args = + (char **)PORT_ArenaZAlloc(arena, sizeof(char *) * header->nargs); + } + + return(header); + +loser: + PORT_FreeArena(arena, PR_FALSE); + return(NULL); +} + + + +void +XP_SetDialogString(XPDialogStrings *strings, int argNum, char *string) +{ + /* make sure we are doing it right */ + PORT_Assert(argNum < strings->nargs); + PORT_Assert(argNum >= 0); + PORT_Assert(strings->args[argNum] == NULL); + + /* set the string */ + strings->args[argNum] = string; + + return; +} + +void +XP_CopyDialogString(XPDialogStrings *strings, int argNum, const char *string) +{ + int len; + + /* make sure we are doing it right */ + PORT_Assert(argNum < strings->nargs); + PORT_Assert(argNum >= 0); + PORT_Assert(strings->args[argNum] == NULL); + + /* copy the string */ + len = PORT_Strlen(string) + 1; + strings->args[argNum] = (char *)PORT_ArenaAlloc(strings->arena, len); + if ( strings->args[argNum] != NULL ) { + PORT_Memcpy(strings->args[argNum], string, len); + } + + return; +} + +char * +XP_FindValueInArgs(const char *name, char **av, int ac) +{ + for( ;ac > 0; ac -= 2, av += 2 ) { + if ( PORT_Strcmp(name, av[0]) == 0 ) { + return(av[1]); + } + } + return(0); +} + +#define BUFLEN 5000 + +#define FLUSH_BUFFER \ + if (buffer) { \ + LocalStrAllocCat(buffer2, buffer); \ + buffer[0] = '\0'; \ + g = 0; \ + } + +extern int XP_EMPTY_STRINGS; diff --git a/mozilla/extensions/wallet/src/makefile.win b/mozilla/extensions/wallet/src/makefile.win new file mode 100644 index 00000000000..8c46178b1ca --- /dev/null +++ b/mozilla/extensions/wallet/src/makefile.win @@ -0,0 +1,52 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=..\..\.. + +LIBRARY_NAME=wallet +CPP_OBJS= .\$(OBJDIR)\wallet.obj +CSRCS = wallet.cpp + +CPPSRCS = \ + $(NULL) + +MODULE=wallet +REQUIRES=wallet +EXPORTS= $(NULL) + +LINCS= \ + -I$(PUBLIC)\raptor \ + -I$(PUBLIC)\xpcom \ + -I$(PUBLIC)\dom \ + -I$(PUBLIC)\js \ + -I$(PUBLIC)\netlib \ + -I$(PUBLIC)\security \ + -I$(PUBLIC)\pref \ + -I$(PUBLIC)\wallet + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/extensions/wallet/src/singsign.cpp b/mozilla/extensions/wallet/src/singsign.cpp new file mode 100644 index 00000000000..352c0bb2355 --- /dev/null +++ b/mozilla/extensions/wallet/src/singsign.cpp @@ -0,0 +1,3193 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (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. + */ + +#if defined(SingleSignon) + +#define alphabetize 1 +#include "libi18n.h" /* For the character code set conversions */ +#include "secnav.h" /* For SECNAV_UnMungeString and SECNAV_MungeString */ + +#ifdef XP_MAC +#include "prpriv.h" /* for NewNamedMonitor */ +#include "prinrval.h" /* for PR_IntervalNow */ +#ifdef APPLE_KEYCHAIN /* APPLE */ +#include "Keychain.h" /* APPLE */ +#define kNetscapeProtocolType 'form' /* APPLE */ +#endif /* APPLE */ +#else +#include "private/prpriv.h" /* for NewNamedMonitor */ +#endif + +#ifdef PROFILE +#pragma profile on +#endif + +#include "prefapi.h" +#include "xpgetstr.h" +#include "xpgetstr.h" + +extern int MK_SIGNON_PASSWORDS_GENERATE; +extern int MK_SIGNON_PASSWORDS_REMEMBER; +extern int MK_SIGNON_PASSWORDS_FETCH; +extern int MK_SIGNON_YOUR_SIGNONS; +extern int MK_SIGNON_YOUR_SIGNON_REJECTS; +extern int MK_SIGNON_NOTIFICATION; +extern int MK_SIGNON_NOTIFICATION_1; +extern int MK_SIGNON_NAG; +extern int MK_SIGNON_REMEMBER; +extern int MK_SIGNON_SELECTUSER; +extern int MK_SIGNON_CHANGE; + +/* locks for signon cache */ + +static PRMonitor * signon_lock_monitor = NULL; +static PRThread * signon_lock_owner = NULL; +static int signon_lock_count = 0; +static Bool si_anonymous = FALSE; + +#ifdef APPLE_KEYCHAIN +static Bool si_list_invalid = FALSE; +static KCCallbackUPP si_kcUPP = NULL; +PRIVATE int +si_SaveSignonDataInKeychain(); + +#endif + +/* SACopy and SACat should really be defined elsewhere */ +#include "plstr.h" +#include "prmem.h" +#define NET_SACopy(dest, src) Local_SACopy (&(dest), src) +#define NET_SACat(dest, src) Local_SACat (&(dest), src) +char * +Local_SACopy(char **destination, const char *source) +{ + if(*destination) { + PL_strfree(*destination); + *destination = 0; + } + *destination = PL_strdup(source); + return *destination; +} + +char * +Local_SACat(char **destination, const char *source) +{ + if (source && *source) { + if (*destination) { + int length = PL_strlen (*destination); + *destination = (char *) PR_Realloc(*destination, length + PL_strlen(source) + 1); + if (*destination == NULL) { + return(NULL); + } + PL_strcpy (*destination + length, source); + } else { + *destination = PL_strdup(source); + } + } + return *destination; +} + +/* temporary */ +/* + * Need this for now because the normal call to FE_Confirm goes through + * a pointer in the context (context->func->confirm) and the context + * doesn't exist when we get control from layout, namely when SI_RememberSignonData + * is called + * + * Same applies to FE_SelectDialog because context doesn't exist when + * SI_RestoreSignonData is called + */ +#undef FE_Confirm +Bool +FE_Confirm(MWContext* context, const char* szMessage) +{ + char c; + fprintf(stdout, "%c%s (y/n)? ", '\007', szMessage); /* \007 is BELL */ + for (;;) { + c = getchar(); + if (tolower(c) == 'y') { + return JS_TRUE; + } + if (tolower(c) == 'n') { + return JS_FALSE; + } + } +} + +#undef FE_SelectDialog +Bool +FE_SelectDialog + (MWContext* context, const char* szMessage, char** pList, int16* pCount) +{ + char c; + int i; + fprintf(stdout, "%s\n", szMessage); + for (i=0; i<*pCount; i++) { + fprintf(stdout, "%d: %s\n", i, pList[i]); + } + fprintf(stdout, "%cType user number (max=9) or type n to cancel. ", '\007'); /* \007 is BELL */ + for (;;) { + c = getchar(); + if (c >= '0' && c <= '9') { + *pCount = c - '0'; + return JS_TRUE; + } + if (tolower(c) == 'n') { + return JS_FALSE; + } + } +} + +/* end of temporary */ + +PRIVATE void +si_lock_signon_list(void) +{ + if(!signon_lock_monitor) { + signon_lock_monitor = + PR_NewNamedMonitor("signon-lock"); + } + + PR_EnterMonitor(signon_lock_monitor); + + while(TRUE) { + + /* no current owner or owned by this thread */ + PRThread * t = PR_CurrentThread(); + if(signon_lock_owner == NULL || signon_lock_owner == t) { + signon_lock_owner = t; + signon_lock_count++; + + PR_ExitMonitor(signon_lock_monitor); + return; + } + + /* owned by someone else -- wait till we can get it */ + PR_Wait(signon_lock_monitor, PR_INTERVAL_NO_TIMEOUT); + + } +} + +PRIVATE void +si_unlock_signon_list(void) +{ + PR_EnterMonitor(signon_lock_monitor); + +#ifdef DEBUG + /* make sure someone doesn't try to free a lock they don't own */ + PR_ASSERT(signon_lock_owner == PR_CurrentThread()); +#endif + + signon_lock_count--; + + if(signon_lock_count == 0) { + signon_lock_owner = NULL; + PR_Notify(signon_lock_monitor); + } + PR_ExitMonitor(signon_lock_monitor); + +} + + +/* + * Data and procedures for rememberSignons preference + */ + +static const char *pref_rememberSignons = + "network.signon.rememberSignons"; +PRIVATE Bool si_RememberSignons = FALSE; + +PRIVATE int +si_SaveSignonDataLocked(char * filename); + +PRIVATE void +si_SetSignonRememberingPref(Bool x) +{ + /* do nothing if new value of pref is same as current value */ + if (x == si_RememberSignons) { + return; + } + + /* if pref is being turned off, save the current signons to a file */ + if (x == 0) { + si_lock_signon_list(); + si_SaveSignonDataLocked(NULL); + si_unlock_signon_list(); +#ifdef APPLE_KEYCHAIN + /* We no longer need the Keychain callback installed */ + KCRemoveCallback( si_kcUPP ); + DisposeRoutineDescriptor( si_kcUPP ); + si_kcUPP = NULL; +#endif + } + + /* change the pref */ + si_RememberSignons = x; + + /* if pref is being turned on, load the signon file into memory */ + if (x == 1) { + SI_RemoveAllSignonData(); + SI_LoadSignonData(NULL); + } +} + +MODULE_PRIVATE int PR_CALLBACK +si_SignonRememberingPrefChanged(const char * newpref, void * data) +{ + Bool x; + PREF_GetBoolPref(pref_rememberSignons, &x); + si_SetSignonRememberingPref(x); + return PREF_NOERROR; +} + +void +si_RegisterSignonPrefCallbacks(void) +{ + Bool x = TRUE; /* initialize to default value in case PREF_GetBoolPref fails */ + static Bool first_time = TRUE; + + if(first_time) + { + first_time = FALSE; + PREF_GetBoolPref(pref_rememberSignons, &x); + si_SetSignonRememberingPref(x); + PREF_RegisterCallback(pref_rememberSignons, si_SignonRememberingPrefChanged, NULL); + } +} + +PRIVATE Bool +si_GetSignonRememberingPref(void) +{ +#ifdef APPLE_KEYCHAIN + /* If the Keychain has been locked or an item deleted or updated, + we need to reload the signon data */ + if (si_list_invalid) + { + /* + * set si_list_invalid to FALSE first because SI_RemoveAllSignonData + * calls si_GetSignonRememberingPref + */ + si_list_invalid = FALSE; + SI_RemoveAllSignonData(); + SI_LoadSignonData(NULL); + } +#endif + + si_RegisterSignonPrefCallbacks(); + return si_RememberSignons; +} + +/* + * Data and procedures for signon cache + */ + +typedef struct _SignonDataStruct { + char * name; + char * value; + Bool isPassword; +} si_SignonDataStruct; + +typedef struct _SignonUserStruct { + XP_List * signonData_list; +} si_SignonUserStruct; + +typedef struct _SignonURLStruct { + char * URLName; + si_SignonUserStruct* chosen_user; /* this is a state variable */ + XP_List * signonUser_list; +} si_SignonURLStruct; + + +typedef struct _RejectStruct { + char * URLName; + char * userName; +} si_Reject; + +PRIVATE XP_List * si_signon_list=0; +PRIVATE XP_List * si_reject_list=0; + +PRIVATE Bool si_signon_list_changed = FALSE; +PRIVATE int si_TagCount = 0; +PRIVATE Bool si_NoticeGiven = FALSE; + + +/* Remove misleading portions from URL name */ +PRIVATE char* +si_StrippedURL (char* URLName) { + char *result = 0; + char *s, *t; + + /* check for null URLName */ + if (URLName == NULL || XP_STRLEN(URLName) == 0) { + return NULL; + } + + /* check for protocol at head of URL */ + s = URLName; + s = (char*) XP_STRCHR(s+1, '/'); + if (s) { + if (*(s+1) == '/') { + /* looks good, let's parse it */ + return NET_ParseURL(URLName, GET_HOST_PART); + } else { + /* not a valid URL, leave it as is */ + StrAllocCopy(result, URLName); + return result; + } + } + + /* initialize result */ + StrAllocCopy(result, URLName); + + /* remove everything in result after and including first question mark */ + s = result; + s = (char*) XP_STRCHR(s, '?'); + if (s) { + *s = '\0'; + } + + /* remove everything in result after last slash (e.g., index.html) */ + s = result; + t = 0; + while ((s = (char*) XP_STRCHR(s+1, '/'))) { + t = s; + } + if (t) { + *(t+1) = '\0'; + } + + /* remove socket number from result */ + s = result; + while ((s = (char*) XP_STRCHR(s+1, ':'))) { + /* s is at next colon */ + if (*(s+1) != '/') { + /* and it's not :// so it must be start of socket number */ + if ((t = (char*) XP_STRCHR(s+1, '/'))) { + /* t is at slash terminating the socket number */ + do { + /* copy remainder of t to s */ + *s++ = *t; + } while (*(t++)); + } + break; + } + } + + /* alll done */ + return result; +} + +/* remove terminating CRs or LFs */ +PRIVATE void +si_StripLF(char* buffer) { + while ((buffer[XP_STRLEN(buffer)-1] == '\n') || + (buffer[XP_STRLEN(buffer)-1] == '\r')) { + buffer[XP_STRLEN(buffer)-1] = '\0'; + } +} + +/* If user-entered password is "generate", then generate a random password */ +PRIVATE void +si_Randomize(char * password) { + PRIntervalTime random; + int i; + const char * hexDigits = "0123456789AbCdEf"; + if (XP_STRCMP(password, XP_GetString(MK_SIGNON_PASSWORDS_GENERATE)) == 0) { + random = PR_IntervalNow(); + for (i=0; i<8; i++) { + password[i] = hexDigits[random%16]; + random = random/16; + } + } +} + +/* + * Get the URL node for a given URL name + * + * This routine is called only when holding the signon lock!!! + */ +PRIVATE si_SignonURLStruct * +si_GetURL(char * URLName) { + XP_List * list_ptr = si_signon_list; + si_SignonURLStruct * url; + char *strippedURLName = 0; + + if (!URLName) { + /* no URLName specified, return first URL (returns NULL if not URLs) */ + return (si_SignonURLStruct *) XP_ListNextObject(list_ptr); + } + + strippedURLName = si_StrippedURL(URLName); + while((url = (si_SignonURLStruct *) XP_ListNextObject(list_ptr))!=0) { + if(url->URLName && !XP_STRCMP(strippedURLName, url->URLName)) { + XP_FREE(strippedURLName); + return url; + } + } + XP_FREE(strippedURLName); + return (NULL); +} + +/* Remove a user node from a given URL node */ +PUBLIC Bool +SI_RemoveUser(char *URLName, char *userName, Bool save) { + si_SignonURLStruct * url; + si_SignonUserStruct * user; + si_SignonDataStruct * data; + XP_List * user_ptr; + XP_List * data_ptr; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()) { + return FALSE; + } + + si_lock_signon_list(); + + /* get URL corresponding to URLName (or first URL if URLName is NULL) */ + url = si_GetURL(URLName); + if (!url) { + /* URL not found */ + si_unlock_signon_list(); + return FALSE; + } + + /* free the data in each node of the specified user node for this URL */ + user_ptr = url->signonUser_list; + + if (userName == NULL) { + + /* no user specified so remove the first one */ + user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr); + + } else { + + /* find the specified user */ + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if (XP_STRCMP(data->value, userName)==0) { + goto foundUser; + } + } + } + si_unlock_signon_list(); + return FALSE; /* user not found so nothing to remove */ + foundUser: ; + } + + /* free the items in the data list */ + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + XP_FREE(data->name); + XP_FREE(data->value); + } + + /* free the data list */ + XP_ListDestroy(user->signonData_list); + + /* free the user node */ + XP_ListRemoveObject(url->signonUser_list, user); + + /* remove this URL if it contains no more users */ + if (XP_ListCount(url->signonUser_list) == 0) { + XP_FREE(url->URLName); + XP_ListRemoveObject(si_signon_list, url); + } + + /* write out the change to disk */ + if (save) { + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + } + + si_unlock_signon_list(); + return TRUE; +} + +/* Determine if a specified url/user exists */ +PRIVATE Bool +si_CheckForUser(char *URLName, char *userName) { + si_SignonURLStruct * url; + si_SignonUserStruct * user; + si_SignonDataStruct * data; + XP_List * user_ptr; + XP_List * data_ptr; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()) { + return FALSE; + } + + si_lock_signon_list(); + + /* get URL corresponding to URLName */ + url = si_GetURL(URLName); + if (!url) { + /* URL not found */ + si_unlock_signon_list(); + return FALSE; + } + + /* find the specified user */ + user_ptr = url->signonUser_list; + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if (XP_STRCMP(data->value, userName)==0) { + si_unlock_signon_list(); + return TRUE; + } + } + } + si_unlock_signon_list(); + return FALSE; /* user not found */ +} + +/* + * Get the user node for a given URL + * + * This routine is called only when holding the signon lock!!! + * + * This routine is called only if signon pref is enabled!!! + */ +PRIVATE si_SignonUserStruct* +si_GetUser( + MWContext *context, char* URLName, Bool pickFirstUser, + char* userText) { + si_SignonURLStruct* url; + si_SignonUserStruct* user; + si_SignonDataStruct* data; + XP_List * data_ptr=0; + XP_List * user_ptr=0; + + /* get to node for this URL */ + url = si_GetURL(URLName); + if (url != NULL) { + + /* node for this URL was found */ + int16 user_count; + user_ptr = url->signonUser_list; + if ((user_count = XP_ListCount(user_ptr)) == 1) { + + /* only one set of data exists for this URL so select it */ + user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr); + url->chosen_user = user; + + } else if (pickFirstUser) { + user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr); + + } else { + /* multiple users for this URL so a choice needs to be made */ + char ** list; + char ** list2; + si_SignonUserStruct** users; + si_SignonUserStruct** users2; + list = (char**)XP_ALLOC(user_count*sizeof(char*)); + users = (struct _SignonUserStruct **) + XP_ALLOC(user_count*sizeof(si_SignonUserStruct*)); + list2 = list; + users2 = users; + + /* step through set of user nodes for this URL and create list of + * first data node of each (presumably that is the user name). + * Note that the user nodes are already ordered by + * most-recently-used so the first one in the list is the most + * likely one to be chosen. + */ + user_count = 0; + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + data_ptr = user->signonData_list; + /* consider first data node to be the identifying item */ + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + if (PL_strcmp(data->name, userText)) { + /* name of current data item does not match name in data node */ + continue; + } + *(list2++) = data->value; + *(users2++) = user; + user_count++; + } + + /* have user select a username from the list */ + if (user_count == 0) { + /* not first data node for any saved user, so simply pick first user */ + user_ptr = url->signonUser_list; + user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr); + } else if (user_count == 1) { + /* only one user for this form at this url, so select it */ + user = users[0]; + } else if ((user_count > 1) && FE_SelectDialog( + context, XP_GetString(MK_SIGNON_SELECTUSER), + list, &user_count)) { + /* user pressed OK */ + if (user_count == -1) { + user_count = 0; /* user didn't select, so use first one */ + } + user = users[user_count]; /* this is the selected item */ + /* item selected is now most-recently used, put at head of list */ + XP_ListRemoveObject(url->signonUser_list, user); + XP_ListAddObject(url->signonUser_list, user); + } else { + user = NULL; + } + url->chosen_user = user; + XP_FREE(list); + XP_FREE(users); + + /* if we don't remove the URL from the cache at this point, the + * cached copy will be brought in containing the last-used username + * rather than the username that was just selected + */ + NET_RemoveURLFromCache + (NET_CreateURLStruct((char *)URLName, NET_DONT_RELOAD)); + + } + } else { + user = NULL; + } + return user; +} + +/* + * Get the user for which a change-of-password is to be applied + * + * This routine is called only when holding the signon lock!!! + * + * This routine is called only if signon pref is enabled!!! + */ +PRIVATE si_SignonUserStruct* +si_GetUserForChangeForm(MWContext *context, char* URLName, int messageNumber) +{ + si_SignonURLStruct* url; + si_SignonUserStruct* user; + si_SignonDataStruct * data; + XP_List * user_ptr = 0; + XP_List * data_ptr = 0; + char *message = 0; + + /* get to node for this URL */ + url = si_GetURL(URLName); + if (url != NULL) { + + /* node for this URL was found */ + user_ptr = url->signonUser_list; + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + char *strippedURLName = si_StrippedURL(URLName); + data_ptr = user->signonData_list; + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + message = PR_smprintf(XP_GetString(messageNumber), + data->value, + strippedURLName); + XP_FREE(strippedURLName); + if (FE_Confirm(context, message)) { + /* + * since this user node is now the most-recently-used one, move it + * to the head of the user list so that it can be favored for + * re-use the next time this form is encountered + */ + XP_ListRemoveObject(url->signonUser_list, user); + XP_ListAddObject(url->signonUser_list, user); + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + XP_FREE(message); + return user; + } + } + } + XP_FREE(message); + return NULL; +} + +/* + * Get the url and user for which a change-of-password is to be applied + * + * This routine is called only when holding the signon lock!!! + * + * This routine is called only if signon pref is enabled!!! + */ +PRIVATE si_SignonUserStruct* +si_GetURLAndUserForChangeForm(MWContext *context, char* password) +{ + si_SignonURLStruct* url; + si_SignonUserStruct* user; + si_SignonDataStruct * data; + XP_List * url_ptr = 0; + XP_List * user_ptr = 0; + XP_List * data_ptr = 0; + char *message = 0; + int16 user_count; + + char ** list; + char ** list2; + si_SignonUserStruct** users; + si_SignonUserStruct** users2; + si_SignonURLStruct** urls; + si_SignonURLStruct** urls2; + + /* get count of total number of user nodes at all url nodes */ + user_count = 0; + url_ptr = si_signon_list; + while((url = (si_SignonURLStruct *) XP_ListNextObject(url_ptr))!=0) { + user_ptr = url->signonUser_list; + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + user_count++; + } + } + + /* allocate lists for maximumum possible url and user names */ + list = (char**)XP_ALLOC(user_count*sizeof(char*)); + users = (struct _SignonUserStruct **) + XP_ALLOC(user_count*sizeof(si_SignonUserStruct*)); + urls = (struct _SignonURLStruct **)XP_ALLOC(user_count*sizeof(si_SignonUserStruct*)); + list2 = list; + users2 = users; + urls2 = urls; + + /* step through set of URLs and users and create list of each */ + user_count = 0; + url_ptr = si_signon_list; + while((url = (si_SignonURLStruct *) XP_ListNextObject(url_ptr))!=0) { + user_ptr = url->signonUser_list; + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + data_ptr = user->signonData_list; + /* find saved password and see if it matches password user just entered */ + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if (data->isPassword && !PL_strcmp(data->value, password)) { + /* passwords match so add entry to list */ + /* consider first data node to be the identifying item */ + data_ptr = user->signonData_list; + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + *list2 = 0; + StrAllocCopy(*list2, url->URLName); + StrAllocCat(*list2,": "); + StrAllocCat(*list2, data->value); + list2++; + *(users2++) = user; + *(urls2++) = url; + user_count++; + break; + } + } + } + } + + /* query user */ + if (user_count && FE_SelectDialog + (context, + XP_GetString(MK_SIGNON_CHANGE), + list, + &user_count)) { + user = users[user_count]; + url = urls[user_count]; + /* + * since this user node is now the most-recently-used one, move it + * to the head of the user list so that it can be favored for + * re-use the next time this form is encountered + */ + XP_ListRemoveObject(url->signonUser_list, user); + XP_ListAddObject(url->signonUser_list, user); + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + } else { + user = NULL; + } + + /* free allocated strings */ + while (--list2 > list) { + XP_FREE(*list2); + } + XP_FREE(list); + XP_FREE(users); + XP_FREE(urls); + + return user; + +} + +PRIVATE void +si_FreeReject(si_Reject * reject) { + + /* + * This routine should only be called while holding the + * signon list lock + */ + + if(!reject) { + return; + } + XP_ListRemoveObject(si_reject_list, reject); + PR_FREEIF(reject->URLName); + PR_FREEIF(reject->userName); + PR_Free(reject); +} + +PRIVATE Bool +si_CheckForReject(char * URLName, char * userName) { + XP_List * list_ptr; + si_Reject * reject; + + si_lock_signon_list(); + if (si_reject_list) { + list_ptr = si_reject_list; + while((reject = (si_Reject *) XP_ListNextObject(list_ptr))!=0) { + if(!PL_strcmp(userName, reject->userName) && + !PL_strcmp(URLName, reject->URLName)) { + si_unlock_signon_list(); + return TRUE; + } + } + } + si_unlock_signon_list(); + return FALSE; +} + +PRIVATE void +si_PutReject(char * URLName, char * userName, Bool save) { + si_Reject * reject; + char * URLName2=NULL; + char * userName2=NULL; + + reject = PR_NEW(si_Reject); + if (reject) { + /* + * lock the signon list + * Note that, for efficiency, SI_LoadSignonData already sets the lock + * before calling this routine whereas none of the other callers do. + * So we need to determine whether or not we were called from + * SI_LoadSignonData before setting or clearing the lock. We can + * determine this by testing "save" since only SI_LoadSignonData + * passes in a value of FALSE for "save". + */ + XP_List * list_ptr; + if (save) { + si_lock_signon_list(); + } + list_ptr = si_reject_list; + + StrAllocCopy(URLName2, URLName); + StrAllocCopy(userName2, userName); + reject->URLName = URLName2; + reject->userName = userName2; + + if(!si_reject_list) { + si_reject_list = XP_ListNew(); + if(!si_reject_list) { + PR_Free(reject->URLName); + PR_Free(reject->userName); + PR_Free(reject); + if (save) { + si_unlock_signon_list(); + } + return; + } + } +#ifdef alphabetize + /* add it to the list in alphabetical order */ + { + si_Reject * tmp_reject; + Bool rejectAdded = FALSE; + while((tmp_reject = (si_Reject *) XP_ListNextObject(list_ptr))!=0) { + if (PL_strcmp (reject->URLName, tmp_reject->URLName)<0) { + XP_ListInsertObject (si_reject_list, tmp_reject, reject); + rejectAdded = TRUE; + break; + } + } + if (!rejectAdded) { + XP_ListAddObjectToEnd (si_reject_list, reject); + } + } +#else + /* add it to the end of the list */ + XP_ListAddObjectToEnd (si_reject_list, reject); +#endif + + if (save) { + si_signon_list_changed = TRUE; + SI_SaveSignonData(NULL); + } + if (save) { + si_unlock_signon_list(); + } + } +} + +/* Ask user if it is ok to save the signon data */ +PRIVATE Bool +si_OkToSave(MWContext *context, char *URLName, char *userName) { + Bool remember_checked = TRUE; + char *strippedURLName = 0; + + /* if url/user already exists, then it is safe to save it again */ + if (si_CheckForUser(URLName, userName)) { + return TRUE; + } + + if (!si_NoticeGiven) { + char* notification = 0; + si_NoticeGiven = TRUE; + si_signon_list_changed = TRUE; + SI_SaveSignonData(NULL); + StrAllocCopy(notification, XP_GetString(MK_SIGNON_NOTIFICATION)); + StrAllocCat(notification, XP_GetString(MK_SIGNON_NOTIFICATION_1)); + if (!FE_Confirm(context, notification)) { + XP_FREE (notification); + PREF_SetBoolPref(pref_rememberSignons, FALSE); + return FALSE; + } + XP_FREE (notification); + } + + strippedURLName = si_StrippedURL(URLName); + if (si_CheckForReject(strippedURLName, userName)) { + XP_FREE(strippedURLName); + return FALSE; + } + + if (!FE_Confirm(context, XP_GetString(MK_SIGNON_NAG))) { + si_PutReject(strippedURLName, userName, TRUE); + XP_FREE(strippedURLName); + return FALSE; + } + XP_FREE(strippedURLName); + return TRUE; +} + +/* + * Put data obtained from a submit form into the data structure for + * the specified URL + * + * See comments below about state of signon lock when routine is called!!! + * + * This routine is called only if signon pref is enabled!!! + */ +PRIVATE void +si_PutData(char * URLName, LO_FormSubmitData * submit, Bool save) { + char * name; + char * value; + Bool added_to_list = FALSE; + si_SignonURLStruct * url; + si_SignonUserStruct * user; + si_SignonDataStruct * data; + int j; + XP_List * list_ptr; + XP_List * user_ptr; + XP_List * data_ptr; + si_SignonURLStruct * tmp_URL_ptr; + Bool mismatch; + int i; + + /* discard this if the password is empty */ + for (i=0; ivalue_cnt; i++) { + if ((((uint8*)submit->type_array)[i] == FORM_TYPE_PASSWORD) && + (!((char **)(submit->value_array))[i] || + !XP_STRLEN( ((char **)(submit->value_array)) [i])) ) { + return; + } + } + + /* + * lock the signon list + * Note that, for efficiency, SI_LoadSignonData already sets the lock + * before calling this routine whereas none of the other callers do. + * So we need to determine whether or not we were called from + * SI_LoadSignonData before setting or clearing the lock. We can + * determine this by testing "save" since only SI_LoadSignonData passes + * in a value of FALSE for "save". + */ + if (save) { + si_lock_signon_list(); + } + + /* make sure the signon list exists */ + if(!si_signon_list) { + si_signon_list = XP_ListNew(); + if(!si_signon_list) { + if (save) { + si_unlock_signon_list(); + } + return; + } + } + + /* find node in signon list having the same URL */ + if ((url = si_GetURL(URLName)) == NULL) { + + /* doesn't exist so allocate new node to be put into signon list */ + url = XP_NEW(si_SignonURLStruct); + if (!url) { + if (save) { + si_unlock_signon_list(); + } + return; + } + + /* fill in fields of new node */ + url->URLName = si_StrippedURL(URLName); + if (!url->URLName) { + XP_FREE(url); + if (save) { + si_unlock_signon_list(); + } + return; + } + + url->signonUser_list = XP_ListNew(); + if(!url->signonUser_list) { + XP_FREE(url->URLName); + XP_FREE(url); + } + + /* put new node into signon list */ + +#ifdef alphabetize + /* add it to the list in alphabetical order */ + list_ptr = si_signon_list; + while((tmp_URL_ptr = + (si_SignonURLStruct *) XP_ListNextObject(list_ptr))!=0) { + if(PL_strcmp(url->URLName,tmp_URL_ptr->URLName)<0) { + XP_ListInsertObject + (si_signon_list, tmp_URL_ptr, url); + added_to_list = TRUE; + break; + } + } + if (!added_to_list) { + XP_ListAddObjectToEnd (si_signon_list, url); + } + } +#else + /* add it to the end of the list */ + XP_ListAddObjectToEnd (si_signon_list, url); +#endif + + /* initialize state variables in URL node */ + url->chosen_user = NULL; + + /* + * see if a user node with data list matching new data already exists + * (password fields will not be checked for in this matching) + */ + user_ptr = url->signonUser_list; + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr))!=0) { + data_ptr = user->signonData_list; + j = 0; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + mismatch = FALSE; + + /* skip non text/password fields */ + while ((j < submit->value_cnt) && + (((uint8*)submit->type_array)[j]!=FORM_TYPE_TEXT) && + (((uint8*)submit->type_array)[j]!=FORM_TYPE_PASSWORD)) { + j++; + } + + /* check for match on name field and type field */ + if ((j < submit->value_cnt) && + (data->isPassword == + (((uint8*)submit->type_array)[j]==FORM_TYPE_PASSWORD)) && + (!XP_STRCMP(data->name, ((char **)submit->name_array)[j]))) { + + /* success, now check for match on value field if not password */ + if (!submit->value_array[j]) { + /* special case a null value */ + if (!XP_STRCMP(data->value, "")) { + j++; /* success */ + } else { + mismatch = TRUE; + break; /* value mismatch, try next user */ + } + } else if (!XP_STRCMP(data->value, ((char **)submit->value_array)[j]) + || data->isPassword) { + j++; /* success */ + } else { + mismatch = TRUE; + break; /* value mismatch, try next user */ + } + } else { + mismatch = TRUE; + break; /* name or type mismatch, try next user */ + } + + } + if (!mismatch) { + + /* all names and types matched and all non-password values matched */ + + /* + * note: it is ok for password values not to match; it means + * that the user has either changed his password behind our + * back or that he previously mis-entered the password + */ + + /* update the saved password values */ + data_ptr = user->signonData_list; + j = 0; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + + /* skip non text/password fields */ + while ((j < submit->value_cnt) && + (((uint8*)submit->type_array)[j]!=FORM_TYPE_TEXT) && + (((uint8*)submit->type_array)[j]!=FORM_TYPE_PASSWORD)) { + j++; + } + + /* update saved password */ + if ((j < submit->value_cnt) && data->isPassword) { + if (XP_STRCMP(data->value, ((char **)submit->value_array)[j])) { + si_signon_list_changed = TRUE; + StrAllocCopy(data->value, ((char **)submit->value_array)[j]); + si_Randomize(data->value); + } + } + j++; + } + + /* + * since this user node is now the most-recently-used one, move it + * to the head of the user list so that it can be favored for + * re-use the next time this form is encountered + */ + XP_ListRemoveObject(url->signonUser_list, user); + XP_ListAddObject(url->signonUser_list, user); + + /* return */ + if (save) { + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + si_unlock_signon_list(); + } + return; /* nothing more to do since data already exists */ + } + } + + /* user node with current data not found so create one */ + user = XP_NEW(si_SignonUserStruct); + if (!user) { + if (save) { + si_unlock_signon_list(); + } + return; + } + user->signonData_list = XP_ListNew(); + if(!user->signonData_list) { + XP_FREE(user); + if (save) { + si_unlock_signon_list(); + } + return; + } + + + /* create and fill in data nodes for new user node */ + for (j=0; jvalue_cnt; j++) { + + /* skip non text/password fields */ + if((((uint8*)submit->type_array)[j]!=FORM_TYPE_TEXT) && + (((uint8*)submit->type_array)[j]!=FORM_TYPE_PASSWORD)) { + continue; + } + + /* create signon data node */ + data = XP_NEW(si_SignonDataStruct); + if (!data) { + XP_ListDestroy(user->signonData_list); + XP_FREE(user); + } + data->isPassword = + (((uint8 *)submit->type_array)[j] == FORM_TYPE_PASSWORD); + name = 0; /* so that StrAllocCopy doesn't free previous name */ + StrAllocCopy(name, ((char **)submit->name_array)[j]); + data->name = name; + value = 0; /* so that StrAllocCopy doesn't free previous name */ + if (submit->value_array[j]) { + StrAllocCopy(value, ((char **)submit->value_array)[j]); + } else { + StrAllocCopy(value, ""); /* insures that value is not null */ + } + data->value = value; + if (data->isPassword) { + si_Randomize(data->value); + } + + /* append new data node to end of data list */ + XP_ListAddObjectToEnd (user->signonData_list, data); + } + + /* append new user node to front of user list for matching URL */ + /* + * Note that by appending to the front, we assure that if there are + * several users, the most recently used one will be favored for + * reuse the next time this form is encountered. But don't do this + * when reading in signons.txt (i.e., when save is false), otherwise + * we will be reversing the order when reading in. + */ + if (save) { + XP_ListAddObject(url->signonUser_list, user); + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + si_unlock_signon_list(); + } else { + XP_ListAddObjectToEnd(url->signonUser_list, user); + } +} + +/* + * When a new form is started, set the tagCount to 0 + */ +PUBLIC void +SI_StartOfForm() { + si_TagCount = 0; +} + +/* + * APPLE + * The Keychain callback. This routine will be called whenever a lock, + * delete, or update event occurs in the Keychain. The only action taken + * is to make the signon list invalid, so it will be read in again the + * next time it is accessed. + */ +#ifdef APPLE_KEYCHAIN +OSStatus PR_CALLBACK +si_KeychainCallback( KCEvent keychainEvent, KCCallbackInfo *info, void *userContext) { + Bool *listInvalid = (Bool*)userContext; + *listInvalid = TRUE; +} +#endif + +#define BUFFER_SIZE 4096 +#define MAX_ARRAY_SIZE 50 +/* + * APPLE + * Get the signon data from the keychain + * + * This routine is called only if signon pref is enabled!!! + */ +#ifdef APPLE_KEYCHAIN +PRIVATE int +si_LoadSignonDataFromKeychain() { + char * URLName; + LO_FormSubmitData submit; + char* name_array[MAX_ARRAY_SIZE]; + char* value_array[MAX_ARRAY_SIZE]; + uint8 type_array[MAX_ARRAY_SIZE]; + char buffer[BUFFER_SIZE]; + XP_File fp; + Bool badInput = FALSE; + int i; + char* unmungedValue; + KCItemRef itemRef; + KCAttributeList attrList; + KCAttribute attr[2]; + KCItemClass itemClass = kInternetPasswordKCItemClass; + KCProtocolType protocol = kNetscapeProtocolType; + OSStatus status = noErr; + KCSearchRef searchRef = NULL; + + /* initialize the submit structure */ + submit.name_array = (PA_Block)name_array; + submit.value_array = (PA_Block)value_array; + submit.type_array = (PA_Block)type_array; + + /* set up the attribute list */ + attrList.count = 2; + attrList.attr = attr; + attr[0].tag = kClassKCItemAttr; + attr[0].data = &itemClass; + attr[0].length = sizeof(itemClass); + + attr[1].tag = kProtocolKCItemAttr; + attr[1].data = &protocol; + attr[1].length = sizeof(protocol); + + status = KCFindFirstItem( &attrList, &searchRef, &itemRef ); + + if (status == noErr) { + /* if we found a Netscape item, let's assume notice has been given */ + si_NoticeGiven = TRUE; + } else { + si_NoticeGiven = FALSE; + } + + si_lock_signon_list(); + while(status == noErr) { + char *value; + uint16 i = 0; + uint32 actualSize; + KCItemFlags flags; + Boolean reject = FALSE; + + submit.value_cnt = 0; + + /* first find out if it is a reject entry */ + attr[0].tag = kFlagsKCItemAttr; + attr[0].length = sizeof(KCItemFlags); + attr[0].data = &flags; + + status = KCGetAttribute( itemRef, attr, nil ); + if (status != noErr) { + break; + } + + if (flags & kNegativeKCItemFlag) { + reject = TRUE; + } + + /* get the server name */ + attr[0].tag = kServerKCItemAttr; + attr[0].length = BUFFER_SIZE; + attr[0].data = buffer; + + status = KCGetAttribute( itemRef, attr, &actualSize ); + if (status != noErr) { + break; + { + + /* null terminate */ + buffer[actualSize] = 0; + + URLName = NULL; + StrAllocCopy(URLName, buffer); + + if (!reject) { + /* get the password data */ + status = KCGetData(itemRef, BUFFER_SIZE, buffer, &actualSize); + if (status != noErr) { + break; + } + + /* null terminate */ + buffer[actualSize] = 0; + + /* parse for '=' which separates the name and value */ + for (i = 0; i < XP_STRLEN(buffer); i++) { + if (buffer[i] == '=') { + value = &buffer[i+1]; + buffer[i] = 0; + break; + } + } + name_array[submit.value_cnt] = NULL; + value_array[submit.value_cnt] = NULL; + + type_array[submit.value_cnt] = FORM_TYPE_PASSWORD; + StrAllocCopy(name_array[submit.value_cnt], buffer); + StrAllocCopy(value_array[submit.value_cnt], value); + } + + /* get the account attribute */ + attr[0].tag = kAccountKCItemAttr; + attr[0].length = BUFFER_SIZE; + attr[0].data = buffer; + + status = KCGetAttribute( itemRef, attr, &actualSize ); + if (status != noErr) { + break; + } + + /* null terminate */ + buffer[actualSize] = 0; + + if (!reject) { + /* parse for '=' which separates the name and value */ + for (i = 0; i < XP_STRLEN(buffer); i++) { + if (buffer[i] == '=') { + value = &buffer[i+1]; + buffer[i] = 0; + break; + } + } + + submit.value_cnt++; + name_array[submit.value_cnt] = NULL; + value_array[submit.value_cnt] = NULL; + + type_array[submit.value_cnt] = FORM_TYPE_TEXT; + StrAllocCopy(name_array[submit.value_cnt], buffer); + StrAllocCopy(value_array[submit.value_cnt], value); + + /* check for overruning of the arrays */ + if (submit.value_cnt >= MAX_ARRAY_SIZE) { + break; + } + + submit.value_cnt++; + /* store the info for this URL into memory-resident data structure */ + if (!URLName || XP_STRLEN(URLName) == 0) { + badInput = TRUE; + } + if (!badInput) { + si_PutData(URLName, &submit, FALSE); + } + + /* free up all the allocations done for processing this URL */ + for (i = 0; i < submit.value_cnt; i++) { + XP_FREE(name_array[i]); + XP_FREE(value_array[i]); + } + } else { + /* reject */ + si_PutReject(URLName, buffer, FALSE); + } + + reject = FALSE; /* reset reject flag */ + XP_FREE(URLName); + KCReleaseItemRef( &itemRef ); + + status = KCFindNextItem( searchRef, &itemRef ); + + } + si_unlock_signon_list(); + + if (searchRef) { + KCReleaseSearchRef( &searchRef ); + } + + /* Register a callback with the Keychain if we haven't already done so. */ + + if (si_kcUPP == NULL) + { + si_kcUPP = NewKCCallbackProc( si_KeychainCallback ); + if (!si_kcUPP) { + return memFullErr; + } + + KCAddCallback( si_kcUPP, kLockKCEventMask + kDeleteKCEventMask + kUpdateKCEventMask, &si_list_invalid ); + /* + * Note that the callback is not necessarily removed. We take advantage + * of the fact that the Keychain will clean up the callback when the app + * goes away. It is explicitly removed when the signon preference is turned off. + */ + } + + if (status == errKCItemNotFound) { + status = 0; + } + + return (status); +} +#endif + +/* + * Load signon data from disk file + * The parameter passed in on entry is ignored + */ + +PUBLIC int +SI_LoadSignonData(char * filename) { + char * URLName; + LO_FormSubmitData submit; + char* name_array[MAX_ARRAY_SIZE]; + char* value_array[MAX_ARRAY_SIZE]; + uint8 type_array[MAX_ARRAY_SIZE]; + char buffer[BUFFER_SIZE]; + XP_File fp; + Bool badInput; + int i; + char* unmungedValue; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()) { + return 0; + } + +#ifdef APPLE_KEYCHAIN + if (KeychainManagerAvailable()) { + return si_LoadSignonDataFromKeychain(); + } +#endif + + /* open the signon file */ + if(!(fp = XP_FileOpen(filename, xpHTTPSingleSignon, XP_FILE_READ))) { + return(-1); + } + + /* skip the initial comment lines */ + do { + XP_FileReadLine(buffer, BUFFER_SIZE, fp); + } while (buffer[0] == '#'); + + /* first line after comment indicates if notice was given */ + si_NoticeGiven = (buffer[0] == 'T'); + + /* read the reject list */ + si_lock_signon_list(); + while(XP_FileReadLine(buffer, BUFFER_SIZE, fp)) { + if (buffer[0] == '.') { + break; /* end of reject list */ + } + si_StripLF(buffer); + URLName = NULL; + StrAllocCopy(URLName, buffer); + XP_FileReadLine(buffer, BUFFER_SIZE, fp); /* get username */ + si_StripLF(buffer); + si_PutReject(URLName, buffer, FALSE); + XP_FREE (URLName); + } + + /* initialize the submit structure */ + submit.name_array = (PA_Block)name_array; + submit.value_array = (PA_Block)value_array; + submit.type_array = (PA_Block)type_array; + + /* read the URL line */ + while(XP_FileReadLine(buffer, BUFFER_SIZE, fp)) { + + si_StripLF(buffer); + URLName = NULL; + StrAllocCopy(URLName, buffer); + + /* preparre to read the name/value pairs */ + submit.value_cnt = 0; + badInput = FALSE; + + while(XP_FileReadLine(buffer, BUFFER_SIZE, fp)) { + + /* line starting with . terminates the pairs for this URL entry */ + if (buffer[0] == '.') { + break; /* end of URL entry */ + } + + /* line just read is the name part */ + + /* save the name part and determine if it is a password */ + si_StripLF(buffer); + name_array[submit.value_cnt] = NULL; + if (buffer[0] == '*') { + type_array[submit.value_cnt] = FORM_TYPE_PASSWORD; + StrAllocCopy(name_array[submit.value_cnt], buffer+1); + } else { + type_array[submit.value_cnt] = FORM_TYPE_TEXT; + StrAllocCopy(name_array[submit.value_cnt], buffer); + } + + /* read in and save the value part */ + if(!XP_FileReadLine(buffer, BUFFER_SIZE, fp)) { + /* error in input file so give up */ + badInput = TRUE; + break; + } + si_StripLF(buffer); + value_array[submit.value_cnt] = NULL; + /* note that we need to skip over leading '=' of value */ + if (type_array[submit.value_cnt] == FORM_TYPE_PASSWORD) { + if ((unmungedValue=SECNAV_UnMungeString(buffer+1)) == NULL) { + /* this is the free source and there is no obscuring of passwords */ + unmungedValue = buffer+1; + StrAllocCopy(value_array[submit.value_cnt++], buffer+1); + } else { + StrAllocCopy(value_array[submit.value_cnt++], unmungedValue); + XP_FREE(unmungedValue); + } + } else { + StrAllocCopy(value_array[submit.value_cnt++], buffer+1); + } + + /* check for overruning of the arrays */ + if (submit.value_cnt >= MAX_ARRAY_SIZE) { + break; + } + } + + /* store the info for this URL into memory-resident data structure */ + if (!URLName || XP_STRLEN(URLName) == 0) { + badInput = TRUE; + } + if (!badInput) { + si_PutData(URLName, &submit, FALSE); + } + + /* free up all the allocations done for processing this URL */ + XP_FREE(URLName); + for (i=0; iURLName, nil, + reject->userName, + kAnyPort, + kNetscapeProtocolType, + kAnyAuthType, + 0, + nil, + &itemRef); + if (status != noErr && status != errKCDuplicateItem) { + return(status); + } + if (status == noErr) { + /* + * make the item invisible so the user doesn't see it and + * negative so we know that it is a reject entry + */ + attr.tag = kFlagsKCItemAttr; + attr.data = &flags; + attr.length = sizeof( flags ); + + status = KCSetAttribute( itemRef, &attr ); + if (status != noErr) { + return(status); + } + status = KCUpdateItem(itemRef); + if (status != noErr) { + return(status); + } + KCReleaseItemRef(&itemRef); + } + } + } + + /* save off the passwords */ + if((si_signon_list)) { + list_ptr = si_signon_list; + while((URL = (si_SignonURLStruct *) XP_ListNextObject(list_ptr)) != NULL) { + + user_ptr = URL->signonUser_list; + + /* add each user node of the URL node */ + while((user = (si_SignonUserStruct *) XP_ListNextObject(user_ptr)) != NULL) { + + data_ptr = user->signonData_list; + + /* write out each data node of the user node */ + while((data=(si_SignonDataStruct *) XP_ListNextObject(data_ptr)) != NULL) { + char* attribute = nil; + if (data->isPassword) { + password = XP_ALLOC(XP_STRLEN(data->value) + + XP_STRLEN(data->name) + 2); + if (!password) { + return (-1); + } + attribute = password; + } else { + account = XP_ALLOC( XP_STRLEN(data->value) + + XP_STRLEN(data->name) + 2); + if (!account) { + XP_FREE(password); + return (-1); + } + attribute = account; + } + + XP_STRCPY(attribute, data->name); + XP_STRCAT(attribute, "="); + XP_STRCAT(attribute, data->value); + + } + /* if it's already there, we just want to change the password */ + status = kcfindinternetpassword + (URL->URLName, + nil, + account, + kAnyPort, + kNetscapeProtocolType, + kAnyAuthType, + 0, + nil, + &actualLength, + &itemRef); + if (status == noErr) { + status = KCSetData(itemRef, XP_STRLEN(password), password); + if (status != noErr) { + return(status); + } + status = KCUpdateItem(itemRef); + KCReleaseItemRef(&itemRef); + } else { + /* wasn't there, let's add it */ + status = kcaddinternetpassword + (URL->URLName, + nil, + account, + kAnyPort, + kNetscapeProtocolType, + kAnyAuthType, + XP_STRLEN(password), + password, + nil); + } + if (account) { + XP_FREE(account); + } + if (password) { + XP_FREE(password); + } + account = password = nil; + if (status != noErr) { + return(status); + } + } + } + } + + si_signon_list_changed = FALSE; + return (0); +} +#endif + +/* + * Save signon data to disk file + * The parameter passed in on entry is ignored + * + * This routine is called only when holding the signon lock!!! + * + * This routine is called only if signon pref is enabled!!! + */ + +PRIVATE int +si_SaveSignonDataLocked(char * filename) { + XP_List * list_ptr; + XP_List * user_ptr; + XP_List * data_ptr; + si_SignonURLStruct * url; + si_SignonUserStruct * user; + si_SignonDataStruct * data; + si_Reject * reject; + XP_File fp; + + /* do nothing if signon list has not changed */ + if(!si_signon_list_changed) { + return(-1); + } + + /* do not save signons if in anonymous mode */ + if(si_anonymous) { + return(-1); + } + +#ifdef APPLE_KEYCHAIN + if (KeychainManagerAvailable()) { + return si_SaveSignonDataInKeychain(); + } +#endif + + /* do nothing if we are unable to open file that contains signon list */ + if(!(fp = XP_FileOpen(filename, xpHTTPSingleSignon, XP_FILE_WRITE))) { + return(-1); + } + + /* format for head of file shall be: + * # comment + * # comment + * # comment + * TRUE -- indicates if notification has already been given to user + * URLName -- first url/username on reject list + * userName + * URLName -- second url/username on reject list + * userName + * ... -- etc. + * . -- end of list + */ + + /* write out leading comments */ + XP_FileWrite("# Netscape HTTP Signons File" LINEBREAK + "# This is a generated file! Do not edit." + LINEBREAK "#" LINEBREAK, -1, fp); + + /* write out si_NoticeGiven */ + if (si_NoticeGiven) { + XP_FileWrite("TRUE" LINEBREAK, -1, fp); + } else { + XP_FileWrite("FALSE" LINEBREAK, -1, fp); + } + + /* write out reject list */ + if (si_reject_list) { + list_ptr = si_reject_list; + while((reject = (si_Reject *) XP_ListNextObject(list_ptr))!=0) { + XP_FileWrite(reject->URLName, -1, fp); + XP_FileWrite(LINEBREAK, -1, fp); + XP_FileWrite(reject->userName, -1, fp); + XP_FileWrite(LINEBREAK, -1, fp); + } + } + XP_FileWrite("." LINEBREAK, -1, fp); + + /* format for cached logins shall be: + * url LINEBREAK {name LINEBREAK value LINEBREAK}* . LINEBREAK + * if type is password, name is preceded by an asterisk (*) + */ + + /* write out each URL node */ + if((si_signon_list)) { + list_ptr = si_signon_list; + while((url = (si_SignonURLStruct *) + XP_ListNextObject(list_ptr)) != NULL) { + + user_ptr = url->signonUser_list; + + /* write out each user node of the URL node */ + while((user = (si_SignonUserStruct *) + XP_ListNextObject(user_ptr)) != NULL) { + XP_FileWrite(url->URLName, -1, fp); + XP_FileWrite(LINEBREAK, -1, fp); + + data_ptr = user->signonData_list; + + /* write out each data node of the user node */ + while((data = (si_SignonDataStruct *) + XP_ListNextObject(data_ptr)) != NULL) { + char* mungedValue; + if (data->isPassword) { + XP_FileWrite("*", -1, fp); + } + XP_FileWrite(data->name, -1, fp); + XP_FileWrite(LINEBREAK, -1, fp); + XP_FileWrite("=", -1, fp); /* precede values with '=' */ + if (data->isPassword) { + if ((mungedValue = SECNAV_MungeString(data->value))) { + XP_FileWrite(mungedValue, -1, fp); + XP_FREE(mungedValue); + } else { + /* in free source, passwords are not obscured */ + XP_FileWrite(data->value, -1, fp); + } + } else { + XP_FileWrite(data->value, -1, fp); + } + XP_FileWrite(LINEBREAK, -1, fp); + } + XP_FileWrite(".", -1, fp); + XP_FileWrite(LINEBREAK, -1, fp); + } + } + } + + si_signon_list_changed = FALSE; + XP_FileClose(fp); + return(0); +} + + +/* + * Save signon data to disk file + * The parameter passed in on entry is ignored + */ + +PUBLIC int +SI_SaveSignonData(char * filename) { + int retval; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()) { + return FALSE; + } + + /* lock and call common save routine */ + si_lock_signon_list(); + retval = si_SaveSignonDataLocked(filename); + si_unlock_signon_list(); + return retval; +} + +/* + * Remove all the signons and free everything + */ + +PUBLIC void +SI_RemoveAllSignonData() { + + /* repeatedly remove first user node of first URL node */ + while (SI_RemoveUser(NULL, NULL, FALSE)) { + } +} + +/* + * Check for a signon submission and remember the data if so + */ +PUBLIC void +SI_RememberSignonData(char* URLName, LO_FormSubmitData * submit) +{ + int i, j; + int passwordCount = 0; + int pswd[3]; + MWContext *context; /* not used -- just a hold-over from the old world order */ + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + return; + } + + /* determine how many passwords are in the form and where they are */ + for (i=0; ivalue_cnt; i++) { + if (((uint8 *)submit->type_array)[i] == FORM_TYPE_PASSWORD) { + if (passwordCount < 3 ) { + pswd[passwordCount] = i; + } + passwordCount++; + } + } + + /* process the form according to how many passwords it has */ + if (passwordCount == 1) { + /* one-password form is a log-in so remember it */ + + /* obtain the index of the first input field (that is the username) */ + for (j=0; jvalue_cnt; j++) { + if (((uint8 *)submit->type_array)[j] == FORM_TYPE_TEXT) { + break; + } + } + + if (si_OkToSave(context, + URLName, /* urlname */ + ((char **)submit->value_array)[j] /* username */)) { + si_PutData(URLName, submit, TRUE); + } + } else if (passwordCount == 2) { + /* two-password form is a registration */ + + } else if (passwordCount == 3) { + /* three-password form is a change-of-password request */ + + XP_List * data_ptr; + si_SignonDataStruct* data; + si_SignonUserStruct* user; + + /* make sure all passwords are non-null and 2nd and 3rd are identical */ + if (!submit->value_array[pswd[0]] || ! submit->value_array[pswd[1]] || + !submit->value_array[pswd[2]] || + XP_STRCMP(((char **)submit->value_array)[pswd[1]], + ((char **)submit->value_array)[pswd[2]])) { + return; + } + + /* ask user if this is a password change */ + si_lock_signon_list(); + user = si_GetURLAndUserForChangeForm + (context, ((char **)submit->value_array)[pswd[0]]); + + /* return if user said no */ + if (!user) { + si_unlock_signon_list(); + return; + } + + /* get to password being saved */ + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if (data->isPassword) { + break; + } + } + + /* + * if second password is "generate" then generate a random + * password for it and use same random value for third password + * as well (Note: this all works because we already know that + * second and third passwords are identical so third password + * must also be "generate". Furthermore si_Randomize() will + * create a random password of exactly eight characters -- the + * same length as "generate".) + */ + si_Randomize(((char **)submit->value_array)[pswd[1]]); + XP_STRCPY(((char **)submit->value_array)[pswd[2]], + ((char **)submit->value_array)[pswd[1]]); + StrAllocCopy(data->value, ((char **)submit->value_array)[pswd[1]]); + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + si_unlock_signon_list(); + } +} + +PUBLIC void +SI_RestoreSignonData + (char* URLName, char* name, char** value) +{ + MWContext *context; /* not used -- just a hold-over from the old world order */ + si_SignonUserStruct* user; + si_SignonDataStruct* data; + XP_List * data_ptr=0; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + return; + } + + si_lock_signon_list(); + +#ifdef xxx + /* + * determine if it is a change-of-password field + * the heuristic that we will use is that if this is the first + * item on the form and it is a password, this is probably a + * change-of-password form + */ + /* see if this is first item in form and is a password */ + /* get first saved user just so we can see the name of the first item on the form */ + user = si_GetUser(context, URLName, TRUE, NULL); /* this is the first saved user */ + if (user) { + data_ptr = user->signonData_list; /* this is first item on form */ + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + if(data->isPassword && name && XP_STRCMP(data->name, name)==0) { + /* current item is first item on form and is a password */ + user = si_GetUserForChangeForm(context, URLName, MK_SIGNON_PASSWORDS_FETCH); + if (user) { + /* user has confirmed it's a change-of-password form */ + data_ptr = user->signonData_list; + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if (data->isPassword) { + *value = data->value; + si_unlock_signon_list(); + return; + } + } + } + } + } +#endif + + /* restore the data from previous time this URL was visited */ + user = si_GetUser(context, URLName, FALSE, name); + if (user) { + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if(name && XP_STRCMP(data->name, name)==0) { + *value = data->value; + si_unlock_signon_list(); + return; + } + } + } + si_unlock_signon_list(); +} + +/* + * Check for remembered data from a previous signon submission and + * restore it if so + */ +PUBLIC void +SI_RestoreOldSignonData + (MWContext *context, LO_FormElementStruct *form_element, char* URLName) +{ + si_SignonURLStruct* url; + si_SignonUserStruct* user; + si_SignonDataStruct* data; + XP_List * data_ptr=0; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + return; + } + + /* get URL */ + si_lock_signon_list(); + url = si_GetURL(URLName); + + /* see if this is first item in form and is a password */ + si_TagCount++; + if ((si_TagCount == 1) && + (form_element->element_data->type == FORM_TYPE_PASSWORD)) { + /* + * it is so there's a good change its a password change form, + * let's ask user to confirm this + */ + user = si_GetUserForChangeForm(context, URLName, MK_SIGNON_PASSWORDS_FETCH); + if (user) { + /* user has confirmed it's a change-of-password form */ + data_ptr = user->signonData_list; + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if (data->isPassword) { +#ifdef XP_MAC + StrAllocCopy( + (char *)form_element->element_data->ele_text.default_text, + data->value); +#else + char* default_text = + (char*)(form_element->element_data->ele_text.default_text); + StrAllocCopy(default_text, data->value); + form_element->element_data->ele_text.default_text = + (unsigned long *)default_text; +#endif + si_unlock_signon_list(); + return; + } + } + } + } + + /* get the data from previous time this URL was visited */ + + if (si_TagCount == 1) { + user = si_GetUser( + context, URLName, FALSE, + (char*)(form_element->element_data->ele_text.name)); + } else { + if (url) { + user = url->chosen_user; + } else { + user = NULL; + } + } + if (user) { + + /* restore the data from previous time this URL was visited */ + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + char * fieldName = + (char *)form_element->element_data->ele_text.name; + if(fieldName && XP_STRCMP(data->name, fieldName)==0) { +#ifdef XP_MAC + StrAllocCopy( + (char *)form_element->element_data->ele_text.default_text, + data->value); +#else + char* default_text = + (char*)(form_element->element_data->ele_text.default_text); + StrAllocCopy(default_text, data->value); + form_element->element_data->ele_text.default_text = + (unsigned long *)default_text; +#endif + si_unlock_signon_list(); + return; + } + } + } + si_unlock_signon_list(); +} + +/* + * Remember signon data from a browser-generated password dialog + */ +PRIVATE void +si_RememberSignonDataFromBrowser(char* URLName, char* username, char* password) +{ + LO_FormSubmitData submit; + char* USERNAME = "username"; + char* PASSWORD = "password"; + char* name_array[2]; + char* value_array[2]; + uint8 type_array[2]; + + /* do nothing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + return; + } + + /* initialize a temporary submit structure */ + submit.name_array = (PA_Block)name_array; + submit.value_array = (PA_Block)value_array; + submit.type_array = (PA_Block)type_array; + submit.value_cnt = 2; + + name_array[0] = USERNAME; + value_array[0] = NULL; + StrAllocCopy(value_array[0], username); + type_array[0] = FORM_TYPE_TEXT; + + name_array[1] = PASSWORD; + value_array[1] = NULL; + StrAllocCopy(value_array[1], password); + type_array[1] = FORM_TYPE_PASSWORD; + + /* Save the signon data */ + si_PutData(URLName, &submit, TRUE); + + /* Free up the data memory just allocated */ + XP_FREE(value_array[0]); + XP_FREE(value_array[1]); +} + +PUBLIC void +SI_RememberSignonDataFromBrowser + (MWContext *context, char* URLName, char* username, char* password) +{ + if (si_OkToSave(context, URLName, username)) { + si_RememberSignonDataFromBrowser (URLName, username, password); + } +} + +/* + * Check for remembered data from a previous browser-generated password dialog + * restore it if so + */ +PRIVATE void +si_RestoreOldSignonDataFromBrowser + (MWContext *context, char* URLName, Bool pickFirstUser, + char** username, char** password) +{ + si_SignonUserStruct* user; + si_SignonDataStruct* data; + XP_List * data_ptr=0; + + /* get the data from previous time this URL was visited */ + si_lock_signon_list(); + user = si_GetUser(context, URLName, pickFirstUser, "username"); + if (!user) { + /* leave original username and password from caller unchanged */ + /* username = 0; */ + /* *password = 0; */ + si_unlock_signon_list(); + return; + } + + /* restore the data from previous time this URL was visited */ + data_ptr = user->signonData_list; + while((data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr))!=0) { + if(XP_STRCMP(data->name, "username")==0) { + StrAllocCopy(*username, data->value); + } else if(XP_STRCMP(data->name, "password")==0) { + StrAllocCopy(*password, data->value); + } + } + si_unlock_signon_list(); +} + +PUBLIC void +SI_RestoreOldSignonDataFromBrowser + (MWContext *context, char* URLName, Bool pickFirstUser, + char** username, char** password) +{ + if (si_GetSignonRememberingPref()){ + si_RestoreOldSignonDataFromBrowser + (context, URLName, pickFirstUser, username, password); + } +} + +/* Browser-generated prompt for user-name and password */ +PUBLIC int +SI_PromptUsernameAndPassword + (MWContext *context, char *prompt, + char **username, char **password, char *URLName) +{ + int status; + char *copyOfPrompt=0; + + /* just for safety -- really is a problem in SI_Prompt */ + StrAllocCopy(copyOfPrompt, prompt); + + /* do the FE thing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + status = FE_PromptUsernameAndPassword + (context, copyOfPrompt, username, password); + XP_FREEIF(copyOfPrompt); + return status; + } + + /* prefill with previous username/password if any */ + si_RestoreOldSignonDataFromBrowser + (context, URLName, FALSE, username, password); + + /* get new username/password from user */ + status = FE_PromptUsernameAndPassword + (context, copyOfPrompt, username, password); + + /* remember these values for next time */ + if (status && si_OkToSave(context, URLName, *username)) { + si_RememberSignonDataFromBrowser (URLName, *username, *password); + } + + /* cleanup and return */ + XP_FREEIF(copyOfPrompt); + return status; +} + +/* Browser-generated prompt for password */ +PUBLIC char * +SI_PromptPassword + (MWContext *context, char *prompt, char *URLName, Bool pickFirstUser) +{ + char *password=0, *username=0, *copyOfPrompt=0, *result; + char *urlname = URLName; + char *s; + + /* just for safety -- really is a problem in SI_Prompt */ + StrAllocCopy(copyOfPrompt, prompt); + + /* do the FE thing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + result = FE_PromptPassword(context, copyOfPrompt); + XP_FREEIF(copyOfPrompt); + return result; + } + + /* get host part of URL which is of form user@host */ + s = URLName; + while (*s && (*s != '@')) { + s++; + } + if (*s) { + /* @ found, host is URL part following the @ */ + urlname = s+1; /* urlname is part of URL after the @ */ + } + + /* get previous password used with this username */ + si_RestoreOldSignonDataFromBrowser + (context, urlname, pickFirstUser, &username, &password); + + /* return if a password was found */ + /* + * Note that we reject a password of " ". It is a dummy password + * that was put in by a preceding call to SI_Prompt. This occurs + * in mknews which calls on SI_Prompt to get the username and then + * SI_PromptPassword to get the password (why they didn't simply + * call on SI_PromptUsernameAndPassword is beyond me). So the call + * to SI_Prompt will save the username along with the dummy password. + * In this call to SI_Password, the real password gets saved in place + * of the dummy one. + */ + if (password && XP_STRLEN(password) && XP_STRCMP(password, " ")) { + XP_FREEIF(copyOfPrompt); + return password; + } + + /* if no password found, get new password from user */ + password = FE_PromptPassword(context, copyOfPrompt); + + /* if username wasn't even found, extract it from URLName */ + if (!username) { + s = URLName; + + /* get to @ in URL if any */ + while (*s && (*s != '@')) { + s++; + } + if (*s) { + /* @ found, username is URL part preceding the @ */ + *s = '\0'; + StrAllocCopy(username, URLName); + *s = '@'; + } else { + /* no @ found, use entire URL as uername */ + StrAllocCopy(username, URLName); + } + } + + /* remember these values for next time */ + if (password && XP_STRLEN(password) && + si_OkToSave(context, urlname, username)) { + si_RememberSignonDataFromBrowser (urlname, username, password); + } + + /* cleanup and return */ + XP_FREEIF(username); + XP_FREEIF(copyOfPrompt); + return password; +} + +/* Browser-generated prompt for username */ +PUBLIC char * +SI_Prompt (MWContext *context, char *prompt, + char* defaultUsername, char *URLName) +{ + char *password=0, *username=0, *copyOfPrompt=0, *result; + + /* + * make copy of prompt because it is currently in a temporary buffer in + * the caller (from GetString) which will be destroyed if GetString() is + * called again before prompt is used + */ + StrAllocCopy(copyOfPrompt, prompt); + + /* do the FE thing if signon preference is not enabled */ + if (!si_GetSignonRememberingPref()){ + result = FE_Prompt(context, copyOfPrompt, defaultUsername); + XP_FREEIF(copyOfPrompt); + return result; + } + + /* get previous username used */ + if (!defaultUsername || !XP_STRLEN(defaultUsername)) { + si_RestoreOldSignonDataFromBrowser + (context, URLName, FALSE, &username, &password); + } else { + StrAllocCopy(username, defaultUsername); + } + + /* prompt for new username */ + result = FE_Prompt(context, copyOfPrompt, username); + + /* remember this username for next time */ + if (result && XP_STRLEN(result)) { + if (username && (XP_STRCMP(username, result) == 0)) { + /* + * User is re-using the same user name as from previous time + * so keep the previous password as well + */ + si_RememberSignonDataFromBrowser (URLName, result, password); + } else { + /* + * We put in a dummy password of " " which we will test + * for in a following call to SI_PromptPassword. See comments + * in that routine. + */ + si_RememberSignonDataFromBrowser (URLName, result, " "); + } + } + + /* cleanup and return */ + XP_FREEIF(username); + XP_FREEIF(password); + XP_FREEIF(copyOfPrompt); + return result; +} + +PRIVATE XP_List * si_dormant_signon_list=0; + +PUBLIC void +SI_AnonymizeSignons() +{ + if (!si_anonymous) { + si_lock_signon_list(); + si_dormant_signon_list = si_signon_list; + si_signon_list = XP_ListNew(); + si_unlock_signon_list(); + si_anonymous = TRUE; + } +} + +PUBLIC void +SI_UnanonymizeSignons() +{ + if (si_anonymous) { + SI_RemoveAllSignonData(); + si_lock_signon_list(); + si_signon_list = si_dormant_signon_list; + si_unlock_signon_list(); + si_dormant_signon_list = 0; + si_anonymous = FALSE; + } +} + +#ifdef HTMLDialogs +#include "htmldlgs.h" +#else +#define XP_DIALOG_CANCEL_BUTTON (1<<0) +#define XP_DIALOG_OK_BUTTON (1<<2) +#define XP_STRINGS_CHUNKSIZE 512 +typedef struct _XPDialogState XPDialogState; +typedef struct _XPDialogInfo XPDialogInfo; +typedef struct _XPDialogStrings XPDialogStrings; +typedef PRBool (* XP_HTMLDialogHandler)(XPDialogState *state, char **argv, + int argc, unsigned int button); +struct _XPDialogState { + PRArenaPool *arena; + void *window; + void *proto_win; + XPDialogInfo *dialogInfo; + void *arg; + void (* deleteCallback)(void *arg); + void *cbarg; + PRBool deleted; +}; +struct _XPDialogInfo { + unsigned int buttonFlags; + XP_HTMLDialogHandler handler; + int width; + int height; +}; +struct _XPDialogStrings +{ + PRArenaPool *arena; + int basestringnum; + int nargs; + char **args; + char *contents; +}; + +extern time_t CookieTime(); +extern XPDialogState * + XP_MakeRawHTMLDialog(void *proto_win, XPDialogInfo *dialogInfo, + int titlenum, XPDialogStrings *strings, + int handlestring, void *arg); +extern XPDialogStrings *XP_GetDialogStrings(int stringnum); +extern void + XP_SetDialogString(XPDialogStrings *strings, int argNum, char *string); +extern char * + XP_FindValueInArgs(const char *name, char **av, int ac); + +#endif + +extern int XP_CERT_PAGE_STRINGS; +extern int SA_REMOVE_BUTTON_LABEL; +extern int MK_SIGNON_VIEW_SIGNONS; +extern int MK_SIGNON_VIEW_REJECTS; + +#define BUFLEN 5000 + +#define FLUSH_BUFFER \ + if (buffer) { \ + StrAllocCat(buffer2, buffer); \ + buffer[0] = '\0'; \ + g = 0; \ + } + +/* return TRUE if "number" is in sequence of comma-separated numbers */ +Bool si_InSequence(char* sequence, int number) { + char* ptr; + char* endptr; + char* undo = NULL; + Bool retval = FALSE; + int i; + + /* not necessary -- routine will work even with null sequence */ + if (!*sequence) { + return FALSE; + } + + for (ptr = sequence ; ptr ; ptr = endptr) { + + /* get to next comma */ + endptr = PL_strchr(ptr, ','); + + /* if comma found, process it */ + if (endptr) { + + /* restore last comma-to-null back to comma */ + if (undo) { + *undo = ','; + } + + /* set the comma to a null */ + undo = endptr; + *endptr++ = '\0'; + + /* compare the number before the comma with "number" */ + if (*ptr) { + i = atoi(ptr); + if (i == number) { + + /* "number" was in the sequence so return TRUE */ + retval = TRUE; + break; + } + } + } + } + + /* restore last comma-to-null back to comma */ + if (undo) { + *undo = ','; + } + return retval; +} + +PR_STATIC_CALLBACK(PRBool) +si_SignonInfoDialogDone(XPDialogState* state, char** argv, int argc, + unsigned int button) +{ + XP_List *url_ptr; + XP_List *user_ptr; + XP_List *data_ptr; + XP_List *reject_ptr; + si_SignonURLStruct *url; + si_SignonURLStruct *URLToDelete = 0; + si_SignonUserStruct* user; + si_SignonUserStruct* userToDelete = 0; + si_SignonDataStruct* data; + si_Reject* reject; + si_Reject* rejectToDelete = 0; + + char *buttonName; + int userNumber; + int rejectNumber; + char* gone; + + buttonName = XP_FindValueInArgs("button", argv, argc); + if (button != XP_DIALOG_OK_BUTTON) { + /* OK button not pressed (must be cancel button that was pressed) */ + return PR_FALSE; + } + + /* OK was pressed, do the deletions */ + + /* get the comma-separated sequence of signons to be deleted */ + gone = XP_FindValueInArgs("goneS", argv, argc); + XP_ASSERT(gone); + if (!gone) { + return PR_FALSE; + } + + /* + * step through all users and delete those that are in the sequence + * Note: we can't delete user while "user_ptr" is pointing to it because + * that would destroy "user_ptr". So we do a lazy deletion + */ + userNumber = 0; + url_ptr = si_signon_list; + while ((url = (si_SignonURLStruct *) XP_ListNextObject(url_ptr))) { + user_ptr = url->signonUser_list; + while ((user = (si_SignonUserStruct *) + XP_ListNextObject(user_ptr))) { + if (si_InSequence(gone, userNumber)) { + if (userToDelete) { + + /* get to first data item -- that's the user name */ + data_ptr = userToDelete->signonData_list; + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + /* do the deletion */ + SI_RemoveUser(URLToDelete->URLName, data->value, TRUE); + } + userToDelete = user; + URLToDelete = url; + } + userNumber++; + } + } + if (userToDelete) { + /* get to first data item -- that's the user name */ + data_ptr = userToDelete->signonData_list; + data = (si_SignonDataStruct *) XP_ListNextObject(data_ptr); + + /* do the deletion */ + SI_RemoveUser(URLToDelete->URLName, data->value, TRUE); + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + } + + /* get the comma-separated sequence of rejections to be deleted */ + gone = XP_FindValueInArgs("goneR", argv, argc); + XP_ASSERT(gone); + if (!gone) { + return PR_FALSE; + } + + /* step through all rejects and delete those that are in the sequence + * Note: we can't delete reject while "reject_ptr" is pointing to it because + * that would destroy "reject_ptr". So we do a lazy deletion + */ + rejectNumber = 0; + si_lock_signon_list(); + reject_ptr = si_reject_list; + while ((reject = (si_Reject *) XP_ListNextObject(reject_ptr))) { + if (si_InSequence(gone, rejectNumber)) { + if (rejectToDelete) { + si_FreeReject(rejectToDelete); + } + rejectToDelete = reject; + } + rejectNumber++; + } + if (rejectToDelete) { + si_FreeReject(rejectToDelete); + si_signon_list_changed = TRUE; + si_SaveSignonDataLocked(NULL); + } + si_unlock_signon_list(); + return PR_FALSE; +} + +typedef struct _SignonViewerDialog SignonViewerDialog; + +struct _SignonViewerDialog { + void *window; + void *parent_window; + PRBool dialogUp; + XPDialogState *state; +}; + +PUBLIC void +SI_DisplaySignonInfoAsHTML() +{ + MWContext * context = NULL; + char *buffer = (char*)XP_ALLOC(BUFLEN); + char *buffer2 = 0; + int g = 0, signonNum, count; + XP_List *url_ptr; + XP_List *user_ptr; + XP_List *data_ptr; + XP_List *reject_ptr; + si_SignonURLStruct *url; + si_SignonUserStruct * user; + si_SignonDataStruct* data; + si_Reject *reject; + SignonViewerDialog *dlg; + int i; + char * view_signons = NULL; + char * view_rejects = NULL; + char * heading = NULL; + + static XPDialogInfo dialogInfo = { + 0, + si_SignonInfoDialogDone, + 350, + 400 + }; + + XPDialogStrings* strings; + strings = XP_GetDialogStrings(XP_CERT_PAGE_STRINGS); + if (!strings) { + return; + } + +#ifdef APPLE_KEYCHAIN + /* If the Keychain has been locked or an item deleted or updated, + we need to reload the signon data */ + if (si_list_invalid) + { + /* set si_list_invalid to FALSE first because SI_RemoveAllSignonData + calls si_GetSignonRememberingPref */ + si_list_invalid = FALSE; + SI_RemoveAllSignonData(); + SI_LoadSignonData(NULL); + } +#endif + + StrAllocCopy(buffer2, ""); + StrAllocCopy (view_signons, XP_GetString(MK_SIGNON_VIEW_SIGNONS)); + StrAllocCopy (view_rejects, XP_GetString(MK_SIGNON_VIEW_REJECTS)); + + /* generate initial section of html file */ + g += PR_snprintf(buffer+g, BUFLEN-g, +"\n" +"\n" +" Signons\n" +" \n" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +"\n" +"\n" +" <BODY> <P> </BODY>\n" +"\n" +"\n" + ); + FLUSH_BUFFER + + si_unlock_signon_list(); + + /* free some strings that are no longer needed */ + PR_FREEIF(view_signons); + PR_FREEIF(view_rejects); + PR_FREEIF(buffer); + + /* put html just generated into strings->arg[2] and invoke HTML dialog */ + if (buffer2) { + XP_SetDialogString(strings, 2, buffer2); + buffer2 = NULL; + } + dlg = (SignonViewerDialog *)PORT_ZAlloc(sizeof(SignonViewerDialog)); + if ( dlg == NULL ) { + return; + } + dlg->parent_window = (void *)context; + dlg->dialogUp = PR_TRUE; + dlg->state =XP_MakeRawHTMLDialog(context, &dialogInfo, MK_SIGNON_YOUR_SIGNONS, + strings, 1, (void *)dlg); + + return; +} +#endif diff --git a/mozilla/extensions/wallet/src/wallet.cpp b/mozilla/extensions/wallet/src/wallet.cpp new file mode 100644 index 00000000000..81ee8778207 --- /dev/null +++ b/mozilla/extensions/wallet/src/wallet.cpp @@ -0,0 +1,1632 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (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. + */ + + +/* + wallet.cpp +*/ + +#include "wallet.h" +#include "nsINetService.h" +#include "nsIServiceManager.h" + +#include "nsIDocument.h" +#include "nsIDOMHTMLDocument.h" +#include "nsIDOMHTMLCollection.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIDOMHTMLInputElement.h" +#include "nsIDOMHTMLSelectElement.h" +#include "nsIDOMHTMLOptionElement.h" +#include "nsIURL.h" + +#include "prthread.h" +#include "xp_list.h" +#include "xp_mem.h" + +static NS_DEFINE_IID(kIDOMHTMLDocumentIID, NS_IDOMHTMLDOCUMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_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_IID(kINetServiceIID, NS_INETSERVICE_IID); +static NS_DEFINE_IID(kNetServiceCID, NS_NETSERVICE_CID); + +#include "htmldlgs.h" + +/***************************************************/ +/* The following declarations define the data base */ +/***************************************************/ + +enum PlacementType {DUP_IGNORE, DUP_OVERWRITE, DUP_BEFORE, DUP_AFTER, AT_END}; + +typedef struct _wallet_MapElement { + nsAutoString * item1; + nsAutoString * item2; + XP_List * itemList; +} wallet_MapElement; + +typedef struct _wallet_Sublist { + nsAutoString * item; +} wallet_Sublist; + +PRIVATE XP_List * wallet_URLFieldToSchema_list=0; +PRIVATE XP_List * wallet_FieldToSchema_list=0; +PRIVATE XP_List * wallet_SchemaToValue_list=0; +PRIVATE XP_List * wallet_SchemaConcat_list=0; + +typedef struct _wallet_PrefillElement { + nsIDOMHTMLInputElement* inputElement; + nsIDOMHTMLSelectElement* selectElement; + nsAutoString * schema; + nsAutoString * value; + PRInt32 selectIndex; + PRUint32 count; + XP_List * resume; +} wallet_PrefillElement; + +/***********************************************************/ +/* The following routines are for diagnostic purposes only */ +/***********************************************************/ + +#ifdef DEBUG + +void +wallet_Pause(){ + fprintf(stdout,"%cpress y to continue\n", '\007'); + for (;;) { + char c; + c = getchar(); + if (tolower(c) == 'y') { + fprintf(stdout,"OK\n"); + break; + } + } +} + +void +wallet_DumpAutoString(nsAutoString as){ + char s[100]; + as.ToCString(s, 100); + fprintf(stdout, "%s\n", s); +} + +void +wallet_Dump(XP_List * list) { + XP_List * list_ptr; + wallet_MapElement * ptr; + + char item1[100]; + char item2[100]; + char item[100]; + list_ptr = list; + while((ptr = (wallet_MapElement *) XP_ListNextObject(list_ptr))!=0) { + ptr->item1->ToCString(item1, 100); + ptr->item2->ToCString(item2, 100); + fprintf(stdout, "%s %s \n", item1, item2); + XP_List * list_ptr1; + wallet_Sublist * ptr1; + list_ptr1 = ptr->itemList; + while((ptr1=(wallet_Sublist *) XP_ListNextObject(list_ptr1))!=0) { + ptr1->item->ToCString(item, 100); + 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 = 0; +PRInt64 stopwatchBase; +PRBool stopwatchRunning = FALSE; + +void +wallet_ClearTiming() { + timing_index = 0; +} + +void +wallet_DumpTiming() { + PRInt32 i; + for (i=1; iitem1; + delete ptr->item2; + + XP_List * list_ptr1; + wallet_Sublist * ptr1; + list_ptr1 = ptr->itemList; + while((ptr1=(wallet_Sublist *) XP_ListNextObject(list_ptr1))!=0) { + delete ptr1->item; + } + delete ptr->itemList; + XP_ListRemoveObject(*list, ptr); + list_ptr = *list; + delete ptr; + } + *list = 0; +} + +/* + * add an entry to the designated list + */ +void +wallet_WriteToList( + nsAutoString& item1, + nsAutoString& item2, + XP_List* itemList, + XP_List*& list, + PlacementType placement = DUP_BEFORE) { + + XP_List * list_ptr; + wallet_MapElement * ptr; + PRBool added_to_list = FALSE; + + wallet_MapElement * mapElement; + mapElement = XP_NEW(wallet_MapElement); + + mapElement->item1 = &item1; + mapElement->item2 = &item2; + mapElement->itemList = itemList; + + /* make sure the list exists */ + if(!list) { + list = XP_ListNew(); + if(!list) { + return; + } + } + + /* + * 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 + */ + list_ptr = list; + item1.ToLowerCase(); + if (AT_END==placement) { + XP_ListAddObjectToEnd (list, mapElement); + return; + } + while((ptr = (wallet_MapElement *) XP_ListNextObject(list_ptr))!=0) { + if((ptr->item1->Compare(item1))==0) { + if (DUP_OVERWRITE==placement) { + delete ptr->item1; + delete ptr->item2; + delete mapElement; + ptr->item1 = &item1; + ptr->item2 = &item2; + } else if (DUP_BEFORE==placement) { + XP_ListInsertObject(list, ptr, mapElement); + } + if (DUP_AFTER!=placement) { + added_to_list = TRUE; + break; + } + } else if((ptr->item1->Compare(item1))>=0) { + XP_ListInsertObject(list, ptr, mapElement); + added_to_list = TRUE; + break; + } + } + if (!added_to_list) { + XP_ListAddObjectToEnd (list, mapElement); + } +} + +/* + * fetch an entry from the designated list + */ +PRInt32 +wallet_ReadFromList( + nsAutoString item1, + nsAutoString& item2, + XP_List*& itemList, + XP_List*& list_ptr) +{ + wallet_MapElement * ptr; + + wallet_MapElement * mapElement; + mapElement = XP_NEW(wallet_MapElement); + + /* make sure the list exists */ + if(!list_ptr) { + return -1; + } + + /* find item1 in the list */ + item1.ToLowerCase(); + while((ptr = (wallet_MapElement *) XP_ListNextObject(list_ptr))!=0) { + if((ptr->item1->Compare(item1))==0) { + item2 = nsAutoString(*ptr->item2); + itemList = ptr->itemList; + return 0; + } + } + return -1; +} + +/* + * given a sublist element, advance to the next sublist element and get its value + */ +PRInt32 +wallet_ReadFromSublist(nsAutoString& value, XP_List*& resume) +{ + wallet_Sublist * ptr; + if((ptr=(wallet_Sublist *) XP_ListNextObject(resume))!=0) { + value = *ptr->item; + return 0; + } + return -1; +} + +/******************************************************/ +/* The following routines are for accessing the files */ +/******************************************************/ + +/* + * get a line from a file + * return -1 if end of file reached + * skip lines starting with # + * strip carriage returns and line feeds from end of line + */ +PRInt32 +wallet_GetLine(FILE * fp, nsAutoString*& line) { + char linebuf[2000]; + char* cp = fgets(linebuf, sizeof(linebuf), fp); + if (nsnull == cp) { + return -1; + } + if (linebuf[0] == '#') { + return wallet_GetLine(fp, line); + } + + // strip crlf's from the line + int len = strlen(linebuf); + if (0 != len) { + if (('\n' == linebuf[len-1]) || ('\r' == linebuf[len-1])) { + linebuf[--len] = 0; + } + } + if (0 != len) { + if (('\n' == linebuf[len-1]) || ('\r' == linebuf[len-1])) { + linebuf[--len] = 0; + } + } + + line = new nsAutoString(linebuf); + return 0; +} + +/* + * write contents of designated list into designated file + */ +void +wallet_WriteToFile(char* filename, XP_List* list) { + XP_List * list_ptr; + wallet_MapElement * ptr; + + /* open the file for writing */ + FILE* fp = fopen(filename, "w"); + if (nsnull==fp) { + return; + } + + /* make sure the list exists */ + if(!list) { + return; + } + + /* traverse the list */ + list_ptr = list; + while((ptr = (wallet_MapElement *) XP_ListNextObject(list_ptr))!=0) { + char * temp; + temp = ptr->item1->ToNewCString(); + fprintf(fp, "%s\n", temp); + delete temp; + if (*ptr->item2 != "") { + temp = ptr->item2->ToNewCString(); + fprintf(fp, "%s\n", temp); + } else { + XP_List * list_ptr1; + wallet_Sublist * ptr1; + list_ptr1 = ptr->itemList; + while((ptr1=(wallet_Sublist *) XP_ListNextObject(list_ptr1))!=0) { + temp = ptr->item1->ToNewCString(); + fprintf(fp, "%s\n", temp); + } + } + delete temp; + fprintf(fp, "\n"); + } + + /* close the file */ + fclose(fp); +} + +/* + * Read contents of designated file into designated list + */ +void +wallet_ReadFromFile(char* filename, XP_List*& list, PlacementType placement = DUP_AFTER) { + FILE* fp = fopen(filename, "r"); + + if (nsnull==fp) { + return; + } + for (;;) { + nsAutoString * aItem1; + if (wallet_GetLine(fp, aItem1) == -1) { + /* end of file reached */ + fclose(fp); + return; + } + + nsAutoString * aItem2; + if (wallet_GetLine(fp, aItem2) == -1) { + /* unexpected end of file reached */ + delete aItem1; + fclose(fp); + return; + } + + nsAutoString * aItem3; + if (wallet_GetLine(fp, aItem3) == -1) { + /* end of file reached */ + XP_List* dummy = NULL; + wallet_WriteToList(*aItem1, *aItem2, dummy, list, placement); + fclose(fp); + return; + } + + if (aItem3->Length()==0) { + /* just a pair of values, no need for a sublist */ + XP_List* dummy = NULL; + wallet_WriteToList(*aItem1, *aItem2, dummy, list, placement); + } else { + /* need to create a sublist and put item2 and item3 onto it */ + XP_List * itemList = XP_ListNew(); + wallet_Sublist * sublist; + sublist = XP_NEW(wallet_Sublist); + sublist->item = new nsAutoString (*aItem2); + XP_ListAddObjectToEnd (itemList, sublist); + delete aItem2; + sublist = XP_NEW(wallet_Sublist); + sublist->item = new nsAutoString (*aItem3); + XP_ListAddObjectToEnd (itemList, sublist); + delete aItem3; + /* add any following items to sublist up to next blank line */ + nsAutoString * dummy2 = new nsAutoString(""); + for (;;) { + /* get next item for sublist */ + if (wallet_GetLine(fp, aItem3) == -1) { + /* end of file reached */ + wallet_WriteToList(*aItem1, *dummy2, itemList, list, placement); + fclose(fp); + return; + } + if (aItem3->Length()==0) { + /* blank line reached indicating end of sublist */ + wallet_WriteToList(*aItem1, *dummy2, itemList, list, placement); + break; + } + /* add item to sublist */ + sublist = XP_NEW(wallet_Sublist); + sublist->item = new nsAutoString (*aItem3); + XP_ListAddObjectToEnd (itemList, sublist); + delete aItem3; + } + } + } +} + +/***************************************************************/ +/* The following routines are for fetching data from NetCenter */ +/***************************************************************/ + +/* + * fetch URL-specific field/schema mapping from netcenter and put into local copy of file + * at URLFieldSchema.tbl + */ +void +wallet_FetchURLFieldSchemaFromNetCenter(nsAutoString urlName) { + FILE* fp_in = fopen("RawURLFieldSchema.tbl", "r"); + FILE* fp_out = fopen("URLFieldSchema.tbl", "w"); + PRUint32 count; + + if (nsnull==fp_in) { + return; + } + + nsAutoString * line; + + for (;;) { + + /* get next line */ + if (wallet_GetLine(fp_in, line) == -1) { + fflush(fp_out); + fclose(fp_out); + fclose(fp_in); + return; + } + + /* see if this is the url we want */ + urlName.ToLowerCase(); + line->ToLowerCase(); + if (line->Compare(urlName)==0) { + /* it is our url so write this group of lines to output file */ + delete line; + count = 0; + for (;;) { + /* get next line */ + if (wallet_GetLine(fp_in, line) == -1) { + fflush(fp_out); + fclose(fp_out); + fclose(fp_in); + return; + } + if (line->Length()==0) { + count++; + if (count==2) { + delete line; + fflush(fp_out); + fclose(fp_out); + fclose(fp_in); + return; + } + } else { + count = 0; + } + char * temp; + temp = line->ToNewCString(); + fprintf(fp_out, "%s\n", temp); + delete line; + delete temp; + } + } + + /* wrong URL, skip ahead to two blank lines */ + delete line; + count = 0; + for (;;) { + if (wallet_GetLine(fp_in, line) == -1) { + fflush(fp_out); + fclose(fp_out); + fclose(fp_in); + return; + } + if (line->Length()==0) { + count++; + } else { + count = 0; + } + delete line; + if (count==2) { + break; + } + } + } +} + +/* + * fetch generic field/schema mapping from netcenter and put into + * local copy of file at FieldSchema.tbl + */ +void +wallet_FetchFieldSchemaFromNetCenter() { +} + +/* + * fetch generic schema-concatenation rules from netcenter and put into + * local copy of file at SchemaConcat.tbl + */ +void +wallet_FetchSchemaConcatFromNetCenter() { +} + +/*********************************************************************/ +/* The following are utility routines for the main wallet processing */ +/*********************************************************************/ + +/* + * given a field name, get the value + */ +PRInt32 FieldToValue( + nsAutoString field, + nsAutoString& schema, + nsAutoString& value, + XP_List*& itemList, + XP_List*& resume) +{ + /* fetch schema name from field/schema tables */ + XP_List* FieldToSchema_list = wallet_FieldToSchema_list; + XP_List* URLFieldToSchema_list = wallet_URLFieldToSchema_list; + XP_List* SchemaToValue_list; + XP_List* dummy; + if (nsnull == resume) { + resume = wallet_SchemaToValue_list; + } + if ((wallet_ReadFromList(field, schema, dummy, URLFieldToSchema_list) != -1) || + (wallet_ReadFromList(field, schema, dummy, FieldToSchema_list) != -1)) { + /* schema name found, now fetch value from schema/value table */ + SchemaToValue_list = resume; + if (wallet_ReadFromList(schema, value, itemList, SchemaToValue_list) != -1) { + /* value found, prefill it into form */ + resume = SchemaToValue_list; + return 0; + } else { + /* value not found, see if concatenation rule exists */ + XP_List * itemList; + + XP_List * SchemaConcat_list = wallet_SchemaConcat_list; + nsAutoString dummy2; + if (wallet_ReadFromList(schema, dummy2, itemList, SchemaConcat_list) != -1) { + /* concatenation rules exist, generate value as a concatenation */ + XP_List * list_ptr1; + wallet_Sublist * ptr1; + list_ptr1 = itemList; + value = nsAutoString(""); + nsAutoString value2; + while((ptr1=(wallet_Sublist *) XP_ListNextObject(list_ptr1))!=0) { + SchemaToValue_list = wallet_SchemaToValue_list; + if (wallet_ReadFromList(*(ptr1->item), value2, dummy, SchemaToValue_list) != -1) { + if (value.Length()>0) { + value += " "; + } + value += value2; + } + } + resume = nsnull; + itemList = nsnull; + return 0; + } + } + } else { + /* schema name not found, use field name as schema name and fetch value */ + SchemaToValue_list = resume; + if (wallet_ReadFromList(field, value, itemList, SchemaToValue_list) != -1) { + /* value found, prefill it into form */ + resume = SchemaToValue_list; + return 0; + } + } + resume = nsnull; + return -1; +} + +PRInt32 +wallet_GetSelectIndex( + nsIDOMHTMLSelectElement* selectElement, + nsAutoString value, + PRInt32& index) +{ + nsresult result; + PRUint32 length; + selectElement->GetLength(&length); + nsIDOMHTMLCollection * options; + result = selectElement->GetOptions(&options); + if ((NS_OK == 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_OK == result) && (nsnull != optionElement)) { + nsAutoString optionValue; + nsAutoString optionText; + optionElement->GetValue(optionValue); + optionElement->GetText(optionText); + if (value==optionValue || value==optionText) { + index = optionX; + return 0; + } + NS_RELEASE(optionElement); + } + NS_RELEASE(optionNode); + } + } + NS_RELEASE(options); + } + return -1; +} + +PRInt32 +wallet_GetPrefills( + nsIDOMNode* elementNode, + nsIDOMHTMLInputElement*& inputElement, + nsIDOMHTMLSelectElement*& selectElement, + nsAutoString*& schemaPtr, + nsAutoString*& valuePtr, + PRInt32& selectIndex, + XP_List*& resume) +{ + nsresult result; + + /* get prefills for input element */ + result = elementNode->QueryInterface(kIDOMHTMLInputElementIID, (void**)&inputElement); + if ((NS_OK == result) && (nsnull != inputElement)) { + nsAutoString type; + result = inputElement->GetType(type); + if ((NS_OK == result) && ((type =="") || (type.Compare("text", PR_TRUE) == 0))) { + nsAutoString field; + result = inputElement->GetName(field); + if (NS_OK == result) { + nsAutoString schema; + nsAutoString value; + XP_List* itemList; + if (FieldToValue(field, schema, value, itemList, resume) == 0) { + if (value == "" && nsnull != itemList) { + /* pick first of a set of synonymous values */ + wallet_ReadFromSublist(value, itemList); + } + valuePtr = new nsAutoString(value); + schemaPtr = new nsAutoString(schema); + selectElement = nsnull; + selectIndex = -1; + return 0; + } + } + } + NS_RELEASE(inputElement); + return -1; + } + + /* get prefills for dropdown list */ + result = elementNode->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&selectElement); + if ((NS_OK == result) && (nsnull != selectElement)) { + nsAutoString field; + result = selectElement->GetName(field); + if (NS_OK == result) { + nsAutoString schema; + nsAutoString value; + XP_List* itemList; + if (FieldToValue(field, schema, value, itemList, resume) == 0) { + if (value != "") { + /* no synonym list, just one value to try */ + result = wallet_GetSelectIndex(selectElement, value, selectIndex); + if (-1 != result) { + /* value matched one of the values in the drop-down list */ + valuePtr = new nsAutoString(value); + schemaPtr = new nsAutoString(schema); + inputElement = nsnull; + return 0; + } + } else { + /* synonym list exists, try each value */ + while (wallet_ReadFromSublist(value, itemList) == 0) { + result = wallet_GetSelectIndex(selectElement, value, selectIndex); + if (-1 != result) { + /* value matched one of the values in the drop-down list */ + valuePtr = new nsAutoString(value); + schemaPtr = new nsAutoString(schema); + inputElement = nsnull; + return 0; + } + } + } + } + } + NS_RELEASE(selectElement); + } + return -1; +} + +/* + * initialization for wallet session (done only once) + */ +#define FIELD_SCHEMA_URL "file:///y|/xxx.html" +void +wallet_Initialize() { + static PRBool wallet_initialized = FALSE; + if (!wallet_initialized) { + +#ifdef experiment + wallet_Pause(); + nsINetService *inet = nsnull; + nsIURL * url; + if (!NS_FAILED(NS_NewURL(&url, FIELD_SCHEMA_URL))) { + nsresult rv = nsServiceManager::GetService(kNetServiceCID, + kINetServiceIID, + (nsISupports **)&inet); + if (rv != NS_OK) { + nsIInputStream* *aNewStream; + rv = inet->OpenBlockingStream(url, nsnull, aNewStream); + rv++; + } + nsServiceManager::ReleaseService(kNetServiceCID, inet); + } +#endif + + wallet_FetchFieldSchemaFromNetCenter(); + wallet_ReadFromFile("FieldSchema.tbl", wallet_FieldToSchema_list); + wallet_ReadFromFile("SchemaValue.tbl", wallet_SchemaToValue_list); + wallet_ReadFromFile("SchemaConcat.tbl", wallet_SchemaConcat_list); +#if DEBUG +// fprintf(stdout,"Field to Schema table \n"); +// wallet_Dump(wallet_FieldToSchema_list); +// fprintf(stdout,"Schema to Value table \n"); +// wallet_Dump(wallet_SchemaToValue_list); +// fprintf(stdout,"SchemaConcat table \n"); +// wallet_Dump(wallet_SchemaConcat_list); +#endif + wallet_initialized = TRUE; + } +} + +/* + * initialization for current URL + */ +void +wallet_InitializeCurrentURL(nsIDocument * doc) { + static nsIURL * lastUrl = NULL; + + /* get url */ + nsIURL* url; + url = doc->GetDocumentURL(); + if (lastUrl == url) { + NS_RELEASE(url); + return; + } else { + if (lastUrl) { +//?? NS_RELEASE(lastUrl); + } + lastUrl = url; + } + + /* get host+file */ + const char* host; + url->GetHost(&host); + nsAutoString urlName = nsAutoString(host); + const char* file; + url->GetFile(&file); + urlName = urlName + file; + NS_RELEASE(url); + + /* read in field/schema mapping specific to current url */ + wallet_Clear(&wallet_URLFieldToSchema_list); + wallet_FetchURLFieldSchemaFromNetCenter(urlName); + wallet_ReadFromFile("URLFieldSchema.tbl", wallet_URLFieldToSchema_list); +// wallet_Dump(wallet_URLFieldToSchema_list); +} + +#define SEPARATOR "#*%&" + +nsAutoString * +wallet_GetNextInString(char*& ptr) { + nsAutoString * result; + char * endptr; + endptr = PL_strstr(ptr, SEPARATOR); + if (!endptr) { + return NULL; + } + *endptr = '\0'; + result = new nsAutoString(ptr); + *endptr = SEPARATOR[0]; + ptr = endptr + PL_strlen(SEPARATOR); + return result; +} + +void +wallet_ReleasePrefillElementList(XP_List * wallet_PrefillElement_list) { + if (wallet_PrefillElement_list) { + wallet_PrefillElement * ptr; + XP_List * list_ptr = wallet_PrefillElement_list; + while((ptr = (wallet_PrefillElement *) XP_ListNextObject(list_ptr))!=0) { + if (ptr->inputElement) { + NS_RELEASE(ptr->inputElement); + } else { + NS_RELEASE(ptr->selectElement); + } + delete ptr->schema; + delete ptr->value; + XP_ListRemoveObject(wallet_PrefillElement_list, ptr); + list_ptr = wallet_PrefillElement_list; + delete ptr; + } + } +} + +PR_STATIC_CALLBACK(PRBool) +wallet_RequestToPrefillDone(XPDialogState* state, char** argv, int argc, + unsigned int button) { + if (button == XP_DIALOG_OK_BUTTON) { + char* listAsAscii; + char* fillins; + nsAutoString * next; + + /* get values that are in environment variables */ + fillins = XP_FindValueInArgs("fillins", argv, argc); + listAsAscii = XP_FindValueInArgs("list", argv, argc); + XP_List * list; + sscanf(listAsAscii, "%ld", &list); + + /* process the list, doing the fillins */ + + /* + * note: there are two lists involved here and we are stepping through both of them. + + * One is the pre-fill list that was generated when we walked through the html content. + * For each pre-fillable item, it contains n entries, one for each possible value that + * can be prefilled for that field. The first entry for each field can be identified + * because it has a non-zero count field (in fact, the count is the number of entries + * for that field), all subsequent entries for the same field have a zero count field. + + * The other is the fillin list which was generated by the html dialog that just + * finished. It contains one entry for each pre-fillable item specificying that + * particular value that should be prefilled for that item. + */ + + XP_List * list_ptr = list; + wallet_PrefillElement * ptr; + char * ptr2; + ptr2 = fillins; + /* step through pre-fill list */ + PRBool first = TRUE; + while((ptr = (wallet_PrefillElement *) XP_ListNextObject(list_ptr))!=0) { + /* advance in fillins list each time a new schema name in pre-fill list is encountered */ + if (ptr->count != 0) { + /* count != 0 indicates a new schema name */ + if (!first) { + delete next; + first = FALSE; + } + next = wallet_GetNextInString(ptr2); + if (nsnull == next) { + return PR_FALSE; + } + if (*next != *ptr->schema) { + delete next; + return PR_FALSE; /* something's wrong so stop prefilling */ + } + delete next; + next = wallet_GetNextInString(ptr2); + } + + if (*next == *ptr->value) { + /* + * Remove entry from wallet_SchemaToValue_list and then reinsert. This will + * keep multiple values in that list for the same field ordered with + * most-recently-used first. That's useful since the first such entry + * is the default value used for pre-filling. + */ + + /* + * Test for ptr->count being zero is an optimization that avoids us from doing a + * reordering if the current entry already was first + */ + if (ptr->resume && (ptr->count == 0)) { + wallet_MapElement * mapElement = (wallet_MapElement *) (ptr->resume->object); + XP_ListRemoveObject(wallet_SchemaToValue_list, mapElement); + wallet_WriteToList( + *(mapElement->item1), + *(mapElement->item2), + mapElement->itemList, + wallet_SchemaToValue_list); + } + } + + /* Change the value */ + + if ((*next == *ptr->value) || ((ptr->count>0) && (*next == ""))) { + if (((*next == *ptr->value) || (*next == "")) && ptr->inputElement) { + ptr->inputElement->SetValue(*next); + } else { + nsresult result; + result = wallet_GetSelectIndex(ptr->selectElement, *next, ptr->selectIndex); + if (-1 != result) { + ptr->selectElement->SetSelectedIndex(ptr->selectIndex); + } else { + ptr->selectElement->SetSelectedIndex(0); + } + } + } + } + delete next; + + /* Release the prefill list that was generated when we walked thru the html content */ + wallet_ReleasePrefillElementList(list); + } + + return PR_FALSE; +} + +static XPDialogInfo dialogInfo = { + 0, + wallet_RequestToPrefillDone, + 1000, + 1200 +}; + +void +wallet_RequestToPrefill(XP_List * list) { + char *buffer = (char*)XP_ALLOC(BUFLEN); + char *buffer2 = 0; + PRInt32 g = 0; + + XPDialogStrings* strings; + strings = XP_GetDialogStrings(16024); +//strings = XP_GetDialogStrings(XP_CERT_PAGE_STRINGS); /* why doesn't this link? */ + if (!strings) { + return; + } + + LocalStrAllocCopy(buffer2, ""); + + /* generate initial section of html file */ + g += PR_snprintf(buffer+g, BUFLEN-g, +"\n" +"\n" +" Pre-Filling\n" +" \n" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +"\n" +"\n" +"\n" +" <BODY> <BR> </BODY>\n" +"\n" +"\n", + list, SEPARATOR, SEPARATOR); + FLUSH_BUFFER + + /* free buffer since it is no longer needed */ + XP_FREEIF(buffer); + + /* put html just generated into strings->arg[0] and invoke HTML dialog */ + if (buffer2) { + XP_CopyDialogString(strings, 0, buffer2); + XP_FREE(buffer2); + buffer2 = NULL; + } + XP_MakeHTMLDialog(NULL, &dialogInfo, 0, strings, NULL, PR_FALSE); + return; +} + +#define WALLET_EDITOR_URL "file:///y|/walleted.html" +#define BREAK '\001' + +void +wallet_PostEdit() { + nsAutoString * nsCookie = new nsAutoString(""); + nsIURL* url; + char* separator; + + nsINetService *netservice; + nsresult res; + res = nsServiceManager::GetService(kNetServiceCID, + kINetServiceIID, + (nsISupports **)&netservice); + if ((NS_OK == res) && (nsnull != netservice)) { + const nsAutoString walletEditor = nsAutoString(WALLET_EDITOR_URL); + if (!NS_FAILED(NS_NewURL(&url, walletEditor))) { + res = netservice->GetCookieString(url, *nsCookie); + } + NS_RELEASE(netservice); + + /* convert cookie to a C string */ + char *cookies = nsCookie->ToNewCString(); + char *cookie = PL_strstr(cookies, "SchemaToValue="); /* get to SchemaToValue= */ + cookie = cookie + PL_strlen("SchemaToValue="); /* get passed htmldlgs=| */ + + /* return if OK button was not pressed */ + separator = strchr(cookie, BREAK); + *separator = '\0'; + if (strcmp(cookie, "OK")) { + *separator = BREAK; + delete cookies; + return; + } + cookie = separator+1; + *separator = BREAK; + + /* open SchemaValue file */ + FILE* fp = fopen("SchemaValue.tbl", "w"); + if (nsnull==fp) { + delete cookies; + return; + } + + /* write the values in the cookie to the file */ + for (int i=0; ((*cookie != '\0') && (*cookie != ';')); i++) { + separator = strchr(cookie, BREAK); + *separator = '\0'; + fprintf(fp, "%s\n", cookie); + cookie = separator+1; + *separator = BREAK; + } + + /* close the file and read it back into the SchemaToValue list */ + fclose(fp); + wallet_Clear(&wallet_SchemaToValue_list); + wallet_ReadFromFile("SchemaValue.tbl", wallet_SchemaToValue_list); + delete cookies; + } +} + +/***************************************************************/ +/* The following are the interface routines seen by other dlls */ +/***************************************************************/ + +/* + * edit the users data + */ +PUBLIC void +WLLT_PreEdit(nsIURL* url) { + + if (nsnull == url) { + wallet_PostEdit(); + return; + } + + nsINetService *netservice; + nsresult res; + res = nsServiceManager::GetService(kNetServiceCID, + kINetServiceIID, + (nsISupports **)&netservice); + if ((NS_OK == res) && (nsnull != netservice)) { + wallet_Initialize(); + nsAutoString * cookie = new nsAutoString("SchemaToValue="); + *cookie += BREAK; + XP_List * list_ptr; + wallet_MapElement * ptr; + list_ptr = wallet_SchemaToValue_list; + + while((ptr = (wallet_MapElement *) XP_ListNextObject(list_ptr))!=0) { + *cookie += *(ptr->item1) + BREAK; + if (*ptr->item2 != "") { + *cookie += *(ptr->item2) + BREAK; + } else { + XP_List * list_ptr1; + wallet_Sublist * ptr1; + list_ptr1 = ptr->itemList; + while((ptr1=(wallet_Sublist *) XP_ListNextObject(list_ptr1))!=0) { + *cookie += *(ptr1->item) + BREAK; + } + } + *cookie += BREAK; + } + res = netservice->SetCookieString(url, *cookie); + delete cookie; + NS_RELEASE(netservice); + } +} + +/* + * get the form elements on the current page and prefill them if possible + */ +PUBLIC void +WLLT_Prefill(nsIPresShell* shell, PRBool quick) { + +#ifndef HTMLDialogs + if (!shell) { + XP_MakeHTMLDialog2(&dialogInfo); + return; + } +#endif + + /* create list of elements that can be prefilled */ + XP_List *wallet_PrefillElement_list=XP_ListNew(); + if (!wallet_PrefillElement_list) { + return; + } + + /* starting with the present shell, get each form element and put them on a list */ + if (nsnull != shell) { + nsIDocument* doc = nsnull; + if (shell->GetDocument(&doc) == NS_OK) { +// doc = shell->GetDocument(); +// if (nsnull != doc) { + wallet_InitializeCurrentURL(doc); + nsIDOMHTMLDocument* htmldoc = nsnull; + nsresult result = doc->QueryInterface(kIDOMHTMLDocumentIID, (void**)&htmldoc); + if ((NS_OK == result) && (nsnull != htmldoc)) { + nsIDOMHTMLCollection* forms = nsnull; + htmldoc->GetForms(&forms); + if (nsnull != forms) { + PRUint32 numForms; + forms->GetLength(&numForms); + for (PRUint32 formX = 0; formX < numForms; formX++) { + nsIDOMNode* formNode = nsnull; + forms->Item(formX, &formNode); + if (nsnull != formNode) { + nsIDOMHTMLFormElement* formElement = nsnull; + result = formNode->QueryInterface(kIDOMHTMLFormElementIID, (void**)&formElement); + if ((NS_OK == result) && (nsnull != formElement)) { + nsIDOMHTMLCollection* elements = nsnull; + result = formElement->GetElements(&elements); + if ((NS_OK == result) && (nsnull != elements)) { + /* got to the form elements at long last */ + wallet_Initialize(); + PRUint32 numElements; + elements->GetLength(&numElements); + for (PRUint32 elementX = 0; elementX < numElements; elementX++) { + nsIDOMNode* elementNode = nsnull; + elements->Item(elementX, &elementNode); + if (nsnull != elementNode) { + wallet_PrefillElement * prefillElement; + XP_List * resume = nsnull; + wallet_PrefillElement * firstElement = nsnull; + PRUint32 numberOfElements = 0; + for (;;) { + /* loop to allow for multiple values */ + /* first element in multiple-value group will have its count + * field set to the number of elements in group. All other + * elements in group will have count field set to 0 + */ + prefillElement = XP_NEW(wallet_PrefillElement); + if (wallet_GetPrefills + (elementNode, + prefillElement->inputElement, + prefillElement->selectElement, + prefillElement->schema, + prefillElement->value, + prefillElement->selectIndex, + resume) != -1) { + /* another value found */ + prefillElement->resume = resume; + if (nsnull == firstElement) { + firstElement = prefillElement; + } + numberOfElements++; + prefillElement->count = 0; + XP_ListAddObjectToEnd(wallet_PrefillElement_list, prefillElement); + if (nsnull == resume) { + /* value was found from concat rules, can't resume from here */ + break; + } + } else { + /* value not found, stop looking for more values */ + delete prefillElement; + break; + } + } + if (numberOfElements>0) { + firstElement->count = numberOfElements; + } + NS_RELEASE(elementNode); + } + } + NS_RELEASE(elements); + } + NS_RELEASE(formElement); + } + NS_RELEASE(formNode); + } + } + NS_RELEASE(forms); + } + NS_RELEASE(htmldoc); + } + NS_RELEASE(doc); + } + NS_RELEASE(shell); + } + + /* return if no elements were put into the list */ + if (!XP_ListCount(wallet_PrefillElement_list)) { + return; + } + + /* prefill each element using the list */ + if (wallet_PrefillElement_list) { + if (quick) { + /* prefill each element without any user verification */ + XP_List * list_ptr = wallet_PrefillElement_list; + wallet_PrefillElement * ptr; + while((ptr = (wallet_PrefillElement *) XP_ListNextObject(list_ptr))!=0) { + if (ptr->count) { + if (ptr->inputElement) { + ptr->inputElement->SetValue(*(ptr->value)); + } else { + ptr->selectElement->SetSelectedIndex(ptr->selectIndex); + } + } + } + /* go thru list just generated and release everything */ + wallet_ReleasePrefillElementList(wallet_PrefillElement_list); + } else { + /* let user verify the prefills first */ + wallet_RequestToPrefill(wallet_PrefillElement_list); + } + } +#ifdef DEBUG +wallet_DumpStopwatch(); +wallet_ClearStopwatch(); +#endif +//wallet_DumpTiming(); +//wallet_ClearTiming(); +} + +/* + * see if user wants to capture data on current page + */ + +/* this routine is temporary -- will be replaced with real dialog box when available */ +PRBool FE_Confirm(char * szMessage) { + fprintf(stdout, "%c%s (y/n)? ", '\007', szMessage); /* \007 is BELL */ + char c; + for (;;) { + c = getchar(); + if (tolower(c) == 'y') { + return JS_TRUE; + } + if (tolower(c) == 'n') { + return JS_FALSE; + } + } +} + +PUBLIC void +WLLT_OKToCapture(PRBool * result, PRInt32 count, char* URLName) { + *result = + (strcmp(URLName, WALLET_EDITOR_URL)) && + (count>=3) && FE_Confirm("Do you want to put the values on this form into your wallet?"); +} + +/* + * capture the value of a form element + */ +PUBLIC void +WLLT_Capture(nsIDocument* doc, nsString field, nsString value) { + + /* do nothing if there is no value */ + if (!value.Length()) { + return; + } + + /* read in the mappings if they are not already present */ + wallet_Initialize(); + wallet_InitializeCurrentURL(doc); + + nsAutoString oldValue; + + /* is there a mapping from this field name to a schema name */ + nsAutoString schema; + XP_List* FieldToSchema_list = wallet_FieldToSchema_list; + XP_List* URLFieldToSchema_list = wallet_URLFieldToSchema_list; + XP_List* SchemaToValue_list = wallet_SchemaToValue_list; + XP_List* dummy; + + if ((wallet_ReadFromList(field, schema, dummy, URLFieldToSchema_list) != -1) || + (wallet_ReadFromList(field, schema, dummy, FieldToSchema_list) != -1)) { + + /* field to schema mapping already exists */ + + /* is this a new value for the schema */ + if ((wallet_ReadFromList(schema, oldValue, dummy, SchemaToValue_list)==-1) || + (oldValue != value)) { + + /* this is a new value so store it */ + nsAutoString * aValue = new nsAutoString(value); + nsAutoString * aSchema = new nsAutoString(schema); + dummy = 0; + wallet_WriteToList(*aSchema, *aValue, dummy, wallet_SchemaToValue_list); + wallet_WriteToFile("SchemaValue.tbl", wallet_SchemaToValue_list); + } + } else { + + /* no field to schema mapping so assume schema name is same as field name */ + + /* is this a new value for the schema */ + if ((wallet_ReadFromList(field, oldValue, dummy, SchemaToValue_list)==-1) || + (oldValue != value)) { + + /* this is a new value so store it */ + nsAutoString * aField = new nsAutoString(field); + nsAutoString * aValue = new nsAutoString(value); + dummy = 0; + wallet_WriteToList(*aField, *aValue, dummy, wallet_SchemaToValue_list); + wallet_WriteToFile("SchemaValue.tbl", wallet_SchemaToValue_list); + } + } +}