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"
+ );
+ 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"
+"
\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);
+ }
+ }
+}